文章目录
- 1 一个alignment概率的计算
- 2 所有alignments概率的计算
- 3 Training
- 4 Inference
- 5 小结
本文为李弘毅老师【Speech Recognition - RNN-T Training (optional)】的课程笔记,课程视频youtube地址,点这里👈(需翻墙)。
下文中用到的图片均来自于李宏毅老师的PPT,若有侵权,必定删除。
文章索引:
上篇 - 1-5 Alignment of HMM, CTC and RNN-T
下篇 - 1-7 Language Modeling
总目录
1 一个alignment概率的计算
不管是HMM,还是CTC,还是RNN-T,它们计算得到某一个alignment的概率的方法是一致的。下面以RNN-T为例,来说一下计算的方法。
如下图所示,我们现在来计算h=ϕcϕϕaϕtϕϕh=\phi c \phi \phi a \phi t \phi \phih=ϕcϕϕaϕtϕϕ的概率,写成公式就是
P(h∣X)=P(ϕ∣X)P(c∣X,ϕ)P(ϕ∣X,ϕc)⋯P(h|X)=P(\phi | X)P(c | X,\phi)P(\phi | X,\phi c) \cdots P(h∣X)=P(ϕ∣X)P(c∣X,ϕ)P(ϕ∣X,ϕc)⋯
那么这个结合模型到底是怎么算出来的呢?在decode的时候,RNN-T会有两个RNN,一个RNN_1(上半图)会吃一个“<BOS><BOS><BOS>“这样的起始符,然后吐出一个l0l_0l0,这个l0l_0l0和encoder吐出的h1h_1h1会一起喂给另一个RNN_2(下半图),RNN_2会生成一个概率分布p1,0p_{1,0}p1,0表示着这个time step由h1h_1h1和l0l_0l0生成的字典中每个字符和"ϕ\phiϕ"的概率,最后我们从中找到”ϕ\phiϕ“对应的概率是多少,就得到了我们的P(ϕ∣X)P(\phi | X)P(ϕ∣X)。
由于我们这次计算的是"ϕ\phiϕ",根据RNN-T的特性,我们不会去计算RNN_1,而是把新的h2h_2h2和旧的l0l_0l0塞进RNN_2当中,吐出一个由h2h_2h2和l0l_0l0生成的概率分布p2,0p_{2,0}p2,0,从这个p2,0p_{2,0}p2,0中找到字符"c"的概率,就得到了P(c∣X,ϕ)P(c | X,\phi)P(c∣X,ϕ)。
又因为RNN-T的特性,在没有遇到"ϕ\phiϕ“不会喂给RNN_2新的hhh,而RNN1RNN_1RNN1需要重新计算一个得到l1l_1l1,于是由h2h_2h2和l1l_1l1生成概率分布p2,1p_{2,1}p2,1,从中找到”ϕ\phiϕ"的对应概率,就得到了P(ϕ∣X,ϕc)P(\phi | X,\phi c)P(ϕ∣X,ϕc)。
依此类推,一致计算下去,直到算完整个hhh。然后把得到的概率值,全都乘起来,就得到了我们的P(h∣X)P(h|X)P(h∣X)。
2 所有alignments概率的计算
P(h∣X)P(h|X)P(h∣X)会算了,接下来,我们要来算一下P(Y∣X)P(Y|X)P(Y∣X)。得益于RNN-T有两个结构上不影响的RNN,我们在计算pi,jp_{i,j}pi,j的时候,不管前面的输出顺序如何,其结果都是保持不变的。比如,在计算p4,2p_{4,2}p4,2时,不管前面的输出序列是"ϕcϕϕa\phi c \phi \phi aϕcϕϕa",还是“cϕϕaϕc \phi \phi a \phicϕϕaϕ",还是“ϕϕϕca\phi \phi \phi c aϕϕϕca",我们的l2l^2l2和h4h^4h4是打死不变的,所以p4,2p_{4,2}p4,2是不会变的。
不过这里我其实有一个疑惑,虽然l2l^2l2和h4h^4h4是不会变的,但是生成p4,2p_{4,2}p4,2的这个RNN的记忆不会因为前面产生token的顺序不同而变化吗?存疑。(疑惑已解,生成p4,2p_{4,2}p4,2的是简单的DNN,不是RNN,黄色方块没有横向的传播)
现在我们就认为pi,jp_{i,j}pi,j是不会变化的,然后来看一下下面这个表格。然后我们会用和HMM中的forward algorithm差不多的方法来计算P(Y∣X)P(Y|X)P(Y∣X)。
首先我们定义αi,j\alpha_{i,j}αi,j表示读取了第iii个声音讯号的特征并且输出了第jjj个token时,所有alignments的概率之和。比如α4,2\alpha_{4,2}α4,2就表示输出了”ccc“和"aaa",且用到h4h_4h4时,所有alignments的概率之和。
而α4,2\alpha_{4,2}α4,2只可能从α4,1\alpha_{4,1}α4,1或者α3,2\alpha_{3,2}α3,2过来,所以有
α4,2=α4,1p4,1(a)+α3,2p3,2(ϕ)\alpha_{4,2} = \alpha_{4,1}p_{4,1}(a)+ \alpha_{3,2}p_{3,2}(\phi) α4,2=α4,1p4,1(a)+α3,2p3,2(ϕ)
按照这个办法,我们就可以把这整个表格填满,而右下角最后一个格子的概率,就是P(Y∣X)P(Y|X)P(Y∣X)。
3 Training
而以上的这些步骤,都只是一个forward的过程,我们还没有到training这一步。我们先要有一个一组参数θ\thetaθ可以输出Pθ(Y^∣X)P_{\theta}(\hat{Y}|X)Pθ(Y^∣X),然后我们再用梯度下降的方法去优化参数,使得给定一段声音讯号XXX,模型输出标签Y^\hat{Y}Y^的概率是最大的。
θ∗=argmax⏟θlogPθ(Y^∣X)\theta^* = \underbrace{argmax}_{\theta} log P_{\theta}(\hat{Y}|X) θ∗=θargmaxlogPθ(Y^∣X)
在梯度下降时,我们当然要先求解一下偏微分
∂P(Y^∣X)∂θ\frac{\partial P(\hat{Y}|X)}{\partial \theta}∂θ∂P(Y^∣X)
而这里的P(Y^∣X)=∑h∈align(Y^)P(h∣X)P(\hat{Y}|X) = \sum_{h \in align(\hat{Y})}P(h|X)P(Y^∣X)=∑h∈align(Y^)P(h∣X)是一堆和p1,0(ϕ)p_{1,0}(\phi)p1,0(ϕ),p2,0(c)p_{2,0}(c)p2,0(c),p2,1(ϕ)p_{2,1}(\phi)p2,1(ϕ),⋯\cdots⋯这些相关的连乘和连加。故
∂P(Y^∣X)∂θ=∂p4,1(a)∂θP(Y^∣X)∂p4,1(a)+⋯\frac{\partial P(\hat{Y}|X)}{\partial \theta} = \frac{\partial p_{4,1}(a)}{\partial \theta} \frac{P(\hat{Y}|X)}{\partial p_{4,1}(a)}+\cdots∂θ∂P(Y^∣X)=∂θ∂p4,1(a)∂p4,1(a)P(Y^∣X)+⋯
我们以∂p4,1(a)∂θP(Y^∣X)∂p4,1(a)\frac{\partial p_{4,1}(a)}{\partial \theta} \frac{P(\hat{Y}|X)}{\partial p_{4,1}(a)}∂θ∂p4,1(a)∂p4,1(a)P(Y^∣X)为例,先来算一下∂p4,1(a)∂θ\frac{\partial p_{4,1}(a)}{\partial \theta}∂θ∂p4,1(a)。这个部分就和正常的RNN神经网络反向传播(BPTT)一致,这里不做说明。示意图如下所示。
而在计算P(Y^∣X)∂p4,1(a)\frac{P(\hat{Y}|X)}{\partial p_{4,1}(a)}∂p4,1(a)P(Y^∣X)时,我们就可以把P(Y^∣X)P(\hat{Y}|X)P(Y^∣X)拆分成
P(Y^∣X)=∑hwithp4,1(a)P(h∣X)+∑hwithoutp4,1(a)P(h∣X)P(\hat{Y}|X) = \sum_{h\ with\ p_{4,1}(a)} P(h|X)+\sum_{h\ without\ p_{4,1}(a)} P(h|X) P(Y^∣X)=h with p4,1(a)∑P(h∣X)+h without p4,1(a)∑P(h∣X)
这里的第二项和p4,1(a)p_{4,1}(a)p4,1(a)没有关系,故求偏导为0,可直接忽略,前一项可以写成
∑hwithp4,1(a)P(h∣X)=∑hwithp4,1(a)p4,1(a)×others\sum_{h\ with\ p_{4,1}(a)} P(h|X) = \sum_{h\ with\ p_{4,1}(a)} p_{4,1}(a) \times others h with p4,1(a)∑P(h∣X)=h with p4,1(a)∑p4,1(a)×others
故
P(Y^∣X)∂p4,1(a)=∑hwithp4,1(a)others=∑hwithp4,1(a)P(h∣X)p4,1(a)=1p4,1(a)∑hwithp4,1(a)P(h∣X)\frac{P(\hat{Y}|X)}{\partial p_{4,1}(a)} = \sum_{h\ with\ p_{4,1}(a)} others=\sum_{h\ with\ p_{4,1}(a)} \frac{P(h|X)}{p_{4,1}(a)}=\frac{1}{p_{4,1}(a)}\sum_{h\ with\ p_{4,1}(a)}P(h|X) ∂p4,1(a)P(Y^∣X)=h with p4,1(a)∑others=h with p4,1(a)∑p4,1(a)P(h∣X)=p4,1(a)1h with p4,1(a)∑P(h∣X)
那么问题来了,这个∑hwithp4,1(a)P(h∣X)\sum_{h\ with\ p_{4,1}(a)}P(h|X)∑h with p4,1(a)P(h∣X)该怎么算呢?这里,我们就要引进HMM中的backward algorithm。这个和之前的forward algorithm很类似,我们定义一个参数βi,j\beta_{i,j}βi,j表示从输入第iii个声音讯号,输出第jjj个token的位置开始,一致走到终点的所有alignments的概率之和。
而这个βi,j\beta_{i,j}βi,j也是和αi,j\alpha_{i,j}αi,j一样,整个表格是可以事先填满的。
那么根据αi,j\alpha_{i,j}αi,j和βi,j\beta_{i,j}βi,j的定义,我们有
∑hwithp4,1(a)P(h∣X)=α4,1p4,1(a)β4,2\sum_{h\ with\ p_{4,1}(a)}P(h|X) = \alpha_{4,1} p_{4,1}(a)\beta_{4,2} h with p4,1(a)∑P(h∣X)=α4,1p4,1(a)β4,2
那么就有
P(Y^∣X)∂p4,1(a)=α4,1β4,2\frac{P(\hat{Y}|X)}{\partial p_{4,1}(a)} = \alpha_{4,1} \beta_{4,2} ∂p4,1(a)P(Y^∣X)=α4,1β4,2
示意图如下所示。
4 Inference
现在假设我们已经train好了一个模型,然后输出XXX和YYY就可以计算出P(Y∣X)P(Y|X)P(Y∣X)这个概率,那么我们要做的就是找到一个Y∗Y^*Y∗使得P(Y∗∣X)P(Y^*|X)P(Y∗∣X)最大。
Y∗=argmax⏟YP(Y∣X)Y^*=\underbrace{argmax}_{Y}P(Y|X) Y∗=YargmaxP(Y∣X)
虽然有演算法可以做到这点,但还是太过复杂,实际情况下,我们不会那么去做。我们会去找一个近似的解。而这个求近似解的方法,就是取每一个pi,jp_{i,j}pi,j中概率最大的那一个就可以了。这个也被称为greedy decoding。
如果希望更精确一些,也可以用Beam Search。greedy decoding可以说是beam search的一种特殊情况,就是beam=1的时候的情况。在遍历每个time step的时候,我会会一直保留一个大小为beam的候选集,候选集中是多个长度相等,但不同的字符串,每个字符串有一个score,也就是其概率大小。
比如我们有一个非常简单的输出矩阵为,其中#就是空白符ϕ\phiϕ
我们用beam search取找其最优组合的过程为
要注意的是,每次得到的新的字符串可能来自于不同的beam,要把他们的概率都加起来。beam越大,最终输出的结果就越准,但相应的计算成本也就更高。一般情况下,我们都是greedy search来做的,没必要用这个,仅作为了解。其实现可见[这里]。(https://github.com/githubharald/CTCDecoder/blob/master/ctc_decoder/beam_search.py)
5 小结
最后,我们来比较一下LAS,CTC以及RNN-T这三者的异同。在decoder这部分,LAS和RNN-T是依赖于之前的输出的,而CTC是不管的;CTC和RNN-T是需要对结果做alignment的,而LAS是输出什么就是什么的;LAS的training就是硬train一发,而CTC和RNN-T由于需要alignment,会复杂一些;LAS是无法做到句子还没念完就输出预测结果的,但是CTC和RNN-T是可以的。