以前、SentencePieceについて記事を書きましたが、
今回は実際にSentencePieceを使ってWikipediaのデータから単語分割モデルを作ってみたいと思います。
この記事を見ればできるようになること。
- 単語分割モデルの作り方
- 単語分割モデルの使い方
Google Colaboratory
今回はGoogle Colaboratoryで使って作業を進めていきます。
Google Colabratoryって何?って方は下の記事を参考にしてください。
関連記事 - Google Colaboratoryを使ってAIプログラミングを始めよう
SentencePieceで単語分割モデルを作る際に使用するデータはファイル形式である必要があるので、まずはGoogle Driveにあるファイルを読み込めように以下を実行します。
Google Colaboratoryを開き、セルに上記を入力して実行してください。
関連記事 - Google ColaboratoryでGoogle Driveにあるファイルを読み書きする方法
次に、現在開いているNotebookがあるフォルダに移動します。
私はNotebookがあるフォルダにWikipediaからダウンロードしたデータとSentencePieceから作る単語分割モデルを置くことにします。(※ここは各自のお好みで。)
SentencePieceのインストール。
BeautifulSoupを使ってWikipediaのデータをダウンロードします。
今回は戦国武将の記事をいくつかダウンロードしました。
関連記事 - BeautifulSoupを使ってWikipediaのテキストを抽出する
上記のプログラムを実行するとwiki.txt
に改行区切りでデータが書き込まれます。
単語分割モデルの学習
データの用意ができたので、単語分割モデルの学習をしていきます。
単語分割モデルの学習はライブラリのインポートをして、sentencepiece.SentencePieceTrainer.Train()
で必要な設定をするだけでできます。特に正規化や前処理などは必要ありません。
学習が完了すれば、--model_prefix
で指定した名前がついたモデル名.modelとモデル名.vocabが生成されます。
学習の際に設定するパラメータは以下になります。
--input
学習データが入ったファイル(ひとつの文が1行になっている)
--model_prefix
モデル名、モデル名.modelとモデル名.vocabが生成される。
--vocab_size
語彙数(SentencePieceの開発者の方によると、翻訳の場合は小規模データなら数千から10k程度、超大規模でも32k程度で高い精度が得られるとのこと。)
--character_coverage
モデルがカバーする文字の量、日本語の場合は0.9995にするのが推奨されている。
--model_type
デフォルトではunigram、他にはbpe、char、wordがある。ただし、wordのときは予めテキストを単語に分割する必要がある。
また、今回は--pad_id=3
に設定しています。言語モデルやSeq2seqを学習する際に入力データの長さを揃えるために使われるpad
を今回単語分割モデルの単語リストに入れました。
SentencePieceでは他に区切り文字として使われる<s>
や</s>
がデフォルトで単語分割モデルに組み込まれています。
単語分割モデルの読み込み
学習した単語分割モデルを読み込むには、
このようにします。
SentencePieceは作成した単語分割モデルからテキストを単語ID列に変換したり、単語ID列からテキストに変換などができます。
EncodeAsPieces (テキストを単語に分割)
EncodeAsIds (テキストを単語ID列に変換)
DecodePieces (単語列からテキストに変換)
DecodeIds (単語ID列からテキストに変換)
GetPieceSize (語彙数)
PieceToId (単語IDの取得)
おまけ
戦国武将のWikipediaのデータと関係なさそうな文をSentencePieceの単語分割モデルに渡すと、
単語(文字)に分割できた。
ちなみに、
圭佑の佑が今回単語分割モデルの学習に使ったデータに含まれていなかったので、未知語<unk>
に変換されました。
MeCabを使うと
MeCabを使って今回用意したWikipediaのデータを形態素解析すると、語彙数がどれくらいになるのか調べてみました。
結果は11901になりました。
学習データが増えれば増えるほど語彙数もそれに伴い増えると思うので、語彙数を抑えることができるSentencePieceのほうが使い勝手が良さそうです。
エラーが出るとき
私がSentencePieceを使っていて2つエラーが出たのでその時の対処法を残しておきます。
① Increase vocab_size or decrease chacter_coverage
単語分割モデルを作成するために上記のプログラムを実行したら以下のようなエラーが出ました。
RuntimeError: Internal: /sentencepiece/src/trainer_interface.cc(427) [(static_cast(required_chars_.size() + meta_pieces_.size())) <= (trainer_spec_.vocab_size())] Vocabulary size is smaller than required_chars. 500 vs 1236. Increase vocab_size or decrease character_coverage with --character_coverage option.
エラーで書かれている内容をそのまんま実行するだけですね。私の場合、設定した語彙数が500で500 vs 1236
とエラーの内容の中に書かれていたので、語彙数を1236以上に設定するだけで解決しました。
② (trainer_spec_.vocab_size()) == (model_proto->pieces_size())
語彙数を8000に設定したときに以下のようなエラーが出ました。
RuntimeError: Internal: /sentencepiece/src/trainer_interface.cc(498) [(trainer_spec_.vocab_size()) == (model_proto->pieces_size())]
このようなエラーが出たときはsentencepiece.SentencePieceTrainer.Train()
の設定で--hard_vocab_limit=false
を加えると解決しました。
おわりに
SentencePieceを使ってみましたが、まだパラメータの設定やMeCabを使った形態素解析をした場合との違いについて完全に理解できたわけではないので、今後言語モデルやSeq2seqで使ってみて理解を深めていこうと思います。
参考ページ - GitHub - google/sentencepiece: Unsupervised text tokenizer for Neural Network-based text generation.