基於GMMs-HMMs的語音識別原理

剛入門ASR的時候一直能聽到HMM模型的相關字眼,這裏就補一下用GMMs-HMMs進行語音識別的原理,雖然這個方法很古老,而且已經近乎被神經網絡所取代,但它背後的思想仍然值得我們去了解和學習~

筆者看了一些教程,包括課程講義、博客還有一些工具書,總算大致理清了思路,相信至少在文章邏輯上比一些沒有相關背景設定、無厘頭、不知所云的教程要好,原理上至少也是能用到的都有介紹。而有些地方太深入的原理筆者也沒有去細究,感興趣的讀者根據筆者的邏輯自己去深入探索即可。

整體的行文思路按照“結果導向”,需要什麼數學知識和原理再去介紹什麼,而不是上來就用GMM和HMM進行轟炸,導致前後脫節。在數學原理上,也是儘量做到通俗易懂,加入自己的理解,而不是甩一堆高深莫測的公式。

一. 最簡單的場景:孤立詞識別

1.1 整體思路

孤立詞識別是語音識別中最簡單的場景,即一個音頻文件裏面只包含一個詞的語音。訓練和識別的整體思路爲:
(1)訓練階段:對於每個詞,用不同人錄製的這個詞的音頻特徵作爲訓練樣本,構建一個生成模型P(XW)P(X|W)WW表示詞,XX表示音頻文件提取出的特徵(如FBank、MFCC等,參見這篇博客)。
(2)識別階段:給定一段音頻特徵,經過上面學習到的每個詞的P(XW)P(X|W)模型,看哪個詞生成這段音頻特徵的概率最大,取最大的那個詞作爲識別詞。

形象化的圖如下:

這裏的重點就是P(XW)P(X|W)這個生成模型的建立。因爲對於每個孤立詞都是分別採用一個生成模型來獨立建模的,所以後面介紹的原理都是以一個孤立詞爲例講解。

1.2 模型結構

對於這種時間序列的建模,自然就是採用HMM模型。其結構圖如下:

不大張旗鼓地講那麼多關於HMM沒用的東西,就看這個圖來講解。它的構建思路就是認爲音頻特徵是由一些隱藏狀態生成的,這些狀態內部會有轉移,並且滿足馬爾可夫性,狀態個數是超參數,需要自己設置(一般3~5個)。

對於除了開始(sIs_I)和結束(sEs_E)這兩個狀態之外的狀態,都有兩種轉移選擇,要麼就轉向自己,要麼就轉向下一個狀態。因爲音頻特徵的序列長度往往要比狀態個數多,所以這裏要有轉向自己的,因此每個狀態可能對應多個音頻特徵的“幀”。

以這個圖裏面的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)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)

這裏主要有兩部分概率需要學習:

(1)aija_{ij}P(sjsi)P(s_j|s_i),狀態轉移概率
(2)bj(xt)b_j(x_t)P(xtsj)P(x_t|s_j),輸出生成概率

其中bj(xt)b_j(x_t)一般採用GMM進行建模,這也就是爲什麼叫GMM-HMM。直接給出GMM的公式:

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

N(x;μ,Σ)=1(2π)D/2Σ1/2exp(12(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))

即認爲輸出生成概率由高斯混合模型生成,先根據概率cjmc_{jm}選擇一個高斯模型,然後根據這個模型的概率分佈N(xt;μjm,Σjm)N(x_t; \mu_{jm}, \Sigma_{jm})生成 xtx_t

總結一下,要學習的參數有:

  1. aija_{ij}:HMM的狀態轉移概率矩陣
  2. cjmc_{jm}:各狀態對應的GMM中的混合權重(如果是單高斯建模,則不用學習)
  3. μjm\mu_{jm}:各狀態對應的GMM中各高斯分量的均值向量
  4. Σjm\Sigma_{jm}:各狀態對應的GMM中各高斯分量的協方差矩陣

建立好這樣的模型之後,後面就是如何根據樣本進行訓練了。

1.3 訓練過程

這裏的訓練,確切來講應該叫參數估計,用一定的算法來估計參數,使其能夠擬合數據分佈(即最大化數據的似然概率)。下面循序漸進地來講這種參數估計算法:

1.3.1 單樣本、單高斯

