6.8.2 KaldiDecoder

6.8.2.1 概要

KaldiDecoder は,深層学習を利用した音声認識ツールキットKaldi 1 のライブラリを用いてHARK  用に作られたデコーダである.HARK  2.2.0 までは,大語彙音声認識システムJulius をもとに追加機能を実装したJuliusMFT を提供していたが,近年の動向を反映しHARK  2.3.0 からは,Kaldi に対応するKaldiDecoder の提供も開始する.

Kaldi の標準デコーダと比較して,KaldiDecoder には下記に挙げる特徴がある.

  1. HARK  モジュールとの接続性(JuliusMFT と同じように扱える)

    • MSLS,MFCC特徴量のネットワーク経由の入力(mfcnet)に対応

    • 音源情報(SrcInfo) の追加に対応

    • 同時発話への対応(排他処理)

    いずれも,従来のJuliusMFT と同様にSpeechRecognitionClient (またはSpeechRecognitionSMNClient )を使ってHARK  と接続出来る.

  2. JuliusMFT との互換性

    • JuliusMFT 出力エミュレーション(モジュールモード及び標準出力の書式)に対応

    KaldiDecoder はJuliusMFT の出力を可能な範囲で再現しているため,JuliusMFT を用いて構築された既存システム(デモやスコアリング評価のシステム)に対する変更が最小限で済むように作られている.

  3. Kaldi への追加機能

    • nnet1モデルのオンラインデコードに対応

    Kaldi の標準デコーダではnnet1モデルについてオフラインデコードのみ対応となっている.

  4. 未実装機能

    • ミッシングフィーチャー(ただし,mfcnetのマスク付きデータ構造には対応している)

    • nnet2モデルおよびnnet3モデル

上記1〜3の実装に関しては,Kaldi 本体に変更を加えない形で実装を行った.

以下のセクションではKaldiDecoder のインストール方法,使用方法を説明するとともに,FlowDesigner 上のHARK  モジュールとの接続について,解説する.

6.8.2.2 起動と設定

KaldiDecoder の実行は,例えば設定ファイル名を kaldi.conf とすれば,以下のように行う.

  > kaldidecoder --config=kaldi.conf (Ubuntu版)
  > kaldidecoder.exe --config=kaldi.conf (Windows版)

HARK  では,KaldiDecoder をオンラインモードで起動したのち, IPアドレスやポート番号が正しく設定された SpeechRecognitionClient (またはSpeechRecognitionSMNClient ) を含んだネットワークを起動することにより,KaldiDecoder とのソケット接続が行われ, 音声認識が可能な状態となる.

上述の kaldi.conf はKaldiDecoder の設定を記述したテキストファイルで ある.設定ファイルの中身は,基本的に “--” で始まる引数オプションからなっており, 起動時に直接,KaldiDecoder のオプションとして引数指定することも可能で ある.また,# 以降はコメントとして扱われる.KaldiDecoder で用いるオプションは,

  > kaldidecoder --help (Ubuntu版)
  > kaldidecoder.exe --help (Windows版)

を実行することで確認する事が出来るので,そちらを参照していただきたいが, nnet1のモデルを使用する場合に最低限必要な設定は,以下の7種類である.

オフラインデコードの場合には,下記のように評価対象の特徴量ファイルリストを指定する. 指定しない場合は,自動的にオンラインデコード(mfcnet入力)で起動したと判断される.

