1. 程式人生 > 實用技巧 >AIBigKaldi(五)| Kaldi的單音子模型訓練(上)

AIBigKaldi(五)| Kaldi的單音子模型訓練(上)

本文來自公眾號“AI大道理”

提取了MFCC特徵,並進行倒譜均值方差歸一化,資料檢查無誤後就可以進行模型訓練了。

首先進行的是單音素模型訓練,然後進行三音子模型訓練。

單音子模型為後期訓練提供對齊基礎。
以kaldi中的yesno為例。​

1 單音子模型訓練


3 train_mono.sh

原始碼解析:

Usage: steps/train_mono.sh [options] <data-dir> <lang-dir> <exp-dir>



過程之道:

初始化模型->生成訓練圖HCLG.fst->對標籤進行初始化對齊->統計估計模型所需的統計量->估計引數得到新模型->迭代訓練->最後的模型final.mdl。

在迭代訓練中:

使用gmm-align-compiled對齊特徵資料,得到新的對齊狀態序列;

呼叫gmm-acc-stats-ali計算更新模型引數所用到的統計量;

呼叫gmm-est更新模型引數,並且在每一輪中增加GMM的分量個數。



2初始化模型

3.1 gmm-init-mono.cc

功能:

初始化模型是最基礎的模型。
這是不需要任何訓練資料就可以得到的模型。
(無中生有)

輸入:HMM的拓撲結構,特徵維度

輸出:模型、決策樹

原始碼解析:



過程之道:

  • 初始化全域性特徵的均值和方差glob_inv_var,glob_mean均為1,大小等於特徵維度。如果有輸入特徵,另外再計算更新。

  • 讀入拓撲結構HmmTopology,建立裡面所有phone到該phone的Pdf class數目的對映。

  • 構建決策樹,只需要根據set.int檔案遞迴的構造樹。

  • gmm-init-mono構建GMM。每個pdf初始化只有一個gmm,也就是單高斯,均值方差來自之前的glob_inv_var,glob_mean, weight為1,均值方差也都為1,計算常數部分gconsts 即高斯分佈x為0時的概率。

  • 將所有gmm模型匯入聲學模型am_gmm中。最後輸出transition和聲學模型的檔案model,決策樹tree。

初始化模型結果:

這已經是一個完整的聲學模型了,可以用它來進行語音識別,只是識別率不高。

0.mdl的內容如下:

/kaldi-trunk/src/gmmbin/gmm-copy --binary=false exp/mono0a/0.mdl -

0.mdl包含TransitionModel轉移模型和多個DiagGMM高斯模型。

其中:

拓撲結構:

三狀態HMM(非靜音)

可見共6個轉移弧。

五狀態HMM(靜音)

可見共4*4+2=18個轉移弧。

音素 hmm狀態:

1號是靜音因素有5個HMM狀態,用01234表示,其他因素只有3個狀態,用012表示 。

pdf-id就是0-10,每個狀態對應一個GMM分佈。


取對數之後的轉移概率:

轉移弧個數31=2*6+1*18+1

其中第一個0是因為transition-id是從1開始,在所有轉移弧前補充一個0。

高斯模型:

維度39維(沒有能量),pdf-id個數為11個,引數包含means_invvars均值和inv_vars方差、權重、每一分量高斯分佈裡的常量部分取log後的數值。

得到了初始化的模型0.mdl, 2個音素,11個狀態。

每個狀態對應一個只包含一個高斯分量的GMM。

可以直接用這個模型進行語音識別,但效果會很差。

後續的引數迭代中要更新每個狀態的HMM轉移概率和GMM的均值向量以及協方差矩陣,同時進行單高斯分量到混合高斯分量的分裂。

tree
檢視tree內容:
/kaldi-trunk/src/bin/copy-tree --binary=false tree -

檔案之後的內容,是遞迴儲存了一棵決策樹。
構造決策樹的過程:
CE(Constant EventMap):葉子節點,直接儲存該節點存放的transition ID;
SE(Split EventMap):非葉子節點,儲存左右子節點yes,no等等;
TE(Table EventMap):非葉子節點,儲存節點數以及各個子節點的指標。

3 預編譯訓練圖

3.2 compile-train-graphs.cc
功能:
訓練用每句話轉換成一個FST結構,輸入是音素,輸出是整個句子。
輸入:tree , transition_model ,L.fst(Lexicon),訓練檔案標註。

輸出:為圖 HCLG.fst

標註文字:

為什麼需要訓練圖?

kaldi訓練模型並不是採用理論中的Baum-Welch演算法的軟對齊,實踐中是使用Vitrerbi演算法進行硬對齊。

(可見理論和實踐的差異。)

為了獲得每一幀對應的狀態號作為訓練的標籤,需要構建一個直線形的狀態圖。

在這個圖上利用Viterbi演算法求得最優路徑,同時得到幀與狀態的對齊。

原始碼解析:


構造結果:
狀態圖是一個直線型的圖,包含了標註文字的狀態序列,同時每個狀態有指向自身的跳轉即self-loop。
在monooa目錄下執行:
/kaldi-trunk/src/bin/compile-train-graphs --read-disambig-syms=../../data/lang/phones/disambig.int tree 0.mdl ../../data/lang/L.fst 'ark:../../utils/sym2int.pl --map-oov 1 -f 2- ../../data/lang/words.txt < ../../data/train_yesno/split1/1/text|' ark,t:HCLG.fst.txt



去掉0_0_0_0_1_1_1_1和其他語音,儲存。
轉化為fst圖:
fstcompile HCLG.fst.txt HCLG.fst
視覺化:
fstdraw --isymbols=phones.txt HCLG.fst | dot -Tps > HCLG111.ps


放大:

整體來看這個狀態圖是一個直線型的圖,包含了標註文字的狀態序列,同時每個狀態有指向自身的跳轉即self-loop。
圓圈表示的就是狀態,裡面的數字是狀態的id。
弧上面,冒號前面的數字是transition-id,冒號後面的數字是輸出的音素;斜槓後面的數字是權重。
只包含標註文字的狀態序列。
(構造訓練圖是基於抄本構建的,比後面的構造解碼圖要簡單些,所採用的程式碼也不一樣。)

4 模型訓練




構造好訓練圖接下來就可以進行訓練了。
所謂訓練就是在訓練圖上進行解碼,獲得最優路徑的同時得到對齊序列,根據對齊序列進行統計資訊量。
轉移概率可以進行數數獲得,GMM引數隨著對齊的幀數變化而更新,同時GMM分量從一開始的單高斯split出更多的高斯。
如此不斷迭代訓練獲得單音子模型。

下期預告

AIBigKaldi(六)|Kaldi的單音子模型訓練(下)

往期精選

AIBigKaldi(四)| Kaldi的特徵提取

AIBigKaldi(三)| Kaldi的資料準備

AIBigKaldi(二)| Kaldi的I/O機制

AIBigKaldi(一)|Kaldi的目錄結構

AI大語音(十四)——區分性訓練
AI大語音(十三)——DNN-HMM
AI大語音(十二)——WFST解碼器(下)
AI大語音(十一)——WFST解碼器(上)

AI大語音(十)——N-gram語言模型
AI大語音(九)——基於GMM-HMM的連續語音識別系統
AI大語音(八)——GMM-HMM聲學模型
AI大語音(七)——基於GMM的0-9語音識別系統
AI大語音(六)——混合高斯模型(GMM)
AI大語音(五)——隱馬爾科夫模型(HMM)
AI大語音(四)——MFCC特徵提取
AI大語音(三)——傅立葉變換家族
AI大語音(二)——語音預處理
AI大語音(一)——語音識別基礎

——————

淺談則止,細緻入微AI大道理

掃描下方“AI大道理”,選擇“關注”公眾號

—————————————————————

—————————————————————

投稿吧 | 留言吧