這是一種最簡單的情況,假設一個詞的訓練樣本只有一個音頻文件,並且對於輸出概率bj(xt)b_j(x_t)採用單高斯建模,即 m=1m=1cjm=1c_{jm}=1。此時需要估計的參數爲:

  1. aija_{ij}:HMM的狀態轉移概率矩陣
  2. μj\mu_{j}:各狀態對應的單高斯模型的均值向量
  3. Σj\Sigma_{j}:各狀態對應的單高斯模型的協方差矩陣

這裏進行參數估計的一大難點就是:各個狀態對應哪些音頻幀是不知道的,不像1.2裏面給出的那個圖那樣具有對齊信息。所以輸出概率bj(xt)b_j(x_t)根本不知道具體去擬合哪些音頻幀數據。

爲了解決這個問題,引入一種軟對齊策略,即給出各個音頻幀屬於各個狀態的概率(各個時刻處於各個狀態的概率)γt(j)=P(st=jX)\gamma_t(j) = P(s_t = j|X),此時對於各個單高斯模型的參數估計就可以寫爲:

μ^j=t=1Tγt(j)xtt=1Tγ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)(xtμ^j)(xtμ^j)Tt=1Tγ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)}

這個地方不好理解的話,再說得深入一些:

如果最理想情況下給出了各個狀態對應的音頻幀,像1.2節的圖那樣。則每個狀態對應的高斯模型需要擬合的數據就確定了,此時根據最大似然概率,均值和方差分別應該估計爲:

μ^j=t=1Tzjtxtt=1Tzjt\hat \mu_j = \frac{\sum_{t=1}^T z_{jt} x_t}{\sum_{t=1}^T z_{jt}}

Σ^j=t=1Tzjt(xtμ^j)(xtμ^j)Tt=1Tzjt\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}}

zjt=1   if  xtsj  else  0z_{jt} = 1 \ \ \ if \ \ x_t \in s_j \ \ else \ \ 0

但是這裏沒有zjtz_{jt}這種“硬對齊”信息,所以要用“軟對齊”的概率γt(j)\gamma_t(j)來代替。

同樣的,對於轉移概率akja_{kj},也引入軟對齊轉移概率ξt(i,j)=P(st=i,st+1=jX)\xi_t(i, j) = P(s_t = i, s_{t+1} = j|X),表示在 tt 時刻的狀態在sis_i,而在 t+1t+1 時刻的狀態爲sjs_j的概率。此時轉移概率可以估計爲:

a^ij=t=1Tξt(i,j)k=1Nt=1Tξ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)}

即狀態sis_i轉到狀態sjs_j(在各個時刻下求和)的概率除以狀態sis_i轉到其他所有狀態sks_k(在各個時刻下求和)的概率。

綜上,在進行參數估計前,需要先拿到γt(j)\gamma_t(j)ξt(i,j)\xi_t(i, j)這兩個概率。

那麼,這兩個軟對齊概率要怎麼計算呢?此時就需要用到HMM中經典的前向-後向概率計算公式。引入兩個概率:

(1)αt(j)\alpha_t(j):前向概率,展開爲αt(j)=P(x1,x2,...,xt,st=j)\alpha_t(j) = P(x_1, x_2, ..., x_t, s_t = j),即已經輸出x1,x2,...,xtx_1, x_2, ..., x_t,並且在時刻 tt 處在狀態sjs_j的概率。
(2)βt(j)\beta_t(j):後向概率,展開爲βt(j)=P(xt+1,xt+2,...,xTst=j)\beta_t(j) = P(x_{t+1}, x_{t+2}, ..., x_{T} | s_t = j),在時刻 tt 處在狀態sjs_j時,後續輸出爲xt+1,xt+2,...,xTx_{t+1}, x_{t+2}, ..., x_T的概率。

在給出了這兩個概率時,就可以計算γt(j)\gamma_t(j)ξt(i,j)\xi_t(i, j),如下:

γt(j)=P(st=jX)=1αT(sE)α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(i,j)=P(st=i,st+1=jX)=αt(i)aijbj(xt+1)βt+1(j)αT(sE)\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(sE)\alpha_T(s_E)實際上就是P(X)P(X)

綜上,在計算γt(j)\gamma_t(j)ξt(i,j)\xi_t(i, j)這兩個概率之前,需要先計算αt(j)\alpha_t(j)βt(j)\beta_t(j)

