人工智能:语音识别理解与实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

7.2 解码加速

每一帧都需要估计大量的参数也使得实时解码有更多的计算挑战。仔细的工程化及灵活的技巧能够极大地加快解码速度。在本节,我们讨论在文献[255]中提出的量化及并行计算技术,在文献[251]中提出的稀疏DNN,在文献[250]中提出的低秩分解技术,以及在文献[256]中提出的多帧DNN计算技术。这些技术都可以加速解码。当然,最好的实践应当将所有这些技术都结合起来。

7.2.1 并行计算

一个减少解码时间的明显解决方案是将DNN的计算并行化。这在GPU上很容易实现。然而在很多任务中,使用消费级CPU硬件是更加经济有效的方案。幸运的是,现代CPU通常支持低级的单指令多数据(Single Instruction Multiple Data,SIMD)指令级并行。在Intel和AMD的x86系列CPU中,它们通常在单一时间计算16B(也就是2个双精度浮点数、4个单精度浮点数、8个短整数或16B)的数据。利用这些指令集的优势,我们可以极大地提升解码速度。

取自文献[255]的表7.4总结了可运用于CPU解码器的技术及在一个配置为440:2000X5:7969的DNN上可以实现的实时率(RTF,定义为处理时间除以音频回放时间)。这是一个典型的以11帧特征作为输入的DNN。每一帧都包含40维从梅尔域三角滤波器组输出系数中提取的对数能量。在所有的5个隐层中,每层都包含2000个sigmoid神经元。输出层包含7969个聚类后的状态。这些结果是在安装了Ubuntu OS的Intel Xeon DP Quad Core E5640机器上获得的。CPU扩展被禁用了,每次计算都进行了至少5次并对结果取平均。

从表7.4中可以清楚地看到,仅从DNN计算后验概率,朴素的实现就需要3.89倍实时的时间,使用了每次处理4个浮点数的浮点数SSE2指令集,解码时间可以显著缩短为1.36倍实时。然而这仍然十分费时,并且比实时音频时间还要慢。作为对比,我们可以把4B浮点数的隐层激活值(如果使用的是sigmoid激活函数,取值范围就是(0, 1))线性量化为无符号字符类型(1B),而权重值量化为有符号字符类型(1B)。偏置可以被编码为4B整数,而输入保持浮点类型。这种量化(quantization)技术可以在不使用SIMD指令的条件下把所需时间降为1.52倍实时。量化技术同时可以把模型大小减小至原来的1/4~1/3。

表7.4 用于语音识别的典型的DNN(440: 2000X5:7969)的计算实时率(RTF)

注:总结自Vanhoucke等人的文章[255]

当使用整数类型SSSE3指令集来处理8位量化值的时候,由于允许16路并行计算,这将减少另外2/3的时间,而将整体计算时间降为0.51倍实时。SSE4指令集引入了一个小的优化,使用一条指令可以完成16位到32位的转化。使用SSE4指令集,可以进一步观察到一个小幅提升,解码时间降为0.47倍实时。

在语音识别中,即使是在线识别模式,在一段语音的开始处整合几百毫秒的预查看技术(look-ahead)也是非常常见的,目的是提高对语音和噪声统计量的实时估计。这意味着处理几十毫秒的小批量的帧不会过多地影响延迟。为了充分利用批量计算的优势,批量数据成块地在神经网络中被传播,使得每个线性计算都成为矩阵乘法,这可以充分利用CPU对权重和激活值的缓存。使用批量计算可以进一步把计算时间降为0.36倍实时。

最后一个进一步提高解码速度的技巧是只计算那些需要计算的状态类别的后验概率。众所周知,在解码过程中,每一帧只有一部分(25%到35%)的状态分数是需要被计算的。在GMM-HMM系统中,这很容易实现,因为每个状态都有属于它自己的高斯成分集合。然而在DNN中,即使只有一个状态是活跃的,由于所有的隐层都是共享的,它们也几乎都需要被计算。一个例外是最后的输出层,在这一层中只有那些与必要的后验概率相关的神经元需要被计算。这意味着我们可以对输出层进行惰性求值。然而,通过惰性方式计算输出层,对矩阵计算增加了额外的低效性,这引入了一个固定的22%的相对代价。总的来说,使用惰性求值(在不使用批量技术的情况下)可以把解码时间降为0.26倍实时,因为输出层占据了主要的计算时间(通常占50%)。

