【ローカルLLM】ELYZA-Llama-2を機械翻訳APIとして使ってみる
LLMの物語生成のテスト(趣味)に使うため「TinyStories」というデータセットを日本語訳したいと思った。
試しに「ELYZA-japanese-Llama-2-7B」を機械翻訳API的に使ってみたのでその記録。
ELYZA社によれば「ELYZA-japanese-Llama-2-7B」にはGPT-3.5に匹敵する日本語性能があるとのこと。
翻訳タスクに限定して検証なされている下記ブログでは、7Bモデルとしては翻訳性能は高いと評価されている。
LoRAの作成
そのまま「ELYZA-japanese-Llama-2-7B-instruct」で翻訳したところ「部屋の中でLily and Benがケンカをしているのが見つかります。」のような、英語が訳出しきれないケースが散見された(特に長文の場合)。
デフォルトのプロンプトフォーマットのままだと扱いづらいこともあり、和訳用途で使いやすいように簡単な翻訳LoRAを作成してみた。
以前の記事で簡易翻訳データセットを使ってVicunaをQLoRAファインチューンしてみたときの手順を踏襲して学習('loss': 0.484, 'learning_rate': 0.0002, 'epoch': 1.51)。
ただし、和訳の場合は指示文が日本語の方がいいみたいなので、以下のようなプロンプトフォーマットに変更した。
コード
text-generation-webuiのAPI機能を使い、GPTQ量子化した「ELYZA-Llama-2-7b-instruct」と今回のLoRAをロードして起動。
# Text Generation WebUIのインストール
!git clone https://github.com/oobabooga/text-generation-webui
%cd text-generation-webui
# 依存関係のインストール
!pip install -r requirements.txt
!pip install flask_cloudflared
# モデル(GPTQ)とLoRAのダウンロード
!python3 download-model.py TFMC/ELYZA-japanese-Llama-2-7b-instruct-GPTQ-4bit-64g
!wget -c https://huggingface.co/TFMC/Translation-LoRA-for-ELYZA-japanese-Llama-2-7b-instruct/resolve/main/adapter_config.json -P ./loras/translation-lora/
!wget -c https://huggingface.co/TFMC/Translation-LoRA-for-ELYZA-japanese-Llama-2-7b-instruct/resolve/main/adapter_model.bin -P ./loras/translation-lora/
# WebUIをAPIサーバーとして起動
!python3 server.py --public-api --verbose --loader exllama --model TFMC_ELYZA-japanese-Llama-2-7b-instruct-GPTQ-4bit-64g --lora translation-lora
元のデータセット(.parquet)はJSONLに変換したうえで、テスト用に10件ほど抽出。
APIによるデータセット和訳用のPythonスクリプトを別途実行(ChatGPTに投げて作ってもらった)。
import json
import requests
URI = 'https://*****-*****-*****-*****.trycloudflare.com/api/v1/generate' # APIのURLを入力
def translate(text):
request = {
'prompt': f"次の英文を日本語に訳してください: {text}\n\n日本語訳: ",
'max_new_tokens': 1024,
'auto_max_new_tokens': True,
'max_tokens_second': 1024,
'preset': 'None',
'do_sample': True,
'temperature': 0.1,
'top_p': 0.1,
'typical_p': 1,
'epsilon_cutoff': 0, # In units of 1e-4
'eta_cutoff': 0, # In units of 1e-4
'tfs': 1,
'top_a': 0,
'repetition_penalty': 1.18,
'repetition_penalty_range': 0,
'top_k': 40,
'min_length': 0,
'no_repeat_ngram_size': 0,
'num_beams': 1,
'penalty_alpha': 0,
'length_penalty': 1,
'early_stopping': False,
'mirostat_mode': 0,
'mirostat_tau': 5,
'mirostat_eta': 0.1,
'guidance_scale': 1,
'negative_prompt': '',
'seed': -1,
'add_bos_token': True,
'truncation_length': 2048,
'ban_eos_token': False,
'skip_special_tokens': True,
'stopping_strings': []
}
response = requests.post(URI, json=request)
if response.status_code == 200:
return response.json()['results'][0]['text']
else:
print(f"Error: {response.text}")
return ""
with open('Dataset-Test.jsonl', 'r') as f_in:
with open('Dataset-Test-JA.jsonl', 'w') as f_out:
for line in f_in:
data = json.loads(line)
ja_text = translate(data['text'])
data['text'] = ja_text
json.dump(data, f_out)
f_out.write('\n')
APIサンプルのパラメータだと長いテキストが処理されなかったので、'auto_max_new_tokens'や'max_tokens_second'を適当に調整した。
Google Colabの標準(T4)GPUで、32 tokens/sくらいの生成速度。
翻訳例
今回のELYZA-Llama-2-7b(GPTQ+LoRA)の出力をDeepLと比較した例は以下の通り。
「it was very hot」を「暑くて気持ち良かった」、「The rain felt cool because of the heat」を「この時期らしい冷たさを感じながら」とする妙な誤訳がある。
感想
全体的に実用レベルにはあと一歩及ばない感じ。オリジナルのLlama-2でもモデルサイズによる差は大きいので、今後リリース予定らしい「ELYZA-japanese-Llama-2-13B」に勝手に期待。