那麼如何計算前向和後向概率呢?先放一張圖:

這是一個典型的所有可能路徑的示意圖,αt(j)\alpha_t(j)即計算從起點的紫色圓圈到其中某個青色圓圈的所有路徑的概率和,βt(j)\beta_t(j)即計算從某個青色圓圈到終點的紫色圓圈的所有路徑的概率和。計算方式採用動態規劃算法,迭代進行:

具體地,對於αt(j)\alpha_t(j),計算方法爲:

(1)初始化:α0(sI)=1\alpha_0(s_I) = 1α0(j)=0   if  j  != sI\alpha_0(j) = 0 \ \ \ if \ \ j \ \ != \ s_I
(2)迭代:αt(j)=i=1Nαt1(j)aijbj(xt)   1<=j<=N,1<=t<=T\alpha_t(j) = \sum_{i=1}^N \alpha_{t-1}(j) a_{ij} b_j(x_t) \ \ \ 1 <= j <= N, 1<=t<=T
(3)終止:P(X)=αT(sE)=i=1NαT(i)aiEP(X) = \alpha_T(s_E) = \sum_{i=1}^N \alpha_T(i) a_{iE}

下圖是迭代計算過程中拆分出的某一步的示意圖,展示了動態規劃的計算方法。

同樣地,對於βt(i)\beta_t(i),計算方法爲:

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

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

到這裏,所有在參數估計中需要用到的概率都已經計算完畢了,下面展示整個流程。

整個參數估計的流程,其實還是需要迭代的,這裏採用EM算法(一種對含有隱變量模型進行參數估計的迭代算法,在HMM的場景裏,也叫前向-後向算法或Baum-Welch算法):

  1. 初始化:

筆者看到的有:對於GMM,一種做法是用所有數據進行估計,另一種是用K-Means先聚類一波;對於HMM的轉移概率,是用的平均。

  1. 對於每一次迭代:

(1)E步:用上一步估計出的參數,迭代計算前向概率αt(j)\alpha_t(j)和後向概率βt(j)\beta_t(j),進而計算軟對齊概率γt(j)\gamma_t(j)ξt(i,j)\xi_t(i, j)
(2)M步:基於E步計算的4組概率,對μ^j\hat \mu_jΣ^j\hat \Sigma_ja^ij\hat a_{ij}進行估計。

其中每一步的計算公式,前面都已經詳細說明了。

1.3.2 擴展到高斯混合模型

一般在對於輸出概率分佈的建模,都會採用GMM方法。理論上,足夠的單高斯模型的混合可以擬合任意的分佈。1.3.1的單高斯建模只是一種特例,目的還是爲了方便擴展到GMM的場景。

這裏需要估計的參數就要加上GMM的混合權重,即:

  1. akja_{kj}:HMM的狀態轉移概率矩陣
  2. cjmc_{jm}:各狀態對應的GMM中的混合權重
  3. μjm\mu_{jm}:各狀態對應的GMM中各高斯分量的均值向量
  4. Σjm\Sigma_{jm}:各狀態對應的GMM中各高斯分量的協方差矩陣

對於GMM的參數估計中,與之前HMM是同樣的道理。因爲在音頻幀對應到某個狀態後,還是不知道其是GMM中的哪個分量生成的。所以還是需要一種軟對齊概率,具體表現在γt(j)\gamma_t(j)上,此時需要改爲γt(j,m)\gamma_t(j, m),表示在時刻t,屬於狀態sjs_j以及第mm個高斯分量的概率。

筆者猜測的γt(j,m)\gamma_t(j, m)計算公式爲:(因爲沒找到相關的資料,如果有錯誤,還請指出~)

γt(j,m)=P(st=j,ct=mX)=P(st=jX)P(ct=mst=j,X)=1αT(sE)αt(j)βt(j)1(2π)D/2Σjm1/2exp(12(xtμjm)TΣjm1(xtμjm))\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}))

相應的,對於μ^jm\hat \mu_{jm}Σ^jm\hat \Sigma_{jm}的參數估計就要改爲:

μ^jm=t=1Tγt(j,m)xtt=1Tγ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)(xtμ^jm)(xtμ^jm)Tt=1Tγ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)}

