PocketSphinx語音識別系統語言模型的訓練和聲學模型的改進
關於語音識別的基礎知識和sphinx的知識,詳細能夠參考我的另外兩篇博文:
語音識別的基礎知識與CMUsphinx介紹:
http://blog.csdn.net/zouxy09/article/details/7941585
PocketSphinx語音識別系統的編譯、安裝和使用:
http://blog.csdn.net/zouxy09/article/details/7942784
以下的工作都是基於上面兩篇博文往下做的,所以最好先了解下前面的情況。
以下的過程參考CMU sphinx的wiki:
http://cmusphinx.sourceforge.net/wiki/
一、訓練語言模型
詞與詞之間存在着合乎句法與否的約束,語言模型就是用來表示這些約束的,它能夠提供字與字之間的上下文信息和語義信息。在pocketsphinx語音識別系統時,採用了N-gram模型,即對訓練音頻文件所相應的文本文件進行統計,提取不同字詞之間先后發生的統計關系。
假設你的語言模型較小(比如小的語音指令集或者任務),並且是英文的,那就能夠直接上CMU提供的網絡server上面訓練,假設較大的話,一般使用CMUclmtk語言模型工具來訓練。以下分兩種情況來介紹:
1.1、利用在線工具建立語言模型
(1)創建一個語料庫:
語料庫實際上就是一些文本的集合,包括了你須要識別的語音的文字的一些集合,比如句子啊,詞啊等等。
#vi corpus.txt
輸入例如以下內容:
stop
forward
backward
turn right
turn left
保存退出
(2)利用在線工具LMTool建立語言模型:
進入網址:http://www.speech.cs.cmu.edu/tools/lmtool.html
點擊Browsebutton,選擇之前創建的corpus.txt,最后點擊COMPILE KNOWLEDGE BASE。這樣就會生成字典文件* .dic 和語言模型文件 *.lm,比如:
生成TAR2916.tar.gz
tar xzf TAR2916.tar.gz
2916.corpus 2916.lm 2916.sent.arpabo 2916.vocab
2916.dic 2916.sent 2916.token
真正實用的是.dic、.lm的文件
(3)測試結果:
pocketsphinx_continuous解碼器用-lm選項來指定要載入的語言模型,-dict來指定要載入的字典。
#pocketsphinx_continuous -lm 2916.lm -dict 2916.dic
INFO: ngram_search_fwdflat.c(295): Utterance vocabulary contains 1 words
INFO: ngram_search_fwdflat.c(912): 97 words recognized (2/fr)
INFO: ngram_search_fwdflat.c(914): 2342 senones evaluated (38/fr)
INFO: ngram_search_fwdflat.c(916): 1011 channels searched (16/fr)
INFO: ngram_search_fwdflat.c(918): 167 words searched (2/fr)
INFO: ngram_search_fwdflat.c(920): 47 word transitions (0/fr)
WARNING: "ngram_search.c", line 1087: </s> not found in last frame, using <sil> instead
INFO: ngram_search.c(1137): lattice start node <s>.0 end node <sil>.56
INFO: ps_lattice.c(1228): Normalizer P(O) = alpha(<sil>:56:60) = -341653
INFO: ps_lattice.c(1266): Joint P(O,S) = -341653 P(S|O) = 0
000000000: STOP (-6531224)
READY....
Listening...
1.2、訓練大文本數據的語言模型
我們通過語言模型訓練工具CMUCLMTK統計大量文本數據得到以單個詞建立的N-Gram模型。
語言模型訓練工具的說明見:
http://www.speech.cs.cmu.edu/SLM/toolkit_documentation.html
詳細的過程例如以下:(得先安裝語言模型訓練工具CMUCLMTK,安裝過程在上一博文中)
(1)准備訓練的文本,也就是語料庫:
這里僅僅是舉一個樣例,所以語料庫也不大,而一般的語料庫都是由大文本來組成的,里面就是有一些我們的日經常使用語或者報紙啊,書啊等等所出現過的句子。文本數據越大,訓練得到的語言模型就越好。
#vi weather.txt
在 .txt中輸入例如以下內容,記住結尾不可留“\n”(實驗證明了這一點)。每一個utterances由 <s> 和 </s>來分隔
<s> 天氣 </s>
<s> 有雨 </s>
<s> 晴朗 </s>
<s> 多雲 </s>
<s> 雷電 </s>
wq 保存退出
(2)產生詞匯表vocabulary文件:
# text2wfreq < weather.txt | wfreq2vocab > weather.tmp.vocab
命令text2wfreq:統計文本文件里每一個詞出現的次數,得到一個后綴為wfreq的文件,內容演示樣例為:
二1334
九1334
</s> 3680
即表示詞二、九和</s>在訓練文本中出現的次數依次為1334、1334、3680。
命令wfreq2vocab:統計文本文件里含有多少個詞,即有哪些詞。如數字識別中包括10個數字和兩個靜音,故共同擁有12個詞,依照拼音順序依次是:</s>、<s>、八、二、九、零、六、七、三、四、五、一。
(3)生成 arpa格式的語言模型:
# text2idngram -vocab weather.vocab -idngram weather.idngram < weather.closed.txt
#idngram2lm -vocab_type 0 -idngram weather.idngram -vocab weather.vocab -arpa weather.arpa
命令text2idngram:列舉文本中出現的每一個n元語法。產生一個二進制文件,含有一個n元數組的數值排序列表,相應於與詞有關的的N-Gram。超出文本范圍的詞匯映射值為0。
命令idngram2lm:輸入文件包括一個idngram文件,一個vocab文件和一個ccs文件,輸出是一個后綴為binlm的語言模型文件。當中ccs文件指句首和句尾的靜音<s>和</s>。
命令binlm2arpa:是將binlm文件轉換為實驗中須要的arpa格式語言模型文件。
(4)轉換為 CMU的二進制格式 (DMP):
假設你的語言模型比較大的話,最好就轉換為CMU的二進制格式 (DMP),這樣能夠加快載入語言模型的速度,降低解碼器初始化的時間。但對於小模型來說,就沒有這個必要,由於sphinx3能處理這兩種后綴名的語言模型文件。
#sphinx_lm_convert -i weather.arpa -o weather.lm.DMP
終於生成了語言模型weather.lm.DMP,此文件為解碼器端所須要的文件格式。
二、改進現有的聲學模型去適應我們的語音:
(原文是Adapting the default acoustic model,但我不知道怎么用中文表達合適,呵呵,請各位前輩指導)
本文主要描寫敘述了怎樣通過對聲學模型做一些簡單工作去改進語音識別。但須要注意的是,他改進的僅僅是你提供的適應數據和模型的匹配。比如:能夠適應你的聲音使得口語較好的識別,或者也能夠使用特定的錄音環境,適應你的或者用戶的口音等等。
適應的過程是通過提供適應的數據(我不知道怎么翻譯,也就是你的錄音數據)去改進現有的模型。這樣獲得的識別效果往往比又一次訓練魯棒性要強,雖然你的適應數據集比較小。比如,對於特定人來說,5分鍾的語音就能夠達到非常明顯的聽寫精確度了。
1、創建一個適應的語料庫
語料庫包括了一些句子,這些句子是隨意指定的,但最好能夠覆蓋你想要識別的句子里面包括的高頻率單詞或者音素。
CMU提供了一個樣例 CMU ARCTIC,里面包括了20個句子,但這個是英文的,所以我們得自己做一個中文的。CMU ARCTIC 見:http://festvox.org/cmu_arctic/
1.1、須要的文件:
共須要四個文件:
arctic20.txt 文本文件:里面是中文的句子
arctic20.fileids控制文件:記錄我的語音文件(讀arctic20.txt里面的句子的錄音)的路徑
arctic20.transcription腳本文件:中文句子和語音文件的相應
arctic20.dic 字典文件:記錄arctic20.txt里面的句子的因素組成
事實上我也不知道詳細應該怎樣建這些文件,我參考了CMU ARCTIC這個英文的,但中文有點不一樣,我自己的這些文件的內容例如以下:(我新建了一個voice文件夾來管理這次的工作)
arctic20.txt由於我是要語音控制系統的,所以我就加入了非常多這類的控制語言,共12個句子:
你確定嗎
打開我的電腦,確定還是取消
關閉計算機,退出瀏覽器
你好嗎?能夠退出程序嗎
返回上一頁還是返回主菜單
放大還是縮小頁面
今天的天氣不錯,不下雨
你喜歡聽音樂嗎,須要打開音樂播放器嗎,聽第幾首歌
須要瀏覽圖片,上一張還是下一張
我想看視頻,有什么電影
打開系統設置,基本設置
進入主菜單,請控制,向左,向右,還是,向上,向下
arctic20.fileids我把上面12個句子相應的錄音文件(放在當前文件夾下的)命名為arctic_*,不須要后綴名的:
arctic_0001
arctic_0002
arctic_0003
arctic_0004
arctic_0005
arctic_0006
arctic_0007
arctic_0008
arctic_0009
arctic_0010
arctic_0011
arctic_0012
arctic20.transcription前面 <s>和 </s>表示靜音,()括號內的就是相應的錄音文件:
<s> 你確定嗎 </s> (arctic_0001)
<s> 打開我的電腦,確定還是取消 </s> (arctic_0002)
<s> 關閉計算機,退出瀏覽器 </s> (arctic_0003)
<s> 你好嗎?能夠退出程序嗎 </s> (arctic_0004)
<s> 返回上一頁還是返回主菜單 </s> (arctic_0005)
<s> 放大還是縮小頁面 </s> (arctic_0006)
<s> 今天的天氣不錯,不下雨 </s> (arctic_0007)
<s> 你喜歡聽音樂嗎,須要打開音樂播放器嗎,聽第幾首歌 </s> (arctic_0008)
<s> 須要瀏覽圖片,上一張還是下一張 </s> (arctic_0009)
<s> 我想看視頻,有什么電影 </s> (arctic_0010)
<s> 打開系統設置,基本設置 </s> (arctic_0011)
<s> 進入主菜單,請控制,向左,向右,還是,向上,向下 </s> (arctic_0012)
arctic20.dic字典文件:記錄arctic20.txt里面的句子的因素組成,我建立這個文件的時候還是比較坎坷的。先是按詞語為單位,到后面統計時,統計只是去,然后我改成以詞為單位,還是統計不了,出現段錯誤,最后我改成以句子為單位,就是以下這樣,才干夠,注意以下標紅的這幾個,和我們平時的拼音有點不一樣:
你確定嗎 n i q uxe d ing m a
打開我的電腦,確定還是取消 d a k ai w o d e d ian n aoq uxe d ing h ai sh ibq ux x i ao
關閉計算機,退出瀏覽器 g uan b i j i s uan j i t ui ch u l iu l an q i
你好嗎?能夠退出程序嗎 n i h ao m a k e y i t ui ch u ch engx ux m a
返回上一頁還是返回主菜單 f an h ui sh ang y i y e h aish ib f an h ui zh u c ai d an
放大還是縮小頁面 f ang d a h ai sh ib s uo x iao y e m ian
今天的天氣不錯,不下雨 j in t ian d e t ian q i b u c uo b u x ia y u
你喜歡聽音樂嗎,須要打開音樂播放器嗎,聽第幾首歌 n i x i h uan t ing y iny uxs uxe m a x ux y ao d a k ai y in y uxe b o f ang q i m a t ing d i j i sh ou g e
須要瀏覽圖片,上一張還是下一張 x ux y ao l iu l an t u p ian sh ang y i zh ang h ai sh i x ia y i zh ang
我想看視頻,有什么電影 w o x iang k an sh i p in y ou sh en m e d ian y ing
打開系統設置,基本設置 d a k ai x i t ong sh ezh ib j i b en sh e zh ib
進入主菜單,請控制,向左,向右,還是,向上,向下 j in r u zh u c ai d an q ing k ong zh ib x iang z uo x iang y ou h ai sh i x iang sh ang x iang x ia
1.2、錄制你的適應數據
為適應語料庫里面的每一個句子錄制一個語音文件,錄音文件的命名須要和arctic20.transcription與arctic20.fileids的一致
注意:此處音頻文件採樣率16KHz,16bit單聲道錄音,並且是wav格式。
我在Linux下寫了一個處理腳本來實現上面這12個句子的錄音:rec_wav.sh,內容例如以下:
for i in `seq 1 12`; do
fn=`printf arctic_%04d $i`;
read sent; echo $sent;
rec -r 16000 -e signed-integer -b 16 -c 1 $fn.wav 2>/dev/null;
done < arctic20.txt
在這里我們須要用到rec這個錄音命令,這個命令是由Linux下一個非常有名的音頻轉換程序sox攜帶的,所以我們須要先安裝sox:
#apt-get install sox
然后改變rec_wav.sh的執行屬性:
#chmod 777 rec_wav.sh
#./rec_wav.sh
這個腳本會顯示一句話,然后進入錄音,我們把這個句子讀出來,然后按ctrl+c顯示下一句話,然后錄音,如此循環到所有的句子的語音數據拿到。這樣在當前文件夾以下就會顯演示樣例如以下文件:
arctic_0001.wav
arctic_0002.wav
.....
arctic_0012.wav
然后,我們須要測試下每一個音頻文件是否正常:
for i in *.wav; do play $i; done
他會依次的播放我們錄下的這些音頻文件;假設不正確的話,就得重錄,我的就沒有什么問題。
2、適應聲學模型
首先我們須要先拷貝現有的默認的聲學模型到當前文件夾下
#cp -a /usr/local/share/pocketsphinx/model/hmm/zh/tdt_sc_8k/ .
這個是pocketsphinx自帶的中文聲學模型
2.1、生成聲學特征文件
我們須要對我們錄制的wav語音文件提取MFCC特征,並且必須以和默認的模型同樣的聲學模型參數去提取這些特征,他們存儲在聲學模型文件夾的feat.params文件里。
#sphinx_fe -argfile tdt_sc_8k/feat.params -samprate 16000 -c arctic20.fileids -di . -do . -ei wav -eo mfc -mswav yes
這樣在當前文件夾下就會對每一個語音文件生成一個*.mfc后綴的特征文件:(我這里生成的是*.mfc,但我執行后面的工作,也就是統計數據時,發現統計程序須要的是*..mfc的,我也不知道哪里出現故障了,所以我僅僅能將其改動為*..mfc)
arctic_0001.mfc
arctic_0001.wav
arctic_0002.mfc
arctic_0002.wav
……
2.2、轉化sendump和mdef文件
有一些模型沒有足夠的數據去做適應。這里有一個額外的文件我們須要下載的,為了節省空間,所以沒有加入進PocketSphinx的發行版包了。我們能夠從以下的鏈接下載:
http://cmusphinx.svn.sourceforge.net/viewvc/cmusphinx/trunk/pocketsphinx-extra/?view=tar
解壓,拷貝pocketsphinx-extra/model/hmm/zh/mandarin_sc3_notone_3s_8k.cd_semi_5000文件夾里面的mixture_weights文件到你的聲學模型文件夾下;
#cp ../sourcecode/pocketsphinx-extra/model/hmm/zh/mandarin_sc3_notone_3s_8k.cd_semi_5000/mixture_weights tdt_sc_8k/
當然,假設你安裝了 SphinxTrain Python modules,那么你就能夠使用sendump.py去把聲學模型的sendump文件轉換為mixture_weights文件。
然后我們須要把聲學模型的mdef文件轉換為SphinxTrain訓練工具能夠使用的plain text格式:
#pocketsphinx_mdef_convert -text tdt_sc_8k/mdef tdt_sc_8k/mdef.txt
2.3、累加觀察序列
通過SphinxTrain訓練工具帶的bw程序去收集適應數據的統計數據。bw程序在sphinxtrain-1.0.7聲學訓練工具源代碼的bin.i686-pc-linux-gnu文件夾中。
把bw 和 map_adapt和 mk_s2sendump和mllr_solve程序都復制到當前文件夾。
#cp ../sourcecode/sphinxtrain-1.0.7/bin.i686-pc-linux-gnu/bw .
#cp ../sourcecode/sphinxtrain-1.0.7/bin.i686-pc-linux-gnu/mk_s2sendump .
#cp ../sourcecode/sphinxtrain-1.0.7/bin.i686-pc-linux-gnu/map_adapt .
#cp ../sourcecode/sphinxtrain-1.0.7/bin.i686-pc-linux-gnu/mllr_solve .
然后開始統計:
./bw -hmmdir tdt_sc_8k -moddeffn tdt_sc_8k/mdef.txt -ts2cbfn .semi. -feat 1s_c_d_dd -svspec 0-12/13-25/26-38 -cmn current -agc none -dictfn arctic20.dic -ctlfn arctic20.fileids -lsnfn arctic20.transcription -accumdir .
確保bw的參數和聲學模型文件夾的feat.params文件一致;
我剛才說過字典文件的建立的時候,以詞語和單字為基本單元的時候,在這個步驟就會出現以下相似的錯誤:
……
utt> 0 arctic_0001stat_retry(arctic_0001..mfc) failed
ERROR: "corpus.c", line 1555: MFCC read of arctic_0001..mfc failed. Retrying after sleep...
stat_retry(arctic_0001..mfc) failed
ERROR: "corpus.c", line 1555: MFCC read of arctic_0001..mfc failed. Retrying after sleep...
stat_retry(arctic_0001..mfc) failed
……
utt> 0 arctic_0001 357INFO: cmn.c(175): CMN: 30.40 -1.07 -0.65 -0.24 1.70 -0.08 -0.39 0.05 0.59 -0.15 0.15 0.40 0.34
0WARNING: "mk_phone_list.c", line 173: Unable to lookup word '你確定嗎' in the lexicon
WARNING: "next_utt_states.c", line 79: Segmentation fault (core dumped)
改動為句單元后,就沒有問題了。
2.4、創建MLLR(最大似然線性回歸算法)變換
MLLR是一種有效的輕量級的自適應方法,尤其是當樣本數據集較小時。在在線適應中使用MLLR是一種比較好的方法。MLLR在連續模型中表現得比較好,可是由於半連續模型非常依賴混合權重,所以它的效果有限。假設想得到最好的精確度,最好將MLLR適應和MAP適應兩種方法結合起來應用;
以下我們產生MLLR變換,並在執行時將其傳入解碼器去適應這個聲學模型。
#./mllr_solve -meanfn tdt_sc_8k/means -varfn tdt_sc_8k/variances -outmllrfn mllr_matrix -accumdir .
這個命令行會產生一個名叫mllr_matrix的適應數據文件。如今,假設我們須要使用這個適應模型,那就能夠通過給pocketsphinx命令行參數加入 -mllr mllr_matrix來使用;
2.5、通過MAP更新聲學模型
MAP是一個不同的適應方法。他不同於MLLR,他不會創建一個通用的變換,而是更新每一個模型參數。
我們將原來的聲學模型文件夾拷貝為一個新的模型文件夾:
#cp tdt_sc_8k/ -rf tdt_sc_8kadapt
通過map_adapt程序來實現適應:
#./map_adapt -meanfn tdt_sc_8k/means -varfn tdt_sc_8k/variances -mixwfn tdt_sc_8k/mixture_weights -tmatfn tdt_sc_8k/transition_matrices -accumdir . -mapmeanfn tdt_sc_8kadapt/means -mapvarfn tdt_sc_8kadapt/variances -mapmixwfn tdt_sc_8kadapt/mixture_weights -maptmatfn tdt_sc_8kadapt/transition_matrices
2.6、又一次創建適應的sendump文件
通過已經更新的mixture_weights文件來又一次創建 sendump文件,能夠節省空間:
#./mk_s2sendump -pocketsphinx yes -moddeffn tdt_sc_8kadapt/mdef.txt -mixwfn tdt_sc_8kadapt/mixture_weights -sendumpfn tdt_sc_8kadapt/sendump
好了,恭喜你,如今你已經擁有一個改進了的適應你的語音的聲學模型了。
新的聲學模型在hub4wsj_sc_8kadapt文件夾下,文件夾有以下文件:
mdef
feat.params
mixture_weights
means
noisedict
transition_matrices
variances
然后把他復制到我們的軟件文件夾,
#pocketsphinx_continuous -hmm <your_new_model_folder> -lm <your_lm> -dict <your_dict>
然后就能夠使用了。當中的語言模型和字典文件用默認的就可以。
我試驗了以下,感覺提升也不是非常大。識別率還是挺低的,呵呵,不知道是不是我這個過程有一些錯誤或者有一些沒有考慮的地方。所以臨時也沒辦法實用。
我也試驗了pocketsphinx所攜帶的英語的識別,感覺比中文的好點,但識別率還是不高,呵呵,也可能是我的發音不標准。對於中文的大詞匯量語音識別來說,我試過微軟的,IBM的,感覺效果也不算特別好,只是商業的一般都會比這些開源的好,由於別人有足夠的樣本(不同人不同錄音環境等等)去訓練一兩個月。但CMU這個開源項目還是得到不少的資助的。另外,不知道國內牛逼的科大訊飛怎樣,還沒試過。
而對於小詞匯量的語音識別,比如一些控制指令集啊,數字啊這些,好像精確度都做得挺好的了。所以難道我要妥協僅僅能採用小詞匯量的語音識別來加入我的人機交互系統嗎?但這樣就僅僅是能控制機器而已,不能像iphone的siri這樣和她聊天了?不知道各位前輩有什么建議嗎?