📖

M2M100 で英日翻訳するメモ(MIT ライセンスで商用利用可能! LLM への翻訳レイヤーとして期待)

2023/06/13に公開

機械翻訳は, FuguMT や NLLB がありますが,

NLLB-200 3.3B で日本語翻訳するメモ(moe-54b もあるよ)
https://zenn.dev/syoyo/articles/9a159ee747835a

FuguMT は

  • 最新 huggingface transformers だと結果がおかしい
  • 英語と日本語以外扱えないので, いろいろ前処理が必要(fugumt ライブラリではいくらか処理してくれるようであるが)
  • 精度としては規模相当(NLLB 1B くらいと同等かしら)

NLLB は

  • ライセンスが CC-BY-NC 4.0 であり商用利用できない
  • 多言語対応で英日翻訳だけしたい場合はちょっとオーバースペック
  • 3.3B の次が moe 54B しかなくて使い勝手が悪い
    • moe 54B を 10B くらいでファインチューン or 再学習する手もあるかもはしれないが...

という問題があります.

Hugging face model をあさっていたら M2M100 をみつけました.
(ちなみに Helsinki Opus も見つかりますが, 試したところ日本語翻訳精度はだめだめだったので諦めた)

https://github.com/facebookresearch/fairseq/blob/main/examples/m2m_100/README.md

fairseq なので, NLLB の元になった?機械翻訳のようです.

NLLB とことなり, fairseq のライセンスがそのまま適用されるので pretrained model も MIT ライセンスで使えます!

M2M100 にかんする論文は 2020 年と古いですが, pretrained model はちょくちょくアップデートされているようです.

400M, 1.2B https://huggingface.co/facebook/m2m100_1.2B , 12B の pretrained model があります. 大きさは正義ということで, 12B を使います.

M2M100 12B

いくつか variant がありますが, こんかいは

https://huggingface.co/facebook/m2m100-12B-avg-5-ckpt

を使います. 最後の 5 epoch の平均を取ったもののようです.

model サイズは 47 GB です(fp32).

とりあえずは CPU で動かします.
ロードでは 90 GB くらい, 実行時は 45 GB くらい CPU memory を使いました.

デフォだと 20 tokens しか生成されないので, max_new_tokens=512 にしています.

from transformers import M2M100ForConditionalGeneration, M2M100Tokenizer

#en_text = """
#VEX uses the VEXcode framework, which enables users to start coding quickly and easily. VEXcode can be written in Blocks, Python, or C++. A VSCode extension can be found in the marketplace to assist students with coding.
#"""

en_text = """A VSCode extension can be found in the marketplace to assist students with coding."""

model = M2M100ForConditionalGeneration.from_pretrained("facebook/m2m100-12B-avg-5-ckpt")
tokenizer = M2M100Tokenizer.from_pretrained("facebook/m2m100-12B-avg-5-ckpt")

tokenizer.src_lang = "en"
encoded_ja = tokenizer(en_text, return_tensors="pt")
generated_tokens = model.generate(**encoded_ja, forced_bos_token_id=tokenizer.get_lang_id("ja"), max_new_tokens=512)
ret = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
print(ret)

'VEXは、ユーザーが簡単かつ迅速にコーディングを開始できるようにするVEXcodeフレームワークを使用しています。VEXcodeはブロック、Python、またはC++で書くことができます。'

'VSCode 拡張子は、学生がコーディングをサポートするために市場で見つけることができます。'

おー.

ただ長い文章そのままだと max_new_tokens 増やしてもうまくいきませんでした.
一文づつ整形して入力するのがよさそうです. また, 一文の長さもあまり長いのはダメかもしれません.

かしこさ

↑の翻訳では, "学生コーディングを", となっているのでさすがに NLLB mode 54B には及ばすですかね.
(まあ元の英語もちょい曖昧なところもあるので, "学生が"が正当な対訳かは議論の余地があろう)

NLLB 3.3B よりはかしこいので, 規模相当という感じでしょうか.

2023 年 6 月時点では, 精度と使いやすさの点で, 英日翻訳(日英翻訳)は M2M100 がベストそうです!

CTranslate2 で効率化(とたぶん高速化)

pytorch CPU でもそこそこ普通に動きますが, GPU でより高速化したいときもあります.

https://github.com/OpenNMT/CTranslate2

ctranslate2 で m2m100(NLLB も!)対応してました.
ctranslate2 使えば pytorch より高速に動くでしょう!(たぶん)

