Open JTalk でほぼ定型文を音声合成するための MeCab 辞書類の縮小化

Open JTalk のほぼ定型文のための辞書類のサイズの調査」では縮小化を試みなかったMeCab 辞書類のサイズを小さくすることを試したので、その記録を備忘録として残しておく。 「Open JTalk のほぼ定型文のための辞書類のサイズの調査」では Open JTalk で使用されている mecab のシステム辞書 sys.dic のサイズを小さくすることを試みたが、それ以外の matrix.bin、unk.dic、char.bin はそのままであった。sys.dic は78,490 kBから 7 kBに大幅に小さくなったが、matrix.binが 3,704 kBあり、ESP32を使った M5Stack などのIoT、組み込みシステムには大きすぎる問題が残っていた。

考え方

Open JTalk のほぼ定型文のための辞書類のサイズの調査」で sys.dic を小さくするときと同様に、定型文で必要なものだけを含むようにすることで、実行時に必要となる辞書類のサイズを小さくする。 用意されているファイルの文脈IDで利用されているものだけを抽出し、その値の範囲が狭くなるようにIDを割り振りなおす。Pythonで処理して小さくしたファイルを生成する。今回は matrix.bin を小さくすることを主たる目的とする。

実行時に必要となるファイル

実行時に必要となるMeCabの辞書類のファイルは以下の通りである。組み込み機器などの資源の乏しい環境で音声合成を可能にするためには、これらのファイルのサイズを小さくすることが必要である。

  • sys.dic
    • unidic-csj.csv、naist-jdic.csv から生成したシステム辞書
  • matrix.bin
    • matrix.def をコンパイルしたバイナリファイル
  • char.bin
    • char.def をコンパイルした文字カテゴリマップのバイナリファイル
  • unk.dic
    • unk.def から生成した未定義語の品詞等の辞書

入力ファイルの検討

MeCab の辞書構造と汎用テキスト変換ツールとしての利用 を基にして変換する観点から調査した。 以下で利用している例はすべて Open JTalk に同梱されている MeCab の ファイルを処理して生成した派生物(の一部)である。 辞書類を小さくするためには、文脈ID の範囲を小さくするように変換する必要がある。

単語ファイル

mecab-dict-index.exe では、unidic-csj.csv、naist-jdic.csv などの .csv 拡張子をもっているファイルが語彙として処理される。これらは「,」区切りのCSVファイルである。 1行が1単語に相当している。次に例を示す。

左から順に、単語、左文脈ID (left-id)、右文脈ID (right-id)であり、その後が単語に関する情報である。 left-id、right-id は、この後に説明する matrix.def で使用されており、matrix.def によって生成される matrix.bin の大きさは、このID数の最大値によって決まるため、matrix.bin を小さくするためには、id の値の範囲(最大値)を小さくする必要がある。つまり .csvファイルの left-id、right-idを書き換える必要がある。 Open JTalk で用意されている辞書ではleft-idとright-idの文脈IDの割り当ては同じと考えられる。

語彙についての unidic-csj.csv、naist-jdic.csv 以外に以下のファイルが存在する。

matrix.def

連接表 matrix.def の例を次に示す。

先頭行が前件文脈ID数、後件文脈ID数を表す。空白で区切られている。ID数はID の最大値+ 1 の値をとる。上記の例では、IDの最大値(最大id)が 1376 のため、id数 は 1377 である。途中で使われていないidがあっても、matrix.def から生成される matrix.bin は、(前件文脈ID数 × 後件文脈ID数) に比例する形で大きくなるので、matrix.bin を小さくするためには、最大ID を小さくする必要があり、結果として2行目以降のID の変換が必要である。

2行目以降が連接表の要素を表し、前件文脈ID、後件文脈ID、コストが空白で区切られている。2行目以降の順序はどのようになっていてもかまわないようである。Open JTalk で用意されているファイルでは ID順にソートされているが、ID順でないファイルでもmatrix.bin の生成には支障がない。 また、同じ前件文脈ID、後件文脈IDに対して複数行があってもエラーなどにはならない。変換処理を行った結果のファイルに重複行があってもそのままでよいことになる。 前件文脈IDと後件文脈IDの割り振りは Open JTalk で用意されている辞書では同じと考えられるので、以下では前件文脈IDと後件文脈IDを区別せず扱う。

matrix.bin のサイズを小さくするために、前件文脈ID、後件文脈IDを変換して、最大IDが小さくなるように処理する。

char.def

char.def は、未知語処理のための文字のカテゴリ定義ファイルとのこと。 unk.def で利用されるカテゴリ名などが定義されている。 処理すべき文脈ID を含まないので、辞書類の縮小のためには何もしない。

char.bin を小さくするためには、何かできることがあるかもしれないが、今回は対象外である。

unk.def

unk.def は未知語用の辞書とのこと。例を次に示す。CSV形式である。

オリジナル辞書/コーパスからのパラメータ推定 などには項目についての明確な説明がないが、左から順に、カテゴリ名、前件文脈ID、後件文脈IDであり、その後がカテゴリ情報と考えられる。 文脈ID の変換が必要である。

DEFAULT と SPACE は、明示的に使っていなくても必要なカテゴリラベルのようである。

_left-id.def

_left-id.def は、左文脈ID の定義ファイルである。 左文脈IDとその情報が空白で区切られている。文脈IDについての変換が必要である。

_right-id.def

Open JTalk に同梱されているものでは _right-id.def と  _left-id.def は同一。

feature.def

