BertJapaneseTokenizer : 日本語BERT向けトークナイザ
東北大学の日本語BERTで使用されているBertJapaneseTokenizerのアルゴリズムを解説します。
日本語向けのトークナイズ処理の概要
BERTで日本語を処理する場合、日本語のテキストを単語に分割し、AIが扱えるトークンIDに変換する必要があります。
テキストを単語分割する際、英語の場合は、ホワイトスペースで単語分割が可能です。しかし、日本語は単語と単語が連続して記載されるため、単純な処理では単語分割ができません。
そのため、東北大学の日本語BERTで使用されているBertJapaneseTokenizerでは、Mecabを使用した形態素解析を行なって単語に分割した後、WordPieceもしくはCharacterでサブワード分割し、トークン番号に変換しています。
トークナイズ方法の定義
Transformersの各モデルがどのようにトークナイズしているかどうかは、config.jsonとtokenizer_config.jsonに記載されています。
cl-tohoku/bert-base-japanese-whole-word-maskingでは、tokenizer_classとしてBertJapaneseTokenizerが使用されており、word_tokenizer_typeにmecab、subword_tokenizer_typeにwordpieceが指定されています。
cl-tohoku/bert-base-japanese-char-whole-word-maskingでは、tokenizer_classとしてBertJapaneseTokenizerが使用されており、word_tokenizer_typeにmecab、subword_tokenizer_typeにcharacterが指定されています。
Word Tokenizer
BertJapaneseTokenizerは、最初に、日本語のテキストを形態素解析し、単語に分割します。形態素解析にはMecabを使用しています。Mecabは日本語向けの形態素解析ソフトウェアです。MecabのCのAPIを使用するサンプルは下記にあります。
「太郎は次郎が持っている本を花子に渡した。」という文章をMecabに与えると、以下のような出力を得ることができます。一番左が、分割された単語です。
太郎 名詞,固有名詞,人名,名,*,*,タロウ,タロウ,太郎,タロー,太郎,タロー,固,*,*,*,*,タロウ,タロウ,タロウ,タロウ,*,*,1,*,*
は 助詞,係助詞,*,*,*,*,ハ,は,は,ワ,は,ワ,和,*,*,*,*,ハ,ハ,ハ,ハ,*,*,*,"動詞%F2@0,名詞%F1,形容詞%F2@-1",*
次郎 名詞,固有名詞,人名,名,*,*,ジロウ,ジロウ,次郎,ジロー,次郎,ジロー,固,*,*,*,*,ジロウ,ジロウ,ジロウ,ジロウ,*,*,1,*,*
が 助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*,ガ,ガ,ガ,ガ,*,*,*,"動詞%F2@0,名詞%F1",*
持っ 動詞,一般,*,*,五段-タ行,連用形-促音便,モツ,持つ,持っ,モッ,持つ,モツ,和,*,*,*,*,モッ,モツ,モッ,モツ,*,*,1,C1,*
て 助詞,接続助詞,*,*,*,*,テ,て,て,テ,て,テ,和,*,*,*,*,テ,テ,テ,テ,*,*,*,"動詞%F1,形容詞%F2@-1",*
いる 動詞,非自立可能,*,*,上一段-ア行,連体形-一般,イル,居る,いる,イル,いる,イル,和,*,*,*,*,イル,イル,イル,イル,*,*,0,C4,*
本 名詞,普通名詞,一般,*,*,*,ホン,本,本,ホン,本,ホン,漢,ホ濁,基本形,*,*,ホン,ホン,ホン,ホン,*,*,1,C3,*
を 助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*,ヲ,ヲ,ヲ,ヲ,*,*,*,"動詞%F2@0,名詞%F1,形容詞%F2@-1",*
花子 名詞,固有名詞,人名,名,*,*,ハナコ,ハナコ,花子,ハナコ,花子,ハナコ,固,*,*,*,*,ハナコ,ハナコ,ハナコ,ハナコ,*,*,1,*,*
に 助詞,格助詞,*,*,*,*,ニ,に,に,ニ,に,ニ,和,*,*,*,*,ニ,ニ,ニ,ニ,*,*,*,名詞%F1,*
渡し 動詞,一般,*,*,五段-サ行,連用形-一般,ワタス,渡す,渡し,ワタシ,渡す,ワタス,和,*,*,*,*,ワタシ,ワタス,ワタシ,ワタス,*,*,0,C2,*
た 助動詞,*,*,*,助動詞-タ,終止形-一般,タ,た,た,タ,た,タ,和,*,*,*,*,タ,タ,タ,タ,*,*,*,"動詞%F2@1,形容詞%F4@-2",*
。 補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*,,,,,*,*,*,*,*
PytorchのTransformersからは、MecabのラッパーであるFugashi経由で使用しています。具体的に、FugashiのGenericTriggerを呼び出し、Mecabのmecab_sparse_tonodeを呼び出し、surface(単語)をlistにappendします。
Mecabの形態素解析には辞書が必要です。辞書が異なると、分割方法が異なるため、辞書は厳密に一致させる必要があります。
bert-base-japanese-whole-word-maskingはipadicを使用しています。bert-base-japanese-v3はunidic-liteを使用しています。
Subword Tokenizer
Mecabで分割した単語をそのままトークンに変換した場合、トークンの種類が膨大になるという問題があります。また、未知語が来た場合にトークンに変換できないという問題があります。
そこで、単語をさらにSubwordに分割します。Subword分割にWordPieceを使用する場合、学習時に単語を尤度(ゆうど)に応じて分割します。トークン数は学習時に決定し、BertJapaneseの場合は32000になります。
WordpieceTokenizerは下記に実装されています。推論時は、トークンに対応する単語表であるVocabが与えられた場合、貪欲な最長一致優先戦略でSubword分割が可能です。
Subword分割にCharacterを使用する場合、単語をUTF32の各文字に分割します。トークン数は、BertJapaneseの場合、4000になります。入力されたテキストは最初にMecabを通して単語に分割するのですが、最終的にSubword分割で1文字単位まで分割してしまうため、実はMecabを使用しなくても実装が可能です。
トークンIDへの変換
Subwordに分割後、vocab.txtの内容と照合してトークンIDを取得します。
Unicode正規化
BertJapaneseTokenizerでは、NFKC形式で日本語を扱います。入力されたUTF8の文字列は、BertJapaneseTokenizerの内部でunicodedata.normalize(“NFKC”, text)が呼ばれた後、トークンへの変換処理が実行されます。
Unicode正規化の例です。NFKC形式では、全角の英数は半角に、半角のカタカナは全角にするような変換を行います。
入力したUTF8文字列:グーグル㍿
正規化されたUTF8文字列:グーグル株式会社
実際のトークンの例
トークナイズを行うPythonコードです。
from transformers import BertTokenizer, BertJapaneseTokenizer
tokenizer = BertJapaneseTokenizer.from_pretrained(
'cl-tohoku/'+'bert-base-japanese-whole-word-masking'
)
text = "太郎は次郎が持っている本を花子に渡した。"
tokenized_text = tokenizer.tokenize(text)
indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)
print(tokenized_text)
print(indexed_tokens)
トークナイズ結果の最終的なSubwordとトークンIDです。
['太郎', 'は', '次郎', 'が', '持っ', 'て', 'いる', '本', 'を', '花', '子', 'に', '渡し', 'た', '。']
[5250, 9, 10833, 14, 1330, 16, 33, 108, 11, 1172, 462, 7, 9427, 10, 8]
Mecabの単語とSubwordです。IPADICでは単語とSubwordが一致します。
Mecab : 太郎 SubWord : 太郎(5250)
Mecab : は SubWord : は(9)
Mecab : 次郎 SubWord : 次郎(10833)
Mecab : が SubWord : が(14)
Mecab : 持っ SubWord : 持っ(1330)
Mecab : て SubWord : て(16)
Mecab : いる SubWord : いる(33)
Mecab : 本 SubWord : 本(108)
Mecab : を SubWord : を(11)
Mecab : 花 SubWord : 花(1172)
Mecab : 子 SubWord : 子(462)
Mecab : に SubWord : に(7)
Mecab : 渡し SubWord : 渡し(9427)
Mecab : た SubWord : た(10)
Mecab : 。 SubWord : 。(8)
Mecabの辞書にUnidicLiteを使うと、花子のWordがSubword分割されます。Subwordに含まれる##は前の単語とスペースなしで連結するという意味となります。
Mecab : 太郎 SubWord : 太郎(5250)
Mecab : は SubWord : は(9)
Mecab : 次郎 SubWord : 次郎(10833)
Mecab : が SubWord : が(14)
Mecab : 持っ SubWord : 持っ(1330)
Mecab : て SubWord : て(16)
Mecab : いる SubWord : いる(33)
Mecab : 本 SubWord : 本(108)
Mecab : を SubWord : を(11)
Mecab : 花子 SubWord : 花(1172) ##子(28601)
Mecab : に SubWord : に(7)
Mecab : 渡し SubWord : 渡し(9427)
Mecab : た SubWord : た(10)
Mecab : 。 SubWord : 。(8)
まとめ
日本語BERTの内部で行われているトークナイズの処理を解説しました。シンプルなトークナイズ処理も、内部では、従来の自然言語処理をベースとした複雑な処理を行なっていることがわかります。
近年は、形態素解析を用いないSentencePieceなども登場してきており、マルチリンガルモデルのXLM_ROBERTAなどで採用されています。MecabもSentencePieceも実は同じ作者で、Googleの工藤拓さんが開発しています。
ailia Tokenizerについて
iOSやAndroidで自然言語処理を行う場合、AIの推論部分以外に、テキストとトークンを相互変換するためのTokenizerを実装する必要があります。ax株式会社では、Python不要でC++やUnityから変換を行えるailia Tokenizerを提供しています。
ax株式会社はAIを実用化する会社として、クロスプラットフォームでGPUを使用した高速な推論を行うことができるailia SDKを開発しています。ax株式会社ではコンサルティングからモデル作成、SDKの提供、AIを利用したアプリ・システム開発、サポートまで、 AIに関するトータルソリューションを提供していますのでお気軽にお問い合わせください。