上一篇在用mfcc特征进行DNN训练后,准确率太低,接下来根据前人经验,由于CNN卷积神经网络在图片识别领域大放异彩,而由音频得到的mel声谱图作为图片,也可以用这种组合来训练。
例如,202.wav的梅尔谱绘制出来
import librosa
import librosa.display
import numpy as np
import pylab as plt
y, sr = librosa.load(path,sr=None)
S = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=1024,hop_length=512, n_mels=40)
plt.figure(figsize=(10, 4))
librosa.display.specshow(librosa.power_to_db(S,ref=np.max),
y_axis='mel', fmax=8000,
x_axis='time')
plt.colorbar(format='%+2.0f dB')
plt.title('Mel spectrogram')
plt.tight_layout()
横坐标表示时域,纵坐标表示梅尔频域,颜色表示能量,这里单位是dB分贝,这不就是一张图么。
由于没有相关知识,我在网络上收集了一堆资料,看起来相当难。就在犯难的时候,老天给了个好东东。又是一个教程,tensorflow中文教程作为入门相当好,而这一篇教程作为后续进阶特别合适。地址如下,拿去不谢?:
https://www.zybuluo.com/hanbingtao/note/485480
我敢说只有大神,才能做出这样的教程。
对于我等小白来说,现在做不到人家大牛那样的,直接手写cnn这种程度,但是利用现成的api还是可以的。这里官方也有个demo,参考https://tensorflow.google.cn/tutorials/estimators/cnn
从目录上可以看到该卷积网络模型的结构。当然这里的结构是可以自行配置的,需要多少个怎样的卷积层,多少个怎样的池化层,都是可以自己定义的。为了方便起见,直接使用它写好的模型来测试一下,看看效果
input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])
很简洁,就一句话。文中解释也很清楚,features[“x”]很明显是28x28的图片像素集,后面
-1 动态计算样本批量的大小
28,28 将一维的像素特征转换为28x28的二维特征。由于需要卷积,转换为长宽合适的二维数组特别重要。
1 由于是黑白图片,单色图像只有 1 个通道(黑色)。
第一个卷积层中,我们需要将 32 个 5x5 过滤器应用到输入层,并应用 ReLU 激活函数。我们可以使用 layers 模块中的 conv2d() 方法创建该层,如下所示:
conv1 = tf.layers.conv2d(
inputs=input_layer,
filters=32,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
32个filter意味着有32个输出,每个输出是由原输入28x28的图像,与卷积核5x5的卷积计算出来。根据卷积原理,步幅为1的时候,如果输入是6x6,与5x5卷积,将得到2x2的输出;如果输入是7x7,与5x5卷积,将得到3x3的输出;依次类推,如果输入是nxn,与mxm(m 打印一下conv1 pooling层的作用主要是下采样,最常用的是Max Pooling。Max Pooling实际上就是在n*n的样本中取最大值,作为采样后的样本值。 除了Max Pooing之外,常用的还有Mean Pooling——取各样本的平均值。 这里的max_pooling2d 用的是Max Pooling。 将卷积层的输出conv1作为它的输入,pool_size指定了2x2的最大池化过滤器 ,strides指定移动步幅是2,28/2=14 最后将得到14x14的输出 该层返回预测的原始值。创建一个具有 10 个神经元(介于 0 到 9 之间的每个目标类别对应一个神经元)的密集层,并应用线性激活函数(默认函数): 输入特征是 55000张图的28x28像素值 因此,音频的特征和标签也是这样。log_mel声谱图作为特征40x40的方便处理,标签也需要转换成数字0-5 这里顺便介绍下数据集,上节中忘了介绍了。本次实验分别使用CASIA数据集和iemocap数据集进行了实验。主要CASIA数据集免费下载到的只有1200条,规模较小。 1)CASIA数据集 2)iemocap数据集 每个Session的结构如下: 这时候只要把这些语音和标注提取出来,就可以进行训练了。经过提取,里面的情感规模如下: 40x40 第一层卷积 32x5x5, 池化 32x2x2 ,最后应该输出 32x20x20 模型训练这里有几个参数说明一下,跟教程里面略有不一样: epoch:将所有训练样本完整训练一次,叫做一个epoch。这里num_epochs指的是重复完整训练的次数,当然要配上shuffle=True,让每次训练都随机打乱样本。 batch_size:单次训练(一个step)的样本数 steps:一次完整训练需要的步数。 要求 总样本数量=batch_size*steps 1)CASIA数据集:随机1000做训集,200做测试集。batch_size=10 2)iemocap数据集:选取了ang,sad,neu,exc四类情绪的样本进行实验,共5000条左右,随机4200条做训练集,剩余的做测试集。为了和上面对齐,这里batch_size=42 20个epoch后: 30个epoch后: 40个epoch后: 50个epoch后: 得到了0.55左右的识别率。
ps:这里是28,28,32 是因为padding=‘same’,padding 参数指定以下两个枚举值之一(不区分大小写):valid(默认值)或 same。要指定输出张量与输入张量具有相同的高度和宽度值,我们在此教程中设置 padding=same,它指示 TensorFlow 向输入张量的边缘添加 0 值,使高度和宽度均保持为 28(没有填充的话,在 28x28 张量上进行 5x5 卷积运算将生成一个 24x24 张量,因为在 28x28 网格中,可以从 24x24 个位置提取出一个 5x5 图块)。2-1-3 池化层 1
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)
2-1-4 卷积层2和池化层2
conv2 = tf.layers.conv2d(
inputs=pool1,
filters=64,
kernel_size=[5, 5],
padding="same",
activation=tf.nn.relu)
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)
2-1-5 密集层
# Dense Layer
#扁平化降维,将7,7,64的张量,降成7x7x64的一维向量,即3136
pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
#密集层,指定1024个神经元
dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
#丢弃正则化,随机丢弃40%的样本
dropout = tf.layers.dropout(
inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)
2-1-6 对数层
logits = tf.layers.dense(inputs=dropout, units=10)
以上就是模型部分,训练部分暂且不论,模仿这个写一个咱需要的CNN模型2-2 CNN 音频情感分类器
标签就是55000条标注2-2-1 数据集
casia数据集结构如上,每个演员中都已经划分好6类情绪,每个情绪中都会有对应的多条语音文件。所以写个程序去获取音频和对应情绪不成问题,然后获取对应音频的特征,就可以得到想要的特征-情绪集合。然后进行训练。经过提取,里面的情感规模如下:
这个数据集较大,共分为5个Session,一起十几个G,包含了视频,音频,面部特征等诸多文件,不过一次下载受益无穷?。
能看得懂可以用的,我用红框框标出来了。dialog中的wav文件,是长音频,每个音频里是两人对话,各种情绪都有。而sentenses中把这些语句做了分离,一小段一小段。比如女人的第一句话,女人的第二句话,男人的第一句话,…这样拆开。然后每段的情绪在EmoEvaluation中的文件中进行了标注。
可以看出,有些情感的样本过少,有些样本情感有争议,这些都可以忽略。可以选取fru,neu,ang,sad,exc等进行实验2-2-2 cnn模型规划
第二层卷积 64x5x5, 池化 64x2x2 ,最后应该输出 64x10x10
密集层一致
对数层units改为62-2-3 模型训练相关
# Train the model
train_input_fn = tf.estimator.inputs.numpy_input_fn(
x={"x": training_examples},
y=training_targets,
batch_size=20,
num_epochs=10,
shuffle=True)
mnist_classifier.train(
input_fn=train_input_fn,
steps=None,
hooks=[logging_hook])
比如CASIA中规划了1000个样本做训练,那么这里的batch_size是20,自然steps应该是50,当然设为None也行,它训练50个steps就会完成一个epoch。2-2-4 实验结果
10个epoch后:
20个epoch后:有提升
30个epoch后:测试集loss变大,后面慢慢开始过拟合了
…
110个epoch后:测试集loss持续变大
得到了0.65左右的识别率。
训练集loss上下震荡
验证集loss略有降低
训练集loss继续下降
测试集loss略有下降
训练集loss震荡
测试集loss变大了,注意后面可能过拟合了
测试集loss继续下降了,难道还有空间?