基于GMMs-HMMs的语音识别原理

刚入门ASR的时候一直能听到HMM模型的相关字眼,这里就补一下用GMMs-HMMs进行语音识别的原理,虽然这个方法很古老,而且已经近乎被神经网络所取代,但它背后的思想仍然值得我们去了解和学习~

笔者看了一些教程,包括课程讲义、博客还有一些工具书,总算大致理清了思路,相信至少在文章逻辑上比一些没有相关背景设定、无厘头、不知所云的教程要好,原理上至少也是能用到的都有介绍。而有些地方太深入的原理笔者也没有去细究,感兴趣的读者根据笔者的逻辑自己去深入探索即可。

整体的行文思路按照“结果导向”,需要什么数学知识和原理再去介绍什么,而不是上来就用GMM和HMM进行轰炸,导致前后脱节。在数学原理上,也是尽量做到通俗易懂,加入自己的理解,而不是甩一堆高深莫测的公式。

一. 最简单的场景:孤立词识别

1.1 整体思路

孤立词识别是语音识别中最简单的场景,即一个音频文件里面只包含一个词的语音。训练和识别的整体思路为:
(1)训练阶段:对于每个词,用不同人录制的这个词的音频特征作为训练样本,构建一个生成模型 P ( X ∣ W ) P(X|W) P(XW) W W W表示词, X X X表示音频文件提取出的特征(如FBank、MFCC等,参见这篇博客)。
(2)识别阶段:给定一段音频特征,经过上面学习到的每个词的 P ( X ∣ W ) P(X|W) P(XW)模型,看哪个词生成这段音频特征的概率最大,取最大的那个词作为识别词。

形象化的图如下:

这里的重点就是 P ( X ∣ W ) P(X|W) P(XW)这个生成模型的建立。因为对于每个孤立词都是分别采用一个生成模型来独立建模的,所以后面介绍的原理都是以一个孤立词为例讲解。

1.2 模型结构

对于这种时间序列的建模,自然就是采用HMM模型。其结构图如下:

不大张旗鼓地讲那么多关于HMM没用的东西,就看这个图来讲解。它的构建思路就是认为音频特征是由一些隐藏状态生成的,这些状态内部会有转移,并且满足马尔可夫性,状态个数是超参数,需要自己设置(一般3~5个)。

对于除了开始( s I s_I sI)和结束( s E s_E sE)这两个状态之外的状态,都有两种转移选择,要么就转向自己,要么就转向下一个状态。因为音频特征的序列长度往往要比状态个数多,所以这里要有转向自己的,因此每个状态可能对应多个音频特征的“帧”。

以这个图里面的3个状态和对齐为例,生成模型可展开为: P ( X ∣ W ) = P ( x 1 ∣ s 1 ) P ( s 1 ∣ s 1 ) P ( x 2 ∣ s 1 ) P ( s 1 ∣ s 1 ) P ( x 3 ∣ s 1 ) P ( s 2 ∣ s 1 ) P ( x 4 ∣ s 2 ) P ( s 2 ∣ s 2 ) P ( x 5 ∣ s 2 ) P ( s 3 ∣ s 2 ) P ( x 6 ∣ s 3 ) P(X|W)=P(x_1|s_1)P(s_1|s_1)P(x_2|s_1)P(s_1|s_1)P(x_3|s_1)P(s_2|s_1)P(x_4|s_2)P(s_2|s_2)P(x_5|s_2)P(s_3|s_2)P(x_6|s_3) P(XW)=P(x1s1)P(s1s1)P(x2s1)P(s1s1)P(x3s1)P(s2s1)P(x4s2)P(s2s2)P(x5s2)P(s3s2)P(x6s3)

这里主要有两部分概率需要学习:

(1) a i j a_{ij} aij P ( s j ∣ s i ) P(s_j|s_i) P(sjsi),状态转移概率
(2) b j ( x t ) b_j(x_t) bj(xt) P ( x t ∣ s j ) P(x_t|s_j) P(xtsj),输出生成概率

其中 b j ( x t ) b_j(x_t) bj(xt)一般采用GMM进行建模,这也就是为什么叫GMM-HMM。直接给出GMM的公式:

b j ( x t ) = ∑ m = 1 M c j m N ( x t ; μ j m , Σ j m ) b_j(x_t) = \sum_{m=1}^M c_{jm} N(x_t; \mu_{jm}, \Sigma_{jm}) bj(xt)=m=1McjmN(xt;μjm,Σjm)

N ( x ; μ , Σ ) = 1 ( 2 π ) D / 2 ∣ Σ ∣ 1 / 2 e x p ( − 1 2 ( x − μ ) T Σ − 1 ( x − μ ) ) N(x_; \mu, \Sigma) = \frac{1}{(2\pi)^{D/2}|\Sigma|^{1/2}}exp(-\frac{1}{2}(x - \mu)^T \Sigma^{-1}(x - \mu)) N(x;μ,Σ)=(2π)D/2Σ1/21exp(21(xμ)TΣ1(xμ))

即认为输出生成概率由高斯混合模型生成,先根据概率 c j m c_{jm} cjm选择一个高斯模型,然后根据这个模型的概率分布 N ( x t ; μ j m , Σ j m ) N(x_t; \mu_{jm}, \Sigma_{jm}) N(xt;μjm,Σjm)生成 x t x_t xt

