🎼Music Recognition🎼

Let’s find your favorite song with Nousifyn!!

Nonthapan
6 min readJun 21, 2022
Ref : https://www.pinterest.com/pin/455848793542063037/
Ref: https://www.pinterest.com/pin/455848793542063037/

— — — มาลองตามหาเพลงที่เพื่อนๆชอบ ด้วยการร้องเพลงกันครับบ!! — — —

สวัสดีครับผม นน วันนี้ผมจะมาแชร์ความรู้เกี่ยวกับโครงงานที่ผมเลือกทำขึ้นมา ในค่ายของ Ai Builders กันครับ

Part : (Problem statement)

เกริ่นในส่วนของปัญหา (Problem statement) ที่ผมเลือกจะนำมาแก้ไขกันก่อนดีกว่าครับ คือ…..ผมเป็นคนที่ชอบฟังเพลงครับ🎶 แต่บางทีผมมักจะนึกชื่อเพลงไม่ออก จำได้แต่เนื้อเพลงบางท่อน หรือแม้กระทั่งเวลาไปคาเฟ่☕ที่เปิดเพลงเพราะๆ ผมก็มักจะไม่รู้ครับว่าเพลงนั้นเป็นเพลงอะไร (ขี้อายครับไม่กล้าถามพนักงาน🥲)

โดยในการทำโครงงานครั้งนี้ก็ได้แรงบันดาลใจมาจากการไปเล่น Application Song Finder ต่างๆ e.g.[Shazam, SoundHound]🎸 แล้วก็อยากมีเป็นของตัวเองบ้าง อยากรู้หลักการทำงานของมันครับ

Let’s go!

✦ โดยเริ่มแรกผมก็ต้องปรึกษากับพี่ๆ Mentor ทั้ง 2 คนของผมก่อนครับและได้ข้อสรุปมาว่าสิ่งที่ผมกำลังจะทำนั้นอยู่ใน Task ของ ASR automatic speech recognition ครับ หรือก็คือการเปลี่ยนเสียงเป็นข้อความนั่นเอง

✦ เอาหล่ะเมื่อรู้เป้าหมายของตัวเองแล้วผมก็ลองไปศึกษา ลองผิดลองถูก(มั่ว)👽 ว่ามันเป็นยังไงกันแน่นะไอ้ ASR เนี่ย จนได้ไปพบกับ Fine-tuning XLS-R for Multi-Lingual ASR with 🤗 Transformers บทความที่สอนการ Finetune model Wav2Wec2 ครับ เพื่อให้ได้ Model Speech to text ที่สามารถแปลงเสียงพูดภาษาไทยเป็นข้อความได้ ไม่รอช้าผมก็ลองเล่นเลยครับ ผลลัพธ์ที่ออกมาถือว่าเกินคาดด้วย WER : Word Eror Rate ที่ 80%!

สีหน้าพี่ปิงกับพี่ทอย TJ

✦ เมื่อนำไปบอกพี่ๆ Mentor ทั้ง 2 ก็ถึงกับกุมขมับและบอกว่าเราจะทำ Speech to text ภาษาไทยขึ้นมาเองทำไมหล่ะะะ ในเมื่อเรามีของดีอยู่แล้วนั่นก็คืออออ…!

🎊 airesearch/wav2vec2-large-xlsr-53-th 🎊 เป็นโมเดลถอดความจากเสียงพูดภาษาไทยที่มีความแม่นยำ ทัดเทียมผู้นำตลาดอย่าง Microsoft, Google, Amazon ….และนี่แหละครับจะเป็น ♛ BASELINE ♛ ของผม

เอาหล่ะเริ่มใหม่ เป้าหมายในครั้งนี้คือการทำให้โมเดลของ Ai research ให้สามารถฟังเสียงร้องเพลงสุดแสบแก้วหู ของผมได้ 💀

เรามาวิเคราะห์ข้อมูลที่เราต้องเก็บกันก่อนดีกว่า

Part : (data collection and cleaning)

♠︎ Model airesearch/wav2vec2-large-xlsr-53-th สามารถทำได้ดีมากใน Task อย่าง Speech to text แต่ยังให้ผลไม่ดีเท่าที่ควรใน Task ของ Sing to text ครับ

*หมายเหตุ ตัวสีแดงไม่ใช่คำที่ ML predict ผิด และนี่เป็นการเก็บข้อมูลคร่าวๆเท่านั้นนะคร้าบบ

ฟังเสียงที่ใช้สำหรับการทดสอบได้ที่นี่เลยย ☛ Here

🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼🐼

♣︎ การที่จะทำให้ Model ข้างต้นเก่งขึ้นมาบน Task ของ Sing to text ได้ก็จำเป็นจะต้อง Train บน Data ที่เป็นเสียงร้องครับ🎤

✦ จะให้เก็บ Data ด้วยการร้องเองก็คงไม่ไหว ….Data ที่ผมเลือกก็เลยเป็นเพลงบน Youtube จำนวน 40เพลง🎵ความยาวประมาณ 2 ชั่วโมงครึ่งครับ โดยที่

✦ หลังจากเราได้เพลง.mp3มาแล้วก็ต้องเตรียมเนื้อเพลงไว้📋 เพื่อใช้ในการ Lebel ด้วยครับ

ตัวอย่างข้อมูล

✦ ต่อไปเราก็ต้องตัดเสียง Background Music ออกครับ✂️ เพราะนอกจากจะเป็นข้อมูลเสียงที่เราก็ไม่ได้ต้องการแล้ว มันยังจะทำให้เกิด Noise เป็นจำนวนมาก บางที Model ของเราอาจเข้าใจผิดคิดว่า เสียงดนตรี ☛ เป็นเสียงพูดครับ

✦ หลังจากนี้ก็เข้าสู่ช่วงนรกดีๆ🔥 นี่แหละครับ เราต้องตัดเนื้อเพลงแบ่งออกมาเป็นท่อนๆ เพราะว่าข้อมูลเสียงของเรามันยาวเกินไปครับ เฉลี่ยอยู่ที่ 3–4 นาที

ถ้าเทียบกับเสียงที่ใช้เทรนบน airesearch/wav2vec2-large-xlsr-53-th นั้นมีความยาวอยู่ที่ 2 –6 วินาที เท่านั้นเอง

https://medium.com/airesearch-in-th/airesearch-in-th-3c1019a99cd

🛠️ เครื่องมือที่ผมใช้แบ่งเนื้อร้องก็จะเป็น Adobe Audition ครับ

Versionทดลองนะอิอิ

🖐แต่ช้าก่อนอนาคิน ไม่ใช่ว่าแค่ตัดเสียงเป็นท่อนๆ แล้วจะได้เลย เราต้องคอยจัดการกับเพลงบางเพลงที่มี เนื้อร้องบางท่อนเป็นภาษาอังกฤษด้วย ก็ตัดมันออกซะะะ ✂️

! หรือจะเป็นเครื่องหมายบางเครื่องหมายเช่น จนผ่านวันร้ายๆจนผ่านวันร้ายร้าย

import re
chars_to_ignore_regex = '[\,\'\.\ๆ\-\;\:\"]'
def remove_special_characters(batch):
batch["sentence"] = re.sub(chars_to_ignore_regex, '', batch["sentence"]).lower() + " "
return batch

datasets = datasets.map(remove_special_characters)

! หรือจะเป็นเรื่องของเสียงคอรัส (เสียงประสานที่มีคนร้องพร้อมกัน)👨‍👩‍👧‍👦 คือถ้ามันร้องประโยคเดียวกันก็พอได้ครับ แต่บางทีมันร้องคนละประโยคซ้อนกันมาเลยนี่สิ

🤯 อีกทั้งเสียงร้องบางช่วงที่มี โทนเสียงใกล้เคียงกับเครื่องดนตรี จนเครื่องมือที่ผมใช้ตัด Background Music นั้นผิดพลาด และยำรวมเสียงดนตรีกับเสียงร้องเละเทะไปหมด เราก็ต้องตัดท่อนนั้นออกไปครับ✌🏼

หลังจากบุกตะลุยทุบตีกับข้อมูลเป็นที่เรียบร้อยแล้วสิ่งที่เราจะได้มาก็คือ

✦ ไฟล์เสียงที่ถูกทำความสะอาดอย่างมีคุณภาพพร้อมใช้งาน📁

✦ กับเนื้อเพลงที่ตรงกับไฟล์เสียงนั้น📜

📩 เราจะจัดเก็บข้อมูลในรูปแบบเดียวกันกับที่ Ai research จัดเก็บเพื่อให้ง่ายต่อการใช้งาน นั่นคือการแบ่ง Colum path ➜ เก็บชื่อของไฟล์เสียง Sentence ➜ เก็บข้อความที่ตรงกับเสียงนั้นๆ

หลังจากนั้นไม่รอช้า Shuffle และแบ่ง Train Valid Test ซะ

#shuffle
import pandas as pd
import numpy as np
df = pd.read_csv(‘all.csv’)
df = df.sample(frac=1).reset_index(drop=True)
df.to_csv(‘Sufflepath.csv’, index=False)

✦ โดยที่ผมแบ่ง Train Valid Test ที่ 80 : 10 : 10 ครับ เท่านี้ก็พร้อมใช้งานแล้วว

เอาหล่ะหลังจากที่เก็บข้อมูลและ ทำความสะอาดมาแล้ว ก็มาทำความเข้าใจกับข้อมูลของเรากันหน่อยย

Part : (exploratory data analysis)🤔🔎

เนื่องจาก Data ที่เราเก็บมามีแต่เสียงจากนักร้องระดับ Top กันทั้งนั้นเลย

✦ คนพวกนี้มีการฝึกฝนที่มากกว่าคนธรรมดาอย่างพวกเราครับ ทั้งเทคนิคในการหายใจ การเข้าถึงจังหว่ะ Metronome สามารถร้องเสียงคีย์สูงต่ำได้อย่างลื่นไหล ลูกคอ การเอื้อนนี่มาเต็ม !

✦ เมื่อ Model ถูกเทรนแค่บนเสียงจำพวกนี้ทำให้มีแนวโน้มว่า มันจะจับเสียงได้แค่คนที่ร้องเพลงเพราะเท่านั้นครับ (มันอาจไม่เข้าใจเสียงร้องของผม🥲)

✦ เพราะฉะนั้น ถ้าเราอยากจะทำให้โมเดลเข้าใจเสียง ในระดับที่เป็นมิตรกับคนที่ร้องเพลงเป็น และคนธรรมดาอย่างผม ก็ต้องเลือกปรับ Parameter ให้เหมาะสมด้วยครับ

✦ จากการวิเคราะห์ในครั้งนี้ทำให้ผมเห็นว่า Data ที่ผมมีนั้น มันเอาไปต่อยอดทำอะไรได้มากกว่านี้!! เกิดเป็น Idea ในการทำ Project ต่อไป ในการทำเครื่องมือตรวจสอบว่าคุณ….เป็นนักร้องเสียงเพี้ยนรึเปล่าา?!💡ด้วย Logic ง่ายๆที่ว่า ถ้า Model ของผมสามารถเข้าใจเสียงของเพื่อนๆได้ ก็แสดงว่าเพื่อนๆก็น่าจะร้องเพลงเพราะ — พอตัวหล่ะน้าาาา🎙

ไว้ถ้ามีโอกาสได้ลองทำ จะมาแชร์แบ่งปันความรู้แบบนี้อีกนะครับบ

เอาหล่ะหลังจากได้ทำความเข้าใจกับข้อมูลไปคร่าวๆ ก็ถึงเวลาในการเทรนแล้วครับบ

Part : (modeling, validation and error analysis)

เราจะ Train บน Wav2Wec2แล้ว……Wav2Wec2 คืออะไรหล่ะ ?

✦ Wav2Vec2 เป็น pretrained model สำหรับ Automatic Speech Recognition (ASR) ซึ่งผ่านการเทรนกับข้อมูลเสียง กว่า 50,000 ชั่วโมง!!😮 ที่ไม่มี label (unlabeled speech) คล้ายกับการเรียนของ BERT’s masked language modeling โดยที่ Wav2Vec2 จะเรียน contextualized speech representations โดยการสุ่ม mask feature vectors ก่อนที่จะผ่านเข้า transformer network ครับ

✦ ต้องขอบคุณเทคนิคที่มีชื่อว่า Tranfer learning ครับที่ทำให้เราไม่ต้องไปหาข้อมูลกว่า 50,000 ชั่วโมงมา ประหยัดทั้ง คลังข้อมูล🗂️ เวลา🕙 และทรัพยากร 🦾 ในการทำให้โมเดลได้ผลลัพธ์แบบที่เราต้องการ ด้วยการนำบางส่วนของโมเดลที่เทรนเรียบร้อยแล้ว กับงานที่ใกล้เคียงกัน มาใช้เป็นส่วนหนึ่งของโมเดลใหม่👨‍💻 🔧

เอาหล่ะก่อนอื่นเรามาเชค GPU ใน Colabของเรากันก่อนดีกว่าา !nvidia-smi

✦ เพื่อความรวดเร็วในการเทรนแนะนำให้ใช้ T4 หรือ P100 ครับ ส่วนวิธีที่จะได้มาถ้าไม่อยากเสียเงินก็…..สุ่มกาชาเอาครับ 🎲 5555555 (Restart Run Time วนไป)

จากนั้นผมแนะนำให้ Login Huggingface🤗 ให้เรียบร้อยยย เราจะได้ Upload Checkpoint ของ Model ไปที่ 🤗Hub กันครับ

!pip install huggingface_hub
from huggingface_hub import notebook_login
notebook_login()

Install Library 📚

!pip install torch==1.9.0+cu111 
!pip install torchvision==0.10.0+cu111
!pip install torchaudio==0.9.0
!pip install datasets==1.11.0
!pip install transformers==4.9.1
!pip install jiwer
!pip install pythainlp

Import Library📗📕 📘

import pandas as pd
import numpy as np
import torch
import torchaudio
from datasets import (
load_dataset,
load_from_disk,
load_metric,)
from transformers import (
Wav2Vec2CTCTokenizer,
Wav2Vec2FeatureExtractor,
Wav2Vec2Processor,
Wav2Vec2ForCTC,
TrainingArguments,
Trainer,)
from pythainlp.tokenize import word_tokenize

ก่อนที่จะส่งข้อมูลให้ Model เราจะต้องจัดการรูปแบบของข้อมูล ให้อยู่ในรูปแบบที่คอมพิวเตอร์เข้าใจกันก่อนครับ

✦ เริ่มที่การตัดคำกันก่อนภาษาไทยจำเป็นต้องมีการตัดคำเนื่องจากไม่มีการเว้นช่องไฟแบบ ภาษาอังกฤษครับ เช่น ผมชอบฟังเพลง กับ I love Music เราจะตัดคำโดยใช้ Libary ของ pythainlp ครับ

Example

word = word_tokenize(“ผมชอบฟังเพลง”)
print(word)

ผลลัพธ์ที่ออกมาก็จะเป็น List ของคำที่แบ่งออกมาได้จำนวน 4คำ 🤟🏼

[ ‘ผม’ , ’ชอบ’, ’ฟัง’ , ’เพลง’ ]

ตัดคำโลดดดดดด ⚔️

def preprocess_data(example, tok_func = word_tokenize):
example['sentence'] = ' '.join(tok_func(example['sentence']))
return example
datasets = datasets.map(preprocess_data)

✦ เมื่อแบ่งคำออกมาได้แล้วก็นำคำเหล่านั้น ไปแปลงเป็นตัวเลขที่คอมพิวเตอร์จะเข้าใจได้ด้วย Connectionist Temporal Classification (CTC) Tokenizer เป็นการ encode ระดับตัวอักษรครับ

tokenizer = Wav2Vec2CTCTokenizer.from_pretrained(
“airesearch/wav2vec2-large-xlsr-53-th”)

✦ เมื่อกี้เราแปลงตัวอักษรเป็นเลขไปแล้ว มาถึงเสียงบ้าง 🔊 ในที่นี้เราจะสกัดเอา Feature ต่างๆของเสียงออกมาครับ

feature_extractor = Wav2Vec2FeatureExtractor(feature_size=1, 
sampling_rate=16000,
padding_value=0.0,
do_normalize=True,
return_attention_mask=False)

⭐ เอามารวมกันก็จะได้ Processer สุดแจ๋วครับบบ ⭐

processor = Wav2Vec2Processor(
feature_extractor=feature_extractor, tokenizer=tokenizer
)

WER : Word Error Rate 💻

แล้วเราจะรู้ได้ยังไงหล่ะว่าโมเดลของเราทำงานได้ดีรึเปล่าา ?

ตัววัดของเราก็คืออ Metric : Word Error Rate นั่นเองง

♠︎ ยาว N คำ
♣︎ คำที่ถูกแทรกขึ้นมาจากข้อความเดิม I คำ (inserted words)
♥︎ คำที่หายไปจากข้อความเดิม D คำ (deleted words)
♦︎ คำที่ถูกแทนที่ไปจากคำเดิม S คำ (substituted words)

ตัวอย่างการใช้งาน

wer_metric = load_metric(“wer”)
pred= ['วันนี้ ฟาง เพลง อะไร ']
ref = ['วันนี้ ฟัง เพลง อะไร ดี'])
wer_metric.compute(predictions=pred,references=ref)

จากตัวอย่างก็จะได้ WER ที่ : 0.4 หรือ 40 % ครับ ⚙️

มาถึงส่วนของการ Train แล้วครับ

✦ เริ่ม Fine-Tune โมเดล airesearch/wav2vec2-large-xlsr-53-th กัน

model = Wav2Vec2ForCTC.from_pretrained(
"airesearch/wav2vec2-large-xlsr-53-th",
attention_dropout=0.1,
hidden_dropout=0.1,
feat_proj_dropout=0.0,
mask_time_prob=0.05,
layerdrop=0.1,
gradient_checkpointing=True,
ctc_loss_reduction="mean",
pad_token_id=processor.tokenizer.pad_token_id,
)

✦ เพื่อที่จะตั้งค่า TrainingArguments…..นี่เป็น Parameter ที่ผมปรับครับ อย่างเช่น :

num_train_epochs=50 : เทรนจำนวน 50 ครั้ง 🦾

learning_rate=2e-4 : และในแต่ละ Stepของการเทรน เราจะปรับ Weight ของ — — — — — — — — — — — Neural Network มากน้อยแค่ไหน

training_args = TrainingArguments(
output_dir="path",
group_by_length=True,
push_to_hub=True,
fp16=True,
per_device_train_batch_size=24,
gradient_accumulation_steps=1,
per_device_eval_batch_size=12,
metric_for_best_model='wer',
evaluation_strategy="steps",
eval_steps=50,
logging_strategy="steps",
logging_steps=50,
save_strategy="steps",
save_steps=40,
num_train_epochs=50,
learning_rate=2e-4,
warmup_steps=500,
save_total_limit=2,
report_to="tensorboard"
)

เตรียมทุกอย่างพร้อมแล้ว ก็จับมัดรวมกัน 🪢 และเริ่มเทรนได้เลยย

trainer = Trainer(model=model,
data_collator=data_collator,
args=training_args,
compute_metrics=partial(compute_metrics,
metric=wer_metric,
processor=processor),
train_dataset=prepared_datasets[“train”],
eval_dataset=prepared_datasets[“validation”],
tokenizer=processor.feature_extractor,
)
trainer.train()
*Train

เสร็จแล้วเรามาทดสอบโมเดลของเรากัน

เราจะเทียบโมเดลของเรากับ Baseline(airesearch/wav2vec2-large-xlsr-53-th) โดยใช้ WER เป็นตัวตัดสินครับบ

และนี่ก็คือผลที่ได้ จะเห็นได้ว่าการ Fine-Tune เพียงไม่กี่ Epocs ใน Data sets ที่เราใส่ใจทำ ก็ช่วยให้ Model นั้นเก่งขึ้นแบบก้าวกระโดดได้

ซึ่งเราลด WER : Word Error Rate ไปได้ถึง 40 % !!

และในที่สุดเราก็ได้ Model ที่สามารถที่จะทนฟังผมร้องเพลงได้!!

Deployment

ผมเลือกใช้ open-source framework ที่เป็นที่นิยมอย่างอย่าง Streamlit ในการ Deploy machine learning ของผมในรูปแบบ Web application ครับ

ในส่วนนี้จะมีการนำเข้าข้อมูลในรูปแบบเสียง และได้ผลลัพธ์ออกมาเป็นเพลงบนแพลตฟอร์มของ Youtube ครับ

Source code: https://github.com/Nonnyss/Ms-Wav2Vec2-Finetune

ขอบคุณที่นั่งอ่านกันจนจบนะครับหวังว่าบทความนี้จะเป็นประโยชน์ให้กับใครอีกหลายๆคนที่สนใจหรือ กำลังศึกษาเรื่อง Ai ครับ

--

--