🍣

Tanukiモデルが全角数字・記号を認識出来ない問題とその解決(LLM学習コーパスの正規化の落とし穴)

2024/09/10に公開

GENIAC 松尾研LLM開発プロジェクトメンバーのArataです。
この記事は、Tanukiモデルにあった不具合とその解決方法についてまとめます。

Tanukiモデルが全角数字や全角記号を認識しない問題について

9/3ごろまで、Tanuki-8BおよびTanuki-8x8Bに全角数字や全角文字を入力した時、上手く認識されない問題がありました。
*記事公開時点でGGUF版以外は対応済み

1つ目の例では「2+2」という全角数字と全角記号を認識できず、おかしな回答をしてしまっています。2つ目の例でも「?」という記号を認識できず変な解説をしてしまっています。

これと同じ挙動が8Bと8x8B双方で確認されました。また、推論エンジンにHuggingface TransformersやvLLMなど何を使っても発生したため、推論側の問題でもないようでした。

原因

今回の問題の原因についてチーム内で調査・議論した結果、学習コーパスのクリーニングを行う際の正規化処理が原因だという結論が出ました。

今回、学習コーパス内の日本語データの大部分に対して、以下のコードで実装されているクリーニングを行っていました。

https://github.com/hatakeyama-llm-team/Dataset_for_BTM/blob/50b/01web_codes/src/cleaner/auto_cleaner.py

このコードの中で、以下のような正規化処理を行っています。この処理中、テキストに対してNFKC形式でのUnicode正規化をかけています。

https://github.com/hatakeyama-llm-team/Dataset_for_BTM/blob/9c56f8b829c81ec39532f69e8ea8ad5e33edea7e/01web_codes/src/cleaner/text_normalizer.py#L175

https://github.com/hatakeyama-llm-team/Dataset_for_BTM/blob/9c56f8b829c81ec39532f69e8ea8ad5e33edea7e/01web_codes/src/cleaner/text_normalizer.py#L74

このNFKC正規化によって、テキストに以下のような改変が行われます。

  • ウ゛ェ → ヴェ
  • ABC → ABC
  • ① → 1
  • ㊤ → 上
  • Ⅲ → III
  • ㌶ → ヘクタール
  • ハンカクカナ → ハンカクカナ
  • ﹣ → -※ 左辺はU+FE63 Small Hyphen-Minus: 小さいハイフンマイナス
  • - → -※ 左辺はU+FF0D Fullwidth Hyphen-Minus: 全角ハイフンマイナス

(参考リンク)
https://qiita.com/y-ken/items/d08eb7f66c8fb2fa7d21
https://rooter.jp/data-format/unicode_normalization/

このように、NFKC正規化によって全角数字や記号は半角に変換されます。つまり、学習コーパスのクリーニング時点で全角数字や記号が含まれないようになります。

そのため、このデータを学習したTanukiのモデルもまた全角の数字や記号を十分学習できておらず、上述した問題が発生しているのではと考えられました。

解決策

今回の問題は学習に利用したデータの前処理にありました。一方、推論時に何も処理をしないと全角数字や記号がそのまま入ってきてしまい、結果的にほぼ学習したことのない入力を受けることとなりおかしな出力をしてしまいます。

この問題について、推論時の入力に対しても同じようにNFKC正規化をかけることで入力中の全角記号等を半角にするという解決方法があります。入力テキストに直接NFKC正規化をかける処理をモデルの推論前に別の場所で実装しても良いのですが、これと同じような処理をtokenizerのnormalizerを使うことでこれを実現することが可能です。

https://huggingface.co/learn/nlp-course/chapter6/4

tokenizerにNFKCのnormalizerを追加します。以下のようにtokenizer.jsonを変更することでこれを実現可能です。

https://huggingface.co/weblab-GENIAC/Tanuki-8B-dpo-v1.0/commit/0ac7ea5d3dc440df4c138c5db887d9332ea6cd80

この変更をした後、問題が解決しているか試してみます。

内部的に入力中の全角が半角に変換されることで、上記の例のように全角数字や記号を上手く認識できるようになりました。

本来はどうするべきなのか?

今回の解決策はある種の緊急的な対応です。全ての学習データにNFKC正規化をかけていたわけではなく一部正規化処理をせず学習していたデータもあるはずですが、その中の全角数字や記号等に対する学習リソースが無駄になってしまっているとも考えられます。

本来は以下のような対応をすべきではないかと思います。

  • 学習コーパスに対して直接正規化をするのではなく、学習時からtokenizerのnormalizerを設定しておき、tokenizer側に正規化を行わせて学習する(これにより、学習時と推論時の動作の一致を図ることが出来る)
  • NFKCのようなUnicode正規化をかけず、そのままのテキストを学習する(これにより、全角数字・記号と半角数字・記号の文脈の違いを学習できる)

あるいは、NFCのような全角→半角の変換をしない正規化を行うのも良いと思います。(実際、Calm3ではtokenizerのnormalizerにNFCを指定しているようです)

まとめ

この記事では、Tanukiモデルに発生した全角数字・記号を認識しない問題とその解決方法についてまとめました。この記事が学習データの正規化に伴う問題への対処の一助となれば幸いです。

東大松尾・岩澤研究室 | LLM開発 プロジェクト[GENIAC]

Discussion