Kaldi腳本分析(3)——單音素建模

1.1單音素模型腳本流程

單音素建模腳本(steps/train_mono.sh):

#monophone

steps/train_mono.sh--boost-silence 1.25 --nj$n --cmd "$train_cmd" data/mfcc/train data/lang exp/mono \

 || exit 1;

輸出在exp/mono中,下面按腳本train_mono.sh運行流程逐項說明。

 

1.1.1       特徵倒譜歸一化(Cepstralnormalization

exp/mono/cmvn.logexp/mono/cmvn.ark:對每個說話人,計算歸一化倒譜均值和方差的統計值

#cepstralnormalization

#feature: add"delta" and "accelaration", dim = 39

feats="ark,s,cs:apply-cmvn$cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spkscp:$sdata/JOB/cmvn.scp scp:$sdata/JOB/feats.scp ark:- | add-deltas ark:- ark:- |"

example_feats="`echo$feats| sed s/JOB/1/g`";

 

1.1.2       模型初始化(Modelinitialization

#modelinitialization

#options used toget plausible means and variances

#tree isphonetic-context decision tree-- doesn’t have any splits in monophone case.

$cmd JOB=1$dir/log/init.log \

    gmm-init-mono $shared_phones_opt"--train-feats=$feats subset-feats --n=10 ark:- ark:-|"$lang/topo$feat_dim  $dir/0.mdl $dir/tree || exit 1;

  • 運行log:exp/mono/log/init.log
  • 調用gmm-init-mono命令行工具,即gmm-init-mono.cc中的函數。

gmm-init-mono<topology-in> <dim> <model-out> <tree-out>

  • 雙引號中爲一些命令行選項,確保求得的均值方差是可行的。
  • 輸入:HMM拓撲文件data/lang/topo和GMM特徵維度39。
  • 輸出:模型文件exp/mono/0.mdl和決策樹exp/mono/tree。

 

注1:單音素決策樹


--可以通過copy-tree命令行工具查看音素上下文決策樹文件。

--決策樹文件中存儲的是多態類型對象EventMap。

--TE指的是TableEventMap,表示樹的各種節點的查詢Table。

--CE指的是ConstantEventMap,表示樹的葉子節點。

--SE指的是SplitEventMap,表示樹的分支,而在單音素模型中不需要做split處理。

--“TE 0 219”表示從第0個音素開始分裂,這裏0指向NULL,因爲phone-id中0是爲epsilon保留的。隨後是219個non-NULL event map。

--“TE -1 3 ( CE5 CE 6 CE 7 ) ”這個字符串表示一個音素的分裂從key-1開始,這個key表示拓撲結構中的pdfclass,在這裏也就是HMM狀態,其中,-1是初始狀態,0、1、2是 HMM 中間的轉移狀態,3 是結束狀態。中間的3個轉移狀態可以有對應的CE,每一個表示決策樹的一個葉子節點。

 

注2:HMM拓撲文件

--可以通過cat data/lang/topo查看。

--給定了所有非靜音音素的3狀態left-to-right型HMM結構,並給出了開始訓練前默認的狀態轉移概率。

--靜音音素單獨給出了5狀態的HMM結構,具有更多的狀態轉移。

 

注3:模型文件0.mdl

--通過gmm-copy命令行工具查看模型文件gmm-copy --binary=false exp/mono/0.mdl - | less

--模型文件中包含兩部分,一部分是TransitionModel(轉移模型),其中包含HMM拓撲結構、triples以及轉移概率;另一部分是AmGmm(聲學模型)。模型文件中的對象都不是Table,所以直接通過Read/Write進行對象讀寫。寫入是 binary or text,取決於命令行選項 --binary。

--Topology信息中,有一個音素(標號1)與其他音素的拓撲結構不同,對比phones.txt可知該音素爲sil(代表靜音silence)。

--topo 文件的慣例,初始狀態和結束狀態(概率爲 1)爲非發射狀態。在如下所示的拓撲結構裏,-1 是初始狀態,0、1、2是 HMM 中間的轉移狀態,3 是結束狀態。

--每一個Triple表示一個三元組(phone,hmm-state,pdf-id),與轉移狀態一一對應。

--<NUMPDFS>即pdf總數,與Triple總數一致。

 




1.1.3       預編譯訓練圖模型(Compiletraining graphs

#compile training graphs(FSTs)

#one for each train utterance

#encode HMM structure for that training utterance

#we precompile them because otherwise this would dominatetraining time

if [$stage -le -2 ];then

  echo"$0: Compiling training graphs"

  $cmd JOB=1:$nj$dir/log/compile_graphs.JOB.log\

   compile-train-graphs --read-disambig-syms=$lang/phones/disambig.int$dir/tree $dir/0.mdl  $lang/L.fst \

    "ark:sym2int.pl --map-oov$oov_sym -f 2-$lang/words.txt <$sdata/JOB/text|" \

    "ark:|gzip -c >$dir/fsts.JOB.gz" ||exit 1;

fi

 


  • 運行log:exp/mono/log/compile_graphs.log
  • 調用compile-train-graphs命令行工具,編譯FSTs,每個訓練語句得到一個FST。
  • n  compile-train-graphs[options] <tree-in> <model-in> <lexicon-fst-in><transcriptions-rspecifier> <graphs-wspecifier>
  • 構造訓練的fst網絡,從源碼級別分析,是每個句子構造一個phonelevelfst網絡。這裏採用預編譯的原因是,可以儘量減少佔用訓練時間。$data/text中包含對每個句子的單詞級別(words level)或音素級別(phone level)的標註, L.fst是詞典的fst表示,作用是將一串的音素轉換成單詞。構造monophone解碼圖就是先將text中的每個句子,生成一個fst(類似於語言模型中的G.fst,只是相對比較簡單,只有一個句子),然後和L.fst進行composition 形成訓練用的音素級別(phone levelfst網絡(類似於LG.fst)。fsts.JOB.gz中使用 key-value 的方式保存每個句子和其對應的fst網絡,通過 key(句子索引)就能找到這個句子的fst網絡,value中保存的是句子中每兩個音素之間互聯的邊(Arc,例如句子轉換成音素後,標註爲:"a b c d e f",那麼value中保存的其實是 a->b b->c c->d d->e e->f這些連接(kaldi會爲每種連接賦予一個唯一的id),後面進行 HMM訓練的時候是根據這些連接的id進行計數,進一步得到音素內(intra)狀態的轉移概率和音素間(inter)狀態的轉移概率。
  • 輸入:決策樹文件,模型文件,詞典fst文件,訓練文件標註transcript_rspecifier(Table格式輸入)。
  • 輸出:訓練圖fsts_wspecifier(Table格式輸出)。

注1   :訓練圖模型

--可以通過fstcopy命令將存檔格式轉到標準輸出查看

--存檔格式:utt-idgraph utt-id graph...

--其中graph格式:from-state to-state input-symboloutput-symbol cost

--input-symbol,傳統意義上是指概率密度函數,GMM中每個混合分量都有一個值。但這樣會增加訓練轉移概率和音素對齊時的難度,所以Kaldi中將input-symbol定義爲轉移標識符trans-id。

--output-symbol是word.txt中的詞。

--cost是轉移概率,其中包含發音概率,對於預編譯訓練圖來說,除初始狀態外沒有轉移概率(後面訓練時加入)。

注2  :rspecifier/wspecifier

--這兩個字符串指明瞭Table文件是archiv還是script-file,文件在磁盤上的存儲位置(普通文件、管道還是標準輸入輸出)以及其他的選項信息。

 

1.1.4       第一次對齊和求累積統計量(Firstalignment stage

#first alignmentstage

#produces alignments“equally spaced” for each utterance, accumulates 1st iteration stats.

#an alignment isa vector of ints (per utterance)

#Note: we doViterbi training not forward-backward, means we use 1-best path.

if [$stage -le -1 ];then

  echo"$0: Aligning data equally(pass 0)"

  $cmd JOB=1:$nj$dir/log/align.0.JOB.log \

    align-equal-compiled"ark:gunzip -c $dir/fsts.JOB.gz|""$feats" ark,t:-  \| \

    gmm-acc-stats-ali --binary=true$dir/0.mdl "$feats" ark:- \

    $dir/0.JOB.acc ||exit 1;

fi

  • 運行log:exp/mono/log/align.0.log
  • 調用align-equal-compiledgmm-acc-stats-ali命令行工具
align-equal-compiled <graphs-rspecifier> <features-rspecifier> <alignments-wspecifier>
gmm-acc-stats-ali [options] <model-in> <feature-rspecifier> <alignments-rspecifier> <stats-out>
  • 對每個語句採用等空間對齊(alignments“equally spaced”),並累積迭代統計量,開始HMM-GMM訓練。
  • 對每個語句來說,對齊相當於一個整數向量vector<int32>,其中存儲trans_id的序列,它的長度與需要對齊的語句一樣長,即一幀數據提取的一個特徵向量對應得到一個trans_id,其中trans_id與(trans_state,trans_index)二元組一一映射,而trans_state與(phone,hmm_state,pdf)三元組一一映射,pdf由GMM計算。對齊(alignments)通常用在訓練階段的Viterbi算法和測試階段的自適應算法。音素trans_id編碼了音素的信息,所以從對齊中可以計算出音素的序列。
  • 訓練轉移概率時,累積的統計量就是數每個trans_id在訓練階段出現了多少次。
  • 由於採用Viterbi算法訓練而不是前向-後向算法,所以只選一個最佳路徑。
  • align-equal-compiled輸入:訓練圖fst_rspecifier(Table格式輸入),特徵feature_rspecifier(Table格式輸入)。
  • align-equal-compiled輸出:對齊向量alignment_wspecifier(Table格式輸出)。
  • gmm-acc-stats-ali輸入:初始模型文件0.mdl、特徵文件(Table格式輸入)、對齊向量(Table格式輸出)。
  • gmm-acc-stats-ali輸出:初始累積統計量0.acc

 

1.1.5       第一次更新(Firstupdate

# In thefollowing steps, the --min-gaussian-occupancy=3 option is important,

# otherwise wefail to est "rare" phones and later on, they never align properly.

 

#first update

#transitionmodel update

#gmm update

#split gauss

#modelfile(.mdl) contains transition-model object, then GMM object

if [$stage -le 0 ];then

  gmm-est --min-gaussian-occupancy=3  --mix-up=$numgauss --power=$power \

    $dir/0.mdl"gmm-sum-accs- $dir/0.*.acc|"$dir/1.mdl 2>$dir/log/update.0.log||exit 1;

  rm $dir/0.*.acc

fi


  • 運行log:exp/mono/log/update.0.log
  • 調用gmm-estgmm-sum-accs命令行工具

gmm-est [options]<model-in> <stats-in> <model-out>
gmm-sum-accs [options]<stats-out> <stats-in1> <stats-in2> ...

  • 狀態轉移(Transition-model)更新,GMM更新,狀態split
  • 輸入:初始模型exp/mono/0.mdl,GMM統計量exp/mono/0.acc
  • 輸出:第一次更新後的模型exp/mono/1.mdl

 

1.1.6       建模過程(Modelbuilding schedule

beam=6 # will change to 10 below after 1st pass

# note: usingslightly wider beams for WSJ vs. RM.

 

#model buildingschedule

x=1

while [$x -lt $num_iters ]; do

  echo"$0: Pass$x"

  if [$stage -le $x ]; then

    ifecho$realign_iters | grep -w$x >/dev/null;then

      echo"$0: Aligning data"

      mdl="gmm-boost-silence --boost=$boost_silence `cat$lang/phones/optional_silence.csl`$dir/$x.mdl - |"

    #newalignment

      $cmd JOB=1:$nj$dir/log/align.$x.JOB.log \

        gmm-align-compiled$scale_opts --beam=$beam --retry-beam=$[$beam*4] --careful=$careful"$mdl" \

        "ark:gunzip -c$dir/fsts.JOB.gz|""$feats""ark,t:|gzip -c >$dir/ali.JOB.gz" \

        || exit 1;

    fi

    $cmd JOB=1:$nj$dir/log/acc.$x.JOB.log \

      gmm-acc-stats-ali $dir/$x.mdl"$feats""ark:gunzip -c$dir/ali.JOB.gz|" \

      $dir/$x.JOB.acc ||exit 1;

    #newupdate

    $cmd$dir/log/update.$x.log \

      gmm-est --write-occs=$dir/$[$x+1].occs --mix-up=$numgauss --power=$power$dir/$x.mdl \

      "gmm-sum-accs-$dir/$x.*.acc|"$dir/$[$x+1].mdl || exit 1;

    rm $dir/$x.mdl$dir/$x.*.acc$dir/$x.occs 2>/dev/null

  fi

  if [$x -le $max_iter_inc ]; then

     numgauss=$[$numgauss+$incgauss];

  fi

  beam=10

  x=$[$x+1]

done

  • 多次對齊(newalignment):調用gmm-align-compiledgmm-acc-stats-ali命令行工具,輸出對齊向量和累積統計量。

gmm-align-compiled[options] model-in graphs-rspecifier feature-rspecifier alignments-wspecifier[scores-wspecifier]
gmm-acc-stats-ali[options] <model-in> <feature-rspecifier><alignments-rspecifier> <stats-out>

  • 多次更新(newupdate):調用gmm-est命令行工具,輸出更新後的模型(更新轉移模型參數和GMM參數)。間接調用gmm-sum-accs命令行工具,計算累積統計量總和。

gmm-est [options]<model-in> <stats-in> <model-out>
gmm-sum-accs [options]<stats-out> <stats-in1> <stats-in2> ...

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