关于深度学习:听音识情绪-程序员手把手教你搭建神经网络更快get女朋友情绪求生欲max⛵

💡 作者:韩信子@ShowMeAI
📘深度学习实战系列:https://www.showmeai.tech/tutorials/42
📘NLP实战系列: https://www.showmeai.tech/tutorials/45
📘本文地址:https://www.showmeai.tech/article-detail/291
📢 申明:版权所有,转载请分割平台与作者并注明出处
📢 珍藏ShowMeAI查看更多精彩内容

《礼记·乐记》中说:“凡音之起,由人心生也。人心之动,物使之然也。感于物而动,故形于声。声相应,故生变。”

这说的是人对于一种事物有感而生,必然体现在声音上。而晚清名臣曾国藩也提到,他在认人识人中有本人独到的办法,其中,特地喜爱通过声音来辨认人才。他认为,声音不仅能反映出一个人的贵贱和涵养,也能听出其心田情绪变动。联合这个办法他毕生提拔了大量人才。

既然声音对一个人的情绪性情体现这么显著,AI算法能不能依据声音辨认情绪和氛围呢?如果来电话的女朋友,一张口AI就晓得是什么情绪状态,钢铁直男小哥哥们可能求生欲技能能够plus max。

在本篇内容中,ShowMeAI就针对「语音情感辨认工作」,手把手带大家来构建一个解决和分类语音检测情绪的零碎。

💡 背景概述

要实现语音情绪辨认工作,咱们先来理解一点基础知识:

语音包含三类不同的特色:

  • 词汇特色(应用的词汇)
  • 视觉特色(谈话者的表达方式)
  • 声学特色(音高、音调、抖动等声音属性)

咱们当然能够基于词汇(文本)或者视觉信息来做情绪分类,在本篇内容中咱们聚焦在声学特色进行分类,咱们构建一个深度学习的神经网络来实现这个工作。

当然应用深度学习网络进行情绪辨认也有其本身的挑战。大家都晓得,情绪是高度主观的,解释因人而异;而且很多时候,咱们很难将情绪归类为繁多类别,咱们在任何给定工夫都可能感触到一系列情绪。所以实在解决这个问题的时候,数据的采集和标注其实是一个有挑战的工作。

💡 数据阐明

在本篇中,ShowMeAI应用到的是公开数据集RAVDESS来训练该模型。RAVDESS 数据集蕴含1440个文件,笼罩两种不同类型的数据:演讲歌曲。由24位业余演员(12位女性,12位男性)录制,语音情绪包含平静、高兴、悲伤、愤恨、恐怖、诧异和讨厌。每种情绪都蕴含2种不同的水平(失常,强烈)。

数据能够在 🏆kaggle平台数据页下载,大家也能够在ShowMeAI的百度网盘中间接下载整顿好的版本。

🏆 实战数据集下载(百度网盘):公众号『ShowMeAI钻研核心』回复『实战』,或者点击 这里 获取本文 [[4] 搭建基于深度学习的语音情感识别系统](https://www.showmeai.tech/art…) 『RAVDESS Emotional speech audio 数据集

ShowMeAI官网GitHub:https://github.com/ShowMeAI-Hub

💡 神经网络开发利用

咱们应用神经网络来对音频数据进行了解和剖析预估,有不同的神经网络能够应用(多层感知器、 CNN 和 LSTM 等都能够解决音频时序数据),基于效率和成果思考,咱们上面会构建深度卷积神经网络来对音频文件中的情绪进行分类。

对于卷积神经网络的具体常识能够参考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)

咱们失去了如下的音频波形图

上面咱们绘制一下音频的频谱图

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()

生成的频谱图如下图所示。

② 数据标签构建与映射

下一步咱们来构建一下分类问题的标签数据

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如下所示

③ 数据处理与特色工程

咱们曾经对数据做了初步了解了,上面咱们从音频文件中提取特色(音频信息表征),模型能够更无效地对音频进行建模和预估。这里的特征提取咱们仍旧应用 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"})

失去的特色列和标签列如下所示:

④ 模型构建与优化

在实现数据特色抽取之后,咱们能够开始建模了,为了迷信地建模和成果评估,咱们会将模型分为训练集和测试集,用测试集评估模型的性能。

# 打乱样本程序
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]

咱们失去如下的训练集局部样本

在理论建模的时候,标签的格局要实用网络最初的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 形如上面格局:

上面咱们构建一个深度卷积网络来实现分类问题。这个 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()

咱们失去如下信息,大家能够清晰地看到模型构造

上面咱们应用模型对数据进行拟合训练

# 编译
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))

局部训练信息如下:

⑤ 模型存储及测试集评估

# 模型存储

# 模型名称
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]

后果如下:

💡 实时预估演示

上面咱们录制了一个实时音频文件,并在失去的模型上进行测试。

# 录制音频
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)

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)

参考资料

  • 🏆 实战数据集下载(百度网盘):公众号『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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理