Kaldi WFST HCLG.fst 構圖 學習

HCLG.fst由四部分構成

1.G:語言模型WFST,輸入輸出符號相同,實際是一個WFSA(acceptor接受機),爲了方便與其它三個WFST進行操作,將其視爲一個輸入輸出相同的WFST。

2.L:發音詞典WFST,輸入符號:monophone,輸出符號:詞;

3.C:上下文相關WFST,輸入符號:triphone(上下文相關),輸出符號:monophnoe;

4.H:HMM聲學模型WFST,輸入符號:HMMtransitions-ids,輸出符號:triphone。

 

將四者逐層合併,即可得到最後的圖。

HCLG= asl(min(rds(det(H'omin(det(Co min(det(Lo G)))))))

其中asl==“add-self-loops”和rds==“remove-disambiguation-symbols“,H'爲沒有自環的H。

 

一、G.fst用於對語言模型進行編碼。當使用統計語言模型時,用srilm訓練出來的語言模型爲arpa格式,可以用arpa2fst將arpa轉換成fst,詳見kaldi中的utils/format_lm.sh。

 

舉個栗子:

假設語言模型由data.txt內的數據訓練得到,$cat data.txt

今天天氣怎麼樣

今天北京的天氣怎麼樣

明天天氣怎麼樣

 

分詞後,$cat data.split

今天 天氣 怎麼 樣

今天 北京 的 天氣 怎麼 樣

明天 天氣 怎麼 樣

 

訓練語言模型$ngram-count -text data.split -order 3 -lm query.arpa

$cat query.arpa

\data\

ngram1=9

ngram2=10

ngram3=2

\1-grams:

-0.7533277 </s>

-99 <s> -0.7907404

-0.9294189今天-1.059586

-1.230449北京-0.6268836

-0.7533277天氣-0.5177391

-0.7533277怎麼-0.5177391

-1.230449明天-0.5688916

-0.7533277樣-0.5177391

-1.230449的-0.5688916

\2-grams:

-0.39794 <s>今天

-0.3309932 <s>明天

-0.3309932今天 北京

-0.3309932今天 天氣

-0.1091445北京 的

-0.1249387天氣 怎麼0

-0.1249387怎麼 樣0

-0.1091445明天 天氣

-0.1249387樣</s>

-0.1091445的 天氣

\3-grams:

-0.1249387天氣 怎麼 樣

-0.1249387怎麼 樣</s>

\end\

 

 

同時還需要給每一個詞賦予一個唯一的id(symboltable

$cat data.split | tr ' ' '\n' | grep -v ^$ | sort -u |awk '{print $1""NR }END{print "<eps>"" "0;print "#0"""NR+1;print "<s>"" "NR+2;print "</s>"""NR+3 }' > words.txt

$cat words.txt

今天1

北京2

天氣3

怎麼4

明天5

樣6

的7

<eps>0

#08

<s>9

</s>10

 

這樣做的原因是Kaldi運行時不會使用文本形式,而是用整數標號形式來表達和傳遞信息。

word.txt文件包含單個消歧符號“#0”(用於G.fst輸入上的epsilon)。在語言模型G中的退避弧上有一個符號#0;

這確保了G在刪除epsilons之後是可確定的。

 

然後即可用arpa2fst將arpa格式語言模型轉換爲fst

arpa2fst--disambig-symbol=#0 --max-arpa-warnings=-1--read-symbol-table=words.txt query.arpa G.fst

 

在實際應用中,需要有剔除不可用/包含集外詞的N元語法等的操作,詳見local/wsj_format_data.sh

 

至此,G.fst已經構好,想看構好的圖長什麼樣,可以用fstdraw與dot

$fstdraw --isymbols=words.txt --osymbols=words.txt G.fst > fst.dot

 

通常dot轉換爲jpg後分辨率會過低且不支持顯示中文,因此打開fst.dot文件,將其中的size大小擴大,

並將編碼格式轉換爲utf-8,在每個fontsize前加上fontname="simsun.ttc",

vim中:%s:fontsize= 14:fontname="simsun.ttc",fontsize = 20:g

 

$dot -Tjpg fst.dot > fst.jpg

 

 

這部分最後一條命令是fstisstochastic,這是一個診斷步驟,他打印出兩個數字,最小權重和最大權重,以告訴用戶FST不隨機的程度。

eg:9.14233e-05-0.259833

第一個數字很小,它證實沒有狀態的弧的概率加上最終狀態明顯小於1。第二個數字是重要的,這意味着有些狀態具有“太多”的概率。對於具有回退的語言模型的FST來說,有一些具有“太多”概率的狀態是正常的。

(thenumeric values of the weights in the FSTs can generally beinterpreted as negated log probabilities)FST中權重的數值通常可以解釋爲負對數概率。

 

 

二、L.fst是一個把音素映射成爲詞的發音詞典FST,L.fst位於data/lang目錄(language,與“語言”本身相關),在該目錄下有如下內容:

L.fst L_disambig.fst oov.int oov.txt phones phones.txt topo words.txt

 

L.fst是FST形式的發音詞典,對每個詞的發音進行編碼,輸入是音素,輸出是詞。

 

L_disambig.fst也是FST形式的發音詞典,不過它還包含爲了消歧而引入的消歧符號(如#1、#2)和爲自環(self-loop)而引入的#0。#0是來自G.fst的特殊消歧符號,它的作用是讓消歧符號能夠“通過”(passthrough)整個語言模型。

 

oov.txt中僅有一個元素:<UNK>,其作用是將所有詞彙表以外的詞都映射爲這個詞,這使得這個詞的發音只包含一個被指定爲“垃圾音素”(garbagephone)的音素。該音素被稱爲<SPN>,就是“spokennoise”的縮寫,該音素會與各種口語噪聲對齊。

#grep -w UNK data/local/dict/lexicon.txt

<UNK>SPN

 

oov.int中有<UNK>所對應的id。

 

phones.txt和words.txt爲符號表(symboltable)文件,第一列爲文本,第二列爲數字。這兩個文件用於將每個元素對應到唯一的id上。

 

topo指明瞭所用的HMM模型的拓撲結構//待補充

 

phones文件夾下有一系列文件,指明音素集合的各種信息,這些文件大多數包含三個不同版本:txt、int、csl。詳見http://www.kaldi-asr.org/doc/data_prep.html

 

以上這些文件都不需要手動創建,kaldi提供了一個腳本utils/prepare_lang.sh可以用於創建這個目錄中的多數文件:

utils/prepare_lang.shdata/local/dict "<UNK>" data/local/lang data/lang。

腳本utils/prepare_lang.sh支持很多選項。

 

--position-dependent-phones(true|false)。默認ture;用於決定是否將phone更詳細地拆分爲開始、

中間、結束、孤立燈給未知相關的phones。如果允許,則在每個phone後面加上_B_I _E _S用於標定位置[(B)egin,(E)nd, (I)nternal and (S)ingleton]。在構建決策樹時可以對phone的位置進行提問,然後產生分裂。

 

-share-silence-phones(true|false)。該選項默認是false。如果該選項被設爲true,所有靜音音素(如靜音、發聲噪聲、噪聲和笑聲)會共享同一個pdf(高斯混合模型),只有模型中的轉移概率不同。這對IARPA的BABEL項目中的廣東話數據集非常有效。它會構造一個roots文件,在文件中同一行出現的所有音素對應的HMM會共享他們的混合高斯分佈。如果不想共享,可以把他們放在不同行。roots文件中,每一行前面都會有shared/not-shared和split/not-split修飾。

 

--sil-prob <probability of silence> # default: 0.5 [must have0 < silprob < 1]也可能很重要,只是具體該設置成多少需要更多的實驗。

 

輸入目錄是data/local/dict/,<UNK>需要在字典中,是標註中所有OOV詞的映射詞(映射情況會寫入data/lang/oov.txt中)。data/local/lang/只是腳本使用的一個臨時目錄,data/lang/纔是輸出文件將會寫入的地方。

 

我們需要做的是準備好data/local/dict/。該目錄下需包含以下文件:

extra_questions.txt lexicon.txt[lexiconp.txt] nonsilence_phones.txt optional_silence.txt silence_phones.txt

 

nonsilence_phones.txt內容爲“真正”的音素,kaldi建議將每個basephone的不同形式都組織在單獨的一行中。他們可以有不用的重音或者聲調,例如aa1 a2 a3 a4

 

silence_phones.txt內容爲“靜音”音素,包含各種噪聲、笑聲、咳嗽、填充停頓等(SIL SPN NSN LAU)

 

extra_questions.txt有可能是空的;但通常會包含多行音素,每行的音素成員都有相同的聲調,有的行可能是靜音音素。這樣做可以增強自動產生問題。在nonsilence_phones.txt中每個音素的不同聲調錶示都在同一行,這確保了他們在data/lang/phones/roots.txt和data/lang/phones/sets.txt也屬同一行,這反過來又確保了它們共享同一個(決策)樹根,並且不會有決策問題弄混它們。因此,我們需要提供一個特別的問題,能爲決策樹的建立過程提供一種區分音素的方法。注意:我們在sets.txt和roots.txt中將音素分組放在一起的原因是,這些同一音素的不同聲調變體可能缺乏足夠的數據去穩健地估計一個單獨的決策樹,或者是產生問題集時需要的聚類信息。像這樣把它們組合在一起,我們可以確保當數據不足以對它們分別估計決策樹時,這些變體能在決策樹的建立過程中“聚集在一起”(staytogether)。

 

optional_silence.txt只包含一個音素來作爲字典中的選擇靜音音素,通常是SIL。

 

lexicon.txt每個詞的發音,格式爲:<詞><phone1> <phone2> …

注意: lexicon.txt中,如果一個詞有不同發音,則會在不同行中出現多次。

在這些輸入中,沒有詞位信息,即沒有像_B和_E這樣的後綴。

腳本prepare_lang.sh會幫我們添加這些後綴。

lexiconp.txt帶概率的發音詞典,格式爲:<詞><pron-prob><phone1> <phone2> …

注: 0.0<pron-prob<=1.0

如果存在lexiconp.txt,則優先使用lexiconp.txt而不用lexicon.txt

 

消歧符號是在詞典中的音素序列末尾插入的符號#1,#2,#3等。當音素序列是詞典中另一個音素序列的前綴,或者出現在一個以上的單詞中時,需要在其後加上這些符號之一。需要這些符號以確保產品Lo G是可確定的。

 

 

可以使用腳本utils/make_lexicon_fst.pl將詞典轉換成fst輸入文件的格式。

Usage:make_lexicon_fst.pl [--pron-probs] lexicon.txt [silprob silphone[sil_disambig_sym]] >lexiconfst.txt

 

使用fstcompile可以將text描述性的fst轉換爲二進制形式:

fstcompile–isymbols=phones.txt --osymbols=words.txt text_format.fstbinary.fst

 

爲了之後要做的compose操作,這裏還需要fstaddselfloops和fstarcsort。

 

生成的二進制fst可以使用fstdraw可視化,命令爲:

fstdraw--isymbol=phones.txt –osymbol=words.txt binary.fst |dot -Tjpg >fst.jpg

 

 

三、有了G和L,我們就可以計算min(det(Lo G)),命令行如下:

fsttablecomposedata/L_disambig.fst data/G.fst | \

fstdeterminizestar--use-log=true | \

fstminimizeencoded| fstpushspecial | \

fstarcsort--sort-type=ilabel > somedir/LG.fst

 

 

四、上下文相關FST:triphone到monophone的轉換器,加入他可以避免枚舉所有可能的monophone

 

我們還有一個消歧符號#-1代替出現在上下文FSTC的左邊的epsilons,在開始的話語(在我們開始輸出符號之前)。這是必要的,以解決一個相當微妙的問題,當我們有一個空的語音表示的話(例如句子符號的開始和結束<s>和</s>)。

 

 

 

 

 

 

 

 

 

 

 

 

數據準備(datapreparation)階段需要的文件有:

 

text中第一列爲錄音編號<utterance-id>,後面跟着每段錄音的標註。

wav.scp中第一列爲錄音編號<recording-id>,第二列爲音頻文件路徑<extended-filename>

utt2spk中第一列爲錄音編號<utterance-id>,第二列爲講話這id<speaker-id>

spk2utt中第一列爲講話着<speaker-id>,後面跟着他所說的話<utterance-id1> <utterance-id2> …

 

thchs30中執行local/thchs-30_data_prep.sh

就可以根據音頻名和標註創建:wav.scp, utt2spk.scp, spk2utt.scp, text以及words.txtphone.txt

 

wav.trn第一行中文標註,第二行拼音,第三行音素

 

 

 

 

 

 

 

 

reference: http://www.kaldi-asr.org/doc/data_prep.html

http://blog.csdn.net/duishengchen/article/details/52514477

http://blog.csdn.net/wbgxx333/article/details/26233527

http://ftli.farbox.com/post/kaldizhong-wen-shi-bie#QuFenDuTrain

http://blog.csdn.net/u012361418/article/details/73006870

 

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