上一節(jié)提到了解碼需要聲學(xué)模型(final.mdl
)和語(yǔ)言模型(HCLG.fst
)强重,這節(jié)就來(lái)看一看這個(gè)model文件里是什么東西渤闷。
Ref
Dan's DNN implementation http://kaldi-asr.org/doc/dnn2.html
Kaldi Lecture 4
Decoders used in the Kaldi toolkit http://kaldi-asr.org/doc/decoders.html
kaldi yesno example http://blog.csdn.net/shichaog/article/details/73264152?locationNum=9&fps=1
單音素GMM學(xué)習(xí)筆記 http://www.itdadao.com/articles/c15a1230377p0.html
model文件是什么?
Kaldi官網(wǎng)上給出的OnlineDecoder Demo用到的是online2-wav-nnet2-latgen-faster
這個(gè)命令,于是查看了一下它的源碼瓦堵,關(guān)于這個(gè)Model的部分如下
//nnet2_rxfilename便是.mdl文件
TransitionModel trans_model;
nnet2::AmNnet nnet;
{
bool binary;
Input ki(nnet2_rxfilename, &binary);
//trans_model和nnet聲學(xué)模型都在final.mdl里面
trans_model.Read(ki.Stream(), binary);
nnet.Read(ki.Stream(), binary);
}
由以上代碼便可知道m(xù)odel文件包含了HMM的部分拓?fù)浣Y(jié)構(gòu)(即TransitionModel,更完整的拓?fù)浣Y(jié)構(gòu)在HCLG.fst中)以及各個(gè)特征對(duì)應(yīng)的概率(即聲學(xué)模型AM)歌亲,通過(guò)聲學(xué)模型加上TransitionModel就能知道這個(gè)特征屬于HMM中的哪個(gè)狀態(tài)谷丸,這個(gè)完整的HMM結(jié)構(gòu)就是HCLG.fst。
HCLG.fst文件是什么应结?
音素由狀態(tài)狀態(tài)組成,單詞由音素組成泉唁,句子由單詞組成鹅龄,只要這要一步步還原就能將上面過(guò)程得到的狀態(tài)還原為文字。HCLG.fst便對(duì)應(yīng)這個(gè)過(guò)程的轉(zhuǎn)化亭畜。
- H: HMM,將狀態(tài)還原為音素扮休。實(shí)際上輸入Kaldi這個(gè)HCLG.fst的并不是狀態(tài),而是一串由TransitionModel產(chǎn)生出來(lái)的
transition-id
拴鸵,不過(guò)理解成狀態(tài)并無(wú)大礙玷坠。 - L: Lexicon,即一個(gè)單詞是怎么讀的劲藐,將音素還原為單詞八堡。可以理解為一個(gè)單詞的音標(biāo)是怎樣的聘芜。
- G: Grammar兄渺,即單詞是如何組成句子的。將單詞合理地組成句子汰现。
- C: Context-dependency挂谍,由它來(lái)構(gòu)建音素之間的上下文相關(guān)性叔壤,即形成
triphone
。這個(gè)過(guò)程是實(shí)時(shí)構(gòu)建的(原文為on-the-fly口叙,大概意思是這個(gè)C是在內(nèi)存里動(dòng)態(tài)構(gòu)建的炼绘?)
NNet2 Model文件分析
感覺(jué)DNN的Model文件比GMM的容易懂一些
Ref1中提到,這個(gè)Model輸入的是一個(gè)窗口內(nèi)的特征串妄田,輸出維數(shù)對(duì)應(yīng)決策樹(shù)的葉節(jié)點(diǎn)數(shù)量俺亮,這樣就能得出這個(gè)特征串最可能是HMM中的哪個(gè)pdf了。先來(lái)使用nnet-am-info
命令查看一下librispeech經(jīng)過(guò)nnet2訓(xùn)練得到的model里面的聲學(xué)模型
num-components 17
num-updatable-components 5
left-context 7
right-context 7
input-dim 140
output-dim 5816
parameter-dim 10351000
component 0 : SpliceComponent, input-dim=140, output-dim=700, context=-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 , const_component_dim=100
component 1 : FixedAffineComponent, input-dim=700, output-dim=700, linear-params-stddev=0.00203155, bias-params-stddev=0.0310742
component 2 : AffineComponentPreconditionedOnline, input-dim=700, output-dim=3500, linear-params-stddev=0.986785, bias-params-stddev=4.42767, learning-rate=0.001, rank-in=20, rank-out=80, num_samples_history=2000, update_period=4, alpha=4, max-change-per-sample=0.075
component 3 : PnormComponent, input-dim = 3500, output-dim = 350, p = 2
component 4 : NormalizeComponent, input-dim=350, output-dim=350
component 5 : AffineComponentPreconditionedOnline, input-dim=350, output-dim=3500, linear-params-stddev=1.0001, bias-params-stddev=0.983017, learning-rate=0.001, rank-in=20, rank-out=80, num_samples_history=2000, update_period=4, alpha=4, max-change-per-sample=0.075
component 6 : PnormComponent, input-dim = 3500, output-dim = 350, p = 2
component 7 : NormalizeComponent, input-dim=350, output-dim=350
component 8 : AffineComponentPreconditionedOnline, input-dim=350, output-dim=3500, linear-params-stddev=1.00021, bias-params-stddev=0.944995, learning-rate=0.001, rank-in=20, rank-out=80, num_samples_history=2000, update_period=4, alpha=4, max-change-per-sample=0.075
component 9 : PnormComponent, input-dim = 3500, output-dim = 350, p = 2
component 10 : NormalizeComponent, input-dim=350, output-dim=350
component 11 : AffineComponentPreconditionedOnline, input-dim=350, output-dim=3500, linear-params-stddev=1.0002, bias-params-stddev=0.943781, learning-rate=0.001, rank-in=20, rank-out=80, num_samples_history=2000, update_period=4, alpha=4, max-change-per-sample=0.075
component 12 : PnormComponent, input-dim = 3500, output-dim = 350, p = 2
component 13 : NormalizeComponent, input-dim=350, output-dim=350
component 14 : AffineComponentPreconditionedOnline, input-dim=350, output-dim=12000, linear-params-stddev=0.607722, bias-params-stddev=0.874339, learning-rate=0.001, rank-in=20, rank-out=80, num_samples_history=2000, update_period=4, alpha=4, max-change-per-sample=0.075
component 15 : SoftmaxComponent, input-dim=12000, output-dim=12000
component 16 : SumGroupComponent, input-dim=12000, output-dim=5816
prior dimension: 5816, prior sum: 1, prior min: 2.69233e-06
LOG (nnet-am-info[5.3.31~1-4e3c1]:main():nnet-am-info.cc:76) Printed info about final.mdl
可以看到librispeech語(yǔ)料庫(kù)訓(xùn)練得到的層數(shù)為16層形庭,Ref1中提到的RM數(shù)據(jù)集的mdl層數(shù)則是10層铅辞,估計(jì)大部分時(shí)間都用在了這個(gè)網(wǎng)絡(luò)的計(jì)算中。影響實(shí)時(shí)性的元兇找到了萨醒,重新訓(xùn)練一個(gè)小一點(diǎn)的網(wǎng)絡(luò)結(jié)構(gòu)吧(說(shuō)的可真輕松呢)斟珊。
GMM Model文件分析
Ref4中提到的有些概念可能會(huì)讓人誤解,還有些數(shù)據(jù)感覺(jué)有問(wèn)題富纸,這里僅以我理解的方式分析一下囤踩。
切換到yesno/s5/exp/mono0a
目錄下,用~/kaldi-bak/src/gmmbin/gmm-copy --binary=false 0.mdl -
命令將二進(jìn)制的mdl文件顯示在標(biāo)準(zhǔn)輸出中晓褪。
<Topology>
這個(gè)包含的就不必多說(shuō)了堵漱,就是整個(gè)HMM的結(jié)構(gòu)和初始參數(shù)(0.mdl和40.mdl這一部分的參數(shù)均相同,可見(jiàn)轉(zhuǎn)移概率等應(yīng)該是儲(chǔ)存在HCLG.fst文件中的)了
<Triples>
共有11個(gè)涣仿,對(duì)應(yīng)11個(gè)狀態(tài)雙圓圈勤庐,如下圖
如Kaldi官網(wǎng)HMM部分所說(shuō),
Each possible triple of (phone, hmm-state, pdf) maps to a unique transition-state.
<LogProbs>
[ 0 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 -0.2876821 -1.386294 ]
這里共有1(進(jìn)入HMM的初始概率為1
好港,log后為0
)+30個(gè)值(不知道Ref4的作者是不是打錯(cuò)了)
也就是說(shuō)這個(gè)LogProbs
是和transition-id
對(duì)應(yīng)起來(lái)的愉镰,描述了轉(zhuǎn)移概率。
<DIMENSION> 39 <NUMPDFS> 11 <DiagGMM>
輸入的MFCC特征為39維钧汹,需要求11個(gè)狀態(tài)的概率密度函數(shù)丈探,后續(xù)的一些值就是記錄這11個(gè)狀態(tài)具體的GMM描述的概率密度函數(shù)啦。一個(gè)GMM原原本本的參數(shù)需要以下參數(shù):分量權(quán)重weights_
拔莱,均值means_
碗降,方差vars_
,不過(guò)為了方便計(jì)算塘秦,在里面記錄了每一分量多維高斯分布里的常量部分取log后的數(shù)值gconsts_
讼渊,方差每一元素求倒數(shù)后的inv_vars_
、均值乘以inv_vars_
后的means_invvars_
尊剔。
RM Model文件分析
從官網(wǎng)上下載各個(gè)階段訓(xùn)練出的model文件精偿,http://kaldi-asr.org/downloads/build/4/trunk/egs/rm/s5/exp/,并轉(zhuǎn)為文本格式,~/kaldi-bak/src/gmmbin/gmm-copy --binary=false 0.mdl 0_text.mdl
笔咽,然后就可以像上面那樣分析一下聲學(xué)模型是如何構(gòu)成的搔预,這里只比較一下Monophone單音素
和Triphone三音素
之間的差異。
Monophone階段
- 1~5為SIL叶组,含5個(gè)狀態(tài)
- 6~193為發(fā)音音素拯田,含3個(gè)狀態(tài)
- 共有5*5+(194-6)*3=589個(gè)
transition state
- 得益于決策樹(shù)的聚類, PDF數(shù)量減少了一些甩十,為146
Triphone 1階段
- 1~5為SIL船庇,含5個(gè)狀態(tài)
-
6~193為發(fā)音音素,含3個(gè)狀態(tài)
Ref:Tree-Based State Tying for High Acoustic Accuracy Modelling - 單音素內(nèi)部三個(gè)狀態(tài)是排列好的侣监,所以之前的計(jì)算是5*5+(194-6)*3=589個(gè)Transition鸭轮;
現(xiàn)在三音素的三個(gè)狀態(tài)可以從相關(guān)的別的音素那里去組合了,所以transition state
增加到了5662 - PDF 1435
關(guān)于實(shí)時(shí)性
觀察一下解碼等命令所用的時(shí)間橄霉,
IO時(shí)間
可以注意到將
final.mdl
這個(gè)接近40MB的文件給讀入內(nèi)存還是需要一定時(shí)間的窃爷,而且在Decoder's lattice
和Align lattice
里面都會(huì)用到它,因此考慮在程序啟動(dòng)的時(shí)候就將它讀入內(nèi)存姓蜂,后續(xù)解碼的時(shí)候直接使用按厘。因此假如想移植到安卓,通過(guò)JNI操作的話就需要全局變量了钱慢。
解碼時(shí)間
也就是第二個(gè)藍(lán)框里的時(shí)間逮京,這部分耗時(shí)是最長(zhǎng)的,目前的想法就是分析這個(gè)解碼運(yùn)算集中在哪里束莫,進(jìn)行優(yōu)化來(lái)提高實(shí)時(shí)性了懒棉。這也是為什么要分析model文件的原因。
分析一下Nnet2方式和GMM方式計(jì)算速度到底誰(shuí)更快以及怎么優(yōu)化: Nnet2輸入特征找到最可能對(duì)應(yīng)的pdf-id
览绿,在這個(gè)過(guò)程中計(jì)算了分別屬于所有pdf-id
的概率漓藕; GMM則可計(jì)算指定個(gè)數(shù)的pdf-id
,找一個(gè)概率最大的出來(lái)挟裂。但是GMM是只找了該特征屬于部分pdf-id
的概率,還是找了所有的呢揍诽?Ref3中提到的
The function LogLikelihood() returns the log-likelihood for this frame and index; the index would normally be the (one-based) transition-id, see Integer identifiers used by TransitionModel. The frame is a zero-based quantity. The most normal DecodableInterface object will just look up the appropriate feature vector (using the index "frame"), work out the pdf-id corresponding to that transition-id, and return the corresponding acoustic log-likelihood.
似乎說(shuō)明是找部分pdf-id
去進(jìn)行計(jì)算的诀蓉,但是實(shí)際運(yùn)行過(guò)程中發(fā)現(xiàn)GMM和NNET2解碼時(shí)間相差并不大。
總結(jié)
model
文件包含聲學(xué)模型和transition model
用于找出特征對(duì)應(yīng)的狀態(tài)的位置暑脆,再將狀態(tài)扔到HCLG.fst
中構(gòu)建出所有狀態(tài)組合成的句子渠啤。除開(kāi)GMM和NNET2之外,還有NNET3模型沒(méi)有分析添吗,留到后面再說(shuō)了沥曹。另外HCLG.fst
是如何構(gòu)建的?下一篇文章見(jiàn)。