語音識別中的CTC演算法的基本原理解釋

語音識別中的CTC演算法的基本原理解釋
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...

歡迎大家前往騰訊雲 社群,獲取更多騰訊海量技術實踐乾貨哦~

本文作者:羅冬日

目前主流的語音識別都大致分為特徵提取,聲學模型,語音模型幾個部分。目前結合神經網路的端到端的聲學模型訓練方法主要CTC和基於Attention兩種。

本文主要介紹CTC演算法的基本概念,可能應用的領域,以及在結合神經網路進行CTC演算法的計算細節。

CTC演算法概念

CTC演算法全稱叫:Connectionist temporal classification。從字面上理解它是用來解決時序類資料的分類問題。

傳統的語音識別的聲學模型訓練,對於每一幀的資料,需要知道對應的label才能進行有效的訓練,在訓練資料之前需要做語音對齊的預處理。而語音對齊的過程本身就需要進行反覆多次的迭代,來確保對齊更準確,這本身就是一個比較耗時的工作。

上圖是“你好”這句話的聲音的波形示意圖, 每個紅色的框代表一幀資料,傳統的方法需要知道每一幀的資料是對應哪個發音音素。比如第1,2,3,4幀對應n的發音,第5,6,7幀對應i的音素,第8,9幀對應h的音素,第10,11幀對應a的音素,第12幀對應o的音素。(這裡暫且將每個字母作為一個發音音素)

與傳統的聲學模型訓練相比,採用CTC作為損失函式的聲學模型訓練,是一種完全端到端的聲學模型訓練,不需要預先對資料做對齊,只需要一個輸入序列和一個輸出序列即可以訓練。這樣就不需要對資料對齊和一一標註,並且CTC直接輸出序列預測的概率,不需要外部的後處理。

既然CTC的方法是關心一個輸入序列到一個輸出序列的結果,那麼它只會關心預測輸出的序列是否和真實的序列是否接近(相同),而不會關心預測輸出序列中每個結果在時間點上是否和輸入的序列正好對齊。

CTC引入了blank(該幀沒有預測值),每個預測的分類對應的一整段語音中的一個spike(尖峰),其他不是尖峰的位置認為是blank。對於一段語音,CTC最後的輸出是spike(尖峰)的序列,並不關心每一個音素持續了多長時間。
如圖2所示,拿前面的nihao的發音為例,進過CTC預測的序列結果在時間上可能會稍微延遲於真實發音對應的時間點,其他時間點都會被標記會blank。
這種神經網路 CTC的結構除了可以應用到語音識別的聲學模型訓練上以外,也可以用到任何一個輸入序列到一個輸出序列的訓練上(要求:輸入序列的長度大於輸出序列)。
比如,OCR識別也可以採用RNN CTC的模型來做,將包含文字的圖片每一列的資料作為一個序列輸入給RNN CTC模型,輸出是對應的漢字,因為要好多列才組成一個漢字,所以輸入的序列的長度遠大於輸出序列的長度。而且這種實現方式的OCR識別,也不需要事先準確的檢測到文字的位置,只要這個序列中包含這些文字就好了。

RNN CTC模型的訓練

下面介紹在語音識別中,RNN CTC模型的訓練詳細過程,到底RNN CTC是如何不用事先對齊資料來訓練序列資料的。
首先,CTC是一種損失函式,它用來衡量輸入的序列資料經過神經網路之後,和真實的輸出相差有多少。

比如輸入一個200幀的音訊資料,真實的輸出是長度為5的結果。 經過神經網路處理之後,出來的還是序列長度是200的資料。比如有兩個人都說了一句nihao這句話,他們的真實輸出結果都是nihao這5個有序的音素,但是因為每個人的發音特點不一樣,比如,有的人說的快有的人說的慢,原始的音訊資料在經過神經網路計算之後,第一個人得到的結果可能是:nnnniiiiii…hhhhhaaaaaooo(長度是200),第二個人說的話得到的結果可能是:niiiiii…hhhhhaaaaaooo(長度是200)。這兩種結果都是屬於正確的計算結果,可以想象,長度為200的資料,最後可以對應上nihao這個發音順序的結果是非常多的。CTC就是用在這種序列有多種可能性的情況下,計算和最後真實序列值的損失值的方法。

