Julius 独自辞書作成方法


Julius は数万語彙が登録されている汎用辞書がありますが、かんたんな挨拶や音声によるコマンド操作を行いたい場合、専用の辞書を作成したほうが認識率およびパフォーマンスが上がります。

Julius の辞書はコンパイルする必要があります。コンパイル環境は 32bit の Linux か Windows です。ここでは Ubuntu 16.04 Server 32bit LTS を使用します。

* 以下より ubuntu-16.04.1-server-i386.iso をダウンロードして使用しています。
    * http://tw.archive.ubuntu.com/ubuntu-cd/16.04.1/
* インストール時に OpenSSH server を有効にしています
* インストール後、特に `apt-get update` 等は行っていません

## 環境設定

Julius の grammar-kit は以下よりダウンロード可能です。

* http://julius.osdn.jp/index.php?q=grammar-kit.html

Git と ZIP があります。今回は ZIP を使用します。

```bash
$ sudo apt-get install unzip
$ sudo apt-get install libasound2
$ wget -c https://github.com/julius-speech/grammar-kit/archive/v4.3.1.zip
$ unzip v4.3.1.zip
$ chmod a+x grammar-kit-4.3.1/bin/linux/*
$ echo "export PATH=$PATH:~/grammar-kit-4.3.1/bin/linux" >> .bash_profile
$ source .bash_profile
$ mkdir ~/dict
```

## 辞書コンパイルの事前知識

Julius が返してくる結果の文字コードは、辞書ファイルの文字コードが適用されます。
つまり、プログラムが UTF-8 を期待しているなら辞書は UTF-8 で、EUC-JP を期待しているなら辞書は EUC-JP で保存しておく必要があります（Julius の起動オプション `-charconv` でコンバートすることも可能）。ただし、Linux 版の grammar-kit は入力に EUC-JP を期待しているため EUC-JP 以外を扱いたい場合は iconv で変換する必要があります。

改行コードは `¥n` 固定です。

## 辞書コンパイル

ここでは辞書関連ファイルは ~/dict というディレクトリに保存するものとします。

以下の語彙を辞書として採用したいとします。

```greeting.txt
おはよう
おはようございます
こんにちは
こんばんは
```

### 音素列へのコンパイル

この辞書に読みをつけて以下のように保存します。

```greeting.yomi
おはよう	おはよう
ございます	ございます
こんにちは	こんにちわ
こんばんは	こんばんわ
```

語彙と読みをタブ文字で区切ります。語彙は漢字や英数字混じりで良いですが、読みはすべてひらがなです。また、「こんにちは」は読みとして「こんにちわ」となることに注意が必要です。「おはよう」と「おはようございます」は構文定義で同一視するので、ここでは分解しています。

このファイルを以下のコマンドで音素列にコンパイルします。

```bash
$ BASENAME=greeting
$ iconv -f utf8 -t eucjp ~/dict/$BASENAME.yomi | yomi2voca.pl | iconv -f eucjp -t utf8 > ~/dict/$BASENAME.phone
```

以下のようなファイルができあがります。

```greeting.phone
おはよう	o h a y o u
ございます	g o z a i m a s u
こんにちは	k o N n i ch i w a
こんばんは	k o N b a N w a
```

### 構文の定義

構文を定義します。今回は以下のようになります。

```greeting.grammar
S : NS_B GREET NS_E
GREET : OHAYOU
GREET : OHAYOU GOZAIMASU
GREET : KONNICHIWA
GREET : KONBANWA
```

`S` は文章を表します。`NS_B` が開始、`NS_E` が終了でその間に `GREET` があり、`GREET` は `OHAYOU` だったり `KONBANWA` だったりする、という具合です。`S` は複数定義することができ、例えば `S : NS_B NAME GREET NS_E` などと追加定義し、`NAME` に「キット[^1]」や「ジャービス[^2]」などと定義すれば、ロボットに対する呼びかけの後の挨拶も認識するようになります。

### 語彙の定義

語彙を定義します。今回は以下のようになります。

```greeting.voca
% OHAYOU
おはよう        o h a y o u
% GOZAIMASU
ございます      g o z a i m a s u
% KONNICHIWA
こんにちは      k o N n i ch i w a
% KONBANWA
こんばんは      k o N b a N w a
% NS_B
[s]             silB
% NS_E
[/s]            silE
```

`%` の後に構文で指定した定義を書き、定義の語彙と音素列を並べていきます。この語彙と音素列は `yomi2voca.pl` の出力を使用しますが、このファイルの区切り文字はスペースなので、タブをスペースに変換する必要があります。今回はひとつの定義にひとつの語彙しかありませんが、例えば `OHAYOU` に `おはよー    o h a y o:` を追加したり、`GOZAIMASU` に `ございまーす    g o z a i m a: s u` を追加することで認識率が上がるかもしれません。また、英語対応したい場合には `OHAYOU` に `グッドモーニング	g u q m o: n i N` を追加してもよいです。

`NS_B` と `NS_E` は Julius の標準では `
` と `
` が用いられています。一方で Julius のモジュールモードでは XML で結果を返してくるのですが、語彙はエスケープされません。つまり、XML パーサによっては語彙が `
` や `
` だとパースエラーになる[^3]ため、他の語彙を採用することをおすすめします。ここでは `[s]` と `[/s]` としました。

### オートマトンと単語辞書へのコンパイル

以下のコマンドでコンパイルします。

```bash
$ mkdfa.pl dict/greeting
dict/greeting.grammar has 5 rules
dict/greeting.voca    has 6 categories and 6 words
---
Now parsing grammar file
Now modifying grammar to minimize states[-1]
Now parsing vocabulary file
Now making nondeterministic finite automaton[5/5]
Now making deterministic finite automaton[5/5] 
Now making triplet list[5/5]
6 categories, 5 nodes, 7 arcs
-> minimized: 5 nodes, 7 arcs
---
generated: dict/greeting.dfa dict/greeting.term dict/greeting.dict
```

.grammar と .voca のベースファイル名を指定します。うまくいくと上記出力のように .dfa、.term、.dict が同一ディレクトリに生成されます。

できあがった辞書を使用する場合には、例えば以下のように指定します。

```bash
$ ALSADEV="plughw:1,0" julius -C ~/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/dict/greeting -module
```

`-gram` で辞書のベースファイル名を指定します。環境変数やパスは実行環境によって変わるので注意してください。


[^1]: ナイトライダーの AI。音声認識やユーモアを含む会話、自動運転などの技術は時代を先取りしていました
[^2]: アイアンマンの AI。まだまだ先になりそうです
[^3]: Java 標準の XML ライブラリだとパースエラー、C++ の TinyXML-2 だとパース成功します