ระบบการแยกแยะชนิดของเพลง โดยใช้ Machine Learning
Tags: machinelearning, python, ai
Published: 2024-04-14 17:20:41

เพลงในโลกของเรานั้นมีหลากหลายแนวด้วยกัน ไม่ว่าจะเป็นป๊อปที่หลายคนคุ้นหู หรือแนวเพลงร็อคที่เร้าใจและทำให้คุณได้โยกหัว เพลงทุกแนวนั้นเป็นศิลปะ ที่บอกถึงเรื่องราวของตัวเอง และความรู้สึกผ่านตัวโน้ตและจังหวะ

ในบทความนี้ เราต้องการสร้างโมเดลที่จำแนกประเภทของเพลงต่างๆ ได้โดย ซึ่งเราต้องการรู้ว่าตัวโมเดลจะสามารถจำแนกประเภทตัวอย่างเพลงที่ถูกป้อนเข้าให้ได้ถูกต้องและแม่นยำหรือเปล่า

โดยทั้งหมดนี้เราจะใช้ Machine Learning กับโค้ดภาษา Python และทำใน Google Colab

ก่อนอื่น ดาวน์โหลดไฟล์นี้ หรือนำเข้า Google Drive [ไฟล์](https://drive.google.com/drive/folders/189jIlfQ-E94eHfKVksbAUSXKX68Ju1GI)

## ขั้นตอนการทำงาน

ขั้นตอนที่ 1: นำเข้า Libraries และ Dataset
Libraries ที่นำเข้านั้นประกอบไปด้วย Pandas สำหรับนำเข้า dataset, Matplotlib และ Seaborn สำหรับการแสดงข้อมูลออกเป็นภาพ, Numpy สำหรับการ scaling และ correlation และ Librosa สำหรับการแสดงข้อมูลเสียงให้เป็นภาพ

```
import numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt 
import seaborn as sns 
import librosa.display
```
จากนั้นจึงนำเข้าไฟล์ ‘file.csv’ ที่ได้ดาวน์โหลดไว้

```
music_data = pd.read_csv('file.csv') 
music_data.head(5)
```
Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3i799d2d1plsv65env1n.png)

---

ขั้นตอนที่ 2: วิเคราะห์ข้อมูลที่นำเข้ามา

ขั้นตอนนี้เป็นการเช็คว่าข้อมูลที่เราได้มานั้น มีอะไรบ้าง มีลักษณะเป็นอย่างไร

เช่นหาว่าแต่ละ label มีกี่อัน

```
music_data['label'].value_counts()
```

Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv6ytys4g7nq7dh47btl.png)

จาก Output พบว่าเราได้มีการใส่เพลงในแต่ละประเภททั้งหมด 100 อัน

หรือวิเคราะห์เพลงในไฟล์ว่ามีรูปแบบอย่างไร ในตัวอย่างนี้เราจะให้วิเคราะห์หมวดหมู่ Disco โดยใช้ไฟล์เสียง disco.00001.wav

```
path = 'drive/MyDrive/genres_original/disco/disco.00001.wav'
plt.figure(figsize=(14, 5)) 
x, sr = librosa.load(path) 
librosa.display.waveshow(x, sr=sr) 
  
print("Disco")
```
Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ws6suv9emi1wcvrkmz3w.png)

วิเคราะห์เพลงหมวดหมู่ Jazz โดยใช้ไฟล์เสียง jazz.00001.wav

```
path = 'drive/MyDrive/genres_original/jazz/jazz.00001.wav'
plt.figure(figsize=(14, 5)) 
x, sr = librosa.load(path) 
librosa.display.waveshow(x, sr=sr) 
  
print("Jazz")
```
Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpxbegl5w8vwaux9kyzg.png)


---

ขั้นตอนที่ 3: ประมวลผลข้อมูล

เพื่อให้การทำงานของตัวโมเดลแยกแนวเพลงนั้นทำงานได้ เราจำเป็นต้องแปลงข้อมูล labels ให้เป็น integer โดยใช้ LabelEncoder()
```
from sklearn import preprocessing 
label_encoder = preprocessing.LabelEncoder() 
music_data['label'] = label_encoder.fit_transform(music_data['label'])

```

เพื่อความถูกต้อง และเพื่อให้ตัวโมเดลทำงานได้เร็ว ไม่ช้าเกินไปเพราะขนาดของข้อมูล เราจึง drop คอลัมน์ filename ออก และปรับขนาดข้อมูล
```
X = music_data.drop(['label','filename'],axis=1) 
y = music_data['label']
cols = X.columns 
minmax = preprocessing.MinMaxScaler() 
np_scaled = minmax.fit_transform(X) 

# new data frame with the new scaled data. 
X = pd.DataFrame(np_scaled, columns = cols)
```

---

ขั้นตอนที่ 4: ฝึกโมเดล

เริ่มด้วยการแยกตัวโมเดลด้วย train_test_split
```
from sklearn.model_selection import train_test_split 

X_train, X_test, y_train, y_test = train_test_split(X, y, 
													test_size=0.3, 
													random_state=111) 
X_train.shape, X_test.shape, y_train.shape, y_test.shape
```

เมื่อทำการแยกตัวโมเดลเรียบร้อย เราต้องการที่จะทดสอบตัวจำแนกประเภทด้วย 5 โมเดลนี้ประกอบไปด้วย KNeighborsClassifier, Decision Tree Classifier, Random Forest, Logistics Regression, Cat Boost, Gradient Boost
```
from sklearn.metrics import accuracy_score 
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.tree import DecisionTreeClassifier 
from sklearn.ensemble import RandomForestClassifier 
from sklearn.linear_model import LogisticRegression 
import catboost as cb 
from xgboost import XGBClassifier 
  
rf = RandomForestClassifier(n_estimators=1000, max_depth=10, random_state=0) 
cbc = cb.CatBoostClassifier(verbose=0, eval_metric='Accuracy', loss_function='MultiClass') 
xgb = XGBClassifier(n_estimators=1000, learning_rate=0.05) 
  
for clf in (rf, cbc, xgb): 
    clf.fit(X_train, y_train) 
    preds = clf.predict(X_test) 
    print(clf.__class__.__name__,accuracy_score(y_test, preds))
```

---

ขั้นตอนที่ 5: Neural Network

ในขั้นตอนนี้จะเป็นการประเมินตัว Dataset ด้วย Neural Network, Neural Network คือโมเดลที่วิเคราะห์แพทเทิร์นของข้อมูลและการเลือกทางเลือกใน Machine learning ซึ่งเหมาะมากในการประเมินความถูกต้องของการจำแนก

```
import tensorflow.keras as keras 
from tensorflow.keras import Sequential 
from tensorflow.keras.layers import *

model = Sequential() 

model.add(Flatten(input_shape=(58,))) 
model.add(Dense(256, activation='relu')) 
model.add(BatchNormalization()) 
model.add(Dense(128, activation='relu')) 
model.add(Dropout(0.3)) 
model.add(Dense(10, activation='softmax')) 
model.summary()
```
Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxv3befpk9mtjfhussev.png)


จากนั้นจึงนำรวบรวมโมเดล โดยใส่ epochs หรือจำนวนข้อมูลที่ใช้ในการเทรน ซึ่งในบทความนี้ใช้ 100 เราจึงใส่ไป 100

```
# compile the model 
adam = keras.optimizers.Adam(lr=1e-4) 
model.compile(optimizer=adam, 
			loss="sparse_categorical_crossentropy", 
			metrics=["accuracy"]) 

hist = model.fit(X_train, y_train, 
				validation_data = (X_test,y_test), 
				epochs = 100, 
				batch_size = 32)

```

---

ขั้นตอนที่ 6: ประเมินผล

ขั้นตอนนี้จะเป็นการประเมินว่าโมเดลนี้มีความถูกต้องเท่าไร โดยเริ่มจากการรันโค้ดนี้

```
test_error, test_accuracy = model.evaluate(X_test, y_test, verbose=1) 
print(f"Test accuracy: {test_accuracy}")
```
Output ของโมเดลที่ใช้ epochs ทั้งหมด 100

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ha5bystutmehzvf56e5b.png)

แล้วนำมาพล็อตกราฟ

```
fig, axs = plt.subplots(2,figsize=(10,10)) 

# accuracy 
axs[0].plot(hist.history["accuracy"], label="train") 
axs[0].plot(hist.history["val_accuracy"], label="test")	 
axs[0].set_ylabel("Accuracy") 
axs[0].legend() 
axs[0].set_title("Accuracy") 
	
# Error 
axs[1].plot(hist.history["loss"], label="train") 
axs[1].plot(hist.history["val_loss"], label="test")	 
axs[1].set_ylabel("Error") 
axs[1].legend() 
axs[1].set_title("Error") 
	
plt.show()
```
Output

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b9yny07xgghyyegagynu.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r90s38fkdexipwodru5m.png)


จากการทดสอบนี้ ทำให้เราสงสัยว่า ถ้าหากเรากำหนดให้จำนวนข้อมูลที่ใช้ลดลงจาก 100 เหลือเพียง 10 เท่านั้น ตัวข้อมูลนั้นจะมีความแม่นยำขนาดไหน

Output เมื่อ epochs เท่ากับ 10

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7f16clqli9lv9cfbrq8n.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfv0gqlvon151ojr66w3.png)

ซึ่งจากกราฟที่ได้มานั้น ไม่แม่นยำเท่าการใช้ข้อมูลที่มากเท่า 100

## สรุป

โมเดลการจำแนกเพลงให้อยู่ในแต่ละประเภทนี้ จะมีประสิทธิภาพมากยิ่งขึ้นเมื่อมีข้อมูลเพลงที่มาก และใช้ Ensemble Learning และ Neural nets ในการสร้างโมเดล

จากตัวอย่างนี้ ทำให้เราพอเห็นไกด์ไลน์ในการทำโมเดลแยกประเภทได้บ้าง โดยเมื่อยิ่งมีจำนวนเพลงมากเท่าไร ความแม่นยำของข้อมูลก็จะมากขึ้นเท่านั้น ซึ่งสามารถใช้ได้กับการเทรนโมเดลตัวอื่นๆ ที่ไม่ใช่การจำแนกประเภทได้อีกด้วย

---

References:
https://www.geeksforgeeks.org/music-genre-classifier-using-machine-learning/
https://drive.google.com/drive/folders/189jIlfQ-E94eHfKVksbAUSXKX68Ju1GI