深度学习在声纹识别中的应用

随着深度学习的迅猛发展,神经网络在越来越多的方向得到了广泛的应用,声纹识别也不例外。有越来越多的使用神经网络的方法来进行声纹识别的文章,并且都取得了不错的效果。最近也看了挺多文章的,总的来说,大致可以分为两个方向:feature learning,大概就是训练一个神经网络当作特征提取器,然后使用提取出来代表说话人的特征再做分类;End to end就是指直接输入两段语音,然后通过神经网络来判断这两段语音是否来自同一个人。

Feature Learning

d-vector

最早在2014年Google将神经网络用于声纹识别:Deep Neural Networks for Small Footprint Text-Dependent。它使用了一个四层的全连接层的网络来完成文本相关的声纹识别任务。它的结构如下:

它使用40维的filterbank特征(和MFCC相比少了离散余弦变换),然后使用当前帧的以及它的前后两帧作为输入,即一个120维的一维向量作为输入。经过四层的全连接层,每层有256个节点,使用maxout作为激活函数,最后两层加入dropout。训练时使用帧级别(frame level)的特征,使用softmax分类。

在网络训练好之后,将之前的最后一层移除,使用隐藏层的最后一层作为输出,即使用这一层当作一段语音所提取出的特征。在注册和验证过程中,使用一段语音(utterance)进行分帧,提取filterbank特征,输入到神经网络,然后将全部帧所对应的隐藏层的最后一层求均值作为这一段语音的特征。在打分的过程中使用consine距离来判断两段语音是否来自同一个人。不过它取得的效果并不是很好,等错误率没有i-vector高。但是在加入噪声的情况下稳定性要稍微好一些。

这种结构的系统可以理解为使用神经网络来做一个特征提取的任务。在训练的过程中,使用softmax来对训练集中的不同说话人做一个分类。而到了注册和验证的阶段,就将这个softmax层去掉,使用倒数第二层(或者说隐藏层的最后一层)当作神经网络的输出,使用这一层当作说话人的特征,论文中也称为d-vector。然后再使用consine similarity来进行打分判别。

d-vector改进

前一篇文章虽然网络的结构比较简单,但是是第一篇完全使用神经网络用于声纹识别的文章。之后也有不少人在此基础上做了改进,下面一篇就是对d-vector对改进:Deep Speaker Feature Learning for Text-independent Speaker Verification这篇文章改进了之前的结构,并且用于文本不相关的任务当中。他的结构如下:

它还是使用了40维filterbank作为输入特征,不过这里使用一帧以及它前后相邻的4帧,即一共九帧作为整个神经网络的输入(9*40)。然后经过两个卷积–池化层,然后再经过一个bottleneck层,之后再有两层time-delay层,以及一个全连接层,最后是一个5000维的softmax输出。

到了注册和测试阶段,同样是将最后的分类层去除,使用隐藏层的最后一层作为提取出来的特征,称为d-vector。并且将帧级别(frame level)的d-vector求均值得到utterance level的d-vector作为一段语音所代表的特征。最后文章也比较了几种分类器的效果,分别是consine、LDA和PLDA。在i-vector系统中PLDA有着最低的EER,而在d-vector中LDA则表现更加优异。(不太清楚这里是用LDA做降维后再接consine similarity还是用LDA做分类)(但是我现在还不太明白LDA是怎么进行分类的,不过找到一篇文章,分别介绍了使用LDA用于分类和降维的方法:Is LDA a dimensionality reduction technique or a classifier algorithm?

x-vector

在18年David Snyder也就是kaldi的作者之一提出了x-vector: Robust DNN Embedding for Speaker Recognition,也是对于前面网络的改进,在训练的数据量较大时,可以有较低的EER。它的网络结构如下表:

看了下kaldi中的代码,感觉这里和之前的time delay有点不同。首先输入是24维的filterbank特征,使用一帧以及前后2两帧,一共5帧一个120维的一维向量作为输入,输出长度为512。如果当前时刻为t,则第二层的输入为t-2、t和t+2时刻的第一层的输入。第三层同理,使用了第二层的t-3、t和t+3时刻作为输入。第四第五就是普通的全连接层。然后到了一个stats pooling,kaldi中的注释说到:Layer after this are segment level,并且segment size是[0,max_chunk_size],在脚本中这个max_chunk_size的大小为10000,这里就是表格中的T。这一层做的是什么呢,就是求一下之前输出的统计值,我看在脚本中是mean+stddev,也就是均值加上标准差。之后后面就是两个全连接层。最后接上一个softmax分类。

在网络训练好之后,把segment7和softmax层都去掉,使用segment6作为提取出来的特征,成为x-vector,然后再使用LDA降维和PLDA打分。在kaldi中,x-vector的脚本还做了其他很多操作,包括使用噪声对数据进行增强,去除时间过短的utt,然后还需要去除utt较少的speaker等。

End to End

接下来就是end to end的结构,和之前的feature learning的结构相比,end to end不需要再把训练好的网络再去掉最后的那么一两层,直接输入两段语音就可以判断这语音是否来自同一个人了。end to end的最大的特点就是在训练的时候需要挑选三段语音:首先需要确定一个anchor,即目标语音;然后还需要选来自同一个说话人的正样本,和来自不同说话人的负样本。训练时候的目标就是希望来自同一个人的语音(positive pair)的embedding要极可能的相似,而来自不同人的语音(negative pair)则要尽可能的不同。在训练完成之后,就可以直接输入两段语音然后判断他们是否来自同一个人了。

Network in Network

同样是David Snyder再16年发表的一篇文章:Deep Neural Network-Based Speaker Embeddings for End-to-End Speaker Verification,它使用了time delay Network in Network的网络结构,系统的结构如下:

首先网络的输入是MFCC特征,每一帧提取20维的MFCC特征,然后取前后各4帧一共9帧共180维的向量作为输入。然后再输入到深度神经网络当中去,它的网络的具体结构如下:(这是另外一篇文章中比较feature learning和E2E两种的模型的所画的图,那篇论文图更加直观一些:Deep Speaker Verification: Do We Need End-to-End

这篇文章使用40维的filterbank特征,选用当前帧以及前后各一帧,一共3帧共120维的向量作为输入。然后是time delay层,取[t-2,t+1]时刻共四个时刻600维向量作为输入经过一个1000维全连接层和500维全连接层,输出到下一个NIN中。一共有3个time delayNIN,这里最后一个time delay NIN再接一个150维的全连接层,然后再求统计值(均值和标准差)这里的方式应该和x-vector是类似的,都是求一段语音前面的再进行一个statistics pooling,最后再有一个NIN,这里就没有time delay了,再加上一个150维的全连接层。

他这里的loss设计的也挺复杂的,我也还是不是特别地理解,它的公式如下:

Triplet Loss

自从triplet loss在人脸识别中取得成功之后,也很多人在声纹识别中也用了triplet loss。这里就选一篇来介绍下:End-to-End Text-Independent Speaker Verification with Triplet Loss on Short Utterance。首先triplet loss的公式如下:

$$L=\sum_{i}[||f(x_i^a)-f(x_i^p)||_2^2-||f(x_i^a)-f(x_i^n)||_2^2+\alpha]$$

其中上标a代表anchor,上标p代表postive,上标n代表negative,$\alpha$是一个经验值。Triplet loss的思想很简单,就是希望positive pair的欧式距离要尽可能的小,而negative pair的欧式距离则要尽可能的大。

对于使用triplet loss的网络来说,triplet的选取非常重要。首先,我们不可能选取全部可能的triplet,因为这样做需要的计算量非常的大。因此选取出更加有效的triplet进行训练既会提高训练的效果也会提高训练的速度。这篇文章中的triplet选取的方式如下:首先一次选出60个说话人,然后每个人随机选择40段语音,这样一个epoch一共就有60*40*39/2=46800个triplet。然后通过选取满足当下面公式alpha=0.2时的triplet拿去训练。

这篇文章的选用的网络结构是Inception-resnet-v1,关于这个网络的介绍网上已经有非常多了,我这里也就不做详细的介绍了。这篇文章使用了语谱图作为神经网络的输入,相当于就是一个图像识别的问题了。

Deep Speaker

基于triplet loss的文章还有很多,更多的就是选用不同的网络结构,如百度的Deep Speaker: an End-to-End Neural Speaker Embedding System,他就对比了使用ResNet和GRU的效果。之后的改进方向也可是选用更加更深层的神经网络,或者是更合理的结构。可以看到随着深度学习技术的发展,声纹识别中也在不断的应用最新的技术

两者的区别

两者的区别大致如下:feature learning的思路就是使用神经网络来提取特征,它在训练的时候和验证的时候网络的结构会有所不同。在训练的时候,最后一般都使用softmax为训练集做分类。而到了验证的时候,就需要把softmax层去掉,使用倒数第二层或第三层作为提取出来的特征,然后在使用consine距离或者plda模型来进行打分判别。而end to end的思路就是去训练神经网络,使其能直接判断两段语音的相似度。Deep Speaker Verification: Do We Need End-to-End这篇文章也列举来这两种结构的不同之处:

  • 不同的模型结构:end to end包括了speaker embedding(front-end)和scoring(back-end),这两个被联合起来去训练成一个完整网络;feature learing就只包括embedding这一步。
  • 不同的训练目标:end to end的训练目标是判别一对语音使来自同一个人还是不同的人;feature learning是判别在训练集中的说话人。
  • 不同的训练方法:end to end是使用一对对的语音进行训练,语音对选取的好坏就会很大程度影响训练的效果;feature learning是一种one-hot式的训练方式,相比于end to end来说更容易去训练。
  • 不同的泛化能力:end to end训练好之后只能用在声纹识别的任务当中去;feature learning还可以在其他的语音任务中去使用。

为什么i-vector依然坚挺

之前在知乎上看到这样的一个问题:为什么在说话人识别技术中,i-vector+plda面对神经网络依然坚挺在目前最前沿的说话人识别系统中,仍然有不少是基于i-vector+PLDA的,在2017年ICASSP和Interspeech中,基于i-vector的说话人识别论文数量和基于神经网络的论文数依然可以抗衡。在神经网络席卷了机器学习众多领域的今天,为什么i-vector依然能够坚挺地存在呢?它有什么优点是神经网络所没有的?最高票的答主做了很好的回答,这里概括一下:

为什么在语音识别中DNN的应用会带来如此明显的提升,在说话人识别任务中却给人一种挣扎的感觉?这和任务属性是直接相关的,语音识别中,输出的是senone,不存在集外的概念。任何一句话里面的音素都能找到它对应的节点。但是说话人识别不一样,我们不可能要求测试的人在训练过程中出现,更不可能直接训练一个所有人的分类器。因此我们需要找到一个隐变量空间,每个人都是空间上的一个点,可以用这个空间的一组基来表示。i-vector就是找到了这样的一个隐变量空间。