N番煎じでCohere社のCommand-R 08-2024をDatabricks上で試す

# 導入

Cohere社が大規模言語モデルCommand-Rシリーズの最新バージョンを公開しました。

https://cohere.com/blog/command-series-0824

Command Rシリーズは、引用によるRAG(Retrieval-augmented generation)、10以上の言語での多言語対応によるグローバルなビジネスオペレーションのサポート、複雑なワークフローを自動化するツールの使用に優れているモデルです。もちろん日本語もOK。
以前のバージョンと比べて、スループット含めて大幅に性能向上しているとのことでした。

ライセンス体系はCC-BY-NCかつCohere社の利用規約遵守が必要です。
商用利用においてはCohere社からの許諾が必要という認識。

既に以下のような御大が試されていますが、N番煎じとしてこちらでもやってみようと思います。

https://note.com/npaka/n/n3237af6ce190

なお、Command-RシリーズはCommand-RとCommand-R-Plusの2種公開されていますが、今回は無印の方を試します。

検証はDatabricks on AWS上で行いました。
DBRは15.4ML、インスタンスタイプはg5.xlargeです。
推論エンジンは[ExLlamaV2](https://github.com/turboderp/exllamav2)を利用し、EXL2形式で量子化されたモデルを利用します。

:::note warn

量子化したモデルのため、本来のモデルとは異なる出力になる可能性があります。

:::

# Step1. パッケージインストール & パラメータ設定

ノートブックを作成し、Flash-AttentionとExLlamaV2をインストール。

```python
# Flash Attensino
%pip install -U flash-attn --no-build-isolation
# ExllamaV2
%pip install https://github.com/turboderp/exllamav2/releases/download/v0.2.0/exllamav2-0.2.0+cu121.torch2.3.1-cp311-cp311-linux_x86_64.whl

dbutils.library.restartPython()
```

また、処理内で利用する各種変数を宣言。

```python
# Command-R推論用の各種パラメータ
model_path = "/Volumes/training/llm/model_snapshots/models--Downtown-Case--CohereForAI_c4ai-command-r-08-2024-exl2-3.75bpw/"
prompt_template = {
    "system": "

{}
",
    "user": "

{}
",
    "assistant": "

{}
",
    "last": "

",
}
max_seq_len = 16384
max_new_tokens = 512
additional_stop_tokens = []
```

# Step2. モデルのロード

ExLlamaV2でモデルファイルをロード。
こちらの3.75bpwで量子化されたモデルをダウンロードして利用しました。

https://huggingface.co/Downtown-Case/CohereForAI_c4ai-command-r-08-2024-exl2-3.75bpw

```python
from exllamav2 import (
    ExLlamaV2,
    ExLlamaV2Config,
    ExLlamaV2Cache_Q4,
    ExLlamaV2Cache_Q8,
    ExLlamaV2Cache_TP,
    ExLlamaV2Tokenizer,
)
from exllamav2.generator import ExLlamaV2DynamicGenerator
from exllamav2.generator import ExLlamaV2Sampler

def load_model(model_path, max_seq_len):
    """ model_pathからモデルをロードします。 """

    config = ExLlamaV2Config(model_path)
    config.arch_compat_overrides()

    model = ExLlamaV2(config)
    cache = ExLlamaV2Cache_Q4(
        model,
        max_seq_len=max_seq_len,
        lazy=True,
    )

    model.load_autosplit(cache, progress=True)
    tokenizer = ExLlamaV2Tokenizer(config)

    generator = ExLlamaV2DynamicGenerator(
        model=model,
        cache=cache,
        tokenizer=tokenizer,
        paged=True,
    )
    generator.warmup()

    return generator


def format_prompt(sp, p):
    """ システムとユーザーの入力でプロンプトをフォーマットします。 """
    return prompt_template['system'].format(sp) + prompt_template['user'].format(p) + prompt_template['last']

# モデルのロード
generator = load_model(model_path, max_seq_len)

# 推論設定の作成
gen_settings = ExLlamaV2Sampler.Settings(
    token_repetition_penalty=1.1,
    temperature=temperature,
    top_k=0,
    top_p=0.6,
)
```

# Step3. 推論実行

いくつかの問い合わせをプロンプトとしてバッチ実行します。


```python
import time

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

system_prompt = """あなたは親切なAIアシスタントです。日本語で回答してください。"""

# プロンプト準備

f_prompts = [format_prompt(system_prompt, p) for p in prompts]
stop_conditions = [generator.tokenizer.eos_token_id] + [
    generator.tokenizer.single_id(s) for s in additional_stop_tokens
]

# 生成

time_begin = time.time()
outputs, last_results = generator.generate(
    prompt=f_prompts,
    max_new_tokens=max_new_tokens,
    gen_settings=gen_settings,
    completion_only=True,
    stop_conditions=stop_conditions,
    encode_special_tokens=True,
    add_bos=True,
    add_eos=False,
    return_last_results=True,
)
elapsed_time = time.time() - time_begin

# 結果表示

for p, output in zip(prompts, outputs):
    print("Q:", p)
    print("A:", output)
    print("---" * 50)    

new_tokens = sum([result["new_tokens"] for result in last_results])
tps = new_tokens / elapsed_time

print("=" * 50)
print(f"Total Generated Tokens: {new_tokens:d}")
print(f"Avg. output tokens/second: {tps:.2f}")
```

結果は以下の通り。

````md:出力
Q: Hello, what is your name?
A: こんにちは！私は、コヒートという名前のAIアシスタントです。何かお手伝いできることはありますか？
------------------------------------------------------------------------------------------------------------------------------------------------------
Q: Databricksとは何ですか？詳細に教えてください。
A: Databricks は、データの収集、分析、および管理のためのクラウドベースのプラットフォームです。これは、ビッグデータと機械学習を扱うための包括的なツールを提供し、企業がデータから価値を引き出すのを支援します。

Databricks の主な特徴には次のようなものがあります：

1. **Apache Spark との統合**: Databricks は Apache Spark と密接に連携しており、Spark の強力な機能を利用できるように設計されています。 Spark は高速なデータ処理と分析のための人気のあるオープンソースフレームワークであり、Databricks はこのテクノロジーを活用して大規模なデータセットを効率的に処理します。

2. **コラボレーションと共有**: Databricks は、データサイエンティスト、エンジニア、ビジネスアナリストなどのチームメンバー間の協業を促進するように設計されています。ユーザーはノートブックやコードを共有し、共同作業することで、データ探索と分析をより効率的に行えます。

3. **スケーラビリティ**: Databricks は、データの量や複雑さが増しても対応できるスケーラブルなアーキテクチャを備えています。クラウドインフラストラクチャ上で実行されるため、需要に応じてリソースを動的に調整できます。

4. **機械学習と AI**: Databricks は機械学習と人工知能 (AI) プロジェクトをサポートするツールを提供します。機械学習モデルを構築、トレーニング、デプロイするための統合された環境を提供し、データサイエンティストが高度な分析タスクを実行できるようにします。

5. **データの可視化**: Databricks は、データの視覚化とレポート作成のためのツールも提供します。これにより、ユーザーはデータをインタラクティブなダッシュボードやグラフで表示し、洞察を得ることができます。

6. **セキュリティ**: Databricks は、データの機密性とプライバシーを保護するために、堅牢なセキュリティ機能を備えています。アクセス制御、暗号化、監査ログなど、さまざまなセキュリティ対策が実装されています。

7. **データパイプライン**: Databricks は、データパイプラインとワークフローを管理するためのツールを提供します。これにより、データの取得、変換、分析、および報告のための自動化されたプロセスを作成できます。

8. **クラウド中立性**: Databricks は複数のクラウドプロバイダーと互換
------------------------------------------------------------------------------------------------------------------------------------------------------
Q: まどか☆マギカでは誰が一番かわいい?
A: 個人の好みによるところが大きいので、誰が一番かわいいと断言するのは難しいですね。

『まどか☆マギカ』には、まどか、ほむら、さやか、マミ、杏子など魅力的なキャラクターがたくさん登場します。それぞれに個性があり、ファンの間でも人気が高いキャラクターが多いです。

例えば、主人公の鹿目まどかは純粋で優しく、その健気な姿に惹かれる人も多いでしょう。また、時間を操る能力を持つ暁美ほむらは、複雑な過去や強い意志を持ったキャラクターとして人気を集めています。

他にも、感情豊かな巴マミや、明るく元気な美樹さやかなど、それぞれの魅力が詰まったキャラクターたちがいます。

どのキャラクターも独特の存在感と魅力を持っているので、ファンにとっては甲乙つけがたいかもしれませんね！
------------------------------------------------------------------------------------------------------------------------------------------------------
Q: ランダムな10個の要素からなるリストを作成してソートするコードをPythonで書いてください。
A: わかりました！以下のようなコードで、ランダムに生成された10個の要素からなるリストを作成し、昇順にソートすることができます：

```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` モジュールを使用して、1から100の範囲でランダムな10個の整数を生成します。その後、`sorted()` 関数を適用することで、リストを昇順にソートします。実行すると、元のリストとソート後のリストが表示されます。
------------------------------------------------------------------------------------------------------------------------------------------------------
Q: 現在の日本の首相は誰？
A: 2023年8月現在、日本の首相は岸田文雄さんです。彼は自由民主党の所属で、第100代内閣総理大臣として2021年10月から在任中です。
------------------------------------------------------------------------------------------------------------------------------------------------------
Q: あなたはマラソンをしています。今3位の人を抜きました。あなたの今の順位は何位ですか?ステップバイステップで考えてください。
A: 現在の状況を整理しましょう：

- 最初、あなたは3位でした。
- その後、3位の人を抜いたので、あなたは2位に上がりました。

なので、現在のあなたの順位は2位です。
------------------------------------------------------------------------------------------------------------------------------------------------------
==================================================
Total Generated Tokens: 1031
Avg. output tokens/second: 16.46
````

うん、自然な回答。マラソン問題は間違えていますが、おそらくPlusだと正解するのではないかと思います。

# まとめ

Command-Rは前バージョンから日本語もかなり強いモデルという印象でしたが、正常に進化している印象を受けました。Plusも[こちら](https://huggingface.co/spaces/CohereForAI/c4ai-command)で触ってみている限り、非常に高い性能です。（軽く試す分にはCommand-RとCommand-R-Plusの差がわからないぐらいどっちも良い）

Command-Rはチャット利用というよりRAGやTool Callingなどの利用に強みがあるモデルですので、そのあたりでも性能の良いLLMを探している方にとっては、有力な候補になりそうですね。