听音识情绪|听音识情绪 | 程序员手把手教你搭建神经网络,更快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。
【听音识情绪|听音识情绪 | 程序员手把手教你搭建神经网络,更快get女朋友情绪,求生欲max!?】在本篇内容中,ShowMeAI就针对「语音情感识别任务」,手把手带大家来构建一个处理和分类语音检测情绪的系统。
背景概述 要完成语音情绪识别任务,我们先来了解一点基础知识:
语音包括三类不同的特征:
  • 词汇特征(使用的词汇)
  • 视觉特征(说话者的表达方式)
  • 声学特征(音高、音调、抖动等声音属性)
听音识情绪|听音识情绪 | 程序员手把手教你搭建神经网络,更快get女朋友情绪,求生欲max!?
文章图片

我们当然可以基于词汇(文本)或者视觉信息来做情绪分类,在本篇内容中我们聚焦在声学特征进行分类,我们构建一个深度学习的神经网络来完成这个任务。
当然使用深度学习网络进行情绪识别也有其自身的挑战。大家都知道,情绪是高度主观的,解释因人而异;而且很多时候,我们很难将情绪归类为单一类别,我们在任何给定时间都可能感受到一系列情绪。所以真实解决这个问题的时候,数据的采集和标注其实是一个有挑战的任务。
数据说明 在本篇中,ShowMeAI使用到的是公开数据集RAVDESS来训练该模型。RAVDESS 数据集包含1440个文件,覆盖两种不同类型的数据:演讲和歌曲。由24位专业演员(12位女性,12位男性)录制,语音情绪包括平静、快乐、悲伤、愤怒、恐惧、惊讶和厌恶。每种情绪都包含2种不同的程度(正常,强烈)。
听音识情绪|听音识情绪 | 程序员手把手教你搭建神经网络,更快get女朋友情绪,求生欲max!?
文章图片

数据可以在 kaggle平台数据页下载,大家也可以在ShowMeAI的百度网盘中直接下载整理好的版本。
实战数据集下载(百度网盘):公众号『ShowMeAI研究中心』回复『实战』,或者点击 这里 获取本文 [[4] 搭建基于深度学习的语音情感识别系统](https://www.showmeai.tech/art...) 『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.wavfilesr,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 = nwinwindow = 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=https://www.it610.com/article/(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=https://www.it610.com/article/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)
参考资料
  • 实战数据集下载(百度网盘):公众号『ShowMeAI研究中心』回复『实战』,或者点击 这里 获取本文 [[4] 搭建基于深度学习的语音情感识别系统](https://www.showmeai.tech/art...) 『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!?
文章图片

    推荐阅读