見出し画像

【ローカル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}\n\n日本語訳: "

コード

  • 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くらいの生成速度。

API側の実行画面

翻訳例

  • 今回のELYZA-Llama-2-7b(GPTQ+LoRA)の出力をDeepLと比較した例は以下の通り。

"One day, it was very hot. The sun was very bright in the sky. Then, suddenly, it started to rain. The rain felt cool because of the heat. It came down very fast. Everyone was surprised by how fast it was raining. The rain kept coming and everyone got very wet. The children were happy to be playing in the rain. They ran around in the rain and danced and laughed. After a while, the rain stopped. The sun came out and it got hot again. All the water had disappeared and the children stopped playing. Everyone was tired from playing in the rain but happy too."

DeepL翻訳
「ある日、とても暑かった。太陽はとても眩しかった。すると突然、雨が降り出した。雨は暑さのために涼しく感じた。雨はあっという間に降ってきた。その雨の速さにみんな驚いた。雨は降り続き、みんなずぶ濡れになった。子どもたちは雨の中で遊べて嬉しそうだった。雨の中を走り回り、踊り、笑った。しばらくすると雨は止んだ。太陽が顔を出し、再び暑くなった。水はすべてなくなり、子供たちは遊ぶのをやめた。みんな雨の中で遊んで疲れたけど、嬉しかったよ」。

ELYZA-Llama-2-7b-instruct(GPTQ+LoRA)の翻訳
「ある日、暑くて気持ち良かった。空には明るい太陽が燦々と輝いていました。それでも、ふと雷が鳴り始め、すぐに降下し始めました。この時期らしい冷たさを感じながら、速く降り注ぎました。みんなびっくりして、どうやってこんなに早く降っているのだろうと思いました。水はすべて消え、子供達は楽しそうに雨で遊ぶようになりました。走り回ったり踊ったり笑ったりして、時間が経つに連れて強く降下し始めました。ある程度降り止み、太陽が出てきて再び暑くなりました。全部の水が無くなり、子供達もやがて遊ばなくなりました。みんな疲れていますが、楽しかったです。」

ELYZA-japanese-Llama-2-7b-instruct-4bitGPTQ+LoRA
  • 「it was very hot」を「暑くて気持ち良かった」、「The rain felt cool because of the heat」を「この時期らしい冷たさを感じながら」とする妙な誤訳がある。

感想

  • 全体的に実用レベルにはあと一歩及ばない感じ。オリジナルのLlama-2でもモデルサイズによる差は大きいので、今後リリース予定らしい「ELYZA-japanese-Llama-2-13B」に勝手に期待。