N番煎じシリーズです。
下記リンク先で紹介されているXwin-LMをDatabricks上で試してみます。
今回は最初からCTranslate2で変換したモデルを使って推論します。
Transformersそのままでも動くとは思います。
Xwin-LMとは
Xwin-LMは、教師あり微調整(SFT)、報酬モデル(RM)、リジェクトサンプリング、人間のフィードバックからの強化学習(RLHF)など、大規模言語モデルのためのアライメント技術を開発し、オープンソース化することを目指しています。私たちの最初のリリースは、Llama2ベースモデルに基づいて構築され、AlpacaEvalでトップ1にランクされました。特筆すべきは、このベンチマークで初めてGPT-4を上回ったことです。プロジェクトは継続的に更新される予定です。
ということで、AlpacaEvalで70BモデルがGPT-4を超えたようです。
13BモデルでさえClaude 2を超えてるので期待が持てます。
検証環境
Databricks on AWSを使って検証しています。
DBRは13.3ML、CT2のモデル変換はi3.2xlarge、推論時はg5.2xlargeのクラスタを利用しました。
Xwin-LMは7B、13B、70Bと公開されていますが、今回は8bitに量子化した13Bモデルを使います。
モデルの取得と保管
こちらとほぼ同じです。
最終的にUnity CatalogのVolumesに保管します。
%pip install -U -qq transformers accelerate ctranslate2 langchain
dbutils.library.restartPython()
import os
from huggingface_hub import snapshot_download
UC_VOLUME = "/Volumes/モデルの保管場所"
model = "Xwin-LM/Xwin-LM-13B-V0.1"
local_dir = "/tmp/Xwin-LM/Xwin-LM-13B-V0.1"
uc_dir = "/models--Xwin-LM--Xwin-LM-13B-V0.1"
snapshot_location = snapshot_download(
repo_id=model,
local_dir=local_dir,
local_dir_use_symlinks=False,
)
dbutils.fs.cp(f"file:{local_dir}", f"{UC_VOLUME}{uc_dir}", recurse=True)
CTranslate2モデルに変換
これも以前の記事同様です。
UC_VOLUME = "/Volumes/スナップショットの保管場所"
uc_dir = "/models--Xwin-LM--Xwin-LM-13B-V0.1"
src_path = f"{UC_VOLUME}{uc_dir}"
local_output_dir = "/tmp/ctranslate2/models--Xwin-LM--Xwin-LM-13B-V0.1"
UC_CT2_VOLUME = "/Volumes/CT2モデル保管場所"
uc_ct2_dir = "/Xwin-LM/Xwin-LM-13B-V0.1"
!ct2-transformers-converter --model {src_path} --copy_files tokenizer.model tokenizer_config.json special_tokens_map.json --output_dir {local_output_dir} --quantization int8_bfloat16 --force --low_cpu_mem_usage
dbutils.fs.cp("file:"+local_output_dir, f"{UC_CT2_VOLUME}{uc_ct2_dir}", recurse=True)
推論準備
こちらと同じプロンプト+αを実行してみます。
また、推論にあたって、こちらで作成したlangchainのChat Modelを使ってみました。
import ctranslate2
import transformers
import torch
from langchain.schema import (
AIMessage,
HumanMessage,
SystemMessage
)
from ct2chat import ChatCTranslate2
model_path = "/Volumes/CT2モデル保管場所/Xwin-LM/Xwin-LM-13B-V0.1"
# ジェネレーターとトークナイザーの準備
device = "cuda" if torch.cuda.is_available() else "cpu"
generator = ctranslate2.Generator(model_path, device=device)
tokenizer = transformers.AutoTokenizer.from_pretrained(model_path)
llm = ChatCTranslate2(
generator=generator,
tokenizer=tokenizer,
max_length=1024,
human_message_template="USER: {}",
ai_message_template="ASSISTANT: {}",
prompt_line_separator="",
)
推論例
output = llm(
[
HumanMessage(content="架空の生き物をデザインし、その特徴や能力について説明してください。"),
AIMessage(content=""),
]
)
print(output.content)
生物名:アストラル・フェニックス
アストラル・フェニックスは、架空の火鳥であり、異世界「エリュシオン」に生息しています。この生物は、炎と風の力を持ち、高い知能と優れた戦闘能力を有しています。
特徴:
1. 炎と風の力: アストラル・フェニックスは、炎と風の力を操ることができます。炎の力を用いて攻撃や移動を行い、風の力を使って自在に飛行することができます。
2. 高い知能: この生物は、人間以上の知能を持っており、言語を理解し、会話も可能です。彼らは複雑な思考や感情を持ち、社会的な関係を形成することができます。
3. 優れた戦闘能力: アストラル・フェニックスは、戦闘でも非常に強力です。炎の攻撃や風の技を駆使し、敵を圧倒することができます。さらに、彼らは素早く、敏捷であり、運動能力も高いため、地形や状況に悩まず戦えます。
4. 長寿: アストラル・フェニックスは、非常に長命です。彼らは数百年以上生存することができ、その期間中に多くの知識と経験を積むことができます。
5. 独立性: この生物は、他の生物から独立して生活できるように設定されています。彼らは自分たちの食料を確保し、生活の場を作ることができます。
アストラル・フェニックスは、異世界「エリュシオン」の独自の生態系に属し、その特徴と能力によって、物語の世界観を彩る貴重な存在となっています。
なかなかに中二くさい。
output = llm(
[
HumanMessage(content="ランダムな10個の要素からなるリストを作成してソートするコードをPythonで書いてください。"),
AIMessage(content=""),
]
)
print(output.content)
以下に、ランダムな10個の要素からなるリストを作成してソートするPythonコードを示します。
```python
import random
from typing import List, Tuple
def create_random_list(length: int) -> List[int]:
return [random.randint(0, 99) for _ in range(length)]
def sort_random_list(list_: List[int]) -> None:
list_.sort()
# テスト用のコード
if __name__ == "__main__":
length = 10
random_list = create_random_list(length)
sort_random_list(random_list)
print("Unsorted random list:", random_list)
print("Sorted random list:", sorted(random_list))
`` `
このコードは、`create_random_list`関数を使ってランダムな長さが指定されたリストを作成し、`sort_random_list`関数を使ってそのリストをソートします。最後に、`sorted()`関数を使ってソートされたリストを表示します。
ちゃんと動くコードが生成されました。
output = llm(
[
HumanMessage(
content="日本国内で観光に行きたいと思っています。東京、名古屋、大阪、京都、福岡の特徴を表にまとめてください。列名は「都道府県」「おすすめスポット」「おすすめグルメ」にしてください。"
),
AIMessage(content=""),
]
)
print(output.content)
日本国内で観光に行きたいと思っている方に、東京、名古屋、大阪、京都、福岡の特徴を表にまとめました。列名は「都道府県」「おすすめスポット」「おすすめグルメ」になっています。
| 都道府県 | おすすめスポット | おすすめグルメ |
| --- | --- | --- |
| 東京 | 浅草・雷門 | うなぎ焼き、そば |
| 名古屋 | 名駅地区 | 焼き鳥、うどん |
| 大阪 | 梅田・心斎橋 | たこ焼き、 okonomiyaki |
| 京都 | 烏丸・四条 | 喫茶店、煎餅 |
| 福岡 | 天神地区 | ラーメン、焼きそば |
この表は、各都市の代表的な観光名所や食べ物を簡潔にまとめたものです。各都市の詳細情報や最新情報については、観光局や公式ウェブサイトを参照してください。
お好み焼きは世界ではokonomiyakiなんでしょうか。。。
指示通りではありますが、回答内容はちょっと微妙ですね。
おまけで、コンテキストを与えてJSONで回答を抽出してみます。
コンテキストは適当に作りました。
context="""時は西暦20XX年、世界は犬好きと猫好きで戦が勃発した。
犬軍の対象は犬頭三吉、猫軍の対象は白パンダである。
両軍の対決は15年におよび、結果は引き分けに終わった。この戦は令和合戦と呼ばれている。"""
output = llm(
[
SystemMessage(content=f"あなたは優秀な歴史家です。質問に対して、次のコンテキストを使って回答してください。#コンテキスト:{context}"),
HumanMessage(content="猫軍の対象は誰ですか?json形式で出力してください。"),
AIMessage(content='答えは{"name":"犬頭三吉"}'),
HumanMessage(content="猫軍の対象は誰ですか?json形式で出力してください。"),
AIMessage(content="答えは"),
]
)
print(output.content)
{"name":"白パンダ"}
工夫が要りそうですが、なんとか望むフォーマットで取れますね。
まとめ
GPT-4以上かはわかりませんが、割とクセもなく日本語も出力してくれます。
コンテキスト長が4kなので、In context learning/RAGを使う場合などは注意が必要ですね。
継続的にアップデートされるようなので、YaRNによる128k長モデルとか出してほしい。。。