詳細描述如下:

訓練集合為$S=\lbrace (x^1,z^1), (x^2, z^2), …(x^N,z^N) \rbrace$, 表示有$N$個訓練樣本,$x$是輸入樣本,$z$是對應的真實輸出的label。一個樣本的輸入是一個序列,輸出的label也是一個序列,輸入的序列長度大於輸出的序列長度。

對於其中一個樣本$(x,z)$,$x=(x_1,x_2,x_3,…,x_T)$表示一個長度為T幀的資料,每一幀的資料是一個維度為m的向量,即每個$x_i \in R^m$。 $x_i$可以理解為對於一段語音,每25ms作為一幀,其中第$i$幀的資料經過MFCC計算後得到的結果。

$z=(z_1,z_2, z_3,…z_U)$表示這段樣本語音對應的正確的音素。比如,一段發音“你好”的聲音,經過MFCC計算後,得到特徵$x$, 它的文字資訊是“你好”,對應的音素資訊是$z=[n,i,h,a,o]$(這裡暫且將每個拼音的字母當做一個音素)。

特徵$x$在經過RNN的計算之後,在經過一個$softmax$層,得到音素的後驗概率$y$。 $y^t_k(k=1, 2,3,…n,t=1,2,3,…,T)$表示在$t$時刻,發音為音素$k$的概率,其中音素的種類個數一共$n$個, $k$表示第$k$個音素,在一幀的資料上所有的音素概率加起來為1。即:

$\sum_{t-1}^{T}y^t_k=1, y^t_k\geq0$

這個過程可以看做是對輸入的特徵資料$x$做了變換$N_w$:$(R^m)^T \rightarrow (R^n)^T$,其中$N_w$表示RNN的變換,$w$表示RNN中的引數集合。

過程如下圖所示:

以一段“你好”的語音為例,經過MFCC特徵提取後產生了30幀,每幀含有12個特徵,即$x \in R^{30\times14}$(這裡以14個音素為例,實際上音素有200個左右),矩陣裡的每一列之和為1。後面的基於CTC-loss的訓練就是基於後驗概率$y$計算得到的。

路徑π和B變換

在實際訓練中並不知道每一幀對應的音素,因此進行訓練比較困難。可以先考慮一種簡單的情況,已知每一幀的音素的標籤$z\prime$, 即訓練樣本為$x$和$z\prime$,其中$z\prime$不再是簡單的$[n,i,h,a,o]$標籤,而是:

$z\prime = [\underbrace{n,n,n,…,n}_{T_1},\underbrace{i,i,i,…i}_{T_2},\underbrace{h,h,h,…h}_{T_3},\underbrace{a,a,a,…,a}_{T_4},\underbrace{o,o,o,…,o}_{T_5}]$

$ T_1 T_2 T_3 T_4 T_5 = T $
在我們的例子中, $z\prime =[n,n,n,n,n,n,n,i,i,i,i,i,i,h,h,h,h,h,h,h,a,a,a,a,a,a,o,o,o,o,o,o,o]$, $z\prime $包含了每一幀的標籤。在這種情況下有:
$p(z\prime|x) = p(z\prime| y = N_w(x)) = y^1_{z\prime_1}y^2_{z\prime_2}y^3_{z\prime_3}….y^T_{z\prime_T}$ $\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad$ (1)

該值即為後驗概率圖中用黑線圈起來的部分相乘。我們希望相乘的值越大越好,因此,數學規劃可以寫為:

$min_w -log(y^1_{z^\prime_1}.y^2_{z^\prime_2}.y^3_{z^\prime_3}…y^T_{z^\prime_T})$ $\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad\qquad$ (2)

subject to: $ y = N_w(x) $$qquadqquadqquadqquadqquadqquadqquadqquadqquadqquad$ (3)