https://gist.github.com/ymoslem/a414a0ead0d3e50f4d7ff7110b1d1c0d

が見つかりますが, の ct2 変換済みモデルは古いのか最新 ctranslate2 では読めなかったため, ctranslate2 用に変換が必要です.

AttributeError: 'Namespace' object has no attribute 'langtoks' と出る場合,

https://forum.opennmt.net/t/convert-m2m-model-to-ctranslate2/4523/12

fairseq==0.10.2 と古いバージョンを使いましょう.
(また, その場合 python 3.8 である必要があります https://github.com/facebookresearch/fairseq/issues/3535 )

transformers ベース

ただ, ctranslate2 側では最新 fairseq 対応する予定はないのと, sentencepiece の tokenizer 設定がめんどいので, transformers ライブラリベースでの変換と利用がよいでしょう.

https://github.com/OpenNMT/CTranslate2/issues/853
https://opennmt.net/CTranslate2/guides/transformers.html#m2m-100

$ ct2-transformers-converter --model facebook/m2m100_1.2B --output_dir m2m100_1.2B

メモリは普通に transformers を動かすときと同じくらい消費するでしょう.
12B を変換する場合, 最低でも 96 GB CPU mem マシンがいるでしょう.
(↑にあるようにロードで 90 GB くらい消費する. )

変換自体は, モデルがダウンロードされていれば 12 B でも数分で終わります.

import ctranslate2
import transformers

ct2_model_path="/path/to/m2m100_1.2B"
translator = ctranslate2.Translator(ct2_model_path)
tokenizer = transformers.AutoTokenizer.from_pretrained("facebook/m2m100_1.2B")
tokenizer.src_lang = "en"

source = tokenizer.convert_ids_to_tokens(tokenizer.encode("Hello world!"))
target_prefix = [tokenizer.lang_code_to_token["ja"]]
results = translator.translate_batch([source], target_prefix=[target_prefix])
target = results[0].hypotheses[0][1:]

print(tokenizer.decode(tokenizer.convert_tokens_to_ids(target)))

これで, tokenizer は transfoermers AutoTokenizer 経由で sentencepiece のをぺろっとよろしくセットアップして, translation してくれます!

ct2 形式にモデル変換されているため, ロードと実行では, 消費メモリは概ね model サイズと同等です(12B なら 48 GB くらいあれば OK).

量子化

https://opennmt.net/CTranslate2/quantization.html

int8 で 12 GB くらい, fp16 で 22 GB くらいに model サイズを減らすことができます.
(22 GB ならギリ 3090 x 1 で動かせますね)

ためしに int8 量子化 と fp16 量子化で翻訳してみます.

A VSCode extension can be found in the marketplace to assist students with coding.

fp16 の結果.

VSCode 拡張子は、学生がコーディングをサポートするために市場で見つけることができます。

fp32 と同等になりました(この一文しか試していないけども...)

int8 の結果.

VSCodeの拡張子は、学生がコーディングを手助けするために市場で見つけることができます。

int8 でもいけそうでしょうか. 1.2B よりはかしこいです. int8 は 16 GB CPU mem サーバーや, ノート PC とかで翻訳させたいときにいいかも.

他にも int16 と int8_float16 もあるので, いくつか試してみてくださいネ.

https://opennmt.net/CTranslate2/quantization.html#implicit-type-conversion-on-load

CPU なら int8, GPU なら float16 がよさそうでしょうか.

llama.cpp(ggml)でうごかす?

llama.cpp(ggml) で M2M100 の model 構築したらいい感じに CPU で爆速で動くことでしょう.

1.2B であれば, 量子化してスマホでオンデバで動かすのもできるでしょう.

翻訳がうまくいかないケース

  • ニュース見出しなど短文だったり省略が多いもの
  • ArXiv 論文など, 専門用語が多いもの

ある程度はドメインに特化したファインチューンで対応できるとは思います...

TODO

  • 翻訳できる文の長さがどこまでいけるか調査する
  • 英語メインの Chat LLM(Falcon-40B instruct など)の前段と後段に M2M100 の翻訳を入れて, 日本語でチャットでいい感じにする.
  • llama.cpp などで動かす
  • 日英翻訳も試す
  • FuguMT の翻訳データセットを参考にして https://staka.jp/wordpress/?p=413 , back translation なども行い 5B ~ 20B くらいの規模で翻訳モデルの自前学習する!
  • ctranslate2 C++ API で利用して, Python フリーで動かす!

Discussion