语音情感分析开发者必读之作,一定带来一个解决新方案( 二 )


提取特征的细节是这样的 。论文中提到,只有约250ms以上的语音信号才包含足够的信息用于识别情感,因此论文中采用长度为25ms的汉明窗,滑动步长10ms的方式(每相邻两次变换有15ms的时域重叠)进行64次STFT-梅尔滤波的处理 。总共处理了10*63+25=635ms长的片段 。而前面提到,采样频率为16kHz的序列中,16点为1ms,25ms就对应400个点,这也是我选用汉明窗长度为401的原因 。
由于语音信号是时域连续的,分帧提取的特征信息只反应了本帧语音(比如25ms的语音片段)的特性,为了使特征更能体现时域连续性,可以在特征维度增加前后帧信息的维度 。因此我们还要对梅尔谱图做差分处理,常用的是一阶差分和二阶差分 。设ct c_tc
t
?
为数字音频信号的数据点,差分计算可写成下式 。
dt=∑Nn=1n(ct+n?ct?n)2∑Nn=1n2 d_t = \frac{\sum_{n=1}^{N}n(c_{t+n}-c_{t-n})}{2\sum_{n=1}^{N}n^2}
dt2∑n=1Nn2∑n=1Nn(ct+n?ct?n)
? [:,:,1] = ..delta([:,:,0],width=3,order=1) # 一阶差分
[:,:,2] = ..delta([:,:,0],width=3,order=2) # 二阶差分
1
2
通过计算梅尔谱图及其一阶二阶差分,并将其堆叠在一起,我们就得到了一个横向长度和信号持续时间有关、纵向长度和滤波器组有关的三通道彩色图片 。这也就是第四部分送入CNN的数据的来源 。
参考代码如下
os,
numpy as np
cv2
##############################################
# 从音频文件生成对应标签和梅尔谱图
##############################################
# 数据集路径
= './data/'
= os.()
# 将标签与对应谱图依次存储
= []
for i in range(len()):
# 读音频文件,不指定采样率
y, sr = .load(+[i],sr=None)
#of
= int(np.floor((len(y)-400)/160)) +1
# 生成64*的梅尔图矩阵
= np.zeros((64,,3))
# 每次生成一列64点的梅尔向量,存到梅尔图矩阵中
for j in range():
ps = ..(y=y[j*160:j*160+400], sr=sr, =64,n_fft=400,=401)
[:,j,0] = ps[:,0]
[:,:,1] = ..delta([:,:,0],width=3,order=1) # 一阶差分
[:,:,2] = ..delta([:,:,0],width=3,order=2) # 二阶差分
# 每个标签对应一个梅尔图,存到列表中
.([[i][5]+'_'+str(i),])
# 保存数据集
with open('.pkl','wb') as f:
.dump(,f)
最后我们得到的三通道的梅尔谱图大致是这个样子,注意由于矩阵中有负数,直接用..()是不行的,需要取一下绝对值再显示 。
四、基于卷积神经网络的特征提取
将原始的声音信号转换成梅尔谱图对于情感识别通常是不够的 。由于梅尔谱图是二维图像,适合作为CNN的输入 。因此,我们在梅尔谱图的基础上继续利用CNN提取高层次的特征 。具体地说,是将输入227*227的梅尔谱图映射为一个4096维的特征向量 。
完成第三步工作后,还需要对梅尔谱图进行裁剪 。图像高度,宽度也应该是,通道数为3 。需要考虑的是裁切时滑动步长,我取20个pixel 。
##############################################
# 从梅尔谱图裁切64*64图像
##############################################
with open('.pkl','rb') as f:
= .load(f)
# 生成梅尔图之后进行裁切,论文中以315ms为滑动步长,生成不了足够多数据
# 以20列pixel为步长进行滑动
= 20
# 标签和64*64mel图存储在列表中,标签命名规则 'W_1_1'即 情绪类型+第1段音频+第1个
= []
# 切图
for i in range(len()):
temp = [i][1] # mel图
h,w,c =np.shape([i][1]) # h=64,c=3
# 计算mel图可以切成多少个64*64图
= int(np.floor((w-64)/)) +1
for j in range():