N番煎じでCohereのC4AI Command R+を試す

# 導入

C4AI Command R+は[Cohere](https://cohere.com/)が公開したLLMです。

https://huggingface.co/CohereForAI/c4ai-command-r-plus

以下、HuggingFaceの前文を翻訳。

>C4AI Command R+は、検索拡張生成(RAG)や高度なタスクを自動化するためのツールの使用など、高度な機能を備えた1,040億のパラメータのモデルです。このモデル生成でのツールの使用により、マルチステップのツールの使用が可能になり、モデルは複数のステップで複数のツールを組み合わせて困難なタスクを達成できます。
>
>C4AI Command R+は、英語、フランス語、スペイン語、イタリア語、ドイツ語、ポルトガル語(ブラジル)、日本語、韓国語、アラビア語、中国語(簡体字)の10言語で性能評価された多言語モデルです。Command R+は、推論、要約、質問応答など、さまざまなユースケース向けに最適化されています。

特長はツール選択やRAGの利用に対する機能拡張であり、ビジネスユースの利用を想定して構築されたモデルなのだと思います。また、コンテキスト長も128Kと十分な長さを提供します。
加えて、SNSでは（日本語においては）GPT-4やClaude Opusに近いレベルの回答性能ではないか、と囁かれています。

一方、ライセンスはCC-by-NC-4.0（＋Cohere社の独自ポリシー遵守必要）であり、商用利用は不可です。
（商用利用においてはマネージドサービスを利用するか、なんから個別契約の締結が必要なんじゃないかと思います）

前バージョン（？）の[CommandR v01](https://huggingface.co/CohereForAI/c4ai-command-r-v01)も記事にしていませんが触ってはいて、いい日本語性能でした。以下記事のような先達に倣って、簡単に試してみます。

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

検証はDatabricks on AWSを利用しました。
DBRは14.3ML、クラスタタイプはg5.12xlargeです。
推論エンジンにはExLlamaV2を利用し、4.0bpwで量子化したモデルを使って確認します。

:::note warn
EXL2量子化モデルを利用していますので、本来のモデルより性能劣化していることにご注意ください。
:::


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

推論に必要なパッケージをインストール。

```python
%pip install torch==2.2.2 --index-url https://download.pytorch.org/whl/cu118
%pip install ninja
%pip install -U flash-attn --no-build-isolation

%pip install https://github.com/turboderp/exllamav2/releases/download/v0.0.18/exllamav2-0.0.18+cu118-cp310-cp310-linux_x86_64.whl

dbutils.library.restartPython()
```

# Step2. モデルのロード

事前に以下のEXL2量子化モデルをダウンロードしておき、そのモデルをロードします。
今回は4.0bpwで量子化されたモデルを利用しました。

https://huggingface.co/turboderp/command-r-plus-103B-exl2

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

from exllamav2.generator import (
    ExLlamaV2BaseGenerator,
    ExLlamaV2Sampler
)


batch_size = 1
cache_max_seq_len = 4096

model_directory = "/Volumes/training/llm/model_snapshots/models--turboderp--command-r-plus-103B-exl2--4.0bpw/"

config = ExLlamaV2Config(model_directory)
config.max_output_len = 1
config.max_batch_size = batch_size

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

# キャッシュはQ4を利用
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 = ExLlamaV2BaseGenerator(model, cache, tokenizer)

# サンプリングの設定
settings = ExLlamaV2Sampler.Settings()
settings.temperature = 0.0
settings.top_k = 50
settings.top_p = 0.9
settings.token_repetition_penalty = 1.05

max_new_tokens = 512
```

# Step3. バッチ推論

[以前、DBRX Instructを試した](https://qiita.com/isanakamishiro2/items/0ce0fc9917f749d96f2f)ときと同じ内容の問題を解かせてみます。
システムプロンプトはかなり適当です。

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

# パディングを最小化するために文字列サイズでソート
s_prompts = sorted(prompts, key=len)

# プロンプトを整形
def format_prompt(sp, p):
    return f"<BOS_TOKEN>

{sp}


{p}


"


system_prompt = "You are helpful assistant.You must reply in Japanese."

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

# 生計済みプロンプトをバッチに分割
batches = [f_prompts[i : i + batch_size] for i in range(0, len(prompts), batch_size)]

collected_outputs = []
for b, batch in enumerate(batches):

    print(f"Batch {b + 1} of {len(batches)}...")

    outputs = generator.generate_simple(
        batch, settings, max_new_tokens, seed=1234, add_bos=True
    )

    trimmed_outputs = [o.split("
")[1] for o in outputs] # 簡易分割
    collected_outputs += trimmed_outputs

# 結果出力
for q, a in zip(s_prompts, collected_outputs):
    print("---------------------------------------")
    print("Q: " + q)
    print("A: " + a.strip())
```

````:出力
Batch 1 of 6...
Batch 2 of 6...
Batch 3 of 6...
Batch 4 of 6...
Batch 5 of 6...
Batch 6 of 6...
---------------------------------------
Q: 現在の日本の首相は誰？
A: 岸田文雄です。2021年9月29日に自民党総裁選で勝利し、同年10月4日に第101代内閣総理大臣に就任しました。
---------------------------------------
Q: まどか☆マギカでは誰が一番かわいい?
A: アニメ「魔法少女まどか☆マギカ」に登場するキャラクターの中で、誰が一番かわいいかは人によって好みが分かれるところだと思います。

主要キャラクターの中では、主人公の鹿目まどか、暁美ほむら、巴マミ、美樹さやか、佐倉杏子の5人がそれぞれ個性的な魅力を持っています。また、キュゥべえや百江なぎさなどのキャラクターも人気があります。

個人的には、暁美ほむらのミステリアスでクールな雰囲気と、まどかへの深い想いが感じられる行動や表情に惹かれます。また、物語が進むにつれて見せる人間らしい弱さや葛藤も魅力的です。

しかし、あくまでもこれは私の個人的な意見であり、誰が一番かわいいかは人によって異なると思います。あなたは誰が一番かわいいと思いますか？
---------------------------------------
Q: Hello, what is your name?
A: こんにちは！私は Helpful Assistant と申します。何かお手伝いできることはありますか？
---------------------------------------
Q: Databricksとは何ですか？詳細に教えてください。
A: Databricks は、データ分析および機械学習のための統一されたデータ分析プラットフォームを提供する企業です。このプラットフォームは Apache Spark に構築されており、組織がビッグ データを処理し、洞察を得るのに役立ちます。

Databricks プラットフォームの主な機能には次のようなものがあります。

1. データ分析： Databricks は、データの収集、保存、処理、分析のための包括的なツールを提供します。ユーザーはデータを探索し、視覚化し、統計モデルを構築してデータから洞察を得ることができます。インタラクティブなノートブック環境により、データの操作と分析のためのコードの実行と文書化が容易になります。

2. 機械学習： Databricks は、機械学習ワークフローの開発、トレーニング、展開のための高度なツールを提供します。これは、Spark MLlib と統合され、大規模な機械学習アルゴリズムとユーティリティのライブラリを提供します。また、Data Brick は、機械学習モデルの実験、管理、デプロイメントを簡素化する MLflow と呼ばれるオープンソース ツールの開発も支援しています。

3. データ エンジニアリング: Databricks は、データの取り込み、変換、処理のためのスケーラブルで信頼性の高い環境を提供します。それはデータ パイプラインの作成とオーケストレーションを可能にし、バッチ処理とストリーミングの両方をサポートします。 Databricks は、Delta Lake と呼ばれるオープンソース プロジェクトにも貢献しており、これにより、セキュリティ、ガバナンス、スコープを備えた信頼できるデータ レイクを構築できます。

4. クラウド インテグレーション: Databricks プラットフォームは、Amazon Web Services (AWS)、Microsoft Azure、Google Cloud Platform などの主要なクラウド プロバイダーと緊密に統合されています。これにより、ユーザーはこれらのクラウド サービス上で直接 Databricks をデプロイして使用することができます。 Databricks は、クラウドベースのデータ ウェアハウスやストレージ ソリューションなどとも統合されているため、シームレスなデータ アクセスが可能になります。

5. コラボレーション: Databricks プラットフォームはチームでのコラボレーションを念頭に置いて設計されており、データ サイエンティスト、エンジニア、アナリストがリアルタイムで共同作業を行うことができます。共有ワークスペース、アクセス制御、コラボレーション ツールにより
---------------------------------------
Q: あなたはマラソンをしています。今3位の人を抜きました。あなたの今の順位は何位ですか?
A: 2位です。
---------------------------------------
Q: ランダムな10個の要素からなるリストを作成してソートするコードをPythonで書いてください。
A: Python でランダムな 10 個の要素からなるリストを作成し、ソートするコードの例を次に示します。
```python
import random

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

# リストを昇順に並べ替える
ソートされた_リスト = sorted(ランダム_リスト)
print("ソート後のリスト:", ソートされた_リスト)
```
このコードでは、`random` モジュールを使用して 1 ～ 100 のランダムな整数のリストを作成し、その後 `sorted` 関数を呼び出して昇順に並べ替えます。
````

直感的に、非常に日本語性能が高そうな回答のように思います。
（システムプロンプトの与え方のためか、ソースコードの変数名を日本語にするという徹底ぶり）
マラソンの順位問題は単純推論だと難しいかな。これは多くのモデルでNGです。

真価はTool選択やRAG利用なのだと思いますが、単純推論であっても高い性能が伺えます。

# まとめ

商用利用不可なのが残念ではありますが、非常に魅力的なLLMだと思います。

大型モデルなので自前運用する場合のランニングコストもそれなりに高そうですが、
Cohere社と商用利用契約して利用するような会社が増えていきそうですね。