总结一下,要学习的参数有:

  1. a i j a_{ij} aij:HMM的状态转移概率矩阵
  2. c j m c_{jm} cjm:各状态对应的GMM中的混合权重(如果是单高斯建模,则不用学习)
  3. μ j m \mu_{jm} μjm:各状态对应的GMM中各高斯分量的均值向量
  4. Σ j m \Sigma_{jm} Σjm:各状态对应的GMM中各高斯分量的协方差矩阵

建立好这样的模型之后,后面就是如何根据样本进行训练了。

1.3 训练过程

这里的训练,确切来讲应该叫参数估计,用一定的算法来估计参数,使其能够拟合数据分布(即最大化数据的似然概率)。下面循序渐进地来讲这种参数估计算法:

1.3.1 单样本、单高斯

这是一种最简单的情况,假设一个词的训练样本只有一个音频文件,并且对于输出概率 b j ( x t ) b_j(x_t) bj(xt)采用单高斯建模,即 m = 1 m=1 m=1 c j m = 1 c_{jm}=1 cjm=1。此时需要估计的参数为:

  1. a i j a_{ij} aij:HMM的状态转移概率矩阵
  2. μ j \mu_{j} μj:各状态对应的单高斯模型的均值向量
  3. Σ j \Sigma_{j} Σj:各状态对应的单高斯模型的协方差矩阵

这里进行参数估计的一大难点就是:各个状态对应哪些音频帧是不知道的,不像1.2里面给出的那个图那样具有对齐信息。所以输出概率 b j ( x t ) b_j(x_t) bj(xt)根本不知道具体去拟合哪些音频帧数据。

为了解决这个问题,引入一种软对齐策略,即给出各个音频帧属于各个状态的概率(各个时刻处于各个状态的概率) γ t ( j ) = P ( s t = j ∣ X ) \gamma_t(j) = P(s_t = j|X) γt(j)=P(st=jX),此时对于各个单高斯模型的参数估计就可以写为:

μ ^ j = ∑ t = 1 T γ t ( j ) x t ∑ t = 1 T γ t ( j ) \hat \mu_j = \frac{\sum_{t=1}^T \gamma_t(j) x_t}{\sum_{t=1}^T \gamma_t(j)} μ^j=t=1Tγt(j)t=1Tγt(j)xt

Σ ^ j = ∑ t = 1 T γ t ( j ) ( x t − μ ^ j ) ( x t − μ ^ j ) T ∑ t = 1 T γ t ( j ) \hat \Sigma_j = \frac{\sum_{t=1}^T \gamma_t(j) (x_t - \hat \mu_j) (x_t - \hat \mu_j) ^ T}{\sum_{t=1}^T \gamma_t(j)} Σ^j=t=1Tγt(j)t=1Tγt(j)(xtμ^j)(xtμ^j)T

这个地方不好理解的话,再说得深入一些:

如果最理想情况下给出了各个状态对应的音频帧,像1.2节的图那样。则每个状态对应的高斯模型需要拟合的数据就确定了,此时根据最大似然概率,均值和方差分别应该估计为:

μ ^ j = ∑ t = 1 T z j t x t ∑ t = 1 T z j t \hat \mu_j = \frac{\sum_{t=1}^T z_{jt} x_t}{\sum_{t=1}^T z_{jt}} μ^j=t=1Tzjtt=1Tzjtxt

Σ ^ j = ∑ t = 1 T z j t ( x t − μ ^ j ) ( x t − μ ^ j ) T ∑ t = 1 T z j t \hat \Sigma_j = \frac{\sum_{t=1}^T z_{jt} (x_t - \hat \mu_j) (x_t - \hat \mu_j) ^ T}{\sum_{t=1}^T z_{jt}} Σ^j=t=1Tzjtt=1Tzjt(xtμ^j)(xtμ^j)T

z j t = 1     i f    x t ∈ s j    e l s e    0 z_{jt} = 1 \ \ \ if \ \ x_t \in s_j \ \ else \ \ 0 zjt=1   if  xtsj  else  0

但是这里没有 z j t z_{jt} zjt这种“硬对齐”信息,所以要用“软对齐”的概率 γ t ( j ) \gamma_t(j) γt(j)来代替。

同样的,对于转移概率 a k j a_{kj} akj,也引入软对齐转移概率 ξ t ( i , j ) = P ( s t = i , s t + 1 = j ∣ X ) \xi_t(i, j) = P(s_t = i, s_{t+1} = j|X) ξt(i,j)=P(st=i,st+1=jX),表示在 t t t 时刻的状态在 s i s_i si,而在 t + 1 t+1 t+1 时刻的状态为 s j s_j sj的概率。此时转移概率可以估计为:

a ^ i j = ∑ t = 1 T ξ t ( i , j ) ∑ k = 1 N ∑ t = 1 T ξ t ( i , k ) \hat a_{ij} = \frac{\sum_{t=1}^T\xi_t (i, j)}{\sum_{k=1}^N \sum_{t=1}^T \xi_t (i, k)} a^ij=k=1Nt=1Tξt(i,k)t=1Tξt(i,j)

