N番煎じでCyberagent社のCALM3-22B-Chat(量子化版)をDatabricks上で試す

いいモデルが本当に次々に出ますね。

# 導入

先日、Cyberagent社からCALM3-22B-Chatが公開されました。

https://huggingface.co/cyberagent/calm3-22b-chat

Cyberagent社は以前から[Open-Calm](https://huggingface.co/cyberagent/open-calm-7b)や[CALM2](https://www.cyberagent.co.jp/news/detail/id=29479)といった優秀な日本語対応LLMを公開していますが、おそらくそのバージョン3ということになるのだと思います。

2024/7月初旬現在、まだプレスリリースや詳細な技術情報が見当たらず、あまり詳しいことがわからないのですが、[HuggingFace](https://huggingface.co/cyberagent/calm3-22b-chat)の情報だと、220億パラメータを持ったLLMであり、コンテキスト長は16K、ライセンスはApache-2.0となります。

なお、以下にデモサイトがあります。

https://huggingface.co/spaces/cyberagent/calm3-22b-chat-demo

CALM2は以前に[こちら](https://qiita.com/isanakamishiro2/items/95c459c7ae3b0e05b3e1)の記事で少し触りましたが、70億パラメータという比較的小型でありながら日本語性能が高かったので、より大型であるCALM3はより凄いんじゃないかと興味を持ったので、試してみます。

試用にあたって、以下のEXL2(5.0bpw)で量子化されたものをダウンロードして利用しました。

https://huggingface.co/blockblockblock/calm3-22b-chat-bpw5-exl2

検証はDatabricks on AWS上で実施しました。
DBRは15.3ML、クラスタタイプはg5.xlargeです。
推論エンジンには[ExLlamaV2](https://github.com/turboderp/exllamav2)を利用します。

:::note warn
量子化モデルを利用していますので、本来のモデルとは出力結果が異なることに注意ください。
:::


# Step1. パッケージインストール

Flash-AttentionとExLlamaV2をインストール。

```python
%pip install https://github.com/Dao-AILab/flash-attention/releases/download/v2.5.9.post1/flash_attn-2.5.9.post1+cu122torch2.3cxx11abiFALSE-cp311-cp311-linux_x86_64.whl
%pip install https://github.com/turboderp/exllamav2/releases/download/v0.1.6/exllamav2-0.1.6+cu121.torch2.3.1-cp311-cp311-linux_x86_64.whl

dbutils.library.restartPython()
```

# Step2. モデルのロード

事前にダウンロードしておいたモデルやトークナイザなどをロードします。
(```/Volumes/training/llm/model_snapshots/models--blockblockblock--calm3-22b-chat-bpw5-exl2/```に保管しているものとします)

```python
from exllamav2 import (
    ExLlamaV2,
    ExLlamaV2Config,
    ExLlamaV2Cache_Q4,
    ExLlamaV2Tokenizer,
)

from exllamav2.generator import ExLlamaV2BaseGenerator, ExLlamaV2Sampler

import time
from exllamav2.generator import (
    ExLlamaV2DynamicGenerator,
    ExLlamaV2DynamicJob,
    ExLlamaV2Sampler,
)

batch_size = 1
cache_max_seq_len = 8192

model_directory = "/Volumes/training/llm/model_snapshots/models--blockblockblock--calm3-22b-chat-bpw5-exl2/"

config = ExLlamaV2Config(model_directory)

model = ExLlamaV2(config)
print("Loading model: " + model_directory)

cache = ExLlamaV2Cache_Q4(
    model,
    lazy=True,
    batch_size=batch_size,
    max_seq_len=cache_max_seq_len,
) 
model.load_autosplit(cache)
tokenizer = ExLlamaV2Tokenizer(config)

generator = ExLlamaV2DynamicGenerator(
    model=model,
    cache=cache,
    tokenizer=tokenizer,
    max_batch_size=1024,
    max_q_size=1,
)

gen_settings = ExLlamaV2Sampler.Settings(
    token_repetition_penalty=1.1,
    temperature=0.1,
    top_k=0,
    top_p=0.6,
)
max_new_tokens = 512
```

# Step3. バッチ推論

[こちらの記事](https://qiita.com/isanakamishiro2/items/fdc8915829fa3a31a176)と同様の問をなげて回答を取得します。

```python
# 今回推論する内容
prompts = [
    "Hello, what is your name?",
    "Databricksとは何ですか？詳細に教えてください。",
    "まどか☆マギカでは誰が一番かわいい?",
    "ランダムな10個の要素からなるリストを作成してソートするコードをPythonで書いてください。",
    "現在の日本の首相は誰？",
    "あなたはマラソンをしています。今3位の人を抜きました。あなたの今の順位は何位ですか?ステップバイステップで考えてください。",
]

system_prompt = """あなたは親切なAIアシスタントです。"""

# プロンプトを整形
def format_prompt(sp, p):
    return (
        f"
system\n{sp}
\n"
        f"
user\n{p}
\n"
        f"
assistant\n"
    )

print()
print("Creating jobs...")

completions = []
f_prompts = [format_prompt(system_prompt, p) for p in prompts]

for idx, p in enumerate(prompts):
    f_prompt = format_prompt(system_prompt, p)
    completions.append(f"Q: {p}\n")
    prompt_ids = tokenizer.encode(
        f_prompt,
        encode_special_tokens=True,
        add_bos=True,
    )
    job = ExLlamaV2DynamicJob(
        input_ids=prompt_ids,
        gen_settings=gen_settings,
        max_new_tokens=max_new_tokens,
        identifier=idx,
        stop_conditions = [tokenizer.eos_token_id],
    )
    generator.enqueue(job)

# Generate

print()
print("Generating...")

num_completions = 0
num_tokens = 0
time_begin = time.time()

while generator.num_remaining_jobs():
    results = generator.iterate()

    bsz = len(set([r["identifier"] for r in results]))

    for result in results:
        if not result["eos"]: continue

        idx = result["identifier"]
        response = result["full_completion"]
        completions[idx] += f"A: {response.lstrip()}"

        # パフォーマンス計測
        num_completions += 1
        num_tokens += result["new_tokens"]
        elapsed_time = time.time() - time_begin
        rpm = num_completions / (elapsed_time / 60)
        tps = num_tokens / elapsed_time
        print()
        print("---------------------------------------------------------------------------")
        print(f"Current batch size: {bsz}")
        print(f"Avg. completions/minute: {rpm:.2f}")
        print(f"Avg. output tokens/second: {tps:.2f}")
        print("---------------------------------------------------------------------------")

        # 推論結果出力
        print()
        print(f"Completion {idx}:")
        print()
        print(completions[idx])
```

以下、回答結果の出力です。（処理の関係上、質問リストの順番通りになっていません）

````:出力

Creating jobs...

Generating...

---------------------------------------------------------------------------
Current batch size: 6
Avg. completions/minute: 3.68
Avg. output tokens/second: 2.70
---------------------------------------------------------------------------

Completion 4:

Q: 現在の日本の首相は誰？
A: 2023年10月時点で、日本の首相は岸田文雄（きしだ ふみお）です。彼は2021年10月に第100代内閣総理大臣に就任しました。

---------------------------------------------------------------------------
Current batch size: 5
Avg. completions/minute: 7.07
Avg. output tokens/second: 5.48
---------------------------------------------------------------------------

Completion 0:

Q: Hello, what is your name?
A: Hi! I am a language model AI developed by OpenAI. I don't have a specific name like humans do, but you can call me "Assistant" or any other friendly term you prefer. How can I assist you today?

---------------------------------------------------------------------------
Current batch size: 4
Avg. completions/minute: 5.23
Avg. output tokens/second: 7.81
---------------------------------------------------------------------------

Completion 5:

Q: あなたはマラソンをしています。今3位の人を抜きました。あなたの今の順位は何位ですか?ステップバイステップで考えてください。
A: もちろんです。順を追って説明しますね。

1. スタート時点での順位を確認します。仮にあなたが最初に4位だったとします。
    - 「スタート時: 4位」

2. 次に、3位の人があなたの前を走っている状態です。この人を追い越すためには、その人の順位を抜く必要があります。
    - 「前を走る人: 3位」

3. 今、あなたはその3位の人に追いつき、追い越しました。この時点で、あなたは3位の人のポジションに入りました。
    - 「追い越し完了: 3位に位置」

4. したがって、あなたが抜いたことで、前の3位の選手のポジションが空きます。この瞬間、あなたは3位になります。
    - 「現在の順位: 3位」

結論として、あなたが3位の人を抜いた後のあなたの順位は「3位」となります。

---------------------------------------------------------------------------
Current batch size: 3
Avg. completions/minute: 6.14
Avg. output tokens/second: 12.23
---------------------------------------------------------------------------

Completion 3:

Q: ランダムな10個の要素からなるリストを作成してソートするコードをPythonで書いてください。
A: もちろんです。以下に、ランダムな10個の要素からなるリストを作成し、それをソートするPythonコードを示します。この例では、`random`モジュールを使用してランダムな要素を生成し、その後`sorted()`関数を使ってリストをソートしています。

```python
import random

# ランダムな10個の要素からなるリストを作成
random_list = [random.randint(1, 100) for _ in range(10)]
print("元のリスト:", random_list)

# リストを昇順にソート
sorted_list = sorted(random_list)
print("ソート後のリスト:", sorted_list)
```

このコードはまず、`random.randint(1, 100)`を用いて1から100までのランダムな整数を生成し、それをリストに格納します。次に、そのリストを`sorted()`関数に渡して昇順にソートし、結果を表示します。

---------------------------------------------------------------------------
Current batch size: 2
Avg. completions/minute: 6.49
Avg. output tokens/second: 16.30
---------------------------------------------------------------------------

Completion 2:

Q: まどか☆マギカでは誰が一番かわいい?
A: 「魔法少女まどか☆マギカ」のキャラクターの中で誰が「一番かわいい」と感じるかは、個々の好みによるところが大きいです。以下に主要なキャラクターを紹介しますが、それぞれ異なる魅力を持っています：

1. 鹿目まどか (Naho Madoka)
   - 主人公で、優しさと純粋さが特徴。彼女の成長や葛藤が見どころ。

2. 暁美ほむら (Homura Akemi)
   - 時間操作の能力を持ち、何度も同じ時間を繰り返している。クールな性格だが、内に秘めた感情が魅力的。

3. 巴マミ (Mami Aizuki)
   - ベテランの魔法少女で、母性的な一面を持つ。戦闘能力が高く、頼れる存在。

4. 美樹さやか (Sayaka Miki)
   - 友達思いで情熱的。彼女の葛藤と成長が描かれる。

5. 佐倉杏子 (Kyouko Sakura)
   - 自由奔放で姉御肌の性格。戦闘スタイルも個性的。

どのキャラクターが一番かわいいと感じるかは、あなた自身の感性や物語のどの側面に共感するかによるでしょう。例えば、優しい性格や成長過程を重視するなら鹿目まどかが好まれるかもしれませんし、強い意志や独自の魅力に惹かれるなら暁美ほむらが選ばれることもあります。

---------------------------------------------------------------------------
Current batch size: 1
Avg. completions/minute: 5.62
Avg. output tokens/second: 19.75
---------------------------------------------------------------------------

Completion 1:

Q: Databricksとは何ですか？詳細に教えてください。
A: Databricksは、データエンジニアリングと機械学習のための統合プラットフォームであり、Apache Sparkを基盤として構築されています。以下にDatabricksの主要な特徴や機能について詳しく説明します。

### 1. Apache Sparkとの統合
- DatabricksはApache Sparkをネイティブにサポートしており、Sparkジョブの実行、管理、監視が容易に行えます。
- データ処理、分析、機械学習のパイプラインを一元的に管理できます。

### 2. クラウドネイティブなアーキテクチャ
- AWS、Azure、Google Cloud Platform (GCP) など主要なクラウドプロバイダ上で動作します。
- Kubernetesベースのコンテナオーケストレーションにより、スケーラビリティと高可用性を提供します。

### 3. ノートブック環境
- Jupyter Notebookに似たインタラクティブな開発環境を提供し、データサイエンティストやアナリストがコードを書きながら結果を即座に確認できます。
- Python、R、Scalaなど複数の言語をサポートしています。

### 4. データレイクとストレージ
- Delta Lake: 高速で信頼性の高いデータレイク技術。変更履歴を保持し、リアルタイムのデータ操作が可能です。
- ファイルシステム（HDFS, S3）やオブジェクトストレージとの連携も容易です。

### 5. セキュリティとガバナンス
- ロールベースのアクセス制御 (RBAC)、データ暗号化、監査ログなどの機能を持ち、コンプライアンス要件に対応しています。
- 組織全体での一貫したデータガバナンスを実現するためのツールとポリシーを提供します。

### 6. 機械学習ワークフロー
- MLflow: 機械学習モデルの開発、デプロイ、モニタリングのためのエコシステム。
- 自動化されたパイプライン: トレーニング、評価、デプロイの自動化を支援します。

### 7. コラボレーションとチーム作業
- リアルタイムでの共同編集と共同作業が可能。
- バージョン管理と変更追跡が容易になります。

### 8. コスト効率
- 自動スケーリング機能により、リソースの効率的な利用が可能。
- クラウドベースの料金体系により、必要なときにだけリソースを使用することができます。

### 9. インテグレーション
- その他のデータソースやサービス（例えば、SQLデータベース、NoSQLデータベース、ストリーミングデータソース）とのシームレスな連携が可能です。

### まとめ
Databricksは、データエンジニアリング、データサイエンス、機械学習の各分野において強力なツールセットを提供し、企業が迅速かつ効率的に
````

非常にしっかりと回答してくれますね！日本に対する知識量も豊富です。
若干端的なところはありますが、まったく違和感がありません。
CoTもどきなプロンプトにしていますが、マラソン問題も正解しています。

これまでよりもパラメータ数が多いモデルになりますが、量子化と組み合わせると十分使いやすいサイズではないでしょうか。

# まとめ

Cyberagent社のCALM3-22B-Chat(量子化版)を試してみました。
このサイズで非常に高い日本語性能を保有しているように思います。
詳しい情報は今後出てくると思うのですが、ライセンスも使いやすいですし、これが使えれば十分というビジネスシチュエーションも多いのではないかと思いました。