GMM的混合參數估計如下:

c^jm=t=1Tγt(j,m)m=1Mt=1Tγt(j,m)\hat c_{jm} = \frac{\sum_{t=1}^T \gamma_t(j, m)}{\sum_{m'=1}^M \sum_{t=1}^T \gamma_t(j, m')}

即處於狀態 jj 和分量 mm 的概率,除以處於狀態 jj 和其他所有分量的概率。

而前向概率αt(j)\alpha_t(j)、後向概率βt(j)\beta_t(j)ξt(i,j)\xi_t(i, j)的計算公式不變,轉移概率aija_{ij}的估計公式也不變。

那麼EM的流程就變爲:

(1)E步:用上一步估計出的參數,迭代計算前向概率αt(j)\alpha_t(j)和後向概率βt(j)\beta_t(j),進而計算軟對齊概率γt(j,m)\gamma_t(j, m)ξt(i,j)\xi_t(i, j)
(2)M步:基於E步計算的4組概率,對μ^jm\hat \mu_{jm}Σ^jm\hat \Sigma_{jm}c^jm\hat c_{jm}a^ij\hat a_{ij}進行估計。

1.3.3 擴展到多個訓練樣本

前面1.3.1和1.3.2討論的都是隻有一個訓練樣本的情況,實際上對於每個詞,都會有很多個音頻文件與之對應,從而提升模型建模的魯棒性。

假設某個詞一共有 RR 個音頻文件,則前面的xtx_t就要改爲xtrx_t^r,表示第 rr 個訓練樣本中的第 tt 幀。此時EM的流程變爲:

(1)E步:對每個樣本都計算出:αtr(j)\alpha_t^r(j)βtr(j)\beta_t^r(j)γtr(j,m)\gamma_t^r(j, m)ξtr(i,j)\xi_t^r(i, j)
(2)M步:對於參數的估計需要在全部的訓練樣本上進行,具體爲

μ^jm=r=1Rt=1Tγtr(j,m)xtrr=1Rt=1Tγtr(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)(xtrμ^jm)(xtrμ^jm)Tr=1Rt=1Tγtr(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)}

c^jm=r=1Rt=1Tγtr(j,m)r=1Rm=1Mt=1Tγtr(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'=1}^M \sum_{t=1}^T \gamma_t^r(j, m')}

a^ij=r=1Rt=1Tξtr(i,j)r=1Rk=1Nt=1Tξtr(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)}

在訓練完成後,就是如何利用訓練好的模型對新音頻進行識別了。

1.4 識別過程

識別的過程,就是給定一段音頻XX,對於每個詞的模型P(XW)P(X|W),都計算出其生成XX的概率,然後取最大的那個W=argmaxWP(XW)W = argmax_W P(X|W)作爲識別出的孤立詞。

這裏的P(XW)P(X|W)實際在前面已經提到了,就是αT(sE)\alpha_T(s_E),但一般在識別過程中,不會對所有路徑的概率計算總和,而是會選擇最大的那一條概率作爲最終的概率。這其實就是HMM中經典的維特比算法。

定義概率Vt(j)V_t(j),表示在時刻 tt 到達狀態sjs_j的所有路徑中概率的最大值,對應到1.3中第一張路徑圖,即從起始的紫色圓圈到某個青色圓圈的所有路徑概率中,最大的那一個。同時定義回溯指針btt(j)bt_t(j),即時刻 tt 到達狀態sjs_j的所有路徑中概率最大的那一條路徑對應的前一個狀態,便於之後進行狀態回溯。

與前向概率αt(j)\alpha_t(j)類似,對於Vt(j)V_t(j)btt(j)bt_t(j)的計算也是採用動態規劃進行迭代計算,具體的計算方式爲:

(1)初始化:
V0(sI)=1V_0(s_I) = 1

V0(j)=0   if  j  != sIV_0(j) = 0 \ \ \ if \ \ j \ \ != \ s_I

bt0(j)=0bt_0(j) = 0

(2)迭代:
Vt(j)=argmaxi=1NVt1(j)aijbj(xt)V_t(j) = argmax_{i=1}^N V_{t-1}(j) a_{ij} b_j(x_t)

btt(j)=argmaxi=1NVt1(j)aijbj(xt)bt_t(j) = argmax_{i=1}^N V_{t-1}(j) a_{ij} b_j(x_t)
(3)終止:
P=VT(sE)=maxi=1NVT(i)aiEP^* = V_T(s_E) = \max_{i=1}^N V_T(i) a_{iE}

sT=btT(sE)=argmaxi=1NVT(i)aiEs_T^* = bt_T(s_E) = argmax_{i=1}^N V_T(i) a_{iE}

下面兩個圖是拆分出的中間某一步的迭代計算過程:

最後的識別詞爲:W=argmaxWP(XW)=argmaxWVTW(sE)W = argmax_W P(X|W) = argmax_W V_T^W(s_E)

至此,對於孤立詞識別的全部內容就已經介紹完畢!

二. 擴展到通用場景:連續語音識別

2.1 整體思路

連續語言識別是比較通用的場景,即一個音頻文件裏面包含一個連續的句子,而不是一個詞,其難點在於不知道每個詞對應音頻文件的起止位置。如果有這種標註好的切分,那麼仍然可以沿用前面的孤立詞識別方式進行訓練和識別,但這樣着實費時費力,而且會有人工誤差。那麼,能不能在沒有切分的情況下,對一整段音頻,識別一整個句子?當然可以,下面將詳細介紹。

與孤立詞識別類似,這裏是希望構建一個判別模型P(SX)P(S|X),其中XX是音頻特徵,SS是其對應的句子。訓練是希望能最大化P(SX)P(S|X),識別是希望能找到argmaxSP(SX)argmax_S P(S|X)。對於P(SX)P(S|X)的建模通常會通過貝葉斯公式轉爲P(SX)P(XS)P(S)P(S|X) \approx P(X|S)P(S)來處理,其中P(XS)P(X|S)即爲生成模型,P(S)P(S)爲語言模型(這裏不涉及到語言模型的細節)。

其訓練和識別的整體思路爲:
(1)訓練階段:對於所有的句子,構建生成模型P(XS)P(X|S),最大化每個句子的似然概率。
(2)識別階段:給定一段音頻特徵,用構建好的生成模型和語言模型,得到識別出的句子argmaxSP(XS)P(S)argmax_S P(X|S)P(S)

2.2 模型結構

對於生成模型P(XS)P(X|S)的構建,可以使用“嵌入訓練(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)\beta_t(j),進而計算軟對齊概率γt(j,m)\gamma_t(j, m)ξt(i,j)\xi_t(i, j)
  4. M步:基於E步計算的4組概率,對μ^jm\hat \mu_{jm}Σ^jm\hat \Sigma_{jm}c^jm\hat c_{jm}a^ij\hat 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一層一層向前回溯,得到整個句子

上面的過程能夠得到argmaxSP(XS)argmax_S P(X|S)的句子,識別的目標是argmaxSP(XS)P(S)argmax_S P(X|S)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(改一下aija_{ij}矩陣的連接方式應該就可以)。而後進行與2.4.1一樣的識別過程即可。

三. 延伸:上下文建模

3.1 三音素建模

前面討論的都是對單音素進行HMM建模的方式,但實際上一個音素的發聲是依賴於其上下文(即鄰居音素)的,只用一個模型對其進行建模,信息量難免會有丟失。因此,應當在建模時考慮到這種上下文信息。

一種較普遍的做法是,對三音素(tripone)進行建模。對於音素 xx,假設它左邊的音素是 ll,右邊的音素是 rr,那麼音素 xx 的三音素形式就可以表示爲 lx+rl-x+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個音素,那麼可能的三音素就會有403=6400040^3=64000個,在實際情況下,可能有5000050000個是真實存在的。那麼,要對這5000050000個三音素進行三狀態的HMM建模,假設用1010個混合分量的GMM模型,那麼一共需要50000310=1.5M50000 * 3 * 10 = 1.5M的高斯模型。假設用39維的音頻特徵,那麼每個高斯模型需要約800800個參數,總的參數量就高達120M120M。這是十分驚人的,需要有大量的數據來進行擬合,同時還要保證每個三音素都有足夠的數據,這點比較困難。

爲了對其進行優化,通常會採用共享參數的方式,減少建模的參數量,方便訓練。共享可以發生在不同的層面:

  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課程講義,考慮上下文的建模

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章