% cd ~ % tar xvfz HTK-3.0.tar.gz
% patch -p0 < htk-20020109.diff
% cd ~/htk/HTKLib % source ~/htk/env/env.linux % makeこれで HTKLib.linux.a ができる
% mkdir ~/htk/bin (もし初めてであれば) % mkdir ~/htk/bin/bin.$CPU (もし初めてであれば) % cd ~/htk/HTKTools % source ~/htk/env/env.linux % setenv HBIN ~/htk/bin % makeこれで HTKTools の中身ががすべてコンパイルされ、~/htk/bin/bin.linux に収まる。ここに PATH を通しておくと良い。
% setenv PATH ~/htk/bin/bin.linux:$PATH
ASCIIで記述された数字の羅列を HTK フォーマットに変換する HAscii2Bin を使う。
まず、HAscii2Bin のコンパイル
% cd ~/htk/contrib % gcc HAscii2Bin.c -g -o ../bin/bin.linux/HAscii2Bin -lmそしてデータファイルを用意して、HAscii2Bin でバイナリに変換。 今回は一次元のベクターから YAMA と TANI の二種類のHMMの認識を行う。
% mkdir ~/htk/work/tr (トレーニングデータを置くディレクトリ)
% cd ~/htk/work/tr
% cat >! yama1
3.2 3 3 3 4.1 4 4 5.3 5.2 5.2 5.5 5.1 5.2 4 4.2 4 4 3.5 3.7 3 3 3.1
^D
% cat >! yama2
2.8 3.2 3.8 3.3 3.5 4.1 4 4.7 5.1 5.2 5.2 5.2 4.7 4.2 4 4 3.5 3.7 3 3 3.1 3.2 2.7
^D
% HAscii2Bin yama1 1 (データが一次元なので'1'。HTKバイナリ形式のファイルには .ext が付く)
opening for data 4 yama1.ext
number of frames 23
% HAscii2Bin yama2 1
opening for data 4 yama2.ext
number of frames 24
% HList -h yama1.ext (データ確認には HList を使う)
---------------------------------- Source: yama1.ext -----------------------------------
Sample Bytes: 4 Sample Kind: USER
Num Comps: 1 Sample Period: 200.0 us
Num Samples: 23 File Format: HTK
------------------------------------ Samples: 0->-1 ------------------------------------
0: 3.200
1: 3.000
2: 3.000
3: 3.000
4: 4.100
5: 4.000
6: 4.000
7: 5.300
8: 5.200
9: 5.200
10: 5.500
11: 5.100
12: 5.200
13: 4.000
14: 4.200
15: 4.000
16: 4.000
17: 3.500
18: 3.700
19: 3.000
20: 3.000
21: 3.100
22: 3.100
----------------------------------------- END ------------------------------------------
この調子で yama3,4 も作成し、変換。tani1,2 は谷とする。
% cat >! tani1 3.2 3.1 3 3.1 2.7 2.3 2.1 2.1 1.9 1.5 1.6 1.1 1.3 2.0 2.8 2.3 2.9 2.9 3 3.3 3 3 ^D % cat >! tani2 3.0 3.1 3 3.1 2.7 2.5 2.3 2.1 2.1 1.9 1.5 1.6 1.3 1.3 1.1 1.3 2.0 2.8 2.3 2.7 2.9 2.9 3 3.3 3 3 3.2 ^D % HAscii2Bin tani1 1 opening for data 4 tani1.ext number of frames 23 % HAscii2Bin tani2 1 opening for data 4 tani2.ext number of frames 28同様に tani3,4 も作成後、変換。トレーニングファイルのリストも作成。
% cat >! ~/htk/work/trfiles tr/tani1.ext tr/tani2.ext tr/tani3.ext tr/tani4.ext tr/yama1.ext tr/yama2.ext tr/yama3.ext tr/yama4.ext ^D
データ毎に yama1.lab, yama2.lab などと作っていっても良いが、ここでは一つのファイルに まとめて記述する。
% cd ~/htk/work % cat >! yamatani.mlf #!MLF!# "*/yama*.lab" YAMA . "*/tani*.lab" TANI . ^D
まず入れ場所を用意。
% cd ~/htk/work % mkdir hmm0 hmm1 hmm2 hmm3 hmm4 hmm5 hmm6次ににプロトタイプ HMM を作る。
% cd ~/htk/work
% cat >! proto
~o <VecSize> 1 <USER>
~h "proto"
<BeginHMM>
<NumStates> 5
<State> 2
<Mean> 1
0.0
<Variance> 1
1.0
<State> 3
<Mean> 1
0.0
<Variance> 1
1.0
<State> 4
<Mean> 1
0.0
<Variance> 1
1.0
<TransP> 5
0.0 1.0 0.0 0.0 0.0
0.0 0.6 0.4 0.0 0.0
0.0 0.0 0.6 0.4 0.0
0.0 0.0 0.0 0.7 0.3
0.0 0.0 0.0 0.0 0.0
<EndHMM>
^D
% HCompV -o YAMA -S trfiles -f 0.01 -m -M hmm0 proto (全データから mean と variance を求める)
% HCompV -o TANI -S trfiles -f 0.01 -m -M hmm0 proto
% HRest -v 0.01 -S trfiles -M hmm1 -I yamatani.mlf hmm0/YAMA
% HRest -v 0.01 -S trfiles -M hmm1 -I yamatani.mlf hmm0/TANI
% HERest -v 0.01 -S trfiles -d hmm1 -I yamatani.mlf -M hmm2 wlist (エンベデッドトレーニング)
% HERest -v 0.01 -S trfiles -H hmm2/newMacros -I yamatani.mlf -M hmm3 wlist
% HERest -v 0.01 -S trfiles -H hmm3/newMacros -I yamatani.mlf -M hmm4 wlist
% HERest -v 0.01 -S trfiles -H hmm4/newMacros -I yamatani.mlf -M hmm5 wlist
% HERest -v 0.01 -S trfiles -H hmm5/newMacros -I yamatani.mlf -M hmm6 wlist
計算結果は hmm6/newMacros に現れる
まず認識用のデータを作る
% mkdir ~/htk/work/te % cat >! ~/htk/work/te/yama5 3 3 3 3 3 4 4 4 5 5 5 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 ^D % cat >! ~/htk/work/te/tani5 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 3 3 ^D % HAscii2Bin tani5 1 opening for data 4 tani5.ext number of frames 35 % HAscii2Bin yama5 1 opening for data 4 yama5.ext number of frames 28 % cat >! ~/htk/work/tefiles te/yama5.ext te/tani5.ext ^D認識用の文法からラティス(wdnet)を作成
% cd ~/htk/work % cat >! grammar ( YAMA | TANI) ^D % HParse grammar wdnetHMMラベルと言葉の対応表を作る(今回のシンプルな例だとあまり意味は無い)
% cat >! ~/htk/work/dict YAMA YAMA TANI TANI ^Dtefiles 内のデータ(tani5, yama5)を viterbi にかけ、結果を見る
% cd ~/htk/work % HVite -T 1 -S tefiles -H hmm6/newMacros -i results -w wdnet dict wlist Read 2 physical / 2 logical HMMs Read lattice with 5 nodes / 5 arcs Created network with 9 nodes / 9 links File: te/yama5.ext YAMA == [28 frames] -0.4559 [Ac=-12.8 LM=0.0] (Act=6.6) File: te/tani5.ext TANI == [35 frames] -1.2518 [Ac=-43.8 LM=0.0] (Act=6.7)HVite の結果を HResult で yamatani.mlf と照らし合わせることができる。
% HResults -t -I yamatani.mlf wlist results
====================== HTK Results Analysis =======================
Date: Wed Jan 9 16:21:40 2002
Ref : yamatani.mlf
Rec : results
------------------------ Overall Results --------------------------
SENT: %Correct=100.00 [H=2, S=0, N=2]
WORD: %Corr=100.00, Acc=100.00 [H=2, D=0, S=0, I=0, N=2]
===================================================================
ということで、バッチ認識は成功。
元々 HTK には Audio を対象としたライブモードしか存在しないので、 HParm.c, HVite.c に手を加えた。HTK 自体に external function を 組み込むための仕組みが存在しているので (HParm.c:296-362行参照) 基本的には HMyFuncs.c で記述したように自分の関数をいくつか 書いて、HVite.c や HParm.c を調整すれば良い。例として出した HMyFuncs.c は scanf で一つづつ float 数字を拾いながら認識を 行っている。
HVite で認識を行う前に config ファイルを作る(バッチの様に、 へッダーからデータの情報を得られないため)。
% cd ~/htk/work % cat >! config SOURCEKIND = USER TARGETKIND = USER ^D後はライブ認識。-h でライブモードが音声ではなくデータであることを 指定して、-T (トレースレベル)を1か7に設定。1 の時はデータを全て 読み込んでから結果を表示、7 だとその時点でもっとも正しいと思われる 結果(その時点のトークンの所在)を逐一表示する。
% HVite -h -D -T 7 -C config -H hmm6/newMacros -i results -w wdnet dict wlist HTK Configuration Parameters[2] Module/Tool Parameter Value # TARGETKIND USER # SOURCEKIND USER Read 2 physical / 2 logical HMMs Read lattice with 5 nodes / 5 arcs Created network with 9 nodes / 9 links READY[1]> numer? (-1 to exit)> 3 0: 3.000 Optimum @1 HMM: YAMA (YAMA) 2 -0.284 numer? (-1 to exit)> 3.4 1: 3.400 Optimum @2 HMM: YAMA (YAMA) 2 -0.541 numer? (-1 to exit)> 3.4 2: 3.400 Optimum @3 HMM: YAMA (YAMA) 7 -0.627 numer? (-1 to exit)> 3.5 3: 3.500 Optimum @4 HMM: YAMA (YAMA) 7 -0.713 numer? (-1 to exit)> 4 4: 4.000 Optimum @5 HMM: YAMA (YAMA) 7 -1.041 numer? (-1 to exit)> 4.3 5: 4.300 Optimum @6 HMM: YAMA (YAMA) 7 -0.973 numer? (-1 to exit)> 4.5 6: 4.500 Optimum @7 HMM: YAMA (YAMA) 7 -0.907 numer? (-1 to exit)> 4.6 7: 4.600 Optimum @8 HMM: YAMA (YAMA) 7 -0.862 numer? (-1 to exit)> 5 8: 5.000 Optimum @9 HMM: YAMA (YAMA) 7 -0.867 numer? (-1 to exit)> 5 9: 5.000 Optimum @10 HMM: YAMA (YAMA) 7 -0.871 numer? (-1 to exit)> 5.3 10: 5.300 Optimum @11 HMM: YAMA (YAMA) 7 -0.923 numer? (-1 to exit)> 4.32 11: 4.320 Optimum @12 HMM: YAMA (YAMA) 7 -0.891 numer? (-1 to exit)> 3.4 12: 3.400 Optimum @13 HMM: YAMA (YAMA) 7 -0.969 numer? (-1 to exit)> 2 13: 2.000 Optimum @14 HMM: YAMA (YAMA) 7 -1.484 numer? (-1 to exit)> -1 14: 2.000 Optimum @15 HMM: YAMA (YAMA) 7 -1.930 YAMA == [15 frames] -3.0803 [Ac=-46.2 LM=0.0] (Act=6.3) READY[2]> numer? (-1 to exit)> %追記:後は自分の HMyFuncs.c を書いたり、データに differencial 属性をつけて認識の精度を上げたり、トレーニング量や文法に時間を かけて楽しむと良いでしょう。