内部状態の素生列を変換するためのテンプレートとのこと。文脈IDを含まないので辞書類を小さくするための変換は不要のはず。

_rewrite.def

素性列から内部状態素生列への変換の定義とのこと。文脈IDを含まないので辞書類を小さくするための変換は不要のはず。

_pos-id.def

品詞IDの定義とのこと。文脈IDではないので変換は不要のはず。

small-jdic.csv.orig

Open JTalk のほぼ定型文のための辞書類のサイズの調査」で生成したファイルも文脈IDを変換する必要がある。以下では、このファイルを small-jdic.csv.orig とする。拡張子を .csv とすると mecab-dict-index.exe で処理されてしまうので、異なる拡張子.orig にする。

変換の必要なファイルのまとめ

変換が必要な部分を次にまとめる matrix.def

ファイル名 区切り 変換対象
カラム番号
入力文字
コード
出力文字
コード
matrix.def 空白 0,1
(2行目以降)

ASCII
(utf-8,
shift-JIS)

ASCII
(utf-8,
shift-JIS)
unk.def コンマ
(CSV)
1,2
(必須ラベル
処理必要)
utf-8 utf-8

_left-id.def
_right-id.def

空白 0 utf-8 utf-8
small-jdic.csv.orig コンマ
(CSV)
1,2 shift-JIS shift-JIS

変換プログラム

文脈IDの割り振り直しの対応関係を示すIDマッピングを生成するプログラムと、IDマッピングに従った変換Iを行うプログラムを Python3 で作成した。

IDマッピングの生成

前処理によって縮小した語彙のCSVファイル  small-jdic.csv.orig から IDマッピングを示すファイル id.map を生成する場合を示す。

必須ラベルとして DEFAULT と SPACE がないといけないようなので、それらに対してもIDのマッピングを割り当てる。DEFAULT と SPACE以外にも「ほぼ定型文」に含まれる品詞情報で必須のものがあるかもしれない。その場合には、必須ラベルを増やす必要がある。

python のプログラム例を示す。

 

コマンド引数は以下の通り。

IDマッピングに従った変換

IDマッピングを示すファイル id.map に基づいて変換を行う。

変換プログラム例を示す。出力ファイルを指定する -o オプションもしくはリダイレクトを利用してファイルに保存する。

-d で delimiter を指定する。スペース(" ") もしくはコンマ(",")を指定する。

-e で encoding を指定する。UTF-8 ("utf-8") もしくは Shift-JIS ("shift-jis") を指定する。

small-jdic.csv.orig

Open JTalk のほぼ定型文のための辞書類のサイズの調査」で生成したファイル(ここでは、small-jdic.csv.orig)にIDマッピングをするためには次のコマンドを実行する。

ファイル small-jdic.csv に出力するためには、リダイレクトするか以下のように -o オプションを利用する。これ以降も同様である。

_matrix.def

_matrix.def にIDマッピングをするためには次のコマンドを実行する。

-s は先頭行の前件文脈ID数、後件文脈ID数を特別扱いするためのオプションである。

_unk.def

_unk.def にIDマッピングをして、出力を得るためには次のコマンドを実行する。

-l は、必須ラベルを特別扱いするためのオプションである。

_left-id.def, _right-id.def

_left-id.def にIDマッピングをするためには次のコマンドを実行する。

_right-id.def も同様というか、_left-id.def を処理した結果を使えばよい。

変換例

「リビングのCO2濃度は1,234.567890ppmです。
窓を開けて換気してください。」を例文として、mecab で処理して生成した次の small-jdic.csv.org を基にした場合を示す。

id.map

small-jdic.csv.orig を基にして IDマッピングの対応表ファイル id.map を生成する。左側のIDを右側のIDにマッピングする必要があることを示す。最後の2行は、必須ラベルの処理のためのものである。

small-jdic.csv

small-jdic.csv.orig にIDマッピングすることで small-jdic.csv を生成する。

matrix.def

_matrix.def にIDマッピングをすることで matrix.def を生成する。

unk.def

_unk.def にIDマッピングすることで unk.def を生成する。

left-id.def, right-id.def

_left-id.def にIDマッピングしたファイルを left-id.def とする。

結果

上記の処理をしたファイルを基に .bin 、.dic ファイルを生成した。

生成された辞書ファイルのサイズを次の表にまとめる。

サイズ(kB) mecab-naist-jdic 文脈IDの割り振り直し後
char.bin 257 257
matrix.bin 3,704 1
sys.dic 78,490 7
unk.dic 6 5

今回の処理をすることで matrix.bin のサイズは十分に小さくなり、ESP32などの組み込みシステムでも利用可能なレベルになっていると思う。今回は入力文が非常に短い場合の結果であるが、文を長くしても語彙が限られる「ほぼ定型文」ならかなり小さくできると考える。char.bin のサイズは変わっていない。合計で270kBが必要である。

Text-to-Speechを実際に実行するためには、HTS_engine が必要である。これを含んだ Windows10上の open_talk.exe は 1,411kBであり、音声合成に必要な音響モデルの例の nitech_jp_atr503_m001.htsvoice が1,142kBである。

以上を合計すると2,823kBであり、ESP32に移植してもそれほど大きく変わらなないことが期待できる。M5Stack Core 2 なら PS RAM が8MBで、フラッシュが 16MBなので容量的には動作させることが可能と思われる。

課題

ESP32 用にクロスコンパイルして、M5Stack Core 2で動作させることが次の課題になる。時間ができたら試してみたい。