[머신러닝][SVM] 음성 별 감정 분류기 만들기

midoi·2022년 10월 12일
0

Capstone Design Project

목록 보기
1/2
post-custom-banner

wav 음성 파일에서 감정을 파악하는 방법

모든 코드는 캐글에 작성되어있다.
https://www.kaggle.com/code/miryeongpark/svm-classifier

이 글에서는 코드를 하나하나 뜯어보겠다.

1. 필요한 라이브러리 import

import numpy as np
import pandas as pd
import os
import sklearn
from os.path import join

2. 데이터 로드

pd_train = pd.read_csv('../input/dataset-csv/train_data.csv') 
#csv 파일안에는 1000개의 wav파일이름과 그 감정값이 저장되어있다.

print(pd_train.info()) #요약

내가 사용한 데이터는 csv안에 파일이름과 그 파일의 감정값이 저장되어있다.
pd.read_csv 를 활용하여 csv파일을 읽어오고,
요약된 내용을 알고 싶다면 info()를 사용한다.

2-2. train data와 label 생성

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 리스트를 돌려준다.

3. 음성데이터 가공 및 전처리

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 값을 내보낸다.

4. 학습용 데이터 생성

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,)으로 잘 추출되었다.

5. 모델 학습 및 추론 (K-fold cross validation 교차검증)

이제 생성한 학습 데이터를 가지고 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개의 정확도가 나온다.
정확도를 출력하는 코드를 작성했다.

6. 테스트 시각화 (히트맵)

히트맵을 사용하여 테스트가 얼마나 잘 이루어졌는지 시각화하기로 한다. 코드는 간단하다.

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/

post-custom-banner

0개의 댓글