DeepSpeech深度學習網絡-結構簡介


 參考博文:https://blog.csdn.net/Left_Think/article/details/75577512 和 https://zhuanlan.zhihu.com/p/38516611 和 https://blog.csdn.net/xmdxcsj/article/details/70300591

  對於傳統的語音識別,通常會分為3個部分:語音模型,詞典,語言模型。語音模型和語言模型都是分開進行訓練的,因此這兩個模型優化的損失函數不是相同的。而整個語音識別訓練的目標(WER:word error rate)與這兩個模型的損失函數不是一致的。

  對於端到端的語音識別,模型的輸入就為語音特征(輸入端),而輸出為識別出的文本(輸出端),整個模型就只有一個神經網絡的模型,而模型的損失采用的CTC Loss。這樣模型就只用以一個損失函數作為訓練的優化目標,不用再去優化一些無用的目標。

       另外語音處理中有幾個難點:輸入的語音與目標文本之間的對齊(alignment);語音的切片,如何切,多長的窗口切一刀,是很難定義的;輸出結果需要處理后才能映射到目標label上;CTC完美地解決了這幾個問題。deepspeech = RNN layers + CTC loss 的模型結構,來學習音頻到文本的映射的,從而實現端到端的語音識別。deepspeech是處理speech-to-text的基於深度學習框架的引擎,詳見百度的paper:  .

Deep Speech1網絡結構

  網絡輸入是context特征,輸出是char,訓練准則是CTC,解碼需要結合ngram語言模型。 共五層,前三層是簡單的DNN結構,第四層是雙向RNN,第五層的輸入是RNN的前向和后向單元,后面跟着softmax分類。

  • data是由音頻文件組成,這里假設格式是wav,采樣頻率是16k,時長是t seconds. 那么,讀進來的一個音頻文件,等於 t (sec) * 16K 的float類型的數組。

  • 接着做快速傅立葉變換(FFT),seq_length和width公式定義,生成維度為(seq_length, width)的數組

  • 再此基礎上,做兩層的卷積(激勵函數用relu,再加batchnorm很重要), 對於音頻來講,是在時域和頻域組成的二維空間上的卷積。怎么理解,我再想想。。。

  • 卷積后的數據shape(seq_len_after_conv, width_after_conv)計算公式:

    • seq_len_after_conv = (seq_length-filter)/step_size+1

  • sclice_channel 是將 seq_len_after_conv, 以1為單位,切成多片,即seq_len_after_conv=10,則切成10片,你可以認為是10個x input,作為下面的rnn層的輸入,你可以理解為是要輸入RNN層的input sequence。

  • RNN層中 ,我們使用的是GRU,seq_len_after_conv的值為多少,則有多少個GRU unit。其中,GRU中的hidden_units數,用戶定義

  • GRU后面的FC中的hidden_units,用戶自己定義。

  • 之后的FC層的hidden_units,是由字母表(alphabet)的數量來決定的。這就是我們要做的分類的類別表。e.g. 若輸入是英文,則alphabet={a-z, blank},若輸入是中文,則alphabet的定義可以多種多樣,完全取決於你的目標,如,可以是音素集合,也可以是帶有聲調的字母集 {a, ā, á, ǎ, à ......}, 這樣學的label sequence就是帶聲調的拼音序列了。這個可以簡單理解為是通過這么多步聚的神經網絡層學到的,input_sequence的特征列表,維數為(seq_len_after_conv, alphabet_size),即輸入序列的每一時刻值,都由alphabet_size長度的向量來表示,做個softmax后,可認為是當前時刻的值為alphabet集合中的任一字母的概率分別是多少。

  • concat后,為與label sequence算Loss的打磨版的(input)sequence了。

  • 接着算CTS LOSS。CTS LOSS是可導的,所以可以用任一種梯度優化算法:SGD, ADAM, NAG etc.

LSTM & GRU

  • LSTM主要組成部分:forget gate, input_gate, output_gate, cell_state, hidden_unit
  • GRU就是LSTM的variants而己,更易於理解,且計算效率更高,效果與LSTM相等,所以越來越受青睞中. GRU主要組成部分:reset_gate, update_gate, hidden_unit,就這么簡單
  • 需要理論基礎的,網上太多,額外我也講不明白,所以靠感興趣的筒子們自學了

GRU右下角的公式是實現代碼,中間的公式更抽象一些。

Deep Speech2網絡結構

  相比於Deep Speech,使用HPC技術,將訓練時間由幾周縮短到幾天,嘗試了更為復雜的網絡結構。

  網絡輸入是context特征,輸出是char(英文對應a/b/c,中文對應6000漢字),訓練准則是CTC,解碼需要結合ngram語言模型。

Batch Normalization

  在網絡層數更深的時候,效果更明顯,收斂更快而且誤差更小。 

SortaGrad

  CTC訓練的早期不穩定,長句子容易出現梯度異常(有些概率near-zero)。在第一個epoch,將訓練句子按照長度排序,首先使用斷句訓練,后面的epoch再按照隨機順序。

GRU

  GRU相比於vanilla RNN可以取得更好的結果,同時比LSTM更容易訓練。

Convolution

  在網絡的最底層使用3層的CNN結構。

Lookahead Convolution

  使用雙向RNN可以獲得更好的准確性,但是對on-line服務來講,延時問題比較明顯,為了解決這個問題,在RNN上面增加了一層Lookahead Convolution。 
這里寫圖片描述

adaptation

  傳統的Hybrid系統在語言之間遷移相對困難,end-to-end系統相對簡單,只需要更換最后的輸出節點就可以。

CTC結構介紹

背景

  Connectionist temporal classification簡稱CTC,翻譯不太清楚,可以理解為基於神經網絡的時序類分類。其中classification比較好理解,表示分類問題;temporal可以理解為時序類問題,比如語音識別的一幀數據,很難給出一個label,但是幾十幀數據就容易判斷出對應的發音label,這個詞也給出CTC最核心的意義;connectionist可以理解為神經網絡中的連接。
  語音識別聲學模型的訓練屬於監督學習,需要知道每一幀對應的label才能進行有效的訓練,在訓練的數據准備階段必須要對語音進行強制對齊。
  CTC的引入可以放寬了這種一一對應的限制要求,只需要一個輸入序列和一個輸出序列即可以訓練。有兩點好處:不需要對數據對齊和一一標注;CTC直接輸出序列預測的概率,不需要外部的后處理。

  如上圖,傳統的Framewise訓練需要進行語音和音素發音的對齊,比如“s”對應的一整段語音的標注都是s;而CTC引入了blank(該幀沒有預測值),“s”對應的一整段語音中只有一個spike(尖峰)被認為是s,其他的認為是blank。對於一段語音,CTC最后的輸出是spike的序列,不關心每一個音素對應的時間長度。

輸出

  語音識別中的DNN訓練,每一幀都有相應的狀態標記,比如有5幀輸入x1,x2,x3,x4,x5,對應的標注分別是狀態a1,a1,a1,a2,a2。

  CTC的不同之處在於輸出狀態引入了一個blank,輸出和label滿足如下的等價關系:F(a−ab−)=F(−aa−−abb)=aab. 多個輸出序列可以映射到一個輸出。

CTC訓練

  訓練流程和傳統的神經網絡類似,構建loss function,然后根據BP算法進行訓練,不同之處在於傳統的神經網絡的訓練准則是針對每幀數據,即每幀數據的訓練誤差最小,而CTC的訓練准則是基於序列(比如語音識別的一整句話)的,比如最大化p(z|x)p(z|x),序列化的概率求解比較復雜,因為一個輸出序列可以對應很多的路徑,所有引入前后向算法來簡化計算。

  前期訓練准備:

  • 輸入

xx,長度為T

  • 輸出集合

AA表示正常的輸出
A′=A⋃{blank}A′=A⋃{blank}表示輸出全集
A′TA′T表示輸入x對應的輸出元素集合

  • 輸出序列

ππ表示輸出路徑
ll表示輸出label序列
FF表示路徑到label序列的映射關系

  • 概率

ytkykt表示時間t輸出k的概率
p(π|x)=∏t=1Tytπtp(π|x)=∏t=1Tyπtt表示基於輸入x的輸出ππ路徑的概率
p(l|x)=∑π∈F−1(l)p(π|x)p(l|x)=∑π∈F−1(l)p(π|x)表示輸出label序列的概率是多條路徑的概率和。
  前后向算法

 

   考慮到計算p(l|x)p(l|x)需要計算很多條路徑的概率,隨着輸入長度呈指數化增加,可以引入類似於HMM的前后向算法來計算該概率值。為了引入blank節點,在label首尾以及中間插入blank節點,如果label序列原來的長度為U,那么現在變為U’=2U+1。

CTC 解碼

  解碼是對於輸入序列x找出概率最大的輸出序列l,而不是概率最大的一條輸出路徑,因為輸出路徑和輸出序列是多對一關系。
  l∗=argmax{p(l|x)}
  best path decoding
  最優路徑找出每一幀輸出的最大概率組成的輸出序列即為最后的解碼結果,這種方式會引入問題。

對於上圖,這種方法解碼出來的結果是blank,但是A的概率反而更高。

  constrained decoding
  對於語音識別,可以引入語言模型等grammar限制,求解問題變為如下形式:
  l∗=argmax{p(l|x)}{p(l|G)}  ;其中G表示grammar;可以使用傳統的token傳播算法進行解碼。

  假設詞典D包含2個單詞w,分別是{北,京},每個單詞對應兩個因素,所以|w′|=5|w′|=5

北 b ei
京 j ing

t=1的時候,每個w的前兩個tok被激活

當t=2的時候,每個w的tok只能在單詞內傳播,對於“北”來說,tok(北,3,2)和tok(北,4,2)將會被激活,同時tok(北,2,2)有兩條路徑可以達到,這里取兩條路徑的最大概率,加上b音素在t=2時刻對應的概率的對數值,作為tok(北,2,2)的得分。與此同時,b->ei這條路徑完成了“北”這個單詞對應的輸出,所以此時“北”將會有對應的輸出tok(北,-1,2)。
當t=3的時候,對於“京”這個單詞,除了正常的單詞內tok傳播,還將涉及到單詞和單詞之間的tok傳播,找到所有單詞w的輸出tok得分和p(京|w)之和的最大值,作為tok(京,0,3),並且將該w對應的單詞放到tok(京,0,3)的history。tok(京,0,3)將可以向tok(京,1,4)傳播。
以此類推…….
整體上來看,解碼過程類似於hmm的維特比,找出最大概率對應的路徑,不同之處在於ctc解碼引入了blank節點用於得到最終的輸出序列,而不關心每一幀的輸出結果。
通過設定beam,可以對每個時刻t對應的word輸出tok進行剪枝,加快解碼速度。

CTC-WFST解碼

  類似於HCLG的wfst結構,EESEN: END-TO-END SPEECH RECOGNITION USING DEEP RNN MODELS AND WFST-BASED DECODING文章提出了TLG的網絡結構

Grammar

Lexicon
  有兩種形式,可以基於characters和phonemes。

Token

對應於傳統的state,前后添加blank,而且狀態存在自旋

網絡表達式

  S=T∘min(det(L∘G))
相比於傳統的hybrid方法,准確率差不多,解碼速度有三倍以上的提升。原因在於,狀態數從幾千個降到了幾十個,減小了網絡復雜度。

CTC-源碼訓練

  essen源碼參考https://github.com/yajiemiao/eesen,這里簡單說一下涉及到訓練前后向的核心算法源碼實現。以單句訓練為准(多句並行類似),用到的變量

  變量 含義
  phones_num 最后一層輸出節點個數,對應於|phones|+1
  labels_num 一句話對應的標注擴展blank以后的個數,比如”123”擴展為”b1b2b3b”
  frames_num 一句話對應的總的幀數,對應於時間t
  ytkykt 最后一層輸出
  atkakt softmax層的輸入
  CTC error
  ctc.Eval(net_out, targets, &obj_diff);
  涉及到的變量的維度

  變量 維度
  net_out frames_num*phones_num
  alpha/beta frames_num*labes_num
  ctc_error frames_num*phones_num
本來可以使用最終的公式求出對atkakt的error,代碼中卻分成了兩部求解,可能邏輯上能體現出error反向傳播的過程,但是實際感覺沒有必要


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM