使用卷积神经网络进行情感识别


对于科学家而言,认识情感一直是令人兴奋的挑战。 最近,我正在进行一个实验性SER项目(语音情感识别),以了解这项技术的潜力-为此,我选择了Github上最受欢迎的存储库,并将其作为我项目的基础。

在我们开始理解该项目之前,最好记住SER有什么样的瓶颈。

主要障碍


  • 情绪是主观的,即使人们对情绪的理解也不同。 很难定义“情感”的概念。
  • 对音频发表评论很难。 我们应该以某种方式标记每个单词,句子或整个交流吗? 识别中使用什么样的情感?
  • 收集数据也不容易。 可以从电影和新闻中收集很多音频数据。 但是,这两个消息来源都是“有偏见的”,因为新闻必须是中立的,并且演员的情感也会被播放。 很难找到音频数据的“客观”来源。
  • 标记数据需要大量的人力和时间资源。 与在图像上绘制框架不同,它需要经过专门培训的人员来收听整个音频记录,对其进行分析并提供评论。 然后,这些评论必须受到许多其他人的赞赏,因为评分是主观的。


项目说明


使用卷积神经网络识别录音中的情绪。 是的,存储库的所有者未引用任何来源。

资料说明


RAVDESS和SAVEE存储库中使用了两个数据集,我只是在模型中改编了RAVDESS。 RAVDESS上下文中有两种类型的数据:语音和歌曲。

数据集RAVDESS(情感言语和歌曲的Ryerson视听数据库)

  • 12位演员和12位女演员录制了表演中的讲话和歌曲;
  • 18号演员没有录制歌曲;
  • 情绪在“歌曲”数据中不存在厌恶(厌恶),中立(中立)和惊奇(惊奇)。

情绪细分:


情绪分布图:


特征提取


当我们处理语音识别任务时,尽管倒谱系数(MFCC)出现在80年代,但它却是一项先进的技术。

引用MFCC教程
此形状确定输出声音是什么。 如果我们可以查明表格的形式,它将使我们能够准确表示所读音素声道的形状在短频谱的包络中表现出来,而MFCC的工作是准确显示该包络。


波形图


频谱图

我们使用MFCC作为输入功能。 如果您有兴趣了解有关MFCC的更多信息,那么本教程适合您。 使用librosa Python软件包可以轻松下载数据并将其转换为MFCC格式。

默认模型架构


作者使用Keras软件包开发了CNN模型,创建了7层-六个Con1D层和一个密度层(Dense)。

model = Sequential() model.add(Conv1D(256, 5,padding='same', input_shape=(216,1))) #1 model.add(Activation('relu')) model.add(Conv1D(128, 5,padding='same')) #2 model.add(Activation('relu')) model.add(Dropout(0.1)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(128, 5,padding='same')) #3 model.add(Activation('relu')) #model.add(Conv1D(128, 5,padding='same')) #4 #model.add(Activation('relu')) #model.add(Conv1D(128, 5,padding='same')) #5 #model.add(Activation('relu')) #model.add(Dropout(0.2)) model.add(Conv1D(128, 5,padding='same')) #6 model.add(Activation('relu')) model.add(Flatten()) model.add(Dense(10)) #7 model.add(Activation('softmax')) opt = keras.optimizers.rmsprop(lr=0.00001, decay=1e-6) 

作者在最新版本(2018年9月18日)中对第4层和第5层进行了评论,该模型的最终文件大小不适合所提供的网络,因此我无法获得相同的准确度结果-72%。

只需使用参数batch_size=16epochs=700即可训练模型,而无需任何训练时间表等。

 # Compile Model model.compile(loss='categorical_crossentropy', optimizer=opt,metrics=['accuracy']) # Fit Model cnnhistory=model.fit(x_traincnn, y_train, batch_size=16, epochs=700, validation_data=(x_testcnn, y_test)) 

此处categorical_crossentropy是损失的函数,评估的方法是准确性。

我的实验


探索性数据分析


在RAVDESS数据集中,每个演员都显示8种情绪,每个句子发音和唱歌2个句子,两次。 结果,从每个演员获得每种情绪的4个示例,除了上述中性情绪,厌恶和惊奇之外。 每个音频持续约4秒钟,在最初和最后几秒钟通常是静音。

典型报价

观察


在从1位演员和1位女演员中选择一个数据集,然后听听他们的所有记录后,我意识到男人和女人表达自己的情感的方式有所不同。 例如:

  • 男性愤怒(愤怒)声音更大;
  • 男人的快乐(Happy)和挫败感(Sad)-“沉默”时笑声和哭声的特征;
  • 女性的快乐(快乐),愤怒(愤怒)和沮丧(悲伤)更大;
  • 女恶心(Disgust)包含呕吐的声音。

实验重复


作者删除了中立,令人反感和惊讶的类,以使RAVDESS对数据集进行10类识别。 尝试重复作者的经历,我得到了以下结果:



但是,我发现,当用于验证的数据集与测试数据集相同时,会发生数据泄漏。 因此,我重复了数据的分离过程,将两个演员和两个女演员的数据集隔离开来,以使它们在测试期间不可见:

  • 演员1至20以8:2的比例用于训练/有效场景;
  • 参与者21至24与测试隔离;
  • 火车设置参数:(1248,216,1);
  • 有效设置参数:(312,216,1);
  • 测试设置参数:(320,216,1)-(隔离)。

我重新训练了模型,结果如下:


性能测试


从“火车有效毛额”图可以明显看出,所选的10个班级没有收敛。 因此,我决定降低模型的复杂性,只保留男性情感。 我在测试集中隔离了两个演员,其余的以8:2的比例放在火车/有效集中。 这样可以确保数据集中没有不平衡。 然后,我分别指导了男性和女性数据进行测试。

男性数据集

  • 训练集-演员1-10中的640个样本
  • 有效集-来自参与者1-10的160个样本;
  • 测试集-来自演员11-12的160个样本。

参考线:男


女性数据集

  • 火车套装-女演员1-10名的608个样本;
  • 有效集-女演员1-10中的152个样本;
  • 测试集-从女演员11-12中获得160个样本。

参考线:女士


如您所见,错误矩阵是不同的。

男人:愤怒和快乐是模型中主要的预测类,但两者并不相同。

妇女:失调(悲伤)和欢乐(快乐)-模型中基本上预测的类别; 愤怒和喜悦很容易混淆。

回顾《 情报数据分析》中的观察结果,我怀疑女性愤怒和快乐与混淆点相似,因为它们的表达方式只是为了表达自己的声音。

最重要的是,我很好奇,如果我进一步简化模型,只留下正,中性和负性类。 或只有正面和负面。 简而言之,我将情绪分别分为2类和3类。

2节课:

  • 积极:喜悦(快乐),镇定(平静);
  • 负面:愤怒,恐惧(恐惧),沮丧(悲伤)。

3个班级:

  • 积极:快乐(快乐);
  • 中立:平静(Calm),中立(Neutral);
  • 负面:愤怒,恐惧(恐惧),沮丧(悲伤)。

在开始实验之前,我使用男性数据建立模型架构,进行5级识别。

 #   -  target_class = 5 #  model = Sequential() model.add(Conv1D(256, 8, padding='same',input_shape=(X_train.shape[1],1))) #1 model.add(Activation('relu')) model.add(Conv1D(256, 8, padding='same')) #2 model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(128, 8, padding='same')) #3 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #4 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #5 model.add(Activation('relu')) model.add(Conv1D(128, 8, padding='same')) #6 model.add(BatchNormalization()) model.add(Activation('relu')) model.add(Dropout(0.25)) model.add(MaxPooling1D(pool_size=(8))) model.add(Conv1D(64, 8, padding='same')) #7 model.add(Activation('relu')) model.add(Conv1D(64, 8, padding='same')) #8 model.add(Activation('relu')) model.add(Flatten()) model.add(Dense(target_class)) #9 model.add(Activation('softmax')) opt = keras.optimizers.SGD(lr=0.0001, momentum=0.0, decay=0.0, nesterov=False) 

我添加了2层Conv1D,一层MaxPooling1D和2层BarchNormalization; 我也将辍学值更改为0.25。 最后,我以0.0001的学习速度将优化器更改为SGD。

 lr_reduce = ReduceLROnPlateau(monitor='val_loss', factor=0.9, patience=20, min_lr=0.000001) mcp_save = ModelCheckpoint('model/baseline_2class_np.h5', save_best_only=True, monitor='val_loss', mode='min') cnnhistory=model.fit(x_traincnn, y_train, batch_size=16, epochs=700, validation_data=(x_testcnn, y_test), callbacks=[mcp_save, lr_reduce]) 

为了训练模型,我减少了“训练平稳期”,只保存了具有最小val_loss的最佳模型。 这是不同目标类别的结果。

新车型性能


男子5节课



5年级女性

2年级男士


男子三班


增加(增强)


当我加强模型的架构,优化器和训练的速度时,事实证明该模型仍然无法在训练模式下收敛。 我建议这是一个数据量问题,因为我们只有800个样本。 这使我想到了增加音频的方法,最后我将数据集增加了一倍。 让我们看一下这些方法。

男子5节课


动态增量

 def dyn_change(data): """    """ dyn_change = np.random.uniform(low=1.5,high=3) return (data * dyn_change) 



音高调整

 def pitch(data, sample_rate): """    """ bins_per_octave = 12 pitch_pm = 2 pitch_change = pitch_pm * 2*(np.random.uniform()) data = librosa.effects.pitch_shift(data.astype('float64'), sample_rate, n_steps=pitch_change, bins_per_octave=bins_per_octave) 


偏移量

 def shift(data): """   """ s_range = int(np.random.uniform(low=-5, high = 5)*500) return np.roll(data, s_range) 


添加白噪声

 def noise(data): """    """ #     : https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.random.html noise_amp = 0.005*np.random.uniform()*np.amax(data) data = data.astype('float64') + noise_amp * np.random.normal(size=data.shape[0]) return data 


值得注意的是,增强极大地提高了准确性,在通常情况下可达70 +%。 特别是在添加白色的情况下,将精度提高到87.19%-但是,测试精度和F1测量值下降了5%以上。 然后我想到了结合几种增强方法以获得更好结果的想法。

结合几种方法


白噪声+偏差


测试男性增强


2年级男士


白噪声+偏差

对于所有样品


白噪声+偏差

仅针对阳性样本,因为2类组不平衡(朝向阴性样本)。


音高+白噪声
对于所有样品


音高+白噪声

仅适用于阳性样品


结论


最后,我只能使用男性数据集进行实验。 我重新划分了数据,以避免不平衡,从而避免数据泄漏。 我设置模型以尝试男性声音,因为我想尽可能简化模型。 我还使用不同的增强方法进行了测试; 白噪声和偏置的添加在不平衡数据上效果很好。

结论


  • 情绪是主观的,难以解决;
  • 有必要事先确定哪些情绪适合该项目;
  • 即使内容众多,也不要总是信任Github的内容;
  • 数据共享-记住这一点;
  • 探索性数据分析总是有一个好主意,但是在处理音频数据时,您需要耐心等待;
  • 确定要为模型输入提供什么:句子,整个记录还是感叹号?
  • 缺少数据是SER成功的重要因素,但是创建具有情感的良好数据集是一项复杂而昂贵的任务;
  • 缺少数据时简化模型。

进一步改善


  • 我仅使用前3秒作为输入来减小整体数据大小-原始项目使用了2.5秒。 我想尝试全尺寸的录音;
  • 您可以对数据进行预处理:修剪静音,通过用零填充来标准化长度等。
  • 为此任务尝试递归神经网络。

Source: https://habr.com/ru/post/zh-CN461435/


All Articles