はじめに
HTK(Hidden Markov Model Toolkit)は、隠れマルコフモデル(HMMs)を組み立てるためのツールキットです。
これを使って、数字の音声認識をやりながら、音声認識の仕組みを理解していきたいと思います。
フリーソフトで作る音声認識システム
という本を参考にしています。音声認識に関してかなりググってみたのですが、何から手を付けていいかいまいちわからず本を買ってみたところ、自分にとって予想以上に良書でした。
環境
Windows10
HKT 3.4.1
WaveSurfer 1.8.8p5-1701260009
セットアップ
まず、下記サイトからダウンロードします。
http://htk.eng.cam.ac.uk/download.shtml
ダウンロードする際はユーザ登録が必要です。
下記はWindowsの手順です。Linux等の場合は、READMEの該当箇所の手順に従ってください。
Windows用をダウンロードしました。
HTK-3.4.1.zip
がダウンロードされるので、解凍します。
直下にあるREADMEを参考にコンパイル、インストールします。
- コマンドプロンプトを開き、ktkフォルダに移動します。
>cd /d d:\Programs\htk
※解凍先をd:\Programs\htk
ということで話を進めます。
- ライブラリとツール用のディレクトリを作成します。
>mkdir bin.win32
- VCVA32.batを実行し、Visual Studioビルド環境をロードします。
>"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat"
※場所は適宜読み替えてください
- HTK Libraryをビルドします。
>cd HTKLib
>nmake /f htk_htklib_nt.mkf all
なんやかんやワーニングが出ますが、ビルドが完了します。
- HTK Toolsをビルドします。
>cd ..
>cd HTKTools
>nmake /f htk_htktools_nt.mkf all
>cd ..
>cd HLMLib
>nmake /f htk_hlmlib_nt.mkf all
>cd ..
>cd HLMTools
>nmake /f htk_hlmtools_nt.mkf all
>cd ..
これで、先ほど作った、bin.win32
フォルダにビルドして出来上がったHTK Toolsが入っています。必要に応じてPATHを通したりしてください。
音声の録音とラベル付け
音声と録音とラベル付けは、WaveSurferというツールを使います。以下からダウンロードしてください。
http://www.speech.kth.se/wavesurfer/
数字音声の保存
WaveSurferの録音機能で、0~9までの音声をそれぞれ3回ずつ保存します。
まずは、設定で、New sound default channelsに1を、New Sound default rateに16000を指定してください。
この16000という数字は、標本化定理に基づいて指定する値です。音声を認識するには8kHz程度の情報が取れればよく、その倍の16kHzを指定すれば標本化定理により元の音を完全に再現できる指定にできます。
「File]-「New」で「Speech analysis」を選んで録音します。1音ごとに「Save As」で保存してください。
上記は「1」を録音したところです。
音声のラベル付け
録音した音声にラベル付けします。
先ほど録音した音声を「File」-「Open」で開きます。その際、「HTK transcription」を選択することで、ラベルを付けることができるようになります。
無音部分を「sil」、数値部分を「zero」~「nine」というラベルを付けます。
下記はdata0-1.wavでゼロのラベル付けをした例です。
そうしたら、ラベルのところで右クリックをして表示されたポップアップで「Save Transcription As...」を選択し、ラベルを保存します。
これをすべての音声で行います。
data0-1.labには以下のような内容が保存されます。
0 5312810 sil
5312810 9533267 zero
9533267 12487587 sil
特徴の抽出
HCopy
コマンドで特徴量を抽出します。
コマンドは以下の形式で指定します。
HCopy [オプション] 音声ファイル名 特徴ファイル名 -C 構成ファイル名 -S スクリプトファイル名
構成ファイル
構成ファイルには、音声ファイルの形式や、どのような特徴を指定するかを指定します。
SOURCEFORMAT = WAV
SOURCEKIND = WAVEFORM
SOURCERATE = 625
TARGETKIND = MFCC_0_D_A
TARGETRATE = 100000.0
WINDOWSIZE = 250000.0
USEHAMMING = T
PREEMCOEF = 0.97
NUMCHANS = 24
NUMCEPS = 12
SOURCERATEは、標本化周期である、1/16000[s]を指定してます。TARGETKINDには、抽出パラメータがMFCCで、0次元目のデータとしてフレームの平均パワーをとり、Dで特徴の1次差分を、Aで2次差分をとることを指定しています。
TARGETRATE はフレーム 周期を 100ns を単位として表した数値,WINDOWSIZE は分析窓長を 100ns を単位として 表した数値で,例では 10ms のフレーム周期で,25ms 長の窓を使うように指定しています。
USEHAMMING は T とすることで分析窓としてハミング窓を使うように指定しています。
PREEMCOEF にはプリエンファシスの係数を指定します。
NUMCHANS にはメルフィルタバン クのフィルタ数を、CEPLIFTER には求めたケプストラムに掛ける等価リフタの次数を指定します。
NUMCEPS には最終的に高次係数を切り捨てて求める MFCC の次数を指定します。
スクリプトファイル
スクリプトファイルには、特徴抽出の入力ファイルと出力ファイルの対応を記述します。
区切り文字はタブです。
data0-1.wav data0-1.mfc
data1-1.wav data1-1.mfc
data2-1.wav data2-1.mfc
data3-1.wav data3-1.mfc
data4-1.wav data4-1.mfc
data5-1.wav data5-1.mfc
data6-1.wav data6-1.mfc
data7-1.wav data7-1.mfc
data8-1.wav data8-1.mfc
data9-1.wav data9-1.mfc
data0-2.wav data0-2.mfc
data1-2.wav data1-2.mfc
data2-2.wav data2-2.mfc
data3-2.wav data3-2.mfc
data4-2.wav data4-2.mfc
data5-2.wav data5-2.mfc
data6-2.wav data6-2.mfc
data7-2.wav data7-2.mfc
data8-2.wav data8-2.mfc
data9-2.wav data9-2.mfc
data0-3.wav data0-3.mfc
data1-3.wav data1-3.mfc
data2-3.wav data2-3.mfc
data3-3.wav data3-3.mfc
data4-3.wav data4-3.mfc
data5-3.wav data5-3.mfc
data6-3.wav data6-3.mfc
data7-3.wav data7-3.mfc
data8-3.wav data8-3.mfc
data9-3.wav data9-3.mfc
HCopy実行
構成ファイルとスクリプトファイルを指定して、HCopyコマンドを実行します。
>HCopy.exe -C config.hcopy -S script.hcopy
mfcファイルができたら、mfccというフォルダを作ってそこに移動させます。
初期モデル作成
HMM(Hidden Markov Model)の構造を定義します。今回は以下の構成とします。
この構成をファイルに表現すると、以下のようになります。
~o <VecSize> 39 <MFCC_0_D_A>
~h "zero"
<BeginHMM>
<NumStates> 5
<State> 2
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
<State> 3
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
<State> 4
<Mean> 39
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
<Variance> 39
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
<TransP> 5
0.0 1.0 0.0 0.0 0.0
0.0 0.5 0.5 0.0 0.0
0.0 0.0 0.5 0.5 0.0
0.0 0.0 0.0 0.5 0.5
0.0 0.0 0.0 0.0 0.0
<EndHMM>
状態1と5は、特徴ベクトルを出力しないので、クラス分布関数の定義は不要となります。ほかの状態に関しては、クラス分布関数の平均ベクトル(Mean)と共分散行列(Variance)を記述します。
共分散行列は対角行列であると仮定し、その成分だけを指定しています。
は状態遷移の定義をしています。今回は5状態なので5$\times$5で指定しています。例えば一行目は、2カラム目が1.0なので、状態1からは状態2に確率1で遷移することが指定されています。2行目は、2カラム目と3カラム目が0.5なので、状態2からは、状態2自身へ0.5、状態3へ0.5の確率で遷移することが指定されています。
このファイルをone.hmm~nine.hmmという名前でコピーし、「~h」の名前をそれぞれ書き換えて保存してください。
#HMMパラメータの初期値の設定
HMMのパラメータはそれぞれの状態でのクラス分布関数や状態遷移確率を定義しています。それらが均一で学習が始まると、局所最適解に陥る可能性があるため、HInitコマンドで初期値を設定します。初期値はビタビアルゴリズムで設定されます。
HInit [オプション] HMM名
オプションは以下の通りです。
-T Num 出力トレースレベルを指定する
-S listFile 学習データリスト名を指定する
-M folderName 初期HMMフォルダ名を指定する
-H hmmFile HMM構成ファイル名を指定する
-l String ラベル名を指定する
-L folderName ラベルフォルダ名を指定する
オプションの-Sに指定する学習データリストを作成します。
HCopyで作成したmfcファイルのファイル名をすべて指定します。
mfcc/data0-1.mfc
mfcc/data1-1.mfc
mfcc/data2-1.mfc
mfcc/data3-1.mfc
mfcc/data4-1.mfc
mfcc/data5-1.mfc
mfcc/data6-1.mfc
mfcc/data7-1.mfc
mfcc/data8-1.mfc
mfcc/data9-1.mfc
mfcc/data0-2.mfc
mfcc/data1-2.mfc
mfcc/data2-2.mfc
mfcc/data3-2.mfc
mfcc/data4-2.mfc
mfcc/data5-2.mfc
mfcc/data6-2.mfc
mfcc/data7-2.mfc
mfcc/data8-2.mfc
mfcc/data9-2.mfc
mfcc/data0-3.mfc
mfcc/data1-3.mfc
mfcc/data2-3.mfc
mfcc/data3-3.mfc
mfcc/data4-3.mfc
mfcc/data5-3.mfc
mfcc/data6-3.mfc
mfcc/data7-3.mfc
mfcc/data8-3.mfc
mfcc/data9-3.mfc
作成したら以下のコマンドを実行します。
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/zero.hmm -l zero -L label zero
以下のようなメッセージが出力されて処理が終了します。
Initialising HMM zero . . .
States : 2 3 4 (width)
Mixes s1: 1 1 1 ( 39 )
Num Using: 0 0 0
Parm Kind: MFCC_D_A_0
Number of owners = 1
SegLab : zero
maxIter : 20
epsilon : 0.000100
minSeg : 3
Updating : Means Variances MixWeights/DProbs TransProbs
- system is PLAIN
3 Observation Sequences Loaded
Starting Estimation Process
Iteration 1: Average LogP = -3215.04102
Iteration 2: Average LogP = -3161.16675 Change = 53.87427
Iteration 3: Average LogP = -3147.54492 Change = 13.62183
Iteration 4: Average LogP = -3142.60547 Change = 4.93945
Iteration 5: Average LogP = -3137.84692 Change = 4.75854
Iteration 6: Average LogP = -3137.84692 Change = 0.00000
Estimation converged at iteration 7
Output written to directory hmm0
-Mで指定したディレクトリhmm0に結果が出力されています。クラス分布関数の平均ベクトルや、共分散行列の対角成分の初期値が設定されています。
~o
<STREAMINFO> 1 39
<VECSIZE> 39<NULLD><MFCC_D_A_0><DIAGC>
~h "zero"
<BEGINHMM>
<NUMSTATES> 5
<STATE> 2
<MEAN> 39
-1.188843e+01 3.477678e+00 3.675378e+00 -3.583102e-01 1.305101e+00 -8.195998e+00 1.164498e+00 -1.343422e+00 -5.572519e-01 -1.641809e+00 4.538788e-01 -3.993519e+00 6.202705e+01 1.258294e-01 -1.618993e+00 -2.157246e-01 -1.482081e+00 -1.093997e+00 -2.445189e+00 -7.862397e-01 5.881087e-01 -7.339767e-01 7.656317e-01 5.172008e-01 -7.833375e-02 2.365453e+00 2.523896e-01 -1.967793e-01 1.320107e-01 -2.817445e-01 -1.703041e-01 -1.349682e-01 -1.753984e-03 7.186008e-02 -4.457561e-02 -1.149647e-02 -1.150950e-01 -1.925533e-01 -1.014521e-01
<VARIANCE> 39
8.134451e+01 2.500010e+01 2.850899e+01 3.407345e+01 3.633406e+01 1.519371e+02 2.309261e+01 1.219199e+01 2.605530e+01 1.669540e+01 7.526879e+00 1.242349e+01 6.291047e+01 1.676000e+01 2.441002e+00 5.652246e+00 3.159509e+00 4.312917e+00 1.023630e+01 1.497224e+00 1.609096e+00 2.166575e+00 1.569044e+00 1.058919e+00 2.794152e+00 1.761050e+00 3.050326e+00 5.784694e-01 1.052930e+00 3.828032e-01 5.059460e-01 2.157578e+00 3.394441e-01 3.012945e-01 5.481936e-01 3.527757e-01 2.134150e-01 3.832273e-01 3.550204e-01
<GCONST> 1.216047e+02
<STATE> 3
<MEAN> 39
-7.309173e-01 -1.048546e+01 2.659467e+00 -1.338165e+01 -8.673465e+00 -2.305907e+01 -5.547618e+00 4.851469e+00 -1.124947e+00 1.360517e+00 -6.829199e-01 -8.349416e+00 7.364520e+01 2.837810e-01 -2.149490e-01 -8.765711e-01 -1.177059e-01 3.576238e-01 9.940961e-01 -1.604020e-01 -3.220538e-01 3.907898e-01 -5.969828e-02 4.719580e-01 8.681932e-02 7.714530e-02 -4.246662e-02 2.011100e-01 4.601711e-03 -4.502578e-02 1.839996e-01 1.834370e-01 1.421157e-01 -1.526191e-01 -1.234164e-01 -4.772357e-02 1.755387e-01 8.219465e-02 -8.779123e-02
<VARIANCE> 39
8.108775e+00 1.834256e+00 3.121191e+01 4.376693e+01 8.521482e+00 2.422301e+01 1.186177e+01 1.053487e+01 2.263748e+01 7.743262e+00 1.453198e+01 1.808433e+01 6.427885e+00 5.204114e-01 4.328600e-01 9.790024e-01 6.985510e+00 1.159161e+00 2.183934e+00 1.309209e+00 1.069459e+00 1.907738e+00 9.514236e-01 3.414848e+00 2.245418e+00 1.005552e+00 1.177312e-01 1.024540e-01 2.142989e-01 1.328135e+00 1.833571e-01 2.062124e-01 3.222685e-01 8.448422e-02 2.971713e-01 2.330663e-01 3.594871e-01 4.487212e-01 2.456534e-01
<GCONST> 9.023790e+01
<STATE> 4
<MEAN> 39
2.184474e+00 -5.833115e+00 -5.189268e+00 -2.197799e+01 -2.865063e+00 -7.106102e-01 5.807543e+00 -3.738693e+00 -1.543543e+00 1.309784e+00 1.105161e+01 -2.566302e+00 6.105293e+01 -5.572022e-01 4.472832e-01 3.408478e-01 2.388481e-01 1.331146e-01 5.106670e-01 5.467352e-01 -5.777531e-02 2.071937e-01 -1.611491e-01 -4.072005e-01 5.497755e-01 -1.642518e+00 -5.422572e-02 -5.406429e-02 6.275102e-02 2.781438e-01 -5.356923e-02 -1.684144e-01 -1.708611e-01 1.139488e-01 1.112158e-01 -1.089825e-02 -2.177670e-01 -5.934791e-03 1.551733e-02
<VARIANCE> 39
2.196372e+01 1.054869e+01 9.056970e+00 4.348963e+01 1.065004e+01 1.313244e+01 2.535172e+01 9.383027e+00 1.420171e+01 1.470503e+01 1.630399e+01 2.157364e+01 1.038608e+02 1.358972e+00 8.380147e-01 1.497663e+00 6.104476e+00 1.432893e+00 1.276902e+00 3.454984e+00 1.076520e+00 1.620838e+00 1.897942e+00 1.662103e+00 5.682069e-01 1.261803e+00 1.517102e-01 1.698475e-01 2.700142e-01 5.574468e-01 2.880678e-01 1.503949e-01 2.872775e-01 2.300916e-01 2.548315e-01 3.564199e-01 2.485757e-01 1.144796e-01 2.613516e-01
<GCONST> 9.621025e+01
<TRANSP> 5
0.000000e+00 1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
0.000000e+00 9.062500e-01 9.375000e-02 0.000000e+00 0.000000e+00
0.000000e+00 0.000000e+00 9.411765e-01 5.882353e-02 0.000000e+00
0.000000e+00 0.000000e+00 0.000000e+00 9.423077e-01 5.769231e-02
0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
<ENDHMM>
HMMの学習
HRestを使用して学習します。学習アルゴリズムは、Baum-Welchアルゴリズムで行われます。HRestコマンドは以下のように定義されています。
HRest [オプション] HMM名
オプションは以下の通りです。
-T Num 出力トレースレベルを指定する
-S listFile 学習データリスト名を指定する
-M folderName 学習後のHMMフォルダ名を指定する
-H hmmFile HMM構成ファイル名を指定する
-l String ラベル名を指定する
-L folderName ラベルフォルダ名を指定する
以下のコマンドを実行します。
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/zero.hmm -l zero -L label zero
コマンドの実行結果として、以下のようなメッセージが出力されます。
Reestimating HMM zero . . .
States : 2 3 4 (width)
Mixes s1: 1 1 1 ( 39 )
Num Using: 0 0 0
Parm Kind: MFCC_D_A_0
Number of owners = 1
SegLab : zero
MaxIter : 20
Epsilon : 0.000100
Updating : Transitions Means Variances
- system is PLAIN
3 Examples loaded, Max length = 48, Min length = 43
Ave LogProb at iter 1 = -3137.81421 using 3 examples
Ave LogProb at iter 2 = -3137.77124 using 3 examples change = 0.04297
Ave LogProb at iter 3 = -3137.59253 using 3 examples change = 0.17871
Ave LogProb at iter 4 = -3136.82495 using 3 examples change = 0.76758
Ave LogProb at iter 5 = -3136.63086 using 3 examples change = 0.19409
Ave LogProb at iter 6 = -3136.62720 using 3 examples change = 0.00366
Ave LogProb at iter 7 = -3136.62695 using 3 examples change = 0.00024
Ave LogProb at iter 8 = -3136.62695 using 3 examples change = 0.00000
Estimation converged at iteration 8
changeの値がEpsilonの値以下になると処理が終了します。今回は、7回の繰り返しでchangeが0.00000になり、閾値(Epsilon)以下になったため処理が終了しています。hmm1には以下のようなファイルが出力されています。
~o
<STREAMINFO> 1 39
<VECSIZE> 39<NULLD><MFCC_D_A_0><DIAGC>
~h "zero"
<BEGINHMM>
<NUMSTATES> 5
<STATE> 2
<MEAN> 39
-1.217227e+01 3.842913e+00 3.533644e+00 1.472756e-01 1.648457e+00 -7.514535e+00 1.386567e+00 -1.436491e+00 -3.542405e-01 -1.861192e+00 4.071339e-01 -3.814390e+00 6.159630e+01 1.141078e-01 -1.565576e+00 -1.964019e-01 -1.410935e+00 -1.062007e+00 -2.575727e+00 -8.264967e-01 5.880688e-01 -7.851771e-01 7.808987e-01 5.518509e-01 -4.987149e-03 2.402865e+00 3.024479e-01 -2.217661e-01 1.633340e-01 -3.199436e-01 -1.993721e-01 -2.153498e-01 -2.831185e-02 8.236580e-02 -7.390657e-02 7.967819e-03 -9.346215e-02 -2.085769e-01 -8.045533e-02
<VARIANCE> 39
8.169442e+01 2.182631e+01 2.887436e+01 2.753969e+01 3.400240e+01 1.431584e+02 2.239446e+01 1.232833e+01 2.568959e+01 1.581773e+01 7.711698e+00 1.187034e+01 5.946759e+01 1.733037e+01 2.438734e+00 5.834223e+00 3.114666e+00 4.429817e+00 1.007105e+01 1.498500e+00 1.663006e+00 2.161969e+00 1.613664e+00 1.056348e+00 2.725916e+00 1.779367e+00 3.079589e+00 5.794673e-01 1.059528e+00 3.519869e-01 4.966784e-01 2.036953e+00 3.298393e-01 3.083083e-01 5.409558e-01 3.534068e-01 2.059905e-01 3.885967e-01 3.535298e-01
<GCONST> 1.208999e+02
<STATE> 3
<MEAN> 39
-7.906535e-01 -1.041732e+01 2.766007e+00 -1.341644e+01 -8.674352e+00 -2.316298e+01 -5.542252e+00 4.780799e+00 -1.234228e+00 1.429336e+00 -6.335033e-01 -8.366649e+00 7.366433e+01 2.875266e-01 -2.754755e-01 -8.747131e-01 -1.874051e-01 3.088014e-01 1.001068e+00 -1.495176e-01 -3.033022e-01 3.986614e-01 -5.198545e-02 4.518696e-01 3.981968e-02 1.016811e-01 -6.619872e-02 2.078234e-01 -1.152948e-02 -2.717815e-02 1.940995e-01 2.248549e-01 1.548931e-01 -1.542719e-01 -1.044020e-01 -5.847171e-02 1.568739e-01 8.602078e-02 -1.004811e-01
<VARIANCE> 39
8.117218e+00 2.026274e+00 3.109494e+01 4.293981e+01 8.363704e+00 2.419632e+01 1.162494e+01 1.057546e+01 2.276046e+01 7.815707e+00 1.434899e+01 1.773967e+01 6.322599e+00 5.111328e-01 5.991596e-01 9.597199e-01 7.079209e+00 1.249156e+00 2.143095e+00 1.288905e+00 1.065011e+00 1.870619e+00 9.363415e-01 3.364549e+00 2.307021e+00 1.013867e+00 1.423830e-01 1.025852e-01 2.221691e-01 1.316545e+00 1.851659e-01 2.836960e-01 3.236317e-01 8.290850e-02 3.086341e-01 2.339674e-01 3.694269e-01 4.403385e-01 2.486919e-01
<GCONST> 9.116265e+01
<STATE> 4
<MEAN> 39
2.184827e+00 -5.833997e+00 -5.189749e+00 -2.197671e+01 -2.865399e+00 -7.114503e-01 5.805620e+00 -3.737938e+00 -1.543275e+00 1.310084e+00 1.105157e+01 -2.567401e+00 6.105442e+01 -5.570874e-01 4.473169e-01 3.408257e-01 2.383701e-01 1.333299e-01 5.111523e-01 5.469086e-01 -5.796339e-02 2.068227e-01 -1.610779e-01 -4.066597e-01 5.497510e-01 -1.642352e+00 -5.422474e-02 -5.401250e-02 6.285939e-02 2.781239e-01 -5.359057e-02 -1.685091e-01 -1.707469e-01 1.139030e-01 1.112104e-01 -1.098443e-02 -2.178366e-01 -5.832497e-03 1.543439e-02
<VARIANCE> 39
2.196155e+01 1.055286e+01 9.057457e+00 4.349560e+01 1.064939e+01 1.313586e+01 2.537523e+01 9.385870e+00 1.420036e+01 1.470367e+01 1.630179e+01 2.157984e+01 1.038633e+02 1.358882e+00 8.379121e-01 1.497464e+00 6.105309e+00 1.433039e+00 1.278445e+00 3.454720e+00 1.076635e+00 1.621630e+00 1.897718e+00 1.664000e+00 5.681398e-01 1.261837e+00 1.516891e-01 1.698446e-01 2.700627e-01 5.573735e-01 2.880323e-01 1.504418e-01 2.873333e-01 2.300760e-01 2.547979e-01 3.564235e-01 2.485776e-01 1.145405e-01 2.613668e-01
<GCONST> 9.621539e+01
<TRANSP> 5
0.000000e+00 1.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
0.000000e+00 9.030307e-01 9.696929e-02 0.000000e+00 0.000000e+00
0.000000e+00 0.000000e+00 9.423689e-01 5.763115e-02 0.000000e+00
0.000000e+00 0.000000e+00 0.000000e+00 9.423156e-01 5.768438e-02
0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00
<ENDHMM>
hmm0内の初期値から値が変更されています。この、HMMの初期値の設定と学習をほかのone~nineのファイルに対して繰り返します。
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/one.hmm -l one -L label one
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/one.hmm -l one -L label one
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/two.hmm -l two -L label two
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/two.hmm -l two -L label two
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/three.hmm -l three -L label three
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/three.hmm -l three -L label three
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/four.hmm -l four -L label four
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/four.hmm -l four -L label four
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/five.hmm -l five -L label five
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/five.hmm -l five -L label five
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/six.hmm -l six -L label six
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/six.hmm -l six -L label six
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/seven.hmm -l seven -L label seven
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/seven.hmm -l seven -L label seven
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/eight.hmm -l eight -L label eight
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/eight.hmm -l eight -L label eight
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/nine.hmm -l nine -L label nine
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/nine.hmm -l nine -L label nine
>HInit -T 1 -S trainlist.txt -M hmm0 -H proto/sil.hmm -l sil -L label sil
>HRest -T 1 -S trainlist.txt -M hmm1 -H hmm0/sil.hmm -l sil -L label sil
終了したら、hmm1フォルダのファイルを結合し、hmmdefs.hmmというファイル名でspeechフォルダに保存します。
Windowsだと、以下のようなコマンドで結合できます。
>copy /b hmm1\*.hmm hmmdefs.hmm
作成したHMMのHMM名の一覧のファイルも作成します。
zero
one
two
three
four
five
six
seven
eight
nine
sil
数字の認識
いよいよ、数字を認識してみます。
認識の対象として、「無音」+「数字」+「無音」という並びを対象にして、一つの数字を認識してみます。
以下のように文法定義ファイルを準備します。
$WORD = ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE;
({SIL} [$WORD] {SIL})
1行目で変数の定義をし、2行目でその定義を使った正規表現を指定しています。
SILは無音を表します。{SIL}は無音が0回以上繰り返される指定です。[$WORD]は、$WORDが0回か1回出現することを指定しています。
この文法定義からHParseを使って認識のためのHMMネットワークを作成します。
HParse 文法ファイル名 ネットワークファイル名
ここでは、以下のコマンドを実行します。
>HParse grammar.txt net.slf
net.slfを確認してみます。
VERSION=1.0
N=16 L=28
I=0 W=SIL
I=1 W=!NULL
I=2 W=NINE
I=3 W=EIGHT
I=4 W=SEVEN
I=5 W=SIX
I=6 W=FIVE
I=7 W=FOUR
I=8 W=THREE
I=9 W=TWO
I=10 W=ONE
I=11 W=ZERO
I=12 W=SIL
I=13 W=!NULL
I=14 W=!NULL
I=15 W=!NULL
J=0 S=1 E=0
J=1 S=13 E=0
J=2 S=0 E=1
J=3 S=2 E=1
J=4 S=3 E=1
J=5 S=4 E=1
J=6 S=5 E=1
J=7 S=6 E=1
J=8 S=7 E=1
J=9 S=8 E=1
J=10 S=9 E=1
J=11 S=10 E=1
J=12 S=11 E=1
J=13 S=13 E=2
J=14 S=13 E=3
J=15 S=13 E=4
J=16 S=13 E=5
J=17 S=13 E=6
J=18 S=13 E=7
J=19 S=13 E=8
J=20 S=13 E=9
J=21 S=13 E=10
J=22 S=13 E=11
J=23 S=13 E=12
J=24 S=12 E=13
J=25 S=15 E=13
J=26 S=1 E=14
J=27 S=13 E=14
次に、単語辞書を作成します。単語辞書は、単語 出力文字列 HMM名 という順番で記述します。
ZERO [zero] zero
ONE [one] one
TWO [two] two
THREE [three] three
FOUR [four] four
FIVE [five] five
SIX [six] six
SEVEN [seven] seven
EIGHT [eight] eight
NINE [nine] nine
SIL [sil] sil
以上で準備完了です。HViteで認識してみましょう。
HVite [オプション] 単語辞書ファイル名 HMMリスト名 入力ファイル名
オプションは以下を指定します。
-T Num 出力トレースレベルを指定する
-H hmmFile HMM構成ファイル名を指定する
-i resultFile 認識結果ファイル名を指定する
-w networkFile ネットワークファイル名を指定する
以下のコマンドを実行します。
>HVite -T 1 -H hmmdefs.hmm -i reco.mlf -w net.slf voca.txt hmmlist.txt mfcc/data0-1.mfc
コマンドラインには以下のように出力されました。
Read 11 physical / 11 logical HMMs
Read lattice with 16 nodes / 28 arcs
Created network with 30 nodes / 42 links
File: mfcc/data0-1.mfc
SIL SIL SIL ZERO SIL == [123 frames] -75.9633 [Ac=-9343.5 LM=0.0] (Act=27.7)
reco.mlfには以下のように出力されました。
#!MLF!#
"mfcc/data0-1.rec"
0 1100000 sil -836.290894
1100000 3100000 sil -1489.876709
3100000 4600000 sil -1255.839355
4600000 9400000 zero -3558.776611
9400000 12300000 sil -2202.708740
.
0.46秒から0.94秒の間で「zero」が認識されています。ラベル付けしたものを確認してみると、大体そのあたりで「zero」が発生されています。
これ面白いです。
新しい音声での認識実験
上の実験では、学習に使用した音声を使った認識実験でしたので、新しく音声を録音してきちんと認識できるかを実験してみます。
WaveSurferで「6」の音声を新たに録音しました。
これで、認識してみましょう
まずは、録音した音声の特徴量を抽出します。
testフォルダ配下に以下のファイルを作成します。区切り文字はタブでしたね。
test/test6-1.wav test/test6-1.mfc
用意ができたら、HCopyコマンドで特徴を抽出する。
>HCopy.exe -C config.hcopy -S test/script.hcopy
コマンド実行が成功したら、testフォルダ内にtest6-1.mfcという特徴量のファイルが出来上がります。
HViteで認識してみましょう。
>HVite -T 1 -H hmmdefs.hmm -i reco.mlf -w net.slf voca.txt hmmlist.txt test/test6-1.mfc
以下のようなログが出力されました。6と認識されています!
Read 11 physical / 11 logical HMMs
Read lattice with 16 nodes / 28 arcs
Created network with 30 nodes / 42 links
File: test/test6-1.mfc
SIL SIL SIL SIX SIL SIL == [167 frames] -70.3251 [Ac=-11744.3 LM=0.0] (Act=27.8)
これがどのくらい6と認識されたのか、認識率の評価をしてみます。
認識率の評価は、HResltコマンドを使用します。
HResults [オプション] HMMリスト名 認識結果ファイル名
オプションは以下の通りです。
-e label1 label2 ラベル2をラベル1に置き換える
-I refFile 正解ファイル名を指定
-L labelFolder ラベルファイルのフォルダを指定
まずは、実験用の音声にラベル付けをして、test/ref.mlfに保存します。
正解ファイル名のリストを作成します。
#!MLF!#
"label"
test6-1.lab
下記のコマンドで認識率を出力してみます。
>HResults -T 1 -e "???" sil -I test/ref.mlf -L test hmmlist.txt reco.mlf
-e "???" sil で、silが正解の集計に影響なしとするように指定しています。"???"はラベルなしの意味です。
以下の結果が出力されました。
====================== HTK Results Analysis =======================
Date: Sat Dec 14 11:59:55 2019
Ref : test/ref.mlf
Rec : reco.mlf
------------------------ Overall Results --------------------------
SENT: %Correct=100.00 [H=1, S=0, N=1]
WORD: %Corr=100.00, Acc=100.00 [H=1, D=0, S=0, I=0, N=1]
===================================================================
100パーセントの認識率です。大成功です。
動的音声認識
動的な音声認識もできます。
まずは、以下の設定ファイルを用意します。
SOURCEFORMAT = HTK
SOURCEKIND = HAUDIO
SOURCERATE = 625
TARGETKIND = MFCC_0_D_A
TARGETRATE = 100000.0
WINDOWSIZE = 250000.0
USEHAMMING = T
PREEMCOEF = 0.97
NUMCHANS = 24
NUMCEPS = 12
USESILDET = T
MEASURESIL = F
OUTSILWARN = T
ENORMALISE = F
下記のコマンドで、動的認識が開始しますので、マイクに向かって数字を言ってみましょう。
>HVite -C config.hvite-mic -H hmmdefs.hmm -i reco.mlf -w net.slf voca.txt hmmlist.txt
下記のような結果が出力されました。
Please speak sentence - measuring levels
Level measurement completed
SIL == [67 frames] -63.5110 [Ac=-4255.2 LM=0.0] (Act=27.5)
READY[2]>
SIL SIL SIX SIL SIL SIL == [237 frames] -67.8191 [Ac=-16073.1 LM=0.0] (Act=27.9)
READY[3]>
SIL SIX SIL SIL SIL SIL == [244 frames] -68.0448 [Ac=-16602.9 LM=0.0] (Act=27.9)
READY[4]>
SIL SIL SIL EIGHT SIL SIL SIL SIL SIL == [271 frames] -69.0263 [Ac=-18706.1 LM=0.0] (Act=27.9)
READY[5]>
SIL FOUR SIL == [111 frames] -69.6964 [Ac=-7736.3 LM=0.0] (Act=27.7)
READY[6]>
SIL THREE SIL SIL SIL SIL == [221 frames] -65.9460 [Ac=-14574.1 LM=0.0] (Act=27.9)
READY[7]>
SIL NINE SIL SIL == [129 frames] -69.9172 [Ac=-9019.3 LM=0.0] (Act=27.8)
動的認識がきちんとなされています。
終わりに
今回は、数字1文字の認識でしたが、HTKを使うと連続数字の認識も可能ですので、やってみてください。
この本でも演習問題として連続数字の認識が課題となってます。おそらく、grammar.txtを以下のように変えればできると思います。
$WORD = ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE;
({SIL} <$WORD SIL> {SIL})
$WORD と SILを繰り返すように指定しています。$WORDと$WORDの間に無音声が入らない場合は、
$WORD = ZERO | ONE | TWO | THREE | FOUR | FIVE | SIX | SEVEN | EIGHT | NINE;
({SIL} <$WORD [SIL]> {SIL})
とすればいいと思います。もっといい方法があったら教えてください。
もし、音声や各設定ファイルの需要がありましたらGitにアップしますので言ってください。私の声でよければ・・・w。