然而,使用惰性求值尽管可以继续批量计算所有的隐层,却再也不能进行跨越多帧的批量计算。进一步说,因为解码器在第t帧需要一个状态,也就有很大可能在第t+1仍然需要这个状态,在权重被缓存的同时,仍旧可能批量计算这些连续帧的后验概率。合并惰性求值和批量计算进一步把DNN计算时间降为0.21倍实时。

总之,这些工程优化技术实现了相对于朴素实现的20倍加速(从3.89倍实时降为0.21倍实时)。注意这个0.21倍实时仅是DNN后验概率的计算时间。解码器仍然需要搜索所有可能的状态序列,这取决于语言模型混淆度及搜索中所用的剪枝策略,通常平均增加0.2~0.3倍实时时间,而在极端情况下可能增加0.6~0.7倍实时时间。最终完成解码的时间可以在不降低正确率的前提下控制在语音实时时间之内。

7.2.2 稀疏网络

在一些设备上,例如智能手机,SIMD指令可能并不存在。在这样的条件下,我们仍然可以使用8位量化来提升解码速度。然而,我们无法使用在7.2.1节中讨论过的很多并行计算技术。

幸运的是,通过观察训练后全连接的DNN,我们发现其在所有的连接中有很大一部分具有很小的权重。举例来说,在语音识别中使用的典型DNN中有70%的权重小于0.1[251],这意味着我们可以减小模型的尺寸,并通过移除具有很小权重的连接来加速解码。注意,我们并没有在偏置参数上观察到类似的模式。非零的偏置值意味着相对于原始超平面的偏移,这是个可以被预料的现象。然而,考虑到与权重参数相比,偏置参数的数量非常少,完整地保留偏置参数不会显著影响最终模型的尺寸及解码速度。

生成稀疏模型的方法有很多种。举例来说,既然我们想要同时最小化交叉熵及非零权重的个数,强制稀疏性的任务就可以被写成一个多目标优化问题的形式。这个双目标优化的问题可以被转化为一个使用L1正则化的单目标优化问题。不幸的是,这种形式无法与DNN训练中通常使用的随机梯度下降(Stochastic Gradient Descent,SGD)算法同时工作[251]。这是因为子梯度的更新无法得到严格的稀疏网络。为了强制得到一个稀疏化的方案,一种方法是每隔T步就删节网络配置,即把小于一个阈值θ的参数设成零[257]。然而这种删节步骤有些武断,而且参数T很难被确定。通常,T取一个很小的值(比如1)并不理想。尤其是当批量块很小的时候就更是如此,原因是这时候每个SGD更新步骤都只能被轻微地更改权重值。当一个参数接近于零的时候,经过几次SGD更新后,它就会围绕零浮动。而且如果T不足够大,那么它可能会被取整为0。其结果是,删节只能在若干(一个合理大的)T步后执行,寄希望于非零系数能有足够长的时间来突破阈值θ。一个大T意味着每次参数被删节,训练准则都会降低,并且需要类似数量的步骤使得损失得以被补偿。

另一种方法是[258, 259]在二阶导训练收敛之后进行权重的删除。不幸的是,这些算法很难被扩展到我们在识别中所使用的大型训练集,并且其优势在删除权重之后的继续迭代中也减弱了。

还有一种方法既可以很好地加速,又能生成好的模型,它把上述问题表达为一个具有凸约束的优化问题:

W0q  (7.17)

其中q是允许的最大数量的非零参数的阈值。

这个约束优化问题很难求解。然而,基于以下两个观察可以得到一个近似方案:第一,在训练数据集迭代过几次之后权重变得相对稳定——它们倾向于保持一个要么很大,要么很小的量级(即绝对值)。第二,在一个稳定的模型中,连接的重要性可以由权重的量级来近似。这就引出了一个简单有效的算法。[1]

