天天看點

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

💡 作者:韓信子@ShowMeAI

📘深度學習實戰系列:https://www.showmeai.tech/tutorials/42

📘NLP實戰系列: https://www.showmeai.tech/tutorials/45

📘本文位址:https://www.showmeai.tech/article-detail/291

📢 聲明:版權所有,轉載請聯系平台與作者并注明出處

📢 收藏ShowMeAI檢視更多精彩内容

《禮記·樂記》中說:“凡音之起,由人心生也。人心之動,物使之然也。感于物而動,故形于聲。聲相應,故生變。”

這說的是人對于一種事物有感而生,必然表現在聲音上。而晚清名臣曾國藩也提到,他在認人識人中有自己獨到的方法,其中,特别喜歡通過聲音來識别人才。他認為,聲音不僅能反映出一個人的貴賤和修養,也能聽出其内心情緒變化。結合這個方法他一生提拔了大量人才。

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

既然聲音對一個人的情緒性格表現這麼明顯,AI算法能不能根據聲音識别情緒和氣氛呢?如果來電話的女朋友,一張口AI就知道是什麼情緒狀态,鋼鐵直男小哥哥們可能求生欲技能可以plus max。

在本篇内容中,ShowMeAI就針對「語音情感識别任務」,手把手帶大家來建構一個處理和分類語音檢測情緒的系統。

💡 背景概述

要完成語音情緒識别任務,我們先來了解一點基礎知識:

語音包括三類不同的特征:

詞彙特征(使用的詞彙)

視覺特征(說話者的表達方式)

聲學特征(音高、音調、抖動等聲音屬性)

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

我們當然可以基于詞彙(文本)或者視覺資訊來做情緒分類,在本篇内容中我們聚焦在聲學特征進行分類,我們建構一個深度學習的神經網絡來完成這個任務。

當然使用深度學習網絡進行情緒識别也有其自身的挑戰。大家都知道,情緒是高度主觀的,解釋因人而異;而且很多時候,我們很難将情緒歸類為單一類别,我們在任何給定時間都可能感受到一系列情緒。是以真實解決這個問題的時候,資料的采集和标注其實是一個有挑戰的任務。

💡 資料說明

在本篇中,ShowMeAI使用到的是公開資料集RAVDESS來訓練該模型。RAVDESS 資料集包含1440個檔案,覆寫兩種不同類型的資料:演講和歌曲。由24位專業演員(12位女性,12位男性)錄制,語音情緒包括平靜、快樂、悲傷、憤怒、恐懼、驚訝和厭惡。每種情緒都包含2種不同的程度(正常,強烈)。

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

資料可以在 🏆kaggle平台資料頁下載下傳,大家也可以在ShowMeAI的百度網盤中直接下載下傳整理好的版本。

🏆 實戰資料集下載下傳(百度網盤):點選 這裡 擷取本文 [4] 搭建基于深度學習的語音情感識别系統 『RAVDESS Emotional speech audio 資料集』

⭐ ShowMeAI官方GitHub:https://github.com/ShowMeAI-Hub

💡 神經網絡開發應用

我們使用神經網絡來對音頻資料進行了解和分析預估,有不同的神經網絡可以使用(多層感覺器、 CNN 和 LSTM 等都可以處理音頻時序資料),基于效率和效果考慮,我們下面會建構深度卷積神經網絡來對音頻檔案中的情緒進行分類。

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

關于卷積神經網絡的詳細知識可以參考ShowMeAI下述教程:深度學習教程 | 吳恩達專項課程 · 全套筆記解讀中的文章 卷積神經網絡解讀

深度學習與計算機視覺教程中的文章 卷積神經網絡詳解

① 資料導入與簡單分析

我們首先導入資料,并做一點簡單的可視化和分析,這裡的音頻資料我們會使用 LibROSA工具庫來處理和繪圖(波形和頻譜圖)。