目標函式對於後驗概率矩陣$y$中的每個元素$y^t_k$的偏導數為:
$\frac{\partial – log(y^1_{z^\prime_1}.y^2_{z^\prime_2}.y^3_{z^\prime_3}…y^T_{z^\prime_T})}{\partial y^t_k} = $$begin{cases} -frac{y^1_{zprime_1}…y^{i-1}_{zprime_{i-1}}.y^{i 1}_{zprime_{i 1}}….y^T_{zprime_T}}{y^1_{z^prime_1}.y^2_{z^prime_2}.y^3_{z^prime_3}…y^T_{z^prime_T}} , qquad if qquad k = zprime_i qquad and qquad t=i \ 0 qquad 其他end{cases}$

也就是說,在每個時刻$t$(對應矩陣的一列),目標只與$y^t_{z\prime_t}$是相關的,在這個例子中是與被框起來的元素相關。

其中$N_w$可以看做是RNN模型,如果訓練資料的每一幀都標記了正確的音素,那麼訓練過程就很簡單了,但實際上這樣的標記過的資料非常稀少,而沒有逐幀標記的資料很多,CTC可以做到用未逐幀標記的資料做訓練。

首先定義幾個符號:
$L=\lbrace a, o, e, i, u, \check{u},b,p,m,…\rbrace$

表示所有音素的集合

$\pi= (\pi_1, \pi_2, \pi_3, …, \pi_T), \pi_i \in L$

表示一條由$L$中元素組成的長度為$T$的路徑,比如$z\prime$就是一條路徑,以下為幾個路徑的例子:

$\pi^1= (j,j,i,n,y,y,e,e,w,w,u,u,u,r,r,e,e,n,n,r,r,u,u,sh,sh,u,u,i,i)$
$\pi^2= (n,n,n,n,i,i,i,i,h,h,h,h,a,a,a,a,a,a,a,a,a,o,o,o,o,o,o,o,o,o)$
$\pi^3= (h,h,h,h,h,h,a,a,a,a,a,a,a,o,o,o,o,n,n,n,n,n,n,i,i,i,i,i,i,i)$
$\pi^4= (n,i,h,a,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o)$
$\pi^5= (n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,i,h,a,o)$
$\pi^6= (n,n,n,i,i,i,h,h,h,h,h,a,,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o)$

這6條路徑中,$\pi^1$可以被認為是“今夜無人入睡”, $\pi^2$可以被認為是在說“你好”,$\pi^3$可以被認為是在說“好你”,$\pi4,\pi5,\pi6$都可以認為是在說“你好”。

定義B變換,表示簡單的壓縮,例如:
$B(a,a,a,b,b,b,c,c,d) = (a,b,c,d)$

以上6條路徑為例:
$B(\pi^1) = (j,i,n,y,e,w,u,r,e,n,r,u,s,h,u,i)$
$B(\pi^2) = (n,i,h,a,)$
$B(\pi^3) = (h,a,o,n,i)$
$B(\pi^4) = (n,i,h,a,o)$
$B(\pi^5) = (n,i,h,a,o)$
$B(\pi^6) = (n,i,h,a,o)$

因此,如果有一條路徑$\pi$有$B(\pi)=(n,i,h,a,o)$,則可以認為$\pi$是在說“你好”。即使它是如$\pi^4$所示,有很多“o”的音素,而其他音素很少。路徑$\pi = (\pi^1,\pi^2,…,\pi^T)$的概率為它所經過的矩陣y上的元素相乘:

$p(\pi|x) = p(\pi| y = N_w(x)) = p(\pi| y)=\prod_{t=1}^{T} y^t_{\pi_t}$

因此在沒有對齊的情況下,目標函式應該為$\lbrace \pi | B(\pi) = z \rbrace$中所有元素概率之和。 即:
$max_w p(z|y=N_w(x)) = p(z|x)= \sum_{B(\pi)=z}p(\pi|x)$ $\qquad\qquad\qquad$ (4)

在T=30,音素為$[n,i,h,a,o]$的情況下,共有$C^5_{29}\approx120000$條路徑可以被壓縮為$[n,i,h,a,o]$。 路徑數目的計算公式為$C^{音素個數}_{T-1}$,量級大約為$(T-1)^{音素個數}$。一段30秒包含50個漢字的語音,其可能的路徑數目可以高達$10^8$,顯然這麼大的路徑數目是無法直接計算的。因此CTC方法中借用了HMM中的向前向後演算法來計算。

