ichou1のブログ

主に音声認識、時々、データ分析のことを書く

音声認識メモ(HMM)その4(HTK HERestコマンド(1))

音声データと、それが意味する音素や単語("ラベル"と表現する)の紐付けには、「音響モデル」を使用する。

Juliusでは、音響モデルとして、HMM (Hidden Markov Model) を用いることができる。

HMMは、HTK(HMM Tool Kit)を使って作成できる。

モデルの学習には、以下の2つの方法がある。

  • ラベルの名前と、始まりと終わりの時間情報を与える(HInitコマンド)
  • ラベルの名前のみ与え、時間情報は与えず、始まりと終わりを推定させる(HERestコマンド)

今回は、後者の方法を試してみる。

流れとしては、HCompVコマンドを使って学習用となる音声データの全平均から求めた初期モデルを用意し、学習を繰り返しながらモデルのパラメータを更新していく。

学習に際しては、インプットとして以下を与える

  1. 音声データ
  2. 音声データに含まれるラベル
  3. 初期モデル(遷移確率と確率密度関数)

モデルのパラメータは、期待する出力に適合する確率がもっとも高くなるように更新される。

確率を求める際には、計算量を削減した「forward-backward」(または「alpha-beta」)アルゴリズムを使用する。
(具体的には、時系列の前から遷移していく確率と、時系列の後ろから遷移していく確率の両方を求める)

具体的に数値を追ってみる。
まずは、時系列の後ろから辿った確率。

<インプット>
音声データ:"もしもし"という発話(HCopyコマンドにより198 frameに変換)
ラベル:silB - m - o - s - i - m - o - s - i - silE

f:id:ichou1:20171112092900p:plain
("sil"は"silence"で、"B"は"Begin"、"E"は"End"を表す)

各ラベルの状態数:5 (1つのラベルが、状態1〜5まで持つということ)
各ラベルの状態遷移確率(初期値、学習を通じて更新されるので、任意に指定してよい)

f:id:ichou1:20171112092938p:plain

(状態4から状態5に遷移する確率:0.3(30%))
(状態4から遷移せず、状態4に留まる確率:0.7(70%))

状態2〜4の3つ分をずらし幅とすると、
各ラベルが該当する可能性があるフレームは以下のとおりとなる。

[10番目のラベルq (silE)] 	-> time(frame) 28 - 198
[ 9番目のラベルq (i)   ] 	-> time(frame) 25 - 195
[ 8番目のラベルq (s)   ] 	-> time(frame) 22 - 192 
[ 7番目のラベルq (o)   ] 	-> time(frame) 19 - 189
[ 6番目のラベルq (m)   ] 	-> time(frame) 16 - 186
[ 5番目のラベルq (i)   ] 	-> time(frame) 13 - 183
[ 4番目のラベルq (s)   ] 	-> time(frame) 10 - 180
[ 3番目のラベルq (o)   ] 	-> time(frame)  7 - 177
[ 2番目のラベルq (m)   ] 	-> time(frame)  4 - 174
[ 1番目のラベルq (silB)] 	-> time(frame)  1 - 171


t=T-1(今回の例ではt=197)において、ラベル10の状態4にいる確率(下図の赤枠)は

f:id:ichou1:20171124205335p:plain

①(遷移確率) * ②(出力確率) * ③(遷移確率)

により求まる。

確率の計算は対数を使う。
対数をとっても大小関係が変わらない性質を利用しており、値が大きいほど確率が高いことを意味する。

log ( ① * ② * ③ )
= log( ① ) + log( ② ) + log( ③ )
= log( 0.3 ) + log( ② ) + log( 0.7 )
= (-1.20) + (-63.58) + (-0.35)
= -65.14


また、t=T-2(今回の例ではt=196)において、ラベル10の状態4にいる確率(下図の赤枠)は

f:id:ichou1:20171124210317p:plain

①(t=T-1で状態4にいる確率) * ②(出力確率) * ③(遷移確率)

により求まる。

log ( ① * ② * ③ )
= log( ① ) + log( ② ) + log( ③ )
= (-65.14) + log( ② ) + log( 0.7 )
= (-65.14) + (-65.09) + (-0.35)
= -130.59

これをt=1まで繰り返す。



プログラムで計算された各状態の確率は以下のとおりであった。

f:id:ichou1:20171112093055p:plain

(赤枠:時間tにおいて、全ラベルで確率がもっとも高いもの)
(緑枠:時間tにおいて、そのラベルで確率がもっとも高いもの)

f:id:ichou1:20171112093249p:plain

時系列が前に進むほど、ラベル内の状態番号、ラベルの番号も若くなっていくことが確認できる。

f:id:ichou1:20171112093300p:plain

次回につづく。