Mozc(Google日本語入力)のコードを読んだメモ

 Google日本語入力OSS化されたということで、気になっていたところをいくつか確認してみた。

変換アルゴリズムはどんな感じか?

 twitterの工藤さんの発言にも「わりと古典的な最小コスト法」とあるけれど、まさにそんな感じ。人名の処理とかでちょっと特別なコードが入ったりもしているが、ほぼ基本的な統計的かな漢字変換のモデル。係り受けの情報とかは使っていない。Viterbiでベストパスを求めて、品詞ベースで文節にまとめあげている。コストモデルは接続コストが品詞対品詞で、単語コストの方は単語毎に設定されているっぽい。
 src/converter/immutable_converter.ccのImmutableConverterImpl::ViterbiがViterbiアルゴリズムの部分で、その後にMakeSegmentsで文節にまとめている。読むならImmutableConverterImpl::Viterbiのあたりから始めるのがおすすめ。
 アルゴリズム自体に興味のある人は 確率的言語モデル を読んだ上で森さんの 確率的モデルによる仮名漢字変換 あたりを読めばちょうどいい感じぐらいかな?

学習はどうやってるのか?

 Mozcでは、かな漢字変換を担当するプログラムはConverterと呼ばれるモジュールである。Converterは具体的にはImmutable ConverterとRewriterという2つのモジュールで構成されている。ConverterはまずImmutable Converterを使って変換を行い、その変換結果をRewriterに渡して変換結果をいじる。ユーザーの入力履歴に基づく学習結果の適用もこのRewriterで行われている。Rewriterは現状では8つがあり、いわゆるユーザーの入力履歴によって変換結果を学習する部分は、このうちのUserBoundaryHistoryRewriter, UserSegmentHistoryRewriterの2つである。文節区切りの変更を適用して、その後で変換候補の順番の変更を適用する。UserBoundaryHistoryRewriterが過去の履歴に基づいて文節区切りを変更する条件は、ちょっと読んだだけではよく分からなかった。UserSegmentHistoryRewriterが変換候補の並び替えを発動する条件は、文節のtrigram, bigram, unigramの情報を使っていて、trigramが一致すれば並び替えをしやすいとか、文節が一つしかないときはunigramでも並び替えをしやすくするだとか、そういった感じになっていた。

DoubleArrayとLOUDSはどう使い分けているのか?

 grep DoubleArray **/*{h,cc} してみた感じ、DoubleArrayはひらがなとカタカナの変換などに使われているようだ(src/base/japanese_util_rule.hのあたり)。システム辞書の方はLOUDSを使っている。ライセンス表記にある通り、Double Arrayの実装にはDartsが、LOUDSの実装にはrxが使われている。

その他

 読んでる最中に気づいたコネタ。

  • src/base/svm.cc というのがあって、SVMが使われている事がわかる。どこで使われてるのかなーと思ったら、予測入力のランキングの部分でSVMClassifyを使っており、分離超平面からのマージンでランキングをつけていた。素性の重み付け(学習)の部分のコードは入ってないので判断がつかないが、おそらく手でpairwiseのデータを用意してRankingSVMっぽく学習してるんじゃないかなーと予想しておく。(学習部分はおそらく公開されないので、この予想が外れててもそれが露見することはないような気もする。)
  • src/data/dictionary/suggestion_filter.txt はサジェスト候補で変なものが出てくるのを防ぐためのフィルタだと思われるが、中身は「ただしイケメンに限る」という1文しか入ってなかった。Google日本語入力の方ではいろいろ入っているのだろう。データは入れられないけど、なにも入ってないのは寂しいから1個だけ入れとこう、的な感じではないかと思われる。