我们首先扫过全部训练数据几次来训练一个初始DNN。接着只保留最大的q个权重,然后保持同样的稀疏连接性不变继续训练DNN。这可通过掩蔽那些要删除的连接,或者把小于量级min{0.02, θ/2}的权重舍入为零来实现。这里θ是能在删除操作中存活的权重的最小量级,0.02则是个超参数,通过观察全连接网络中权重量级的模式来确定。掩蔽权重的方法虽然很清晰,但需要存储一个巨大的掩蔽矩阵。舍入为零的方法更加高效,但也更具技巧性,因为只将那些比min{0.02, θ/2}更小的,而不是比θ更小的权值舍入为零很重要。这是因为权值在训练过程中会产生收缩,如果不这样做,可能会被很突然地移除。另外,很重要的是,在删除之后,需要继续训练DNN,以弥补突然移除一些小的权重导致的精确度下降。

在文献[251]中所提供的表7.5和表7.6总结了在6.2.1节中所描述的语音搜索(VS)和Switchobard(SWB)数据集上的实验结果。通过利用模型的稀疏性属性,我们在两个数据集上可以获得0.2%~0.3%错误率的降低的同时把连接数降低至30%。或者,我们可以在VS和SWB数据集上把权重数量分别降至12%和19%,而不牺牲模型准确率。在这种情况下,在VS和SWB数据集上,CD-DNN-HMM的大小分别只有CD-GMM-HMM的1.5倍和0.3倍,并且相对全连接模型只有18%和29%的模型尺寸。这种转变在SIMD指令不存在的条件下,在VS和SWB数据集上可以把DNN的计算量分别降为全连接模型的14%和23%。

表7.5 在VS数据集上存在或不存在稀疏性约束时的模型大小、计算时间和句子错误率(SER)