訓練實施方法

CTC的訓練過程是通過$\frac {\partial p(z|x)}{\partial w} $調整w的值使得4中的目標值最大,而計算的過程如下:

因此,只要得到$\frac {\partial p(z|x)}{\partial y^t_k} $,即可根據反向傳播,得到$\frac {\partial p(z|x)}{\partial w} $。下面以“你好”為例,介紹該值的計算方法。

首先,根據前面的例子,找到所有可能被壓縮為$z=[n,i,h,a,o]$的路徑,記為$\lbrace \pi|B(\pi) = z \rbrace$。 可知所有$\pi$均有$[n,n,n,….,n,i,…..,i,h,…..h,a,….a,o,…,o]$的形式,即目標函式只與後驗概率矩陣y中表示$n,i,h,a,o$的5行相關,因此為了簡便,我們將這5行提取出來,如下圖所示。

在每一個點上,路徑只能向右或者向下轉移,畫出兩條路徑,分別用q和r表示,這兩條路徑都經過$y^{14}_h$這點,表示這兩點路徑均在第14幀的時候在發“h”音。因為在目標函式4的連加項中,有的項與$y^{14}_h$無關,因此可以剔除這一部分,只留下與$y^{14}_h$有關的部分,記為$\lbrace \pi|B(\pi) = z, \pi_{14}=h \rbrace$

$\frac {\partial p(z|y)}{\partial y^{14}_h} $

= $\frac {\partial \sum_{B(\pi)=z}p(\pi|y)}{\partial y^{14}_h} $

= $\frac {\partial \sum_{B(\pi)=z}\prod_{t=1}^T y^t_{\pi_t}}{\partial y^{14}_h} $
=$\frac {\overbrace{\partial \sum_{B(\pi)=z,\pi_{14}=h}\prod_{t=1}^T y^t_{\pi_t}}^{和y^{14}_h有關的項} \overbrace{\partial \sum_{B(\pi)=z,\pi_{14} \neq h}\prod_{t=1}^T y^t_{\pi_t}}^{和y^{14}_h無關的項}}{\partial y^{14}_h}$

=$\frac {\partial \sum_{B(\pi)=z,\pi_{14}=h}\prod_{t=1}^T y^t_{\pi_t}}{\partial y^{14}_h}$

這裡的q和r就是與$y^{14}_h$相關的兩條路徑。用$q_{1:13}$和$q_{15:30}$分別表示$q$在$y^{14}_h$之前和之後的部分,同樣的,用$r_{1:13}$和$r_{15:30}$分別表示$r$在$y^{14}_h$之前和之後的部分.。可以發現,$q_{1:13} h r_{15:30}$與$r_{1:13} h q_{15:30}$同樣也是兩條可行的路徑。$q_{1:13} h r_{15:30}$、$r_{1:13} h q_{15:30}$、$q$ 、$r$這四條路徑的概率之和為:
$\underbrace{y^1_{q1}..y^{13}_{q13}.y^{14}_{h}.y^{15}_{q15}….y^{30}_{q30}}_{路徑q的概率}$

$\underbrace{y^1_{q1}..y^{13}_{q13}.y^{14}_{h}.y^{15}_{r15}….y^{30}_{r30}}_{路徑q_{1:14} r_{14:30}的概率}$

$\underbrace{y^1_{r1}..y^{13}_{r13}.y^{14}_{h}.y^{15}_{q15}….y^{30}_{q30}}_{路徑r_{1:14} q_{14:30}的概率}$

$\underbrace{y^1_{r1}..y^{13}_{r13}.y^{14}_{h}.y^{15}_{r15}….y^{30}_{r30}}_{路徑r的概率}$

=$(y^1_{q1}….y^{13}_{q13} y^1_{r1}…..y^{13}_{r13}).y^{14}_h.(y^{15}_{q15}….y^{30}_{q15} y^{15}_{r15}….y^{30}_{r30})$

可以發現,該值可以總結為:(前置項)$.y^{14}_h.$(後置項)。由此,對於所有的經過$y^{14}_h$的路徑,有:

$\sum_{B(\pi)=z,\pi_{14}=h}\prod_{t=1}^T y^t_{\pi_t}= (前置項).y^{14}_h.$(後置項)$

