1. 程式人生 > >一些kaldi常用的術語和命令(二)

一些kaldi常用的術語和命令(二)

指令碼執行前當前目錄結構(data是新生成的目錄)

• local : 包含當前資料的目錄

• train : 資料庫中分離出來的訓練資料.

• test_* : 資料庫中分離出來的測試資料.

有些檔案不是通過Kaldi得到的,而是通過OpenFst自己準備得到,比如

•lexicon.txt : 詞典檔案

•silence.txt : 包含哪個音素是靜音的,哪個音素不是靜音的資訊

到/train目錄,檢視生成檔案資訊(如果要用自己的資料集,以下檔案必須自己手動處理生成)

head text
head spk2gender.map #這個檔案是說話人性別對映檔案,很多情況用不上
head spk2utt
head utt2spk
head wav.scp
 text – 此檔案包含了語音和Kaldi要用的語音id的對映關係。這個檔案會被轉成整型格式-文字檔案,但是檔名這些會被整型的id代替。
•   spk2gender.map – 檔案包含說話人和他們的性別資訊對映。這在訓練的時候也表現了說話人的唯一性。
•   spk2utt – 這個是說話人標識和說話人對應所有語音標識的對映。
•   utt2spk – 這個是語音id和語音所屬說話人的一對一的對映關係。
•   wav.scp – 特徵提取的時候Kaldi會讀取這個檔案。它被解析成鍵值對,key是每行的第一個字串(在例子裡是語音的id,Integer型),值就是擴充套件的檔名。擴充套件檔名分為rxfilename(用於讀)和wxfilename(用於寫)。這兩種檔名有各自的規則。
比如rxfilename:
"-"或者""意味著標準輸入;
"some command |"意味著輸入管道命令;
"/some/filename:12345"意味著檔案的偏移量;
"/some/filename"…類似這樣,任何不匹配前3條命令的都被當做普通檔案來處理。
wxfilename也和rxfilename類似,除了沒有檔案偏移量。
具體可看http://www.kaldi-asr.org/doc/io.html#io_sec_xfilename。
這就會建立lang資料夾,這裡麵包含了FST的描述所涉及的語言。prepare_lang.sh這個指令碼把/data裡面建立的一些檔案轉換成可以被Kaldi閱讀的更規範的形式。這個指令碼建立的輸出檔案在data/lang中。

接下來說的就是這裡面的一些檔案。

首先建立的兩個檔案就是words.txt和phones.txt,這是OpenFst格式符號表,是字串到integer型別的對映關係。理解這種格式的含義: 
http://www.kaldi-asr.org/doc/tutorial_looking.html 
而理解kaldi更入門的需要理解openFst,連結: 
http://www.openfst.org/twiki/bin/view/FST/WebHome 
有限狀態機分為:接收器/識別器(輸出一個二元狀態,是或者不是);變換器(使用動作基於給定的輸入和/或狀態生成輸出)分為Moore和Mealy FSM。兩種變換器定義:Moore狀態機的輸出只與當前的狀態有關,即:輸出=f(當前狀態);Mealy狀態機的輸出與當前狀態和輸入有關,即:輸出=f(當前狀態,輸入)。不管是Moore機還是Mealy機,兩者的下一狀態都與當前狀態和輸入有關,即:下一狀態=f(當前狀態,輸入),這是兩種狀態機模型的共性。

.scp和.ark檔案都可以看成是資料表。這種格式有如下特點:

.scp格式是純文字格式,一行有key的id和“可擴充套件檔名”讓Kaldi去找資料

• .ark格式可能是文字/二進位制,”t”引數表示文字,預設是二進位制。格式:key的id,空格,目標資料。

.scp和.ark檔案幾個通用的點:

 指定讀表的字串叫rspecifier;比如 "ark:gunzip -c my/dir/foo.ark.gz|".
•   指定寫表的字串叫 wspecifier;比如 "ark,t:foo.ark".
•   .ark檔案可以共同連線起來,仍然是有效的ark檔案(沒有中心索引)
•   程式碼可以順序或隨機訪問.scp和.ark檔案。使用者級程式碼只需要知道它是迭代還是查詢,不需要知道訪問的是哪種型別檔案。
•   Kaldi不會在.ark檔案中表示物件型別;需要提前知道物件型別。
•   .ark和.scp檔案不包含混合型別
•   通過隨機訪問來讀取.ark檔案可能是無效的,因為程式碼可能必須將物件快取在記憶體中。
•   為了有效地隨機訪問.ark檔案,您可以使用“ark,scp”寫入機制(例如用於將mfcc功能寫入磁碟)來寫出相應的指令碼檔案。 然後,通過scp檔案訪問它。
•   在檔案上進行隨機訪問時,避免程式碼必須快取一堆內容的另一種方法是告知程式碼歸檔歸檔並按排序順序呼叫(例如“ark,s,cs: - ”))


.scp和.ark怎麼在管道內使用的命令:

head -1 $featdir/raw_mfcc_train.1.scp | copy-feats scp:- ark:- | copy-feats ark:- ark,t:- | head

注意輸出要用head,否則會出現一大堆內容(.ark可能是二進位制檔案)

最後,為了方便起見,將所有測試資料合併到一個目錄中。對這個一般的步驟進行所有的測試。 以下命令還將合併說話人,注意重複和重新生成這些說話人的統計資訊,以便我們的工具不會出錯。 通過執行以下命令(從s5目錄)執行此操作。

檢視最近的輸出命令:

tail nohup.out
1
可以用–nj這種方式跑更長時間的任務,這樣在斷開連線時候也能跑完資料。用”screen”方式會更好,它不會被kill掉。實際上這個指令碼(train_mono.sh)的標準輸出(命令列輸出)和錯誤(ERROR)很少輸出,大部分的輸出都是輸出到exp/mono/下的log檔案。

執行的時候看檔案data/lang/topo。檔案是實時生成的。每一個音素都有從其它音素來的不同拓撲結構。看data/phones.txt從數字id可以看出它到底是哪個音素。拓撲檔案中的約定是第一個狀態是初始狀態(概率為1),最後一個狀態是最終狀態(概率為1)。

檢視模型檔案命令:

gmm-copy --binary=false exp/mono/0.mdl - | less

可以看到拓撲檔案頭部資訊,在模型引數之前,還有一些其它東西。.mdl檔案包含兩個物件:轉移概率模型包括HMM拓撲資訊,還有一種相關模型類的物件(AmGmm)。 通過“包含兩個物件”,意思是物件具有標準形式的寫入和讀取功能,呼叫這些函式將物件寫入檔案。 對於這樣的物件,這不是表的一部分(即沒有涉及到“ark:”或“scp:”),寫入二進位制或文字模式,可以由標準的命令列選項設定 -binary = true或-binary = false(不同的程式具有不同的預設值)。 對於表(.ark和.scp),是二進位制還是文字模型由說明符中的”,t”選項控制。