針對語音相關的任務(語音識别、聲紋識别等),MFCC(Mel Frequency Cepstrum Coefficient,Mel頻率倒譜系數)是非常有效的表征特征。Mel頻率是基于人耳聽覺特性提出來的,它與Hz頻率成非線性對應關系。Mel頻率倒譜系數(MFCC)則是利用它們之間的這種關系,計算得到的Hz頻譜特征,它廣泛地應用在語音各項任務中。使用 LibROSA 包可以輕松導入音頻資料并提取 MFCC 格式資訊。

# 在notebook中通過pip install安裝librosa包
!pip install librosa           

複制

# 導入工具庫
import librosa
import librosa.display
import numpy as np
import pandas as pd
import glob
import os, sys
import matplotlib.pyplot as plt           

複制

# 讀取音頻資料
data, sampling_rate = librosa.load('Data/03-02-06-02-02-02-12.wav')

# 繪制音頻圖像
%matplotlib inline
plt.figure(figsize=(15, 5))
librosa.display.waveshow(data, sr=sampling_rate)           

複制

我們得到了如下的音頻波形圖

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

下面我們繪制一下音頻的頻譜圖

import scipy.io.wavfile

sr,x = scipy.io.wavfile.read('RawData/03-02-06-02-02-02-12.wav')

# 參數: 10ms一步, 30ms窗長
nstep = int(sr * 0.01)
nwin  = int(sr * 0.03)
nfft = nwin

window = np.hamming(nwin)