定義:
$\alpha_(14)(h)=(前置項).y^{14}_h = \sum_{B(\pi_{1:14})=[n,i,h] }\prod_{t\prime=1}^t y^{t\prime}_{\pi_{t\prime}} $

該值可以理解為從初始到$y^{14}_h$這一段裡,所有正向路徑的概率之和。並且發現,$\alpha_{14}(h)$可以由$\alpha_{13}(h)$和$\alpha_{13}(i)$遞推得到,即:
$\alpha_{14}(h) = (\alpha_{13}(h) \alpha_{13}(i))y^{14}_h$

該遞推公式的含義是,只是在$t=13$時發音是“h”或“i”,在$t=14$時才有可能發音是“h”。那麼在$t=14$時刻發音是“h”的所有正向路徑概率$\alpha_{14}(h)$就等於在$t=13$時刻,發音為“h”的正向概率$\alpha_{13}(h)$加上發音為“i”的正向概率$\alpha_{13}(i)$,再乘以當前音素被判斷為“h”的概率$y^{14}_h$。由此可知,每個$\alpha_t(s)$都可以由$\alpha_{t-1}(s)$和$\alpha_{t-1}(s-1)$兩個值得到。$\alpha$的遞推流程如下圖所示:

即每個值都由上一個時刻的一個或者兩個值得到,總計算量大約為$2.T.音素個數$。類似的,定義$\beta_t(s)$, 遞推公式為:

$\beta_{14}(h)=(\beta_{15}(h) \beta_{15}(a))y^{14}_h$

因此有:

$\sum_{B(\pi)=z,\pi_{14}=h}\prod_{t=1}^T y^t_{\pi_t}= (前置項).y^{14}_h.$(後置項)$

=$\frac{\alpha_{14}(h)}{y^{14}_h}. y^{14}_h.\frac{\beta_{14}(h)}{y^{14}_h}$

=$\frac{\alpha_{14}(h)\beta_{14}(h)}{y^{14}_h}$

然後:

$\frac {\partial p(z|y)}{\partial y^{14}_h} $

= $\frac {\sum_{B(\pi)=z,\pi_{14}=h}\prod_{t=1}^T y^t_{\pi_t}}{\partial y^{14}_h}$

= $\frac {\frac{\alpha_{14}(h)}{y^{14}_h}. y^{14}_h.\frac{\beta_{14}(h)}{y^{14}_h}}{\partial y^{14}_h}$

=$\frac{\alpha_{14}(h)\beta_{14}(h)}{{(y^{14}_h)}^2}$

得到此值後,就可以根據反向傳播演算法進行訓練了。
可以看到,這裡總的計算量非常小,計算$\alpha$和$\beta$的計算量均大約為$(2.T.音素個數)$,(加法乘法各一次),得到$\alpha$和$\beta$之後,在計算對每個$y^t_k$的偏導值的計算量為$(3.T.音素個數)$,因此總計算量大約為$(7.T.音素個數)$,這是非常小的,便於計算。

目前,深度學習的演算法已經大規模應用於騰訊雲的語音識別產品中。騰訊雲擁有業內最先進的語音識別技術,基於海量的語音資料,積累了數十萬小時的標註語音資料,採用LSTM,CNN,LFMMI,CTC等多種建模技術,結合超大規模語料的語言模型,對標準普通話的識別效果超過了97%的準確率。騰訊雲的語音技術,應用涵蓋範圍廣泛,具備出色的語音識別、語音合成、關鍵詞檢索、靜音檢測、語速檢測、情緒識別等能力。並且針對遊戲,娛樂,政務等幾十個垂直做特殊定製的語音識別方案,讓語音識別的效果更精準,更高效,全面滿足電話客服質檢、語音聽寫、實時語音識別和直播字幕等多種場景的應用。

問答
語音識別API如何呼叫?
相關閱讀
智慧機器人語音識別技術
python語音識別終極指南
tensorflow LSTM CTC實現端到端OCR

此文已由作者授權騰訊雲 社群釋出,原文連結:https://cloud.tencent.com/dev…

相關文章

人工智慧 最新文章