はじめに
先日リリースしたSentencePieceを形態素解析のように使えるWebAPIですが、SentencePiece作者の工藤さんから色々とアドバイスを頂きました。前回の投稿は一部適切でない実装があったので、それを修正しました。こちらから無料で使えます。
API
サンプルコード
関連記事
やったこと
前回との違いだけ記述します。
まず、SentencePieceでのモデル計算はいくつかモードがあります。今回はUnigramとBPEを試しました。
Unigramモード
工藤さんから以下のコメントをもらいました。
unigram だと、語彙テーブルの対数尤度に -1 かけて整数コストにし、未知語処理を切れば原理的には一緒になります。
というわけで、そのとおりにしました。
私がやったことを正確に伝えると、語彙テーブルの対数尤度に-100をかけてroundして整数コストにし、kuromoji/mecabの辞書に追加しました。未知語のところはkuromojiをextendモードで実行するとしました。未知語の単語コストはSentencePieceの語彙テーブルよりも十分高かったので、基本的にSentencePieceの語彙テーブルで形態素解析されます(たぶん)。extendモードで実行したのは、未知語が出てきたときに文字区切りにするためです。
BPEモード
こちらも工藤さんからコメントをもらいました。
BPE での分割は、ナイーブな実装でよければそれほど難しくありません。2つの文字を連結してみて辞書にあれば、その2文字を新しいシンボルに置換していきます。置換する箇所が複数ある場合は、優先度(最初に登録されている方が優先)順に置換します。
https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E5%AF%BE%E7%AC%A6%E5%8F%B7%E5%8C%96
2文字の連続を連結して、辞書引きをします。みつかれば、その2文字をつなげてつなげたものを1文字とみなします。
それを辞書引きができなくなるまで繰り返します。ナイーブな実装は、毎回2文字連続をスキャンするので、O(n^2) ですが、ヒープを使えば O(n log n)になります。
ヒープを使ううまいやり方が私にはわからなかったので、愚直にやりました。「語彙テーブルをルールとみなし、上から順番にルールを適用する」というものです。例えば、ルールが以下のように定義されているとします。
あい
うえ
あいう
入力が「あいうえお」だとしたら、この場合は出力は「あい うえ お」になります。過剰な説明かもしれませんが、下に示す別のルールの場合は、
あい
あいう
うえ
出力は「あいう え お」になります。
で結果はどう変わったのか?
ほぼ同じでした。
前回の例はUnigramだろうとBPEだろうとどちらも結果は変わりませんでした。UnigramとBPEの語彙テーブルを見比べてみましたが、かなーり近いです。Unigramの方はつっこんだデータも多いことがあり、一応BPEとの違いはあります。
ただ、正確に実装できた(と思うので)、安心して使ってもらえると思います。
おわりに
余談ですけど、UnigramモードはBPEモードに比べると省メモリなので、Wikipedia全文を学習につっこめました。その結果、12日間も計算しつづけました。。。電気代が・・・。というわけで、12日分の演算結果をApitoreでは無料で使えるので是非使ってみてください。