注:全连接DNN包含5个隐层,每层2048个神经元。集外词(OOV)率在开发集和测试集均是6%(总结自Yu等的文章[251]

表7.6 在SWB数据集上存在和不存在稀疏性约束时的模型大小、计算时间和句子错误率(SER)

注:全连接DNN包含7个隐层,每层2048个神经元(总结自Yu等的文章[251]

需要注意的是,学习得到的稀疏矩阵通常具有随机模式。这使得即使能够取得很高的稀疏性,存储和计算都不能很有效率,在使用SIMD并行化的情况下就更是如此。

7.2.3 低秩近似

低秩矩阵分解技术既可以减少训练时间,也可以减少解码时间。在7.1.5节中,我们提到了甚至可以在训练开始之前把softmax层替换为两个更小的矩阵。然而,这种方法具有诸多不足。第一,事先并不容易知道需要保留的秩,因此需要使用不同的秩r构建多种模型。第二,如果我们在较低的隐层使用低秩技术,最终模型的性能就可能会变得非常差[249]。换句话说,我们无法为较低层减小模型尺寸并降低解码时间。然而,即使只有一个输出状态,也要计算低层的神经元。因此,减小低层的模型尺寸是非常重要的。

如果只在乎解码时间,我们就可以通过奇异值分解(Singular Value Decomposition,SVD)来确定秩r[250]。一旦我们训练了一个全连接的模型,就可以把每一个m×nmn)的权重矩阵W换成SVD

这里 是一个降序排列的非负奇异值的对角矩阵,UVT是酉矩阵,各列构成了一组可以被视为基向量的正交向量。Um列和Vn列被称为W的左奇异值向量和右奇异值向量。我们已经讨论过,DNN中有很大比例的权重会接近于零,因此,很多奇异值也应该接近于零。试验已经证明,对一个DNN中的典型权重矩阵,40%最大的奇异值占了奇异值总体大小的80%。如果我们保留最大的k个奇异值,权重矩阵W就可以被估计为两个更小的矩阵

这里。注意,在抛弃了一些小的奇异值之后,近似错误率会上升。因此,类似于稀疏网络方法,低秩近似分解后继续训练模型很重要。试验已经证明,如果我们保留30%的模型大小,没有或仅能观察到很小的性能损失[250]。这个结果与在稀疏网络[251]中的观察一致。然而,低秩矩阵分解方法在这两种方法中更好,因为它可以很容易地利用SIMD架构,并在不同的计算设备上实现更好的总体加速效果。

7.2.4 用大尺寸DNN训练小尺寸DNN

低秩近似技术能够减小模型规模并减少2/3的解码时间。为了进一步减小模型规模,使模型可以运行在小的设备上且不牺牲精确度,我们需要利用一些其他技术。最有效的方法是使用一个大尺寸的DNN输出训练一个小尺寸的DNN,从而使小的DNN能够产生和大的DNN一样的输出。这个技术第一次由Buciluǎ等人[260]提出并用于压缩模型。随后由Ba和Caruana[261]提出,用浅层多层感知器的输出去模仿DNN的输出。通过将采用不同随机种子训练出的DNN组合起来,他们首先得到一个非常复杂的模型,这种模型的性能远好于单个DNN模型。然后,他们把整个训练集送入这个复杂的模型,从而产生对应的输出,最后利用最小均方错误准则输出训练浅层的模型。这样,浅层模型的性能就可以和单个DNN模型一样。

Li等人[262]进一步从两个方面扩展了这种方法。首先,他们用于最小化的准则是小模型与大模型输出分布的KL距离;其次,他们不仅使用了有标注的数据,而且把没标注的数据都送入大模型产生训练数据,用于训练小模型。他们发现,使用额外的无监督数据有助于降低大模型和小模型之间的性能差异。

7.2.5 多帧DNN

在CD-DNN-HMM中,我们对9~13帧(每10ms一帧)的窗口输入估计聚类后状态的后验概率。当采用10ms的帧率时,语音信号是一个相当平稳的过程,自然地认为相邻帧产生的预测是相似的。一个简单并高效的计算方法是利用特征帧之间的相关性,简单地把前一帧的预测复制到当前帧,这样可以使计算量减半。这种简单的方法在文献[256]中被讨论过,它被称为帧异步(Frame-asynchronous)DNN,其性能令人惊奇得好。

一个被称为多帧DNN(MFDNN)的改善方法在文献[256]中被提出。这种方法并不像在帧异步方法中那样从前一帧复制状态预测,它使用和t帧一样的输入窗口,但同时预测t帧时刻及邻接帧的帧标注。这是通过把传统DNN中单一的softmax层替换为多个softmax层,其中每个softmax都对应不同的帧标注来实现的。由于所有的softmax层都共享相同的隐层,因此MFDNN可以省去隐层的计算时间。

例如,在文献[256]中,MFDNN联合预测ttK帧标注,其中,K是向后预测的帧数。这是一个多任务学习的典型例子。需要注意的是,MFDNN是预测过去的(t−1, ..., tK)帧,而不是将来的(t+1, ..., t+K)帧。这是因为在文献[256]中,所使用的上下文窗口包括了过去的20帧和未来的5帧,这使得在DNN的输入向量中包含过去的上下文信息比未来的上下文信息更多。而在绝大部分的DNN实现[12, 13]中,输入窗口都平衡了过去和将来帧的上下文信息。对这些DNN,其联合预测的帧标注可以是来自过去的,也可以是来自未来的。如果K很大,那么系统的总体延迟将变大。由于延迟将影响用户体验,K一般被设为小于4,从而由MFDNN带来的额外延迟将小于30ms。

在训练一个这样的MFDNN时,可以把所有的softmax层产生的误差一起进行反向传播。如果这样做,由于误差信号是已经乘以总体预测帧数量得到的,因此其梯度将会增加。为了保持收敛性质,学习率可能要降低。

MFDNN的性能要比帧异步DNN好,可以达到基线的水平。根据文献[256]的报告,对比相同的基线系统,一个系统联合预测2帧时,在查询处理速率上实现了10%的改善而精度不降。一个系统同时预测4帧时,在查询处理速率上进一步实现了10%的改善,而绝对字错误率仅仅增加了0.4%。

[1]更精确地讲,它可以由权重和输入值的乘积的量级来近似。然而,各层输入值的量级大体相对均匀,这是因为在输入层特征被归一化为均值为0、方差为1的数据,而隐藏层的值是概率。