Open27

Scala(JVM) で機械学習(NLP, Deep Learning, Neural Net, etc)

110416110416

BERT 周りの知識

tokenize

(日本語向け)BERT では, 分かち書き(word segmentation) + subword 分割した後でトークナイズ処理をする. 分かち書き + subword 分割 の部分は pre-tokenize と呼ぶことがある.
入力テキストを subword まで分割して辞書(語彙)に含まれる tokenid にマッピングする処理をトークナイズと呼ぶ. subword 分割とトークナイズ処理は model の vocabulary に依存する.

vocabularyファイルがサブワード分割の学習の結果生成され*5、サブワード分割を行う際に必要になる。

BERT派生のモデルでは従来の単語分かち書きだけでなく、さらに細かい分かち書き単位であるサブワード分割という処理が適用される。 モデル的にはこの処理は必須というわけではないものの、報告されているタスク性能のほとんどがサブワード分割を入れた上での性能値なので、特別な理由がなければ入れておきたい。(https://tech.mntsq.co.jp/entry/2021/02/26/120013)

tokenize の一連の処理は以下のように整理できる
Encode: 文字列 → 事前学習モデル入力可能なEncodingオブジェクト

  • Normalizer: 文字列正規化の前処理(Unicode正規化や小文字化など)
  • PreTokenizer: 文字列→基本トークン(単語)の変換
  • Model: 基本トークン→トークン(サブワード)の変換;学習済みvocabularyが必要な箇所
  • PostProcessor: 最終的なEncodingデータを生成する後処理(BERTの特殊トークンの追加など)

https://tech.mntsq.co.jp/entry/2021/02/26/120013

word segmentation subwording link
cl-tohoku/bert-base-japanese-whole-word-masking mecab wordpiece https://huggingface.co/cl-tohoku/bert-base-japanese-whole-word-masking
cl-tohoku/bert-japanese mecab wordpiece https://github.com/cl-tohoku/bert-japanese
gpt2-japanese bpe https://github.com/tanreinama/gpt2-japanese/blob/master/report/models.md

BERT のモデルにも tokenizer がはいっているが、ユニコード正規化が cjk を意識していなかったり、漢字の分割の単位が小さくなりすぎるので mecab など日本語の形態素解析ライブラリで分割する必要がある.

外国語のモデルのトークナイザをそのまま日本語に使うのは避けた方がいい.
日本語に bert-base-cased の tokenizer を利用すると多くの単語が [UNK] になる.

tokenizer の違いがその後のタスクに影響するか調べたレポート?研究発表?
https://www.anlp.jp/proceedings/annual_meeting/2023/pdf_dir/Q6-1.pdf
https://www.anlp.jp/proceedings/annual_meeting/2021/pdf_dir/P4-12.pdf

tokenType

一文に論理的に複数の文章が含まれているときにそれを識別するための id. 通常はすべて同じ値でいいが、質問文と回答などを扱うときは tokenType を 0, 1 などと指定する.

https://qiita.com/Dash400air/items/a616ef8d088e003dfd4c

vocab size

モデルに含まれる語彙のサイズ. 30500 とか 32000 とかベースのモデルに近い値がはいっていることが多い.

一般的には、Transformerモデルが50,000を超える語彙数を持つことはほとんどありません。

https://note.com/npaka/n/nb08941a36c8b

ベースのモデルによっては vocab size を変更すると動かなくなるものがあるらしいのであまり変えない方が良さそう.

https://blog.recruit.co.jp/data/articles/huggingface_tokenizer/

JVM のライブラリ

sentencepiece は djl の実装がある.
https://docs.djl.ai/extensions/sentencepiece/index.html

110416110416

scikit learn や w2v も onnx に変換できるらしい. 一通り試してみたい.

110416110416

tokenizer の encode/decode さえ JVM でできればあとは onnx runtime に突っ込むだけ.

文書分類などの基本的なタスクなら一応 djl でもできそう.

HuggingFaceTokenizer.newInstance("sentence-transformers/msmarco-distilbert-dot-v5")
110416110416
input_tkn_ids = tknz.tokenize(text)
out_tkn_ids = model.generate(input_ids, ...)
tknz.decode(out_tkn_ids)
// => human-readable text
110416110416

djl を挟んでもいいが ggml や llama のラッパーを書いてもいいかも.

110416110416
//> using dep "ai.djl.huggingface:tokenizers:0.28.0"
val t = HuggingFaceTokenizer.newInstance("sentence-transformers/paraphrase-xlm-r-multilingual-v1")
val encoding = t.encode("これはテストです")