wav 음성 파일에서 감정을 파악하는 방법
모든 코드는 캐글에 작성되어있다.
https://www.kaggle.com/code/miryeongpark/svm-classifier
이 글에서는 코드를 하나하나 뜯어보겠다.
import numpy as np
import pandas as pd
import os
import sklearn
from os.path import join
pd_train = pd.read_csv('../input/dataset-csv/train_data.csv')
#csv 파일안에는 1000개의 wav파일이름과 그 감정값이 저장되어있다.
print(pd_train.info()) #요약
내가 사용한 데이터는 csv안에 파일이름과 그 파일의 감정값이 저장되어있다.
pd.read_csv 를 활용하여 csv파일을 읽어오고,
요약된 내용을 알고 싶다면 info()를 사용한다.
from tqdm import tqdm
def load_data(data_info, isTrain=True):
if isTrain:
train_data = {'mfcc':[]} #음성 feature들을 담는 dictionary
train_label = []#학습에 사용할 label을 담는 list
file_list = data_info['file_name']
emotion_list = data_info['emotion']
audio_path = ("../input/voice-sentiment-train-data")
for file_name, emotion in tqdm(zip(file_list, emotion_list)):
mfccs = extract_mfcc_feature(join(audio_path, file_name))
train_data['mfcc'].append(mfccs)
train_label.append(emotion)
return train_data, np.array(train_label)
csv파일에 1000개의 wav파일이름과 그 감정값이 들어있었다. 이를 읽고
train_data 딕셔너리와 train_label 리스트에 넣어준다.
train_data 딕셔너리에 넣어줄 때에는 wav파일의 mfcc특징값만을 넣어주는데, 이 extract_mfcc_feature함수는 바로 밑에 있다.
리턴값으로 train_data 딕셔너리와 train_label 리스트를 돌려준다.
wav파일에서 감정을 읽어오기 위해서는, 음성의 특징값을 추출해야한다.
음성의 특징값으로 mfcc값을 추출하는 방법이 대중적이다.
순서는 다음과 같다.
1. mp4파일을 windowing & sampling
2. 학습데이터 실수로 벡터화
3. 음성 feature을 퓨리에변환 하고 mel filter을 통해 mel_spectrogram으로 변환
4. mel_spectrogram에 scale normalization 적용
이 과정을 1000개의 파일마다 매번 하면 너무 낭비이기 때문에 한번에 하는 함수를 작성한다. 코드는 간단하다.
import librosa
import glob, pickle
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import librosa, librosa.display
def extract_mfcc_feature(file_name):
audio_signal, sample_rate = librosa.load(file_name, sr=22050)
#spectrogram 구현
spectrogram = librosa.stft(audio_signal, n_fft=512)
spectrogram = np.abs(spectrogram) #shape=(1025, 150)
#Mel-spectrogram 구현
power_spectrogram = spectrogram**2
mel = librosa.feature.melspectrogram(S=power_spectrogram, sr=sample_rate)
mel = librosa.power_to_db(mel)
#mfcc 구현
mfccs = librosa.feature.mfcc(S = mel, n_mfcc=20)
mfcc_feature = np.mean(mfccs.T, axis=0)
return mfcc_feature
librosa 라이브러리는 음성파일을 다루는 데에 있어 아주 유용하고 대중적이다.
librosa.load로 wav파일을 읽는다. 두 가지의 값이 생성되는데,
audio_signal과 sample rate가 생성된다.
spectrogram -> mel_spectrogram -> mfcc 차례대로 구해준다.
리턴값으로 mfcc 값을 내보낸다.
train_data, y_train = load_data(pd_train)
print("train data의 shape:",np.array(train_data['mfcc']).shape)
print("label data의 shape:",y_train.shape)
위에서 작성한 load_data에 csv파일을 넣어주면, 1000개의 wav파일의 mfcc추출값들과, 감정값이 추출된다.
제대로 추출되었는지 확인하기 위해 train_data와 y_train data의 shape을 확인한다.
각각 (1000,20), (1000,)으로 잘 추출되었다.
이제 생성한 학습 데이터를 가지고 SVM모델에 넣어 분류한다.
K-fold cross validation이란 데이터셋을 n개로 나누어 1:n-1 그룹이 차례로 Test용데이터로 이용되는 것이다.
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC
from sklearn.preprocessing import MinMaxScaler
X = np.array(train_data['mfcc']) #(1000, 20)
y = y_train #(1000,)
accuracy_history = []
#K-fold cross validation (train data 800개, test data 200개)
kf = KFold(n_splits=5, shuffle=True, random_state=50)
#그룹을 다섯개로 나눔 (1000개의 데이터를 5개그룹으로 나누어 한개의 그룹이 test용 데이터가 됨)
for train_index, test_index in kf.split(X):
#데이터 스플릿(5개의 그룹으로 나누었으니 train용과 test용을 구분함)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
#MinMAx Scaler을 이용한 특징 벡터 전처리
scaler = MinMaxScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
#분류기 커널 설정
clf = SVC(C=100, kernel='rbf', probability=True)
#분류기 학습
clf.fit(X_train_scaled, y_train)
#예측 결과
y_pred = clf.predict(X_test_scaled)
accuracy_history.append(accuracy_score(y_pred, y_test))
print("각 분할의 정확도 기록: ", accuracy_history)
print("평균 정확도 :", np.mean(accuracy_history))
MinMax Scaler을 이용하여 데이터를 전처리해주었다.
분류기는 SVM을 사용하기로 했으니
clf=SVC 를 작성하면 된다.
분류기를 학습하려면 clf.fit(train 데이터 , label값) 을 작성하고
분류기가 잘 학습되었는지 확인하려면 clf.predict(test 데이터)를 작성한다.
우리는 K-fold로 그룹을 5개로 나누었으니 각각의 그룹들이 테스트용으로 사용되며, 총 5개의 정확도가 나온다.
정확도를 출력하는 코드를 작성했다.
히트맵을 사용하여 테스트가 얼마나 잘 이루어졌는지 시각화하기로 한다. 코드는 간단하다.
from sklearn.metrics import confusion_matrix, plot_confusion_matrix
import matplotlib.pyplot as plt
label = ['angry', 'calm', 'surprised','disgust','neutral','sad','happy','fearful'] #데이터의 라벨값
plot = plot_confusion_matrix(clf,
X_test_scaled, y_test,
display_labels=label,
cmap = plt.cm.Reds,
normalize=None)
#파라미터로 분류기, 테스트데이터, 테스트라벨값을 넣어주고, 추가로 옵션값을 넣어준다.
plot.ax_.set_title('Voice Emotion Recognition Accuracy')
히트맵을 보니 angry가 매우 잘 예측되었고, fearful은 예측이 가장 덜 정확한 것 같다. ㅎㅎ
🥰참고🥰
https://www.kaggle.com/competitions/21-ai-w11-p2/overview
https://jerimo.github.io/python/svm/