オンラインデコードでmfcnet入力ポート,または結果出力ポートを変更したい場合には 下記のように指定出来る.下記はデフォルトポート(変更なし)である.

  1. 基本設定(入力ファイルと動作モードの設定)

    • --nnet-type=モデル形式

      Kaldi におけるnnetモデル形式を指定する.初期値は1である. 現在のバージョンでは1のみ動作し,残りのnnetモデル形式には将来のバージョンで対応する. Karel Veselyの手法で作成された nnet1 モデルを指定する場合は 1, Daniel Poveyの手法で作成された nnet2 モデルを指定する場合は 2, Daniel Poveyの手法で作成された nnet3 モデルを指定する場合は 3 を指定する.

    • --filename-words=単語リストファイル名

      単語リストファイルを指定する. 引数にカレントディレクトリからの相対パス,もしくは絶対パスを指定する. 単語リストファイルの書式は Kaldi の学習や検証で使用するLexiconディレクトリ または,評価で使用する言語モデルに含まれる words.txt と同じ形式である. なお,認識結果の出力に必要であるため本オプションは必須である.

    • --filename-phones=音素リストファイル名

      音素リストファイルを指定する. 引数にカレントディレクトリからの相対パス,もしくは絶対パスを指定する. 音素リストファイルの書式は Kaldi の学習や検証で使用するLexiconディレクトリ または,評価で使用する言語モデルに含まれる phones.txt と同じ形式である. なお,音素アラインメントを行う場合にのみ必要であり,本オプションは任意である.

    • --filename-align-lexicon=語彙ファイル名

      語彙ファイルを指定する. 引数にカレントディレクトリからの相対パス,もしくは絶対パスを指定する. 語彙ファイルの書式は Kaldi の学習や検証で使用するLexiconディレクトリ または,評価で使用する言語モデルに含まれる align_lexicon.int と同じ形式である. ここで指定する語彙ファイルは,prepare_lang.pl を用いて lang ディレクトリを作成しているなら lang/phones/aligned_lexicon.int に出力される. なお,認識結果の出力に必要であるため本オプションは必須である.

    • --filename-feature-transform=FeatureTransformファイル名

      FeatureTransformファイルを指定する. ここで指定するFeatureTransformファイルは,DNN学習を行った出力先の exp/tri*dnn*/final.feature_transform に出力される. なお,nnet1 形式では音響モデルと別ファイルとなっているためnnet1 形式の場合, 本オプションは必須である.

    • --filename-nnet=nnetファイル名

      nnetファイルを指定する. ここで指定するnnetファイルは,DNN学習を行った出力先の
      exp/tri*dnn*/final.nnet (注:これはSymbolicLinkである)に出力される. なお,nnet1 形式では音響モデルと別ファイルとなっているためnnet1 形式の場合, 本オプションは必須である.

    • --filename-mdl=mdlファイル名

      mdlファイルを指定する. ここで指定するmdlファイルは,DNN学習を行った出力先の
      exp/tri*dnn*/final.mdl (注:これはSymbolicLinkである)に出力される. なお,音響モデルは認識結果の出力に必要であるため本オプションは必須である.

    • --filename-class-frame-counts=クラスフレーム数ファイル名

      クラスフレーム数ファイルを指定する. ここで指定するmdlファイルは,DNN学習を行った出力先の exp/tri*dnn*/ali_train_pdf.counts に出力される. なお,nnet1 形式では音響モデルと別ファイルとなっているためnnet1 形式の場合, 本オプションは必須である.

    • --filename-fst=FSTファイル名

      FSTファイルを指定する. ここで指定するFSTファイルは,mkgraph.sh を用いて graph ディレクトリを作成しているなら graph*/HCLG.fst に出力される. なお,FSTファイルは認識結果の出力に必要であるため本オプションは必須である.

    • --filename-features-list=特徴量リストファイル名

      KaldiDecoder がオフラインデコードを行う場合に, 評価したい特徴量のファイル名(Path付き)がリストアップされた テキストファイルを指定する.(特徴量のファイル名ではないので注意する事) 本オプションが指定されない場合は,オンラインデコードを行う.

    • --port-mfcnet=ポート番号

      SpeechRecognitionClient (または,SpeechRecognitionSMNClient )から 送信される音響特徴量とマスクをネットワーク経由で受信するポート番号を指定する. これはJuliusMFT の mfcnet 入力ポート指定 “-adport” と同様である. 指定がない場合はJuliusMFT のデフォルトと同じ 5530 が設定される. オンラインデコード時のみ有効なオプション.

    • --port-result=ポート番号

      認識結果の出力をネットワーク経由で送信するポート番号を指定する. これはJuliusMFT のモジュールモード出力ポート指定 “-module” と同様である. 指定がない場合はJuliusMFT のデフォルトと同じ 10500 が設定される.

    • --lm-name

      言語モデル名を指定する.指定するとモジュールモード出力時に LMNAME 属性を付与する. 初期値は指定なし.

  2. デコーダのチューニング関連設定(重み付けと枝刈りの設定) 本項目はKaldi のデコーダ(クラス)で実装されている機能から継承されたオプションである.

    • --acoustic-scale=音響スケール

      音響スケールを指定する.初期値は0.5である.一般的にスコアリングで得られた最適なLMウェイトの逆数となる.
      参考: https://sourceforge.net/p/kaldi/discussion/1355348/thread/924c555b/

    • --max-active

      デコーダの最大活性状態数を指定する. 大きくするとより正確になるが遅くなる.初期値は2147483647(int32の最大値)である. 経験上,2000から5000の間ぐらいで指定する事を推奨.

    • --min-active

      デコーダの最小活性状態数を指定する.初期値は200である.

    • --beam=ビーム幅

      デコード処理のビーム幅を指定する.大きくするとより正確になるが遅くなる.初期値は16である. 詳細は引用6.125を参照.

    • --beam-delta=ビーム差分

      デコード処理のビーム差分を指定する. デコード処理に使われるこのパラメータは漠然とmax-activeの制約が適用された方法での高速化に関係する. 大きくするとより正確になる.初期値は0.5である.詳細は引用6.125を参照.

    • --delta=デルタ

      決定化に使用される許容範囲.初期値は0.000976562である. 詳細は引用6.125を参照.

    • --hash-ratio

      デコーダで使用されるハッシュ動作を制御するための指定.初期値は2である.

    • --prune-interval=フレーム数

      指定したフレーム間隔でトークンを枝刈りする.初期値は25である.

    • --splice=スプライス数

      DNN入力のスプライス数を指定する.現在フレーム周辺のコンテキストのフレーム数.初期値は3である. 初期値3の場合,前後に3フレームある事を意味する.

    これはKaldi のサイト(http://www.danielpovey.com/kaldi-docs/decoders.html)からの引用である.

    Table 6.125: FasterDecoder: a more optimized decoderからの引用

    
      The code in FasterDecoder as it relates to cutoffs is a little more complicated than just having the 
    one pruning step. The basic observation is this: it's pointless to create a very large number of tokens 
    if you are only going to ignore most of them later. So the situation in ProcessEmitting is: we have  
    "weight_cutoff" but wouldn't it be nice if we knew what the value of "weight_cutoff" on the next frame 
    was going to be? Call this "next_weight_cutoff". Then, whenever we process arcs that have the current 
    frame's acoustic likelihoods, we could just avoid creating the token if the likelihood is worse than 
    "next_weight_cutoff". In order to know the next weight cutoff we have to know two things. We have to 
    know the best token's weight on the next frame, and we have to know the effective beam width on the 
    next frame. The effective beam width may differ from "beam" if the "max_active" constraint is limiting, 
    and we use the heuristic that the effective beam width does not change very much from frame to frame. 
    We attempt to estimate the best token's weight on the next frame by propagating the currently best 
    token (later on, if we find even better tokens on the next frame we will update this estimate). We get 
    a rough upper bound on the effective beam width on the next frame by using the variable "adaptive_beam". 
    This is always set to the smaller of "beam" (the specified maximum beam width), or the effective beam 
    width as determined by max_active, plus beam_delta (default value: 0.5). When we say it is a 
    "rough upper bound" we mean that it will usually be greater than or equal to the effective beam width 
    on the next frame. The pruning value we use when creating new tokens equals our current estimate of the 
    next frame's best token, plus "adaptive_beam". With finite "beam_delta", it is possible for the pruning 
    to be stricter than dictated by the "beam" and "max_active" parameters alone, although at the value 0.5 
    we do not believe this happens very often.
        

    Povey, Daniel:
    引用元: [http://www.danielpovey.com/kaldi-docs/decoders.html#decoders_faster]: 3項: [2016年12月16日]
        

  3. Lattice関連設定 本項目はKaldi のデコーダ(クラス)で実装されている機能から継承されたオプションである.

    • --determinize-lattice

      Latticeを決定化する.Lattice決定化は各単語順序のために最良のPDF(確率分布関数)順序のみを保持する.

    • --lattice-beam=ビーム幅

      Lattice生成ビーム幅.大きいほどLatticeが深くなり遅い.初期値は10である.

    • --max-mem=最大メモリ確保サイズ

      Latticeの決定化における,おおよその最大メモリ確保サイズを指定する. 但し,実際のメモリ使用量はここで指定された確保サイズで,複数回行われる可能性がある.

    • --minimize

      このオプションを指定すると,決定化の後でLatticeの最小化を行う.

    • --phone-determinize

      このオプションを指定すると,音素と単語両方に関する決定化の第一パスを行う.“--word-determinize”を参照.

    • --word-determinize

      このオプションを指定すると,単語のみに関する決定化の第二パスを行う.“--phone-determinize”を参照.

  4. その他

    • --config=コンフィグファイル

      コンフィグファイルの指定.繰り返し指定可能.

    • --enable-debug

      このオプションを指定すると,デバッグ出力を有効にする.初期値は無効.

    • --help

      ヘルプの表示.このオプションが指定された場合,他のすべてのオプションは無視されます.

    • --print-args

      このオプションを指定すると,コマンドライン引数の内容を標準出力へ出力する.初期値は有効. 無効にする場合,“--print-args=false”と指定する.

    • --verbose=ログレベル

      ログの詳細レベルを指定する.大きいほどより詳細にログを取る.初期値は0である.

なお,Julius や,JuliusMFT でモジュールモードと呼ばれていた機能は オンラインデコードを選択すると自動的に有効になる. その場合,Julius や,JuliusMFT のように標準出力が停止することはなく 標準出力とソケット出力の両方が利用できる.


6.8.2.3 詳細説明

6.8.2.3.1 mfcnet通信仕様

 

mfcnet を入力として利用するには,上述のように,KaldiDecoder 起動時に“--filename-features-list” を引数として指定しなければ良い.この際,KaldiDecoder は TCP/IP 通信サーバとなり,接続待ちとなる. また,HARK  のモジュールであるSpeechRecognitionClient や,SpeechRecognitionSMNClient は, 音響特徴量とミッシングフィーチャーマスクをKaldiDecoder に送出するためのクライアントとして動作する. クライアントは,1発話ごとにKaldiDecoder に接続し,送信終了後ただちに接続を切断する. 送信されるデータはリトルエンディアンである必要がある(ネットワークバイトオーダーでないことに注意). 具体的には,1発話に対して以下の流れで通信を行う.

  1. ソケット接続

    ソケットを開き,KaldiDecoder の mfcnet 指定ポート番号に接続.

  2. 通信初期化(最初に1回だけ送信するデータ)

    クライアントから,ソケット接続直後に1回だけ, 表 6.126に示すこれから送信する音源に関する情報を送信する. 音源情報は SourceInfo 構造体(表 6.127)で表され, 音源ID,音源方向,送信を開始した時刻を持つ.時刻は,<sys/time.h>で定義されている timeval 構造体で表し,システムのタイムゾーンにおける紀元(1970年1月1日00:00:00)からの経過時間である. 以後,時刻は紀元からの経過時間を指すものとする.

  3. データ送信(毎フレーム送信するデータ)

    音響特徴量とミッシングフィーチャーマスクを送信する. 表 6.128 に示すデータを1フレームとし,1発話の特徴量を 音声区間が終了するまで繰り返し送信する.特徴量ベクトルとマスクベクトルの次元数 は同じ大きさであることがKaldiDecoder 内部で仮定されている.

  4. 終端処理(最後に1回だけ送信するデータ)

    1音源分の特徴量を送信し終えたら,終端を示すデータ(表 6.129)を送信する. KaldiDecoder は終端を示すデータが送信されるかソケットが切断されない限り,データが継続するものとして 次フレームの受信を待機し続ける.よってある程度不安定な通信環境であってもデータ受信を再開する事が出来る.

  5. ソケット切断

    終端処理を行った後,ソケットを閉じる. 終端処理を行わずにソケットを閉じた場合,異常系の処理が走るため認識結果の出力が遅れる場合がある. また,終端処理後にデータを送出した場合,ソケットを閉じていなくても該当のデータは無視される.

    Table 6.126: 最初に1回だけ送信するデータ(音源情報を示すデータ)

    サイズ[byte]

    送信するデータ

    4

    int 

    28 (= sizeof(SourceInfo))

    28

    SourceInfo

    これから送信する特徴量の音源情報


    Table 6.127: SourceInfo 構造体

    メンバ変数名

    説明

    source_id

    int 

    音源ID

    azimuth

    float 

    水平方向[deg]

    elevation

    float 

    垂直方向[deg]

    time

    timeval

    時刻(64 bit 処理系に統一,サイズは16バイト)


    Table 6.128: 毎フレーム送信するデータ(特徴量とマスクデータ,および次元数情報)

    サイズ[byte]

    送信するデータ

    4

    int 

    N1=(特徴量ベクトルの次元数)$\times $ sizeof(float )

    N1

    float [N1]

    特徴量ベクトル(float配列)

    4

    int 

    N2=(マスクベクトルの次元数) $\times $ sizeof(float )

    N2

    float [N2]

    マスクベクトル(float配列)


    Table 6.129: 最後に1回だけ送信するデータ(終端を示すデータ)

    サイズ[byte]

    送信するデータ

    4

    int 

    0


6.8.2.3.2 モジュールモード通信仕様

 

オンラインデコードを指定するとJulius と同様にモジュールモードで動作させることができる. モジュールモードでは,KaldiDecoder がTCP/IP通信のサーバとして機能し, 認識結果を jcontrol などのクライアントに提供する. 日本語文字列の文字コードは,言語モデルの文字コードに依存する. データ表現にはJulius と同様に XML ライクな形式が用いられており, 一つのメッセージごとにデータの終了を表す目印として “.”(ピリオド)が送信される. また,KaldiDecoder の追加機能で “.”(ピリオド)を使用せず XML 準拠で出力することも出来る. KaldiDecoder で送信される代表的なタグの意味は以下の通りである.

オリジナルのJulius と比較した場合,KaldiDecoder における変更点は,以下の2点である.


6.8.2.3.3 KaldiDecoder 出力例

 

  1. 標準出力の出力例

    
     source_id = 0, azimuth = 5.000000, elevation = 16.700001, sec = 1268718777, usec =
      474575
     ### Recognition: 2nd pass (RL heuristic best-first)
     STAT: 00
     sentence1: 注文 お 願い し ます
     wseq1: 注文+名詞 お+接頭辞 願い+名詞 し+動詞 ます+助動詞
     phseq1: ch ch ch u: u: u: u: u: m m m o o N N N o o n n n e e e g g a a i i sh sh 
     i i i m m a a a a a s s s u u u
     cmscore1: 1.000 1.000 1.000 1.000 1.000
     score1: 403.611786 ( AM: 409.323194, LM: -5.711408 )
    
    

  2. ソケット出力(モジュールモード)の出力例

    
     <SOURCEINFO SOURCEID="0" AZIMUTH="5.000000" ELEVATION="16.700001" SEC="1268718638"
     USEC="10929"/>
     .
     <STARTRECOG SOURCEID="0"/>
     .
     <ENDRECOG SOURCEID="0"/>
     .
     <RECOGOUT SOURCEID="0">
       <SHYPO RANK="1" SCORE="403.611786" AMSCORE="409.323194" LMSCORE="-5.711408">
         <WHYPO WORD="注文" CLASSID="注文+名詞" PHONE="" CM="1.000"/>
         <WHYPO WORD="お" CLASSID="お+接頭辞" PHONE="" CM="1.000"/>
         <WHYPO WORD="願い" CLASSID="願い+名詞" PHONE="" CM="1.000"/>
         <WHYPO WORD="し" CLASSID="し+動詞" PHONE="" CM="1.000"/>
         <WHYPO WORD="ます" CLASSID="ます+助動詞" PHONE="" CM="1.000"/>
       </SHYPO>
     </RECOGOUT>
     .
    
    

6.8.2.4 注意事項


6.8.2.5 インストール方法


Footnotes

  1. http://kaldi-asr.org/