上面命令是看模型包含哪種資訊。要更多細節和模型的表示意義,則看HMM topology and transition modeling

有一個很重要的點,Kaldi中的pdf是用數字id表示的,從0開始。pdf在HTK中是沒有名字的。而且.mdl模型檔案是沒有足夠的資訊來對上下文相關音素和pdf-id進行對映的。要看這些資訊,需要檢視樹檔案,執行命令:

copy-tree --binary=false exp/mono/tree - | less
1
格式示例:

ContextDependency 3 1 ToPdf TE 1 49 ( NULL SE -1 [ 0 1 ]
{ SE -1 [ 0 ]
{ CE 0 CE 54 } 
CE 48 } 
SE -1 [ 0 1 ]
{ SE -1 [ 0 ]
{ SE 0 [ 1 ]
{ SE 2 [ 4 19 36 ]
{ CE 1 CE 1612 } 
SE 2 [ 4 19 36 ]
{ SE 0 [ 16 29 45 ]
{ CE 110 SE 0 [ 21 ]
{ CE 748 SE 0 [ 9 12 13 22 ]
{ SE 0 [ 9 ]
{ CE 623 CE 1599 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
這是單音素的“樹”,單音素的“樹”很小——它沒有任何分裂。儘管這種樹格式並不是很人性化,還是解釋下:ToPdf後面,包含了多型別的EventMap物件,有個key,value的鍵值對,代表 上下文和HMM狀態 ,對映到一個整型的pdf ID。來自EventMap的是型別ConstantEventMap(表示樹的葉子),TableEventMap(表示某種查詢表)和SplitEventMap(表示樹分割)。在檔案exp / mono / tree中,“CE”是ConstantEventMap的標記(對應於樹的葉子),“TE”是TableEventMap的標記(沒有“SE”或SplitEventMap,因為這個是單聲道的情況)。 “TE 0 49”是TableEventMap的開始,它在key 0 上“分割”(表示在單聲道情況下長度為1的音素上下文向量中的第0個音素位置)。在括號中,接下里是EventMap型別的49個物件。第一個為NULL,表示指向EventMap的零指標,因為將phone-id中的0留給“epsilon”。例子中非NULL物件是字串“TE -1 3(CE 33 CE 34 CE 35)”,它表示在鍵-1上分割的TableEventMap。該鍵表示拓撲檔案中指定的PdfClass,在本例中與HMM狀態索引相同。該音素具有3個HMM狀態,因此分配給該鍵的值可以取值0,1或2.括號內有三個型別為ConstantEventMap的物件,每個物件都表示樹的葉子。

來看看exp/mono/ali.1.gz檔案(對齊檔案)

copy-int-vector "ark:gunzip -c exp/mono/ali.1.gz|" ark,t:- | head -n 2
1
timit資料集的ali.1.gz檔案格式示例如下:

faem0_si1392 2 4 3 3 3 3 3 3 6 5 5 5 5 38 37 37 37 40 42 218 217 217 217 217 217 217 217 217 217 217 217 220 219 222 221 221 248 247 247 247 247 247 247 250 252 176 
……
1
2
這是訓練資料的viterbi對齊檔案;每個訓練檔案都有對應的一行。再對比看上面說的tree檔案,找到數字最大的pdf-id(tree檔案最後一個數字,比如timit中最大的數字是(48音素*3-1 = 143)),會發現對齊檔案中的數字比最大的pdf-id還要大得多。為什麼?因為對齊檔案中的數字不包含pdf-id,而是包含一個稍微更細粒度的識別符號,我們稱之為“transition-id”。這也對音素的原型拓撲中的音素和狀態轉移對應地進行編碼。

可以通過”show-transitions”命令來看轉移-id的資訊。 
如果有佔用計算檔案?.occs檔案,可以把這個檔案當成第二個引數,這樣會有更多資訊

show-transitions data/lang/phones.txt exp/mono/0.mdl
1
得到結果如下:

Transition-state 1: phone = sil hmm-state = 0 pdf = 0
 Transition-id = 1 p = 0.84957 [self-loop]
 Transition-id = 2 p = 0.15043 [0 -> 1]
Transition-state 2: phone = sil hmm-state = 1 pdf = 1
 Transition-id = 3 p = 0.87305 [self-loop]
 Transition-id = 4 p = 0.12695 [1 -> 2]
Transition-state 3: phone = sil hmm-state = 2 pdf = 2
 Transition-id = 5 p = 0.690806 [self-loop]
 Transition-id = 6 p = 0.309194 [2 -> 3]
1
2
3
4
5
6
7
8
9
可以看到轉移-id和音素及其狀態的對應關係。

檢視更人性化的對齊檔案形式

show-alignments data/lang/phones.txt exp/mono/0.mdl "ark:gunzip -c exp/mono/ali.1.gz |" | less
1
會把同一個音素的狀態用[ ]圈起來

更多資訊像 HMM拓撲,轉移-id,轉移模型等東西,可以看 HMM topology and transition modeling.

檢視訓練的處理過程,輸入命令:

grep Overall exp/mono/log/acc.{?,??}.{?,??}.log
1
可以看到每次迭代的聲學似然。 
還可以檢視update.*.log檔案看更新log的資訊,命令如下:

grep Overall exp/mono/log/update.*.log
1
效果如下:

log/update.0.log:LOG (gmm-est[5.2]:main():gmm-est.cc:102) Transition model update: Overall 0.0380546 log-like improvement per frame over 1.12482e+06 frames.
log/update.0.log:LOG (gmm-est[5.2]:main():gmm-est.cc:113) GMM update: Overall 0.7529 objective function improvement per frame over 1.12482e+06 frames
log/update.0.log:LOG (gmm-est[5.2]:main():gmm-est.cc:116) GMM update: Overall avg like per frame = -111.162 over 1.12482e+06 frames.
1
2
3
當單音素訓練完成後,可以測試單音素的解碼過程。 
在解碼前,需要建立詞圖。輸入命令:

utils/mkgraph.sh --mono data/lang exp/mono exp/mono/graph
1
檢視utils / mkgraph.sh呼叫的程式。 這些程式的名字很多都以“fst”(例如fsttablecompose)開頭,其中大多數程式實際上並不是來自OpenFst發行版。 Kaldi建立了一些自己的FST操作程式。 可以通過後面的命令找到這些程式的位置。 使用在utils / mkgraph.sh中呼叫的任意程式(例如fstdeterminizestar)。 然後輸入:

which fstdeterminizestar
1
可以找到程式位置。

有不同版本的程式的原因主要是因為在語音識別中使用FST有一點差別(較少的AT&T-ish)。 例如,“fstdeterminizestar”對應於刪除ε弧的“classical”。 有關更多資訊,檢視Decoding graph construction in Kaldi。

在圖建立過程之後,我們可以通過以下方式開始單音子解碼:

steps/decode.sh --config conf/decode.config --nj 20 --cmd "$decode_cmd" \
  exp/mono/graph data/test exp/mono/decode
1
2
可以看看一些解碼的輸出檔案

less exp/mono/decode/log/decode.2.log 
1
可以看到螢幕上輸出了轉錄的檔案(生成的標註)。轉錄檔案的文字形式只在日誌資訊中出現:程式實際上的輸出在exp/mono/decode/scoring/2.tra中。這些tra檔案代表了使用解碼過程的語言模型(LM)。LM的範圍預設使用2-13。 
檢視實際的解碼序列,輸入命令:

utils/int2sym.pl -f 2- data/lang/words.txt exp/mono/decode/scoring/2.tra
1
還有個指令碼叫sym2int,可以轉回來:

utils/int2sym.pl -f 2- data/lang/words.txt exp/mono/decode/scoring/2.tra | \
utils/sym2int.pl -f 2- data/lang/words.txt 
1
2
The -f 2- 選項的意思是避免把utt-id轉換成int型別。輸入命令:

tail exp/mono/decode/log/decode.2.log 
1
會列印末尾一些有用的總結資訊,包括實時因子和每幀的平均對數似然。實時因子一般是0.2到0.3之間(比實時更快)。取決於CPU和用了多少執行緒執行任務和一些其它因素。指令碼並行執行20個作業,如果機器少於20個核心就會慢得多。注意解碼過程中用了很寬容的剪枝(值為20),以獲取更精確的結果。在典型的大詞彙量的語音識別集中,beam會小得多(大概13)。 
再次檢視日誌檔案的頂部,並專注於命令列。 可選引數位於目標引數之前(這是必需的)。輸入

gmm-decode-faster
1
檢視使用資訊,並將引數和log檔案看到的引數匹配。回想 “rspecifier” 是專門用來讀表的字串之一, “wspecifier”是專門用來寫入表的一個。 
單音子系統介紹結束,後續可看三音子系統。 
Up: Kaldi tutorial 
Previous: Overview of the distribution 
Next: Reading and modifying the code

是翻譯kaldi主頁裡的Karel的深度學習模型的實現。


KALDI拓展深度學習:1.https://blog.csdn.net/wbgxx333/article/details/19765727

2.https://blog.csdn.net/wbgxx333/article/details/45641341

如果想了解kaldi的全部深度神經網路程式碼,請Deep Neural Networks in Kaldi, 和Dan的版本, 請看Dan’s DNN implementation

這個文件的目標就是更加詳細的介紹DNN部分,和簡單介紹神經網路訓練工具。我們將從Top-level script開始, 解釋the Training script internals到底做了什麼, 展示一些Advanced features, 和對The C++ code做了一些簡單的介紹,和解釋如何來擴充套件這些。

Top-level script

讓我們來看一下指令碼egs/wsj/s5/local/nnet/run_dnn.sh。這個指令碼是使用單CUDA GPU,和使用CUDA編譯過的kaldi(可以在 src/kaldi.mk中使用’CUDA = true’來檢查)。我們也假設’cuda_cmd’在egs/wsj/s5/cmd.sh裡設定是正確的,或者是使用’queue.pl’的GPU叢集節點,或者是使用’run.pl’的本地機器。最後假設我們由egs/wsj/s5/run.sh得到了一個SAT GMM系統exp/tri4b和對應的fMLLR變換。注意其他資料庫的 run_dnn.sh一般都會在s5/local/nnet/run_dnn.sh.

指令碼 egs/wsj/s5/local/nnet/run_dnn.sh分下面這些步驟:

0.儲存在本地的40維fMLLR特徵, 使用steps/nnet/make_fmllr_feats.sh,這簡化了訓練指令碼,40維的特徵是使用CMN的MFCC-LDA-MLLT-fMLLR

1. RBM 預訓練, steps/nnet/pretrain_dbn.sh,是根據Geoff Hinton’s tutorial paper來實現的。訓練方法是使用1步馬爾科夫鏈蒙特卡羅取樣的對比散度演算法(CD-1)。 第一層的RBM是Gaussian-Bernoulli, 和接下里的RBMs是Bernoulli-Bernoulli。這裡的超引數基準是在100h Switchboard subset資料集上調參得到的。如果資料集很小的話,迭代次數N就需要變為100h/set_size。訓練是無監督的,所以可以提供足夠多的輸入特徵資料目錄。

當訓練Gaussian-Bernoulli的RBM時,將有很大的風險面臨權重爆炸,尤其是在很大的學習率和成千上萬的隱層神經元上。為了避免權重爆炸,我們在實現時需要在一個minbatch上比較訓練資料的方差和重構資料的方差。如果重構的方差是訓練資料的2倍以上,權重將縮小和學習率將暫時減小。

2. 幀交叉熵訓練,steps/nnet/train.sh, 這個階段時訓練一個DNN來把幀分到對應的三音素狀態(比如: PDFs)中。這是通過mini-batch隨機梯度下降法來做的。預設的是使用Sigmoid隱層單元,Softmax輸出單元和全連線層AffineTransform。學習率是0.008,minibatch的大小是256;我們未使用衝量和正則化(注: 最佳的學習率與不同的隱含層單元型別有關,sigmoid的值0.008,tanh是0.00001)。

輸入變換和預訓練DBN(比如:深度信念網路,RBMs塊)是使用選項 
‘–input-transform’和’–dbn’傳遞給指令碼的,這裡僅僅輸出層是隨機初始化的。我們使用提早停止(early stopping)來防止過擬合。為了這個,我們需要在交叉驗證集(比如: held-out set)上計算代價函式,因此兩對特徵對齊目錄需要做有監督的訓練。

對DNN訓練有一個好的總結文章是http://research.google.com/pubs/archive/38131.pdf

3.,4.,5.,6. sMBR序列區分性訓練,steps/nnet/train_mpe.sh, 這個階段對所有的句子聯合優化來訓練神經網路,比幀層訓練更接近一般的ASR目標。

  • sMBR的目標是最大化從參考的對齊中得到的狀態標籤的期望正確率,然而一個詞圖框架是來使用表示這種競爭假設。
  • 訓練是使用每句迭代的隨機梯度下降法,我們還使用一個低的固定的學習率1e-5 (sigmoids)和跑3-5輪。
  • 當在第一輪迭後重新生成詞圖,我們觀察到快速收斂。我們支援MMI, BMMI, MPE 和sMBR訓練。所有的技術在Switchboard 100h集上是相同的,僅僅在sMBR好一點點。
  • 在sMBR優化中,我們在計算近似正確率的時候忽略了靜音幀。具體更加詳細的描述見http://www.danielpovey.com/files/2013_interspeech_dnn.pdf

其他一些有意思的top-level scripts:

除了DNN指令碼,這裡也有一些其他的指令碼: 
* DNN : egs/wsj/s5/local/nnet/run_dnn.sh , (main top-level script) 
* CNN : egs/rm/s5/local/nnet/run_cnn.sh , (CNN = Convolutional Neural Network, see paper, we have 1D convolution on frequency axis) 
* Autoencoder training : egs/timit/s5/local/nnet/run_autoencoder.sh 
* Tandem system : egs/swbd/s5c/local/nnet/run_dnn_tandem_uc.sh , (uc = Universal context network, see paper
* Multilingual/Multitask : egs/rm/s5/local/nnet/run_multisoftmax.sh, (Network with output trained on RM and WSJ, same C++ design as was used in SLT2012 paper)

Training script internals

主要的神經網路訓練指令碼steps/nnet/train.sh的呼叫如下: 
steps/nnet/train.sh <data-train> <data-dev> <lang-dir> <ali-train> <ali-dev> <exp-dir>

神經網路的輸入特徵是從資料目錄<data-train><data-dev>中獲得的,訓練的目標是從目錄<ali-train> <ali-dev>得到的。目錄<lang-dir> 
僅僅在使用LDA特徵變換時才被使用,和從對齊中生成音素幀的統計量,這個對於訓練不是很重要。輸出(比如:訓練得到的網路和log檔案)都存到<exp-dir>

在內部,指令碼需要準備特徵和目標基準,從而產生一個神經網路的原型和初始化,建立特徵變換和使用排程指令碼 steps/nnet/train_scheduler.sh,用來跑訓練迭代次數和控制學習率。

當看steps/nnet/train.sh指令碼內部時,我們將看到

  1. CUDA是需要的,如果沒有檢測到GPU或者CUDA沒有被編譯,指令碼將退出。(你可以堅持使用’–skip-cuda-check true’來使用CPU執行,但是速度將慢10-20倍)

  2. 對齊基準需要提前準備,訓練工具需要的目標是以後驗概率格式,因此ali-to-post.cc被使用: 
    labels_tr="ark:ali-to-pdf $alidir/final.mdl \"ark:gunzip -c $alidir/ali.*.gz |\" ark:- | ali-to-post ark:- ark:- |" 
    labels_cv="ark:ali-to-pdf $alidir/final.mdl \"ark:gunzip -c $alidir_cv/ali.*.gz |\" ark:- | ali-to-post ark:- ark:- |"

  3. 重組的特徵拷貝到/tmp/???/…,如果使用’–copy-feats false’,這個失效。或者目錄改為–copy-feats-tmproot <dir>

    • 特徵使用呼叫列表被重新儲存到本地,這些顯著的降低了在訓練過程中磁碟的重要性,它防止了大量磁碟訪問的操作。
  4. 特徵基準被準備:

# begins with copy-feats:
feats_tr="ark:copy-feats scp:$dir/train.scp ark:- |"
feats_cv="ark:copy-feats scp:$dir/cv.scp ark:- |"
# optionally apply-cmvn is appended: 
feats_tr="$feats_tr apply-cmvn --print-args=false --norm-vars=$norm_vars --utt2spk=ark:$data/utt2spk scp:$data/cmvn.scp ark:- ark:- |"
feats_cv="$feats_cv apply-cmvn --print-args=false --norm-vars=$norm_vars --utt2spk=ark:$data_cv/utt2spk scp:$data_cv/cmvn.scp ark:- ark:- |"
# optionally add-deltas is appended:
feats_tr="$feats_tr add-deltas --delta-order=$delta_order ark:- ark:- |"
feats_cv="$feats_cv add-deltas --delta-order=$delta_order ark:- ark:- |"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

5.特徵變換被準備:

  • 特徵變換在DNN前端處理中是一個固定的函式,是通過GPU來計算的。Usually it performs a type of dimensionality expansion. 這就要使得在磁碟上有低維的特徵和DNN前端處理的高維特徵, 即節約了磁碟空間,由節約了讀取吞吐量。
  • 大多數的nnet-binaries有選項’–feature-transform’
  • 它的產生依賴於選項’–feat-type’,它的值是(plain|traps|transf|lda)。

6.網路的原型是由utils/nnet/make_nnet_proto.py產生的:

  • 每個成分在單獨一行上,這裡的維度和初始化超引數是指定的
  • 對於AffineTransform,偏移量的初始化是 給定<BiasMean>和<BiasRange>的均勻分佈 
    ,而權重的初始化是通過通過對<ParamStddev>拉伸的正態分佈
  • 注意:如果你喜歡使用外部準備的神經網路原型來實驗,可以使用選項’–mlp-proto ’ 

    $ cat exp/dnn5b_pretrain-dbn_dnn/nnet.proto 
    <NnetProto> 
    <AffineTransform> <InputDim> 2048 <OutputDim> 3370 <BiasMean> 0.000000 <BiasRange> 0.000000 <ParamStddev> 0.067246 
    <Softmax> <InputDim> 3370 <OutputDim> 3370 
    </NnetProto>

7.神經網路是通過nnet-initialize.cc來初始化。下一步中, DBN是通過使用nnet-concat.cc得到的。

8.最終訓練是通過執行排程指令碼steps/nnet/train_scheduler.sh來完成的。

注:無論神經網路還是特徵變換都可以使用nnet-info.cc來觀看,或者用nnet-copy.cc來顯示。

當具體看steps/nnet/train_scheduler.sh,我們可以看到:

一開始需要在交叉驗證集上執行和主函式需要根據$iter來執行迭代和控制學習率。典型的情況就是,train_scheduler.sh被train.sh呼叫

  • 預設的學習率排程是根據目標函式的相對性的提高來決定的: 
    • 如果提高大於’start_halving_impr=0.01’,初始化學習率保持常數。
    • 然後學習率在每次迭代中乘以’halving_factor=0.5’來縮小
    • 最後,如果提高小於’end_halving_impr=0.001’,訓練被終止。

神經網路被儲存在dir/nnet,log檔案被儲存在dir/nnet,log檔案被儲存在dir/log: 
1. 神經網路的名字包含迭代的次數,學習率和在訓練和交叉驗證集上的目標函式值 
* 我們可以看到從第五次迭代開始,學習率減半,這是一個普通的情況。

$ ls exp/dnn5b_pretrain-dbn_dnn/nnet
nnet_6.dbn_dnn_iter01_learnrate0.008_tr1.1919_cv1.5895
nnet_6.dbn_dnn_iter02_learnrate0.008_tr0.9566_cv1.5289
nnet_6.dbn_dnn_iter03_learnrate0.008_tr0.8819_cv1.4983
nnet_6.dbn_dnn_iter04_learnrate0.008_tr0.8347_cv1.5097_rejected
nnet_6.dbn_dnn_iter05_learnrate0.004_tr0.8255_cv1.3760
nnet_6.dbn_dnn_iter06_learnrate0.002_tr0.7920_cv1.2981
nnet_6.dbn_dnn_iter07_learnrate0.001_tr0.7803_cv1.2412
...
nnet_6.dbn_dnn_iter19_learnrate2.44141e-07_tr0.7770_cv1.1448
nnet_6.dbn_dnn_iter20_learnrate1.2207e-07_tr0.7769_cv1.1446
nnet_6.dbn_dnn_iter20_learnrate1.2207e-07_tr0.7769_cv1.1446_final_```


2.訓練集和交叉驗證集分別儲存了對應的log檔案。
每一個log檔案命令列:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

$ cat exp/dnn5b_pretrain-dbn_dnn/log/iter01.tr.log 
nnet-train-frmshuff –learn-rate=0.008 –momentum=0 –l1-penalty=0 –l2-penalty=0 –minibatch-size=256 –randomizer-size=32768 –randomize=true –verbose=1 –binary=true –feature-transform=exp/dnn5b_pretrain-dbn_dnn/final.feature_transform –randomizer-seed=777 ‘ark:copy-feats scp:exp/dnn5b_pretrain-dbn_dnn/train.scp ark:- |’ ‘ark:ali-to-pdf exp/tri4b_ali_si284/final.mdl “ark:gunzip -c exp/tri4b_ali_si284/ali.*.gz |” ark:- | ali-to-post ark:- ark:- |’ exp/dnn5b_pretrain-dbn_dnn/nnet_6.dbn_dnn.init exp/dnn5b_pretrain-dbn_dnn/nnet/nnet_6.dbn_dnn_iter01“`

gpu被使用的資訊:

LOG (nnet-train-frmshuff:IsComputeExclusive():cu-device.cc:214) CUDA setup operating under Compute Exclusive Process Mode.
LOG (nnet-train-frmshuff:FinalizeActiveGpu():cu-device.cc:174) The active GPU is [1]: GeForce GTX 780 Ti    free:2974M, used:97M, total:3071M, free/total:0.968278 version 3.5```

從神經網路訓練得到的內部統計量是通過函式
[Nnet::InfoPropagate][(http://kaldi.sourceforge.net/classkaldi_1_1nnet1_1_1Nnet.html#aec9726c8d4a85c21f77b5fc9ee701efb)],[Nnet::InfoBackPropagate](http://kaldi.sourceforge.net/classkaldi_1_1nnet1_1_1Nnet.html#a86e9d5a82ce336c589751b6c4dea1b57)和 [Nnet::InfoGradient](http://kaldi.sourceforge.net/classkaldi_1_1nnet1_1_1Nnet.html#ac281a443ce10ccd7c7ef7c6375025768)來準備的。它們將在迭代的一開始列印和迭代的最後第二次列印。注意當我們實現新的特徵除錯網路訓練時,每一個成分的統計量就尤其便利,所以我們可以比較參考的值和期望的值: 

VLOG[1] (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:236) ### After 0 frames,
VLOG[1] (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:237) ### Forward propagation buffer content :
[1] output of <Input> ( min -6.1832, max 7.46296, mean 0.00260791, variance 0.964268, skewness -0.0622335, kurtosis 2.18525 ) 
[2] output of <AffineTransform> ( min -18.087, max 11.6435, mean -3.37778, variance 3.2801, skewness -3.40761, kurtosis 11.813 ) 
[3] output of <Sigmoid> ( min 1.39614e-08, max 0.999991, mean 0.085897, variance 0.0249875, skewness 4.65894, kurtosis 20.5913 ) 
[4] output of <AffineTransform> ( min -17.3738, max 14.4763, mean -2.69318, variance 2.08086, skewness -3.53642, kurtosis 13.9192 ) 
[5] output of <Sigmoid> ( min 2.84888e-08, max 0.999999, mean 0.108987, variance 0.0215204, skewness 4.78276, kurtosis 21.6807 ) 
[6] output of <AffineTransform> ( min -16.3061, max 10.9503, mean -3.65226, variance 2.49196, skewness -3.26134, kurtosis 12.1138 ) 
[7] output of <Sigmoid> ( min 8.28647e-08, max 0.999982, mean 0.0657602, variance 0.0212138, skewness 5.18622, kurtosis 26.2368 ) 
[8] output of <AffineTransform> ( min -19.9429, max 12.5567, mean -3.64982, variance 2.49913, skewness -3.2291, kurtosis 12.3174 ) 
[9] output of <Sigmoid> ( min 2.1823e-09, max 0.999996, mean 0.0671024, variance 0.0216422, skewness 5.07312, kurtosis 24.9565 ) 
[10] output of <AffineTransform> ( min -16.79, max 11.2748, mean -4.03986, variance 2.15785, skewness -3.13305, kurtosis 13.9256 ) 
[11] output of <Sigmoid> ( min 5.10745e-08, max 0.999987, mean 0.0492051, variance 0.0194567, skewness 5.73048, kurtosis 32.0733 ) 
[12] output of <AffineTransform> ( min -24.0731, max 13.8856, mean -4.00245, variance 2.16964, skewness -3.14425, kurtosis 16.7714 ) 
[13] output of <Sigmoid> ( min 3.50889e-11, max 0.999999, mean 0.0501351, variance 0.0200421, skewness 5.67209, kurtosis 31.1902 ) 
[14] output of <AffineTransform> ( min -2.53919, max 2.62531, mean -0.00363421, variance 0.209117, skewness -0.0302545, kurtosis 0.63143 ) 
[15] output of <Softmax> ( min 2.01032e-05, max 0.00347782, mean 0.000296736, variance 2.08593e-08, skewness 6.14324, kurtosis 35.6034 ) 

VLOG[1] (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:239) ### Backward propagation buffer content :
[1] diff-output of <AffineTransform> ( min -0.0256142, max 0.0447016, mean 1.60589e-05, variance 7.34959e-07, skewness 1.50607, kurtosis 97.2922 ) 
[2] diff-output of <Sigmoid> ( min -0.10395, max 0.20643, mean -2.03144e-05, variance 5.40825e-05, skewness 0.226897, kurtosis 10.865 ) 
[3] diff-output of <AffineTransform> ( min -0.0246385, max 0.033782, mean 1.49055e-05, variance 7.2849e-07, skewness 0.71967, kurtosis 47.0307 ) 
[4] diff-output of <Sigmoid> ( min -0.137561, max 0.177565, mean -4.91158e-05, variance 4.85621e-05, skewness 0.020871, kurtosis 7.7897 ) 
[5] diff-output of <AffineTransform> ( min -0.0311345, max 0.0366407, mean 1.38255e-05, variance 7.76937e-07, skewness 0.886642, kurtosis 70.409 ) 
[6] diff-output of <Sigmoid> ( min -0.154734, max 0.166145, mean -3.83602e-05, variance 5.84839e-05, skewness 0.127536, kurtosis 8.54924 ) 
[7] diff-output of <AffineTransform> ( min -0.0236995, max 0.0353677, mean 1.29041e-05, variance 9.17979e-07, skewness 0.710979, kurtosis 48.1876 ) 
[8] diff-output of <Sigmoid> ( min -0.103117, max 0.146624, mean -3.74798e-05, variance 6.17777e-05, skewness 0.0458594, kurtosis 8.37983 ) 
[9] diff-output of <AffineTransform> ( min -0.0249271, max 0.0315759, mean 1.0794e-05, variance 1.2015e-06, skewness 0.703888, kurtosis 53.6606 ) 
[10] diff-output of <Sigmoid> ( min -0.147389, max 0.131032, mean -0.00014309, variance 0.000149306, skewness 0.0190403, kurtosis 5.48604 ) 
[11] diff-output of <AffineTransform> ( min -0.057817, max 0.0662253, mean 2.12237e-05, variance 1.21929e-05, skewness 0.332498, kurtosis 35.9619 ) 
[12] diff-output of <Sigmoid> ( min -0.311655, max 0.331862, mean 0.00031612, variance 0.00449583, skewness 0.00369107, kurtosis -0.0220473 ) 
[13] diff-output of <AffineTransform> ( min -0.999905, max 0.00347782, mean -1.33212e-12, variance 0.00029666, skewness -58.0197, kurtosis 3364.53 ) 

VLOG[1] (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:240) ### Gradient stats :
Component 1 : <AffineTransform>, 
  linearity_grad ( min -0.204042, max 0.190719, mean 0.000166458, variance 0.000231224, skewness 0.00769091, kurtosis 5.07687 ) 
  bias_grad ( min -0.101453, max 0.0885828, mean 0.00411107, variance 0.000271452, skewness 0.728702, kurtosis 3.7276 ) 
Component 2 : <Sigmoid>, 
Component 3 : <AffineTransform>, 
  linearity_grad ( min -0.108358, max 0.0843307, mean 0.000361943, variance 8.64557e-06, skewness 1.0407, kurtosis 21.355 ) 
  bias_grad ( min -0.0658942, max 0.0973828, mean 0.0038158, variance 0.000288088, skewness 0.68505, kurtosis 1.74937 ) 
Component 4 : <Sigmoid>, 
Component 5 : <AffineTransform>, 
  linearity_grad ( min -0.186918, max 0.141044, mean 0.000419367, variance 9.76016e-06, skewness 0.718714, kurtosis 40.6093 ) 
  bias_grad ( min -0.167046, max 0.136064, mean 0.00353932, variance 0.000322016, skewness 0.464214, kurtosis 8.90469 ) 
Component 6 : <Sigmoid>, 
Component 7 : <AffineTransform>, 
  linearity_grad ( min -0.134063, max 0.149993, mean 0.000249893, variance 9.18434e-06, skewness 1.61637, kurtosis 60.0989 ) 
  bias_grad ( min -0.165298, max 0.131958, mean 0.00330344, variance 0.000438555, skewness 0.739655, kurtosis 6.9461 ) 
Component 8 : <Sigmoid>, 
Component 9 : <AffineTransform>, 
  linearity_grad ( min -0.264095, max 0.27436, mean 0.000214027, variance 1.25338e-05, skewness 0.961544, kurtosis 184.881 ) 
  bias_grad ( min -0.28208, max 0.273459, mean 0.00276327, variance 0.00060129, skewness 0.149445, kurtosis 21.2175 ) 
Component 10 : <Sigmoid>, 
Component 11 : <AffineTransform>, 
  linearity_grad ( min -0.877651, max 0.811671, mean 0.000313385, variance 0.000122102, skewness -1.06983, kurtosis 395.3 ) 
  bias_grad ( min -1.01687, max 0.640236, mean 0.00543326, variance 0.00977744, skewness -0.473956, kurtosis 14.3907 ) 
Component 12 : <Sigmoid>, 
Component 13 : <AffineTransform>, 
  linearity_grad ( min -22.7678, max 0.0922921, mean -5.66685e-11, variance 0.00451415, skewness -151.169, kurtosis 41592.4 ) 
  bias_grad ( min -22.8996, max 0.170164, mean -8.6555e-10, variance 0.421778, skewness -27.1075, kurtosis 884.01 ) 
Component 14 : <Softmax>,```
全部集的目標函式值的總結log檔案,它的progress vector是由第一步產生的,和幀正確率:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

LOG (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:273) Done 34432 files, 21 with no tgt_mats, 0 with other errors. [TRAINING, RANDOMIZED, 50.8057 min, fps8961.77] 
LOG (nnet-train-frmshuff:main():nnet-train-frmshuff.cc:282) AvgLoss: 1.19191 (Xent), [AvgXent: 1.19191, AvgTargetEnt: 0] 
progress: [3.09478 1.92798 1.702 1.58763 1.49913 1.45936 1.40532 1.39672 1.355 1.34153 1.32753 1.30449 1.2725 1.2789 1.26154 1.25145 1.21521 1.24302 1.21865 1.2491 1.21729 1.19987 1.18887 1.16436 1.14782 1.16153 1.1881 1.1606 1.16369 1.16015 1.14077 1.11835 1.15213 1.11746 1.10557 1.1493 1.09608 1.10037 1.0974 1.09289 1.11857 1.09143 1.0766 1.08736 1.10586 1.08362 1.0885 1.07366 1.08279 1.03923 1.06073 1.10483 1.0773 1.0621 1.06251 1.07252 1.06945 1.06684 1.08892 1.07159 1.06216 1.05492 1.06508 1.08979 1.05842 1.04331 1.05885 1.05186 1.04255 1.06586 1.02833 1.06131 1.01124 1.03413 0.997029 ] 
FRAME_ACCURACY >> 65.6546% <<“`

log檔案的結尾是CUDA的資訊,CuMatrix::AddMatMat是矩陣乘法和大多數的花費時間如下:

[cudevice profile]
Destroy 23.0389s
AddVec  24.0874s
CuMatrixBase::CopyFromMat(from other CuMatrixBase)  29.5765s
AddVecToRows    29.7164s
CuVector::SetZero   37.7405s
DiffSigmoid 37.7669s
CuMatrix::Resize    41.8662s
FindRowMaxId    42.1923s
Sigmoid 48.6683s
CuVector::Resize    56.4445s
AddRowSumMat    75.0928s
CuMatrix::SetZero   86.5347s
CuMatrixBase::CopyFromMat(from CPU) 166.27s
AddMat  174.307s
AddMatMat   1922.11s```

直接執行steps/nnet/train_scheduler.sh:

   * 指令碼train_scheduler.sh可以被train.sh呼叫,它允許覆蓋預設的NN-input和NN-target streams,可以很便利的設定。
   * 然而這個指令碼假設所有的設定是正確的,僅僅對高階使用者來說是合適的。
   * 在直接呼叫前,我們非常建議去看指令碼train_scheduler.sh是如何呼叫的。 

## Training tools

與[nnet1](http://kaldi.sourceforge.net/namespacekaldi_1_1nnet1.html)相關的程式碼在目錄src/nnetbin下,重要的工具如下: 

* [nnet-train-frmshuff.cc ](http://kaldi.sourceforge.net/nnet-train-frmshuff_8cc.html):最普遍使用的神經網路訓練工具,執行一次迭代訓練。
  *  過程如下:
    1. on-the-fly feature expansion by –feature-transform,
    2. per-frame shuffling of NN input-target pairs,
    3. mini-batch隨機梯度下降法(SGD)訓練,
 * 支援每一幀的目標函式(選項–objective-function):
   1. [Xent](http://kaldi.sourceforge.net/classkaldi_1_1nnet1_1_1Xent.html) :每一幀的交叉熵![](form_160.png) 
   2. [Mse](http://kaldi.sourceforge.net/classkaldi_1_1nnet1_1_1Mse.html): 每一幀的最小均方誤差![](form_161.png)
這裡的![](http://kaldi.sourceforge.net/form_162.png)表示目標向量![](http://kaldi.sourceforge.net/form_163.png)的元素,![](http://kaldi.sourceforge.net/form_164.png)是DNN輸出向量![](http://kaldi.sourceforge.net/form_165.png)的元素,和D是DNN輸出的維度。
* [nnet-forward.cc ](http://kaldi.sourceforge.net/nnet-forward_8cc.html): 通過神經網路計算前向資料,預設使用CPU
 * 看選項:
   * –apply-log :產生神經網路的對數輸出(比如:得到對數後驗概率)
   *   –no-softmax :從模型中去掉soft-max層(decoding with pre-softmax values leads to the same lattices as with log-posteriors)
   *  –class-frame-counts : counts to calculate log-priors, which get subtracted from the acoustic scores (a typical trick in hybrid decoding).

* [rbm-train-cd1-frmshuff.cc](http://kaldi.sourceforge.net/rbm-train-cd1-frmshuff_8cc.html) :使用CD1來訓練RBM,當內部調整學習率/衝量時需要訓練資料好幾次。 
* [nnet-train-mmi-sequential.cc](http://kaldi.sourceforge.net/nnet-train-mmi-sequential_8cc.html) : MMI / bMMI DNN training
* [nnet-train-mpe-sequential.cc](http://kaldi.sourceforge.net/nnet-train-mpe-sequential_8cc.html) : MPE / sMBR DNN training

## Other tools

* [nnet-info.cc ](http://kaldi.sourceforge.net/nnet-info_8cc.html)列印關於神經網路的資訊
* [nnet-copy.cc ](http://kaldi.sourceforge.net/nnet-copy_8cc.html)使用選項–binary=false把神經網路轉換為ASCII格式,可以用來移除某些成分

## Showing the network topology with nnet-info

接下來從nnet-info.cc裡的列印資訊顯示"feature_transform"與steps/nnet/train.sh裡的'–feat-type plain'相對應,它包含三個成分:
* <Splice> which splices features to contain left/right context by using frames with offsets relative to the central frame [ -5 -4 -3 -2 -1 0 1 2 3 4 5 ]
* <Addshift> 把特徵變為零均值
* <Rescale> 把特徵變成單位方差
* 注意:我們從磁碟中讀取低維特徵,通過選項"feature_transform"擴充套件到高維特徵,這樣會節省磁碟空間和可讀的吞吐量。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

$ nnet-info exp/dnn5b_pretrain-dbn_dnn/final.feature_transform 
num-components 3 
input-dim 40 
output-dim 440 
number-of-parameters 0.00088 millions 
component 1 : , input-dim 40, output-dim 440, 
frame_offsets [ -5 -4 -3 -2 -1 0 1 2 3 4 5 ] 
component 2 : , input-dim 440, output-dim 440, 
shift_data ( min -0.265986, max 0.387861, mean -0.00988686, variance 0.00884029, skewness 1.36947, kurtosis 7.2531 ) 
component 3 : , input-dim 440, output-dim 440, 
scale_data ( min 0.340899, max 1.04779, mean 0.838518, variance 0.0265105, skewness -1.07004, kurtosis 0.697634 ) 
LOG (nnet-info:main():nnet-info.cc:57) Printed info about exp/dnn5b_pretrain-dbn_dnn/final.feature_transform“`

接下來會列印6層的神經網路資訊:

  • 每一層是由2個成分構成,一般和一個非線性 or
  • 對於每一個,對於權重和偏移量來說,一些統計量將分開顯示(min, max, mean, variance, …)
$ nnet-info exp/dnn5b_pretrain-dbn_dnn/final.nnet
num-components 14
input-dim 440
output-dim 3370
number-of-parameters 28.7901 millions
component 1 : <AffineTransform>, input-dim 440, output-dim 2048,
  linearity ( min -8.31865, max 12.6115, mean 6.19398e-05, variance 0.0480065, skewness 0.234115, kurtosis 56.5045 )
  bias ( min -11.9908, max 3.94632, mean -5.23527, variance 1.52956, skewness 1.21429, kurtosis 7.1279 )
component 2 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 3 : <AffineTransform>, input-dim 2048, output-dim 2048,
  linearity ( min -2.85905, max 2.62576, mean -0.00995374, variance 0.0196688, skewness 0.145988, kurtosis 5.13826 )
  bias ( min -18.4214, max 2.76041, mean -2.63403, variance 1.08654, skewness -1.94598, kurtosis 29.1847 )
component 4 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 5 : <AffineTransform>, input-dim 2048, output-dim 2048,
  linearity ( min -2.93331, max 3.39389, mean -0.00912637, variance 0.0164175, skewness 0.115911, kurtosis 5.72574 )
  bias ( min -5.02961, max 2.63683, mean -3.36246, variance 0.861059, skewness 0.933722, kurtosis 2.02732 )
component 6 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 7 : <AffineTransform>, input-dim 2048, output-dim 2048,
  linearity ( min -2.18591, max 2.53624, mean -0.00286483, variance 0.0120785, skewness 0.514589, kurtosis 15.7519 )
  bias ( min -10.0615, max 3.87953, mean -3.52258, variance 1.25346, skewness 0.878727, kurtosis 2.35523 )
component 8 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 9 : <AffineTransform>, input-dim 2048, output-dim 2048,
  linearity ( min -2.3888, max 2.7677, mean -0.00210424, variance 0.0101205, skewness 0.688473, kurtosis 23.6768 )
  bias ( min -5.40521, max 1.78146, mean -3.83588, variance 0.869442, skewness 1.60263, kurtosis 3.52121 )
component 10 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 11 : <AffineTransform>, input-dim 2048, output-dim 2048,
  linearity ( min -2.9244, max 3.0957, mean -0.00475199, variance 0.0112682, skewness 0.372597, kurtosis 25.8144 )
  bias ( min -6.00325, max 1.89201, mean -3.96037, variance 0.847698, skewness 1.79783, kurtosis 3.90105 )
component 12 : <Sigmoid>, input-dim 2048, output-dim 2048,
component 13 : <AffineTransform>, input-dim 2048, output-dim 3370,
  linearity ( min -2.0501, max 5.96146, mean 0.000392621, variance 0.0260072, skewness 0.678868, kurtosis 5.67934 )
  bias ( min -0.563231, max 6.73992, mean 0.000585582, variance 0.095558, skewness 9.46447, kurtosis 177.833 )
component 14 : <Softmax>, input-dim 3370, output-dim 3370,
LOG (nnet-info:main():nnet-info.cc:57) Printed info about exp/dnn5b_pretrain-dbn_dnn/final.nnet```

# Advanced features
### Frame-weighted training

呼叫帶選項的teps/nnet/train.sh:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

–frame-weights “`

這裡的一般是表示每一幀權重的浮點型向量的ark檔案。 
* the weights are used to scale gradients computed on single frames, which is useful in confidence-weighted semi-supervised training, 
* or weights can be used to mask-out frames we don’t want to train with by generating vectors composed of weights 0, 1 
Training with external targets

呼叫帶選項的steps/nnet/train.sh:

--labels <posterior-rspecifier> --num-tgt <dim-output>```

while ali-dirs and lang-dir become dummy dirs. The "<posterior-rspecifier>" is typically ark file with Posterior stored, and the "<dim-output>" is the number of neural network outputs. Here the Posterior does not have probabilistic meaning, it is simply a data-type carrier for representing the targets, and the target values can be arbitrary float numbers.

When training with a single label per-frame (i.e. the 1-hot encoding), one can prepare an ark-file with integer vectors having the same length as the input features. The elements of this integer vector encode the indices of the target class, which corresponds to the target value being 1 at the neural network output with that index. The integer vectors get converted to Posterior using ali-to-post.cc, and the integer vector format is simple:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

utt1 0 0 0 0 1 1 1 1 1 2 2 2 2 2 2 … 9 9 9 
utt2 0 0 0 0 0 3 3 3 3 3 3 2 2 2 2 … 9 9 9“`

In the case of multiple non-zero targets, one can prepare the Posterior directly in ascii format

each non-zero target value is encoded by a pair

utt1 [ 0 0.9991834 64 0.0008166544 ] [ 1 1 ] [ 0 1 ] [ 111 1 ] [ 0 1 ] [ 63 1 ] [ 0 1 ] [ 135 1 ] [ 0 1 ] [ 162 1 ] [ 0 1 ] [ 1 0.9937257 12 0.006274292 ] [ 0 1 ]```

The external targets are used in the autoencoder example egs/timit/s5/local/nnet/run_autoencoder.sh

### Mean-Square-Error training

呼叫帶選項的steps/nnet/train.sh:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

–train-tool “nnet-train-frmshuff –objective-function=mse” 
–proto-opts “–no-softmax –activation-type= –hid-bias-mean=0.0 –hid-bias-range=1.0”“`

最小均方誤差訓練是用在自編碼的例子裡,在指令碼egs/timit/s5/local/nnet/run_autoencoder.sh

Training with tanh

呼叫帶選項的steps/nnet/train.sh:


--proto-opts "--activation-type=<Tanh> --hid-bias-mean=0.0 --hid-bias-range=1.0"

tanh的最佳學習率一般小於sigmoid,通常最佳為0.00001。

Conversion of a DNN model between nnet1 -> nnet2

在Kaldi中,有二個DNN的例子,一個是Karel’s (本頁)和Dan’s Dan’s DNN implementation。這兩個使用不相容的DNN格式,這裡是把Karel’s DNN 轉換為Dan的格式。

  • 指令碼為:egs/rm/s5/local/run_dnn_convert_nnet2.sh, model conversion
  • 模型轉換的指令碼為: steps/nnet2/convert_nnet1_to_nnet2.sh, 它是通過呼叫模型轉換程式碼來實現的:nnet1-to-raw-nnet.cc
  • 支援成分的列表可以看ConvertComponent

The C++ code

nnet1的程式碼位於src/nnet,工具在src/nnetbin。它是根據 
src/cudamatrix。

Neural network representation

神經網路是由稱為成分的塊構成的,其中一些簡單的例子就是AffineTransform或者一個非線性Sigmoid, Softmax。一個單獨的DNN層一般是由2個成分構成: AffineTransform和一個非線性。

表示神經網路的類:Nnet is holding a vector of Component pointers Nnet::components_. Nnet最重要的一些方法如下:

  • Nnet::Propagate : 從輸入傳播到輸出,while keeping per-component buffers that are needed for gradient computation
  • Nnet::Backpropagate : 通過損失函式來後向傳播,更新權重
  • Nnet::Feedforward :傳播,當使用兩個翻動buffer來節省記憶體
  • Nnet::SetTrainOptions : 設定訓練的超引數(比如:學習率,衝量,L1, L2-cost)

為了除錯,成分和buffers塊是通過Nnet::GetComponent, Nnet::PropagateBuffer, Nnet::BackpropagateBuffer可以看到的。

Extending the network by a new component

當建立一個新成分,你需要使用下面2個介面中的一個:

  1. Component : a building block, contains no trainable parameters (see example of implementation nnet-activation.h)

  2. UpdatableComponent : child of Component, a building block with trainable parameters (implemented for example in nnet-affine-transform.h)

The important virtual methods to implement are (not a complete list) :

使用一個新的成分來擴充套件神經網路的框架,你需要:

  1. 定義一個新的成分入口Component::ComponentType
  2. 在表Component::kMarkerMap定義新的一行
  3. 新增一個”new Component”去呼叫像工廠一樣的函式 Component::Read
  4. 實現介面Component或者 UpdatableComponent的所有虛擬方法

3.https://blog.csdn.net/dearwind153/article/details/62044689
參考:

1.https://blog.csdn.net/llearner/article/details/77543337