最近需要解決一個問題:
在Kaldi下做完DNN訓練之後,要怎麼得到一段錄音feature的後驗概率,以及在有了這個後驗概率之後怎麼知道每一幀對應的是哪個狀態,同時又是對應哪個phone。
首先,如何得到一段錄音feature的後驗概率。
由於DNN訓練已經做完,已經得到了訓練後的網絡,那麼只要把feature放進這個網絡裏面進行一遍從頭到尾的運算,就可以得到這個後驗概率。
在Kaldi裏面用來完成這個穿行網絡的過程的命令行工具叫做nnet-forward。
具體的使用方法是(文件具體路徑已省略):
- nnet-forward --feature-transform=transformFile --apply-log=false --use-gpu=no nnet ark:featureFile ark,t:fwd.ark
於是就可以得到fwd.ark這個文件,這個文件裏面是什麼內容呢?
裏面就是這段feature經過這個網絡的處理之後生成的一個矩陣。
那麼這個矩陣的含義是什麼呢?
我剛開始對這個矩陣的模糊理解是每一行表示一幀,每一列表示一個狀態。
於是我就有了一個疑問,那麼每一列對應的是哪一個狀態呢?
首先我打開了.mdl文件,文件的第一部分是HMM的拓撲結構的描述,第二部分是(取前面幾行):
<Triples> 2045
1 0 0
1 1 56
1 2 48
2 0 57
2 0 125
2 0 211
...
我在想這個部分的內容是否和state有關係。
那麼就需要理解這個部分表示的是什麼內容,後來經過在Kaldi羣裏面得到的指點知道了官方解釋的地址:
http://kaldi.sourceforge.net/hmm.html#transition_model
- A triple means a triple (phone, hmm-state, pdf) which is mappable to and from a transition-state.
經過觀察,有兩個特點:
1. 總共有2045個這樣的三元組
2. 第三列只有0-1963這1964個值
理解就是,2045代表的是triphone的個數,1964代表的是1964種不同的pdf。
這個時候還觀察到的一點就是:
nnet-forward跑出來的矩陣的列數也是1964。
那麼可以猜測:
這個矩陣的列對應的就是不同的pdf。
那麼就有了下一個問題,怎麼把pdf對應到state?
在翻閱資料下,我找到了一個工具:show-transitions。
這個工具的使用方法是(已省略文件具體路徑):
- show-transitions phones.txt final.mdl
輸出內容如下(取前幾行):
- Transition-state 1: phone = sil hmm-state = 0 pdf = 0
- Transition-id = 1 p = 0.728349 [self-loop]
- Transition-id = 2 p = 0.27165 [0 -> 1]
- Transition-state 2: phone = sil hmm-state = 1 pdf = 56
- Transition-id = 3 p = 0.809842 [self-loop]
- Transition-id = 4 p = 0.190158 [1 -> 2]
- Transition-state 3: phone = sil hmm-state = 2 pdf = 48
- Transition-id = 5 p = 0.475911 [self-loop]
- Transition-id = 6 p = 0.524089 [2 -> 3]
但很明顯,並不是一一對應的關係,一個pdf可能對應多個phone。
一開始我也覺得這樣似乎沒法找到那個矩陣列項對應的phone。但後來在Kaldi官網上看到了一句話:
- If two states have the same pdf_class variable, then they will always share the same probability distribution function (p.d.f.)
也就是說,如果兩個狀態有着同樣的pdf,那麼它們就會共享同樣的概率分佈函數。
這說明了什麼呢?
後來我突然想到,既然有着同樣的概率分佈函數,那麼說明共享這個pdf的那些狀態都是對應同一列後驗概率呀。
所以現在實際上已經知道了每一幀與所有狀態對應的後驗概率。
基本上知道這個已經可以解決我目前的需要了。如有理解不對還望指出。
但是關於知道了每個狀態的後驗概率之後怎麼轉換成phone序列?
這個似乎是decoding的事情,如果是decoding的話那麼nnet-forward的用法是有所不同的。
有個參數--no-softmax=true,去掉後面的softmax,還有一個----class-frame-counts=xx用來加入一個先驗概率。
後面好像是用HCLG這個東西,但是其中怎麼運作的還不是很懂。有時間再看看