nn = range(nwin, len(x), nstep)
X = np.zeros( (len(nn), nfft//2) )

for i,n in enumerate(nn):
    xseg = x[n-nwin:n]
    z = np.fft.fft(window * xseg, nfft)
    X[i,:] = np.log(np.abs(z[:nfft//2]))

plt.imshow(X.T, interpolation='nearest',
    origin='lower',
    aspect='auto')

plt.show()           

複制

生成的頻譜圖如下圖所示。

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

② 資料标簽建構與映射

下一步我們來建構一下分類問題的标簽資料

feeling_list=[]

# 所有資料
mylist= os.listdir('Data/')

# 周遊資料
for item in mylist:
    if item[6:-16]=='02' and int(item[18:-4])%2==0:
        feeling_list.append('female_calm') #女性平靜
    elif item[6:-16]=='02' and int(item[18:-4])%2==1:
        feeling_list.append('male_calm') #男性平靜
    elif item[6:-16]=='03' and int(item[18:-4])%2==0:
        feeling_list.append('female_happy') #女性開心
    elif item[6:-16]=='03' and int(item[18:-4])%2==1:
        feeling_list.append('male_happy') #男性開心
    elif item[6:-16]=='04' and int(item[18:-4])%2==0:
        feeling_list.append('female_sad') #女性悲傷
    elif item[6:-16]=='04' and int(item[18:-4])%2==1:
        feeling_list.append('male_sad') #男性悲傷
    elif item[6:-16]=='05' and int(item[18:-4])%2==0:
        feeling_list.append('female_angry') #女性憤怒
    elif item[6:-16]=='05' and int(item[18:-4])%2==1:
        feeling_list.append('male_angry') #男性憤怒
    elif item[6:-16]=='06' and int(item[18:-4])%2==0:
        feeling_list.append('female_fearful') #女性恐懼
    elif item[6:-16]=='06' and int(item[18:-4])%2==1:
        feeling_list.append('male_fearful') #男性恐懼
    elif item[:1]=='a':
        feeling_list.append('male_angry') #男性憤怒
    elif item[:1]=='f':
        feeling_list.append('male_fearful') #男性恐懼
    elif item[:1]=='h':
        feeling_list.append('male_happy') #男性開心
    #elif item[:1]=='n':
        #feeling_list.append('neutral')
    elif item[:2]=='sa':
        feeling_list.append('male_sad') #男性悲傷           

複制

# 建構label Dataframe
labels = pd.DataFrame(feeling_list)
# 輸出前920個樣本label
labels[:920]           

複制

輸出的label如下所示

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

③ 資料處理與特征工程

我們已經對資料做了初步了解了,下面我們從音頻檔案中提取特征(音頻資訊表征),模型可以更有效地對音頻進行模組化和預估。這裡的特征提取我們依舊使用 LibROSA 庫。

因為CNN模型的輸入次元是固定的,我們在特征提取過程中,限制了音頻長度(3 秒,大家在計算資源足的情況下可以選擇更長的時間)。我們還做了一點處理,把每個檔案的采樣率增加了一倍,同時保持采樣頻率不變。這個操作是為了收集到更多特征。

# 建構1個包含feature特征列的Dataframe
df = pd.DataFrame(columns=['feature'])
bookmark=0

# 周遊資料
for index,y in enumerate(mylist):
    if mylist[index][6:-16] not in ['01', '07', '08'] and mylist[index][:2]!='su' and mylist[index][:1] not in ['n','d']:
        X, sample_rate = librosa.load('Data/'+y, res_type='kaiser_fast',duration=2.5,sr=22050*2,offset=0.5)
        mfccs = librosa.feature.mfcc(y=X, sr=np.array(sample_rate), n_mfcc=13)
        feature = np.mean(mfccs, axis=0)
        df.loc[bookmark] = [feature]
        bookmark=bookmark+1                

複制

# 拼接特征與标簽
df3 = pd.DataFrame(df['feature'].values.tolist())
newdf = pd.concat([df3,labels], axis=1)
# 重命名标簽字段
rnewdf = newdf.rename(index=str, columns={"0": "label"})           

複制

得到的特征列和标簽列如下所示:

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

④ 模型建構與優化

在完成資料特征抽取之後,我們可以開始模組化了,為了科學地模組化和效果評估,我們會将模型分為訓練集和測試集,用測試集評估模型的性能。

# 打亂樣本順序
from sklearn.utils import shuffle
rnewdf = shuffle(newdf)

# 80%的訓練集,20%的測試集
newdf1 = np.random.rand(len(rnewdf)) < 0.8
train = rnewdf[newdf1]
test = rnewdf[~newdf1]

# 輸出部分資料看看
train[250:260]           

複制

我們得到如下的訓練集部分樣本

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

在實際模組化的時候,标簽的格式要适用網絡最後的softmax結構,我們對标簽label使用LabelEncoder進行映射處理,得到one-hot的表示。

關于one-hot獨熱向量編碼,可以檢視ShowMeAI的機器學習實戰教程中的文章 機器學習特征工程最全解讀
# 訓練集特征與标簽
trainfeatures = train.iloc[:, :-1]
trainlabel = train.iloc[:, -1:]

# 測試集特征與标簽
testfeatures = test.iloc[:, :-1]
testlabel = test.iloc[:, -1:]

from tensorflow.keras.utils import np_utils
from sklearn.preprocessing import LabelEncoder
# 轉為numpy array格式
X_train = np.array(trainfeatures)
y_train = np.array(trainlabel)
X_test = np.array(testfeatures)
y_test = np.array(testlabel)

# 映射編碼
lb = LabelEncoder()
y_train = np_utils.to_categorical(lb.fit_transform(y_train))
y_test = np_utils.to_categorical(lb.fit_transform(y_test))           

複制

我們得到的 y_train 形如下面格式:

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

下面我們建構一個深度卷積網絡來完成分類問題。這個 CNN 模型包括Conv1D卷積層、pooling池化層,以及 Dropout 随機失活層,以及最後的全連接配接層。

# 擴充次元
x_traincnn =np.expand_dims(X_train, axis=2)
x_testcnn= np.expand_dims(X_test, axis=2)

# 建構CNN序貫模型
model = Sequential()
# 卷積層+激活層
model.add(Conv1D(256, 5,padding='same', input_shape=(216,1)))
model.add(Activation('relu'))
model.add(Conv1D(128, 5,padding='same'))
model.add(Activation('relu'))
# Dropout防止過拟合
model.add(Dropout(0.1))
# 池化層降維
model.add(MaxPooling1D(pool_size=(8)))
# 卷積層+激活層
model.add(Conv1D(128, 5,padding='same',))
model.add(Activation('relu'))
model.add(Conv1D(128, 5,padding='same',))
model.add(Activation('relu'))
# 展平+全連接配接層
model.add(Flatten())
model.add(Dense(10))
model.add(Activation('softmax'))           

複制

# 輸出模型資訊
model.summary()           

複制

我們得到如下資訊,大家可以清晰地看到模型結構

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

下面我們使用模型對資料進行拟合訓練

# 編譯
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=['accuracy'])
# 訓練
cnnhistory=model.fit(x_traincnn, y_train, batch_size=16, epochs=700, validation_data=(x_testcnn, y_test))           

複制

部分訓練資訊如下:

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

⑤ 模型存儲及測試集評估

# 模型存儲

# 模型名稱
model_name = 'Emotion_Voice_Detection_Model.h5'
# 路徑名稱
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_path = os.path.join(save_dir, model_name)
# 模型存儲
model.save(model_path)
print('模型存儲在 %s ' % model_path)           

複制

# 模型重加載與測試集評估
from tensorflow import keras
loaded_model = keras.models.load_model(model_path)

# 測試集評估
score = loaded_model.evaluate(x_testcnn, y_test, verbose=0)
print("%s: %.2f%%" % (loaded_model.metrics_names[1], score[1]*100))           

複制

⑥ 測試集預估

# 預估得到機率
preds = loaded_model.predict(x_testcnn, batch_size=32, verbose=1)
# 取出機率最高的類别
pred_labels = preds.argmax(axis=1)
# 映射回情緒名稱
pred_labels = pred_labels.astype(int).flatten()
predictedvalues = (lb.inverse_transform((pred_labels)))

# 真實測試集标簽
actual_labels = y_test.argmax(axis=1).astype(int).flatten()
actualvalues = (lb.inverse_transform((actual_labels)))

# 合并預測标簽與真實标簽
final_df = pd.DataFrame({'actualvalues': actualvalues, 'predictedvalues': predictedvalues})

# 輸出部分結果
final_df[170:176]           

複制

結果如下:

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料

💡 實時預估示範

下面我們錄制了一個實時音頻檔案,并在得到的模型上進行測試。

# 錄制音頻
import sounddevice as sd
from scipy.io.wavfile import writefs = 44100  # 采樣率
seconds = 4  # 時長
sd.wait()  # 錄制直至結束
write('output.wav', fs, myrecording)  # 存儲為wav檔案           

複制

data, sampling_rate = librosa.load('output.wav')
plt.figure(figsize=(15, 5))
librosa.display.waveshow(data, sr=sampling_rate)           

複制

聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料
X, sample_rate = librosa.load('output.wav', res_type='kaiser_fast',duration=2.5,sr=22050*2,offset=0.5)
mfccs = np.mean(librosa.feature.mfcc(y=X, sr=np.array(sample_rate), n_mfcc=13),axis=0)
livedf= pd.DataFrame(data=mfccs)
livedf = np.expand_dims(livedf.stack().to_frame().T, axis=2)
livepreds = loaded_model.predict(livedf, batch_size=32, verbose=1)
lb.inverse_transform(livepreds.argmax(axis=1))           

複制

我們得到正确的結果

array(['male_sad'], dtype=object)

參考資料

  • 🏆 實戰資料集下載下傳(百度網盤):點選 這裡 擷取本文 [4] 搭建基于深度學習的語音情感識别系統 『RAVDESS Emotional speech audio 資料集』
  • ⭐ ShowMeAI官方GitHub:https://github.com/ShowMeAI-Hub
  • 📘深度學習教程 | 吳恩達專項課程 · 全套筆記解讀: https://www.showmeai.tech/tutorials/35
  • 📘卷積神經網絡解讀: https://www.showmeai.tech/article-detail/221
  • 📘深度學習與計算機視覺教程: https://www.showmeai.tech/tutorials/37
  • 📘卷積神經網絡詳解: https://www.showmeai.tech/article-detail/264
  • 📘機器學習實戰教程: http://showmeai.tech/tutorials/41
  • 📘機器學習特征工程最全解讀: https://www.showmeai.tech/article-detail/208
聽音識情緒 | 程式員手把手教你搭建神經網絡,更快get女朋友情緒,求生欲max!⛵💡 背景概述💡 資料說明💡 神經網絡開發應用💡 實時預估示範參考資料