即状态 s i s_i si转到状态 s j s_j sj(在各个时刻下求和)的概率除以状态 s i s_i si转到其他所有状态 s k s_k sk(在各个时刻下求和)的概率。

综上,在进行参数估计前,需要先拿到 γ t ( j ) \gamma_t(j) γt(j) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)这两个概率。

那么,这两个软对齐概率要怎么计算呢?此时就需要用到HMM中经典的前向-后向概率计算公式。引入两个概率:

(1) α t ( j ) \alpha_t(j) αt(j):前向概率,展开为 α t ( j ) = P ( x 1 , x 2 , . . . , x t , s t = j ) \alpha_t(j) = P(x_1, x_2, ..., x_t, s_t = j) αt(j)=P(x1,x2,...,xt,st=j),即已经输出 x 1 , x 2 , . . . , x t x_1, x_2, ..., x_t x1,x2,...,xt,并且在时刻 t t t 处在状态 s j s_j sj的概率。
(2) β t ( j ) \beta_t(j) βt(j):后向概率,展开为 β t ( j ) = P ( x t + 1 , x t + 2 , . . . , x T ∣ s t = j ) \beta_t(j) = P(x_{t+1}, x_{t+2}, ..., x_{T} | s_t = j) βt(j)=P(xt+1,xt+2,...,xTst=j),在时刻 t t t 处在状态 s j s_j sj时,后续输出为 x t + 1 , x t + 2 , . . . , x T x_{t+1}, x_{t+2}, ..., x_T xt+1,xt+2,...,xT的概率。

在给出了这两个概率时,就可以计算 γ t ( j ) \gamma_t(j) γt(j) ξ t ( i , j ) \xi_t(i, j) ξt(i,j),如下:

γ t ( j ) = P ( s t = j ∣ X ) = 1 α T ( s E ) α t ( j ) β t ( j ) \gamma_t(j) = P(s_t = j|X) = \frac{1}{\alpha_T(s_E)} \alpha_t(j) \beta_t(j) γt(j)=P(st=jX)=αT(sE)1αt(j)βt(j)

ξ t ( i , j ) = P ( s t = i , s t + 1 = j ∣ X ) = α t ( i ) a i j b j ( x t + 1 ) β t + 1 ( j ) α T ( s E ) \xi_t (i, j) = P(s_t = i, s_{t+1} = j|X) = \frac{\alpha_t(i) a_{ij} b_j(x_{t+1}) \beta_{t+1} (j)}{\alpha_T(s_E)} ξt(i,j)=P(st=i,st+1=jX)=αT(sE)αt(i)aijbj(xt+1)βt+1(j)

这里的 α T ( s E ) \alpha_T(s_E) αT(sE)实际上就是 P ( X ) P(X) P(X)

综上,在计算 γ t ( j ) \gamma_t(j) γt(j) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)这两个概率之前,需要先计算 α t ( j ) \alpha_t(j) αt(j) β t ( j ) \beta_t(j) βt(j)

那么如何计算前向和后向概率呢?先放一张图:

这是一个典型的所有可能路径的示意图, α t ( j ) \alpha_t(j) αt(j)即计算从起点的紫色圆圈到其中某个青色圆圈的所有路径的概率和, β t ( j ) \beta_t(j) βt(j)即计算从某个青色圆圈到终点的紫色圆圈的所有路径的概率和。计算方式采用动态规划算法,迭代进行:

具体地,对于 α t ( j ) \alpha_t(j) αt(j),计算方法为:

(1)初始化: α 0 ( s I ) = 1 \alpha_0(s_I) = 1 α0(sI)=1 α 0 ( j ) = 0     i f    j    ! =   s I \alpha_0(j) = 0 \ \ \ if \ \ j \ \ != \ s_I α0(j)=0   if  j  != sI
(2)迭代: α t ( j ) = ∑ i = 1 N α t − 1 ( j ) a i j b j ( x t )     1 &lt; = j &lt; = N , 1 &lt; = t &lt; = T \alpha_t(j) = \sum_{i=1}^N \alpha_{t-1}(j) a_{ij} b_j(x_t) \ \ \ 1 &lt;= j &lt;= N, 1&lt;=t&lt;=T αt(j)=i=1Nαt1(j)aijbj(xt)   1<=j<=N,1<=t<=T
(3)终止: P ( X ) = α T ( s E ) = ∑ i = 1 N α T ( i ) a i E P(X) = \alpha_T(s_E) = \sum_{i=1}^N \alpha_T(i) a_{iE} P(X)=αT(sE)=i=1NαT(i)aiE

下图是迭代计算过程中拆分出的某一步的示意图,展示了动态规划的计算方法。

同样地,对于 β t ( i ) \beta_t(i) βt(i),计算方法为:

(1)初始化: β T ( i ) = a i E \beta_T(i) = a_{iE} βT(i)=aiE
(2)迭代: β t ( i ) = ∑ j = 1 N a i j b j ( x t + 1 ) β t + 1 ( j )     f o r    t    = T − 1 , . . . , 1 \beta_t(i) = \sum_{j=1}^N a_{ij} b_j(x^{t+1}) \beta_{t+1}(j) \ \ \ for \ \ t \ \ = T-1, ..., 1 βt(i)=j=1Naijbj(xt+1)βt+1(j)   for  t  =T1,...,1
(3)终止: P ( X ) = β 0 ( s I ) = ∑ j = 1 N a I j b j ( x 1 ) β 1 ( j ) = α T ( s E ) P(X) = \beta_0(s_I) = \sum_{j=1}^N a_{Ij}b_j(x^1)\beta_1(j) = \alpha_T(s_E) P(X)=β0(sI)=j=1NaIjbj(x1)β1(j)=αT(sE)

下图是迭代过程中拆分出的某一步的示意图:

到这里,所有在参数估计中需要用到的概率都已经计算完毕了,下面展示整个流程。

整个参数估计的流程,其实还是需要迭代的,这里采用EM算法(一种对含有隐变量模型进行参数估计的迭代算法,在HMM的场景里,也叫前向-后向算法或Baum-Welch算法):

  1. 初始化:

笔者看到的有:对于GMM,一种做法是用所有数据进行估计,另一种是用K-Means先聚类一波;对于HMM的转移概率,是用的平均。

  1. 对于每一次迭代:

(1)E步:用上一步估计出的参数,迭代计算前向概率 α t ( j ) \alpha_t(j) αt(j)和后向概率 β t ( j ) \beta_t(j) βt(j),进而计算软对齐概率 γ t ( j ) \gamma_t(j) γt(j) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)
(2)M步:基于E步计算的4组概率,对 μ ^ j \hat \mu_j μ^j Σ ^ j \hat \Sigma_j Σ^j a ^ i j \hat a_{ij} a^ij进行估计。

其中每一步的计算公式,前面都已经详细说明了。

1.3.2 扩展到高斯混合模型

一般在对于输出概率分布的建模,都会采用GMM方法。理论上,足够的单高斯模型的混合可以拟合任意的分布。1.3.1的单高斯建模只是一种特例,目的还是为了方便扩展到GMM的场景。

这里需要估计的参数就要加上GMM的混合权重,即:

  1. a k j a_{kj} akj:HMM的状态转移概率矩阵
  2. c j m c_{jm} cjm:各状态对应的GMM中的混合权重
  3. μ j m \mu_{jm} μjm:各状态对应的GMM中各高斯分量的均值向量
  4. Σ j m \Sigma_{jm} Σjm:各状态对应的GMM中各高斯分量的协方差矩阵

对于GMM的参数估计中,与之前HMM是同样的道理。因为在音频帧对应到某个状态后,还是不知道其是GMM中的哪个分量生成的。所以还是需要一种软对齐概率,具体表现在 γ t ( j ) \gamma_t(j) γt(j)上,此时需要改为 γ t ( j , m ) \gamma_t(j, m) γt(j,m),表示在时刻t,属于状态 s j s_j sj以及第 m m m个高斯分量的概率。

笔者猜测的 γ t ( j , m ) \gamma_t(j, m) γt(j,m)计算公式为:(因为没找到相关的资料,如果有错误,还请指出~)

γ t ( j , m ) = P ( s t = j , c t = m ∣ X ) = P ( s t = j ∣ X ) P ( c t = m ∣ s t = j , X ) = 1 α T ( s E ) α t ( j ) β t ( j ) 1 ( 2 π ) D / 2 ∣ Σ j m ∣ 1 / 2 e x p ( − 1 2 ( x t − μ j m ) T Σ j m − 1 ( x t − μ j m ) ) \gamma_t(j, m) = P(s_t = j, c_t = m |X) = P(s_t = j | X) P(c_t = m | s_t = j, X) = \frac{1}{\alpha_T(s_E)} \alpha_t(j) \beta_t(j) \frac{1}{(2\pi)^{D/2}|\Sigma_{jm}|^{1/2}}exp(-\frac{1}{2}(x_t - \mu_{jm})^T \Sigma_{jm}^{-1}(x_t - \mu_{jm})) γt(j,m)=P(st=j,ct=mX)=P(st=jX)P(ct=mst=j,X)=αT(sE)1αt(j)βt(j)(2π)D/2Σjm1/21exp(21(xtμjm)TΣjm1(xtμjm))

相应的,对于 μ ^ j m \hat \mu_{jm} μ^jm Σ ^ j m \hat \Sigma_{jm} Σ^jm的参数估计就要改为:

μ ^ j m = ∑ t = 1 T γ t ( j , m ) x t ∑ t = 1 T γ t ( j , m ) \hat \mu_{jm} = \frac{\sum_{t=1}^T \gamma_t(j, m) x_t}{\sum_{t=1}^T \gamma_t(j, m)} μ^jm=t=1Tγt(j,m)t=1Tγt(j,m)xt

Σ ^ j m = ∑ t = 1 T γ t ( j , m ) ( x t − μ ^ j m ) ( x t − μ ^ j m ) T ∑ t = 1 T γ t ( j , m ) \hat \Sigma_{jm} = \frac{\sum_{t=1}^T \gamma_t(j, m) (x_t - \hat \mu_{jm}) (x_t - \hat \mu_{jm}) ^ T}{\sum_{t=1}^T \gamma_t(j, m)} Σ^jm=t=1Tγt(j,m)t=1Tγt(j,m)(xtμ^jm)(xtμ^jm)T

GMM的混合参数估计如下:

c ^ j m = ∑ t = 1 T γ t ( j , m ) ∑ m ′ = 1 M ∑ t = 1 T γ t ( j , m ′ ) \hat c_{jm} = \frac{\sum_{t=1}^T \gamma_t(j, m)}{\sum_{m&#x27;=1}^M \sum_{t=1}^T \gamma_t(j, m&#x27;)} c^jm=m=1Mt=1Tγt(j,m)t=1Tγt(j,m)

即处于状态 j j j 和分量 m m m 的概率,除以处于状态 j j j 和其他所有分量的概率。

而前向概率 α t ( j ) \alpha_t(j) αt(j)、后向概率 β t ( j ) \beta_t(j) βt(j) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)的计算公式不变,转移概率 a i j a_{ij} aij的估计公式也不变。

那么EM的流程就变为:

(1)E步:用上一步估计出的参数,迭代计算前向概率 α t ( j ) \alpha_t(j) αt(j)和后向概率 β t ( j ) \beta_t(j) βt(j),进而计算软对齐概率 γ t ( j , m ) \gamma_t(j, m) γt(j,m) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)
(2)M步:基于E步计算的4组概率,对 μ ^ j m \hat \mu_{jm} μ^jm Σ ^ j m \hat \Sigma_{jm} Σ^jm c ^ j m \hat c_{jm} c^jm a ^ i j \hat a_{ij} a^ij进行估计。

1.3.3 扩展到多个训练样本

前面1.3.1和1.3.2讨论的都是只有一个训练样本的情况,实际上对于每个词,都会有很多个音频文件与之对应,从而提升模型建模的鲁棒性。

假设某个词一共有 R R R 个音频文件,则前面的 x t x_t xt就要改为 x t r x_t^r xtr,表示第 r r r 个训练样本中的第 t t t 帧。此时EM的流程变为:

(1)E步:对每个样本都计算出: α t r ( j ) \alpha_t^r(j) αtr(j) β t r ( j ) \beta_t^r(j) βtr(j) γ t r ( j , m ) \gamma_t^r(j, m) γtr(j,m) ξ t r ( i , j ) \xi_t^r(i, j) ξtr(i,j)
(2)M步:对于参数的估计需要在全部的训练样本上进行,具体为

μ ^ j m = ∑ r = 1 R ∑ t = 1 T γ t r ( j , m ) x t r ∑ r = 1 R ∑ t = 1 T γ t r ( j , m ) \hat \mu_{jm} = \frac{\sum_{r=1}^R \sum_{t=1}^T \gamma_t^r(j, m) x_t^r}{\sum_{r=1}^R \sum_{t=1}^T \gamma_t^r(j, m)} μ^jm=r=1Rt=1Tγtr(j,m)r=1Rt=1Tγtr(j,m)xtr

Σ ^ j m = ∑ r = 1 R ∑ t = 1 T γ t r ( j , m ) ( x t r − μ ^ j m ) ( x t r − μ ^ j m ) T ∑ r = 1 R ∑ t = 1 T γ t r ( j , m ) \hat \Sigma_{jm} = \frac{\sum_{r=1}^R \sum_{t=1}^T \gamma_t^r(j, m) (x_t^r - \hat \mu_{jm}) (x_t^r - \hat \mu_{jm}) ^ T}{\sum_{r=1}^R \sum_{t=1}^T \gamma_t^r(j, m)} Σ^jm=r=1Rt=1Tγtr(j,m)r=1Rt=1Tγtr(j,m)(xtrμ^jm)(xtrμ^jm)T

c ^ j m = ∑ r = 1 R ∑ t = 1 T γ t r ( j , m ) ∑ r = 1 R ∑ m ′ = 1 M ∑ t = 1 T γ t r ( j , m ′ ) \hat c_{jm} = \frac{\sum_{r=1}^R \sum_{t=1}^T \gamma_t^r(j, m)}{\sum_{r=1}^R \sum_{m&#x27;=1}^M \sum_{t=1}^T \gamma_t^r(j, m&#x27;)} c^jm=r=1Rm=1Mt=1Tγtr(j,m)r=1Rt=1Tγtr(j,m)

a ^ i j = ∑ r = 1 R ∑ t = 1 T ξ t r ( i , j ) ∑ r = 1 R ∑ k = 1 N ∑ t = 1 T ξ t r ( i , k ) \hat a_{ij} = \frac{\sum_{r=1}^R \sum_{t=1}^T\xi_t^r (i, j)}{\sum_{r=1}^R \sum_{k=1}^N \sum_{t=1}^T \xi_t^r (i, k)} a^ij=r=1Rk=1Nt=1Tξtr(i,k)r=1Rt=1Tξtr(i,j)

在训练完成后,就是如何利用训练好的模型对新音频进行识别了。

1.4 识别过程

识别的过程,就是给定一段音频 X X X,对于每个词的模型 P ( X ∣ W ) P(X|W) P(XW),都计算出其生成 X X X的概率,然后取最大的那个 W = a r g m a x W P ( X ∣ W ) W = argmax_W P(X|W) W=argmaxWP(XW)作为识别出的孤立词。

这里的 P ( X ∣ W ) P(X|W) P(XW)实际在前面已经提到了,就是 α T ( s E ) \alpha_T(s_E) αT(sE),但一般在识别过程中,不会对所有路径的概率计算总和,而是会选择最大的那一条概率作为最终的概率。这其实就是HMM中经典的维特比算法。

定义概率 V t ( j ) V_t(j) Vt(j),表示在时刻 t t t 到达状态 s j s_j sj的所有路径中概率的最大值,对应到1.3中第一张路径图,即从起始的紫色圆圈到某个青色圆圈的所有路径概率中,最大的那一个。同时定义回溯指针 b t t ( j ) bt_t(j) btt(j),即时刻 t t t 到达状态 s j s_j sj的所有路径中概率最大的那一条路径对应的前一个状态,便于之后进行状态回溯。

与前向概率 α t ( j ) \alpha_t(j) αt(j)类似,对于 V t ( j ) V_t(j) Vt(j) b t t ( j ) bt_t(j) btt(j)的计算也是采用动态规划进行迭代计算,具体的计算方式为:

(1)初始化:
V 0 ( s I ) = 1 V_0(s_I) = 1 V0(sI)=1

V 0 ( j ) = 0     i f    j    ! =   s I V_0(j) = 0 \ \ \ if \ \ j \ \ != \ s_I V0(j)=0   if  j  != sI

b t 0 ( j ) = 0 bt_0(j) = 0 bt0(j)=0

(2)迭代:
V t ( j ) = a r g m a x i = 1 N V t − 1 ( j ) a i j b j ( x t ) V_t(j) = argmax_{i=1}^N V_{t-1}(j) a_{ij} b_j(x_t) Vt(j)=argmaxi=1NVt1(j)aijbj(xt)

b t t ( j ) = a r g m a x i = 1 N V t − 1 ( j ) a i j b j ( x t ) bt_t(j) = argmax_{i=1}^N V_{t-1}(j) a_{ij} b_j(x_t) btt(j)=argmaxi=1NVt1(j)aijbj(xt)
(3)终止:
P ∗ = V T ( s E ) = max ⁡ i = 1 N V T ( i ) a i E P^* = V_T(s_E) = \max_{i=1}^N V_T(i) a_{iE} P=VT(sE)=i=1maxNVT(i)aiE

s T ∗ = b t T ( s E ) = a r g m a x i = 1 N V T ( i ) a i E s_T^* = bt_T(s_E) = argmax_{i=1}^N V_T(i) a_{iE} sT=btT(sE)=argmaxi=1NVT(i)aiE

下面两个图是拆分出的中间某一步的迭代计算过程:

最后的识别词为: W = a r g m a x W P ( X ∣ W ) = a r g m a x W V T W ( s E ) W = argmax_W P(X|W) = argmax_W V_T^W(s_E) W=argmaxWP(XW)=argmaxWVTW(sE)

至此,对于孤立词识别的全部内容就已经介绍完毕!

二. 扩展到通用场景:连续语音识别

2.1 整体思路

连续语言识别是比较通用的场景,即一个音频文件里面包含一个连续的句子,而不是一个词,其难点在于不知道每个词对应音频文件的起止位置。如果有这种标注好的切分,那么仍然可以沿用前面的孤立词识别方式进行训练和识别,但这样着实费时费力,而且会有人工误差。那么,能不能在没有切分的情况下,对一整段音频,识别一整个句子?当然可以,下面将详细介绍。

与孤立词识别类似,这里是希望构建一个判别模型 P ( S ∣ X ) P(S|X) P(SX),其中 X X X是音频特征, S S S是其对应的句子。训练是希望能最大化 P ( S ∣ X ) P(S|X) P(SX),识别是希望能找到 a r g m a x S P ( S ∣ X ) argmax_S P(S|X) argmaxSP(SX)。对于 P ( S ∣ X ) P(S|X) P(SX)的建模通常会通过贝叶斯公式转为 P ( S ∣ X ) ≈ P ( X ∣ S ) P ( S ) P(S|X) \approx P(X|S)P(S) P(SX)P(XS)P(S)来处理,其中 P ( X ∣ S ) P(X|S) P(XS)即为生成模型, P ( S ) P(S) P(S)为语言模型(这里不涉及到语言模型的细节)。

其训练和识别的整体思路为:
(1)训练阶段:对于所有的句子,构建生成模型 P ( X ∣ S ) P(X|S) P(XS),最大化每个句子的似然概率。
(2)识别阶段:给定一段音频特征,用构建好的生成模型和语言模型,得到识别出的句子 a r g m a x S P ( X ∣ S ) P ( S ) argmax_S P(X|S)P(S) argmaxSP(XS)P(S)

2.2 模型结构

对于生成模型 P ( X ∣ S ) P(X|S) P(XS)的构建,可以使用“嵌入训练(embedded training)”的方式。

理想情况下,在词表比较小的时候,可以对每个词进行一个HMM建模(与之前孤立词识别一样),而后将整个句子中所有词的HMM状态都串起来,作为一个超长的HMM,其训练方式与1.3节的一样。

但在真实场景中,词表往往很庞大,此时如果对所有的词建模,HMM模型将非常多。所以,一般都是将句子转成音素串(可以将音素理解为音标,一个词会对应一条音素序列)进行处理,音素表往往会小很多,这样对每个音素建模较为简便。

总结一下,在连续语音场景中,是为每个音素建立一个HMM模型,将句子转为音素串之后,将句子中所有音素对应的HMM状态都串在一起(中间的开始和结束状态会去掉),成为一个超长的HMM模型,如下图:

这里的句子“six quid”转为音素串为“/s/ /ih/ /k/ /s/ … /d/”,每个“beg mid end”是对一个音素的3状态HMM建模。

2.3 训练过程

在串成2.2节中超长的HMM之后,训练的方式就与1.3节中的类似了,只不过1.3节中是每次对一个HMM模型进行训练,这里是一次对很多个HMM模型进行并行训练。

其训练流程为:

  1. 获取下一个句子;
  2. 转成音素串后,按照2.2节构建成超长的HMM模型,当成一个HMM模型来处理;
  3. E步:迭代计算前向概率 α t ( j ) \alpha_t(j) αt(j)和后向概率 β t ( j ) \beta_t(j) βt(j),进而计算软对齐概率 γ t ( j , m ) \gamma_t(j, m) γt(j,m) ξ t ( i , j ) \xi_t(i, j) ξt(i,j)
  4. M步:基于E步计算的4组概率,对 μ ^ j m \hat \mu_{jm} μ^jm Σ ^ j m \hat \Sigma_{jm} Σ^jm c ^ j m \hat c_{jm} c^jm a ^ i j \hat a_{ij} a^ij进行估计;
  5. 重复整个流程,直到所有的句子遍历完成。

在训练完成之后,每个音素的HMM模型也就训练好了。

2.4 识别过程

识别过程与孤立词识别的差别就比较大了,因为要考虑“音素->词->句子”的层级传递。这里介绍一个比较常用的识别算法——“token passing算法”,属于剪枝的维特比译码算法的一种。

PS:其实这个算法本身不难理解,但因为相关资料比较少,而且说的都比较模糊。笔者也是看了很久才明白原理,希望能用通俗的方式把它呈现出来,细节上如果有不周到的地方,还望指出~

2.4.1 较简单的情况:假设是对词进行HMM建模

虽然2.2节和2.3节介绍的内容都是对音素建模,但从音素到句子要经过“音素->词->句子”的两层识别传递。这里为了方便更好地讲明白原理,先假设之前构建和训练的都是针对每个词的HMM模型,这样只需要经过“词->句子”的一层识别传递,更容易理解原理。后面再进一步扩展到对音素建模的情况。

首先需要声明的是,因为只针对训练样本中有的词构建了HMM模型,所以在识别时,只能识别这些已有的词。假设词表中只有“one”、“two”和“three”这三个词,那么识别的示意图可以画成下面这样:

其实还是与之前1.4节孤立词识别同样的方法,只不过这里是并行对所有词进行识别。同时,在孤立词识别过程中,如果到达了结束状态,则识别就结束了;但在这里,如果到达了结束状态,还是要继续识别下一个词,所以在图里是一个循环。

在每个HMM内部,还是采用维特比识别方法,用动态规划,在每个时刻对于每个状态选择一条最大概率的路径。因为是并行的,那么在某个时刻,可能同时会有多个词到达结束状态,分别对应着一段已识别出的句子(路径),然后又都要同时再进行下一个词的识别。这里为了避免多余的计算,采用与维特比识别一样的思路,只需要取一个最大概率的句子,而扔掉其他的。那么,在这个过程中,就需要记录概率和路径,这个就叫“token”。看下面这个图:

每个“token”里面存储score和WLR,前者是这条路径的概率,后者是“word link record”,记录当前的路径(包括score:分数;path id:它是从之前哪个WLR过来的;model id:当前识别出的词是哪个;time:时间等)。这样在某个时刻,每条到达结束状态的路径,都会有一个对应的token,从这些“tokens”里面选一个具有最大score的token保留,扔掉其他所有的token后,继续下一步的识别。

写成伪代码就是:

先定义两个特殊的token:
	(1)“start token”(P=1,score=logP=0,WLR=null),
	(2)“null token”(P=0,score=logP=-inf,WLR=null)
假设时间长度为T,状态数目为N+2,其中0和N+1分别表示开始状态和结束状态

初始化:在开始状态中放入“start token”,在其他状态中放入“null token”
迭代:for time t =  1, ..., T
    	for state i <= N
        	将状态i的token复制到与其连接的所有不是结束状态的状态j中
        	更新token的score为:score += log a_ij + log b_j(y_t)
        end
        for state i in (与结束状态连接的状态集合)
            将状态i的原始token复制到结束状态
            更新token的score为:score += log a_iE
            创建一个新的WLR,其path id指向token的WLR,model id为这个token对应的识别词,time为t,score为当前token的分数
            更新token的WLR为这个新建的WLR
        end
        扔掉所有的原始token
        for state i <= N+1
        	保留状态i中所有tokens中最大score的那个token,扔掉其他所有的tokens
        end
        将结束状态的token复制到开始状态中
    返回结束状态的token
识别结果:根据token的model id以及path id一层一层向前回溯,得到整个句子

上面的过程能够得到 a r g m a x S P ( X ∣ S ) argmax_S P(X|S) argmaxSP(XS)的句子,识别的目标是 a r g m a x S P ( X ∣ S ) P ( S ) argmax_S P(X|S)P(S) argmaxSP(XS)P(S)。语言模型可以通过两种方式加进去:

  1. rescore:即重打分排序,这就需要前面保留token的时候,要保留NBest(参考beam search的思想),然后对NBest识别出来的句子,通过LM进行rescore即可。
  2. fusion:直接融合进去,每次识别出一个词之后,可以用语言模型,根据它之前的句子和这个词,得到当前这个词的分数,一起加到token的计算里面,具体加入的位置可以是更新token的score为:score += log a_iE + (LM分数 log P(w_t|w_1, ..., w_{t-1})),找了一个比较形象的图:
2.4.2 扩展到对音素建模的情况

有了上面的对词建模的识别过程之后,既可以很容易地扩展到对音素建模的情况,只是这里要多加一层从“音素->词”的传递,通过发音词典即可完成,比如下图:

可以将一个词的所有音素的HMM状态都串起来,作为一整个HMM(改一下 a i j a_{ij} aij矩阵的连接方式应该就可以)。而后进行与2.4.1一样的识别过程即可。

三. 延伸:上下文建模

3.1 三音素建模

前面讨论的都是对单音素进行HMM建模的方式,但实际上一个音素的发声是依赖于其上下文(即邻居音素)的,只用一个模型对其进行建模,信息量难免会有丢失。因此,应当在建模时考虑到这种上下文信息。

一种较普遍的做法是,对三音素(tripone)进行建模。对于音素 x x x,假设它左边的音素是 l l l,右边的音素是 r r r,那么音素 x x x 的三音素形式就可以表示为 l − x + r l-x+r lx+r。比如don't ask就可以表示为sil sil-d+oh d-oh+n oh-n+t n-t+ah t-ah+s ah-s+k s-k+sil sil这样的三音素串。

这样在建模的时候就是对类似d-oh+n这样的三音素(三个音素当成一个音素)进行建模。

3.2 优化:参数共享

只考虑单音素的情况下,音素表可能比较小,方便建模。但如果考虑三音素的情况,音素表可能就呈指数级增长了。

简单计算一下,假设单音素表有40个音素,那么可能的三音素就会有 4 0 3 = 64000 40^3=64000 403=64000个,在实际情况下,可能有 50000 50000 50000个是真实存在的。那么,要对这 50000 50000 50000个三音素进行三状态的HMM建模,假设用 10 10 10个混合分量的GMM模型,那么一共需要 50000 ∗ 3 ∗ 10 = 1.5 M 50000 * 3 * 10 = 1.5M 50000310=1.5M的高斯模型。假设用39维的音频特征,那么每个高斯模型需要约 800 800 800个参数,总的参数量就高达 120 M 120M 120M。这是十分惊人的,需要有大量的数据来进行拟合,同时还要保证每个三音素都有足够的数据,这点比较困难。

为了对其进行优化,通常会采用共享参数的方式,减少建模的参数量,方便训练。共享可以发生在不同的层面:

  1. 共享高斯模型:所有状态都用同样的高斯模型,只是混合权重不一样(捆绑混合物)
  2. 共享状态:允许不同的HMM模型使用一些相同的状态(状态聚类)
  3. 共享模型:相似的三音素使用同样的HMM模型(三音素泛化)

所有的方法都是数据驱动的,下面进行一些简单介绍:(笔者没有过多细究这部分,只是大概了解了原理,对此感兴趣的读者可以前往传送门查找细节)

3.2.1 共享状态

这部分的重点,其实是对状态进行聚类。找到相似的一堆状态,然后让不同的HMM模型之间共享这些状态,比如下图:

具体怎么找这些相似的状态?可以采用自顶向下的拆分,建立决策树来聚类,看下面这个形象的图:

顶层节点是所有中间音素为/iy/的三音素,然后通过问各种问题,比如左边是鼻音吗?右边是浊音吗?等等,将这些三音素进行划分,最后在同一个叶子节点里面的所有三音素的中间状态就可以共享。

3.2.2 共享模型

这部分的重点,其实就是对三音素进行泛化,找到一堆相似的三音素,用同一个泛化的三音素来表示,有点儿像词干的感觉。看下面这个图:

这里就是将s-iy+lf-iy+l泛化为(s,f)-iy+l,将t-iy+nt-iy+m泛化为t-iy+(n,m),模型个数缩减了一半。

具体怎么找这些相似的三音素?可以采用自底向上的合并,比较具有不同三音素的异音素(allophone)模型,合并相似的那些。(PS:这句话笔者是翻译过来的,,只能意会)

传送门:

HTK Book:HTK工具包的说明文档(需要先注册才能看),第一章的教程对于整体脉络的把握很清晰
HMM acoustic modelling: HMMs and GMMs:英国爱丁堡大学的ASR课程讲义,主攻HMM和GMM模型和孤立词识别,在数学原理上很详细
HMM acoustic modelling: Context-dependent phone modelling:英国爱丁堡大学的ASR课程讲义,考虑上下文的建模

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值