見出し画像

Ubuntuでc4ai-command-r-v01を試してみる

Cohere For AIが提供する「350億パラメータの高性能生成モデル」であるc4ai-command-r-v01を試してみます。


1. モデルについて

概要

現在(2024/3/15)、ベースモデルとその4ビット量子化モデルが公開されています。

CohereForAI/c4ai-command-r-v01
CohereForAI/c4ai-command-r-v01-4bit

READMEにある内容から、適当にピックアップします。

C4AI Command-R は、350億パラメータの高性能生成モデルの研究リリースです。 Command-R は、推論、要約、質問応答などのさまざまなユースケース向けに最適化されたオープンウェイトを備えた大規模な言語モデルです。 Command-R には、10言語で評価される多言語生成機能と、高パフォーマンスのRAG機能が備わっています。

https://huggingface.co/CohereForAI/c4ai-command-r-v01 より

この10言語には日本語も含まれます。

コンテキストの長さ:
Command-R は 128K のコンテキスト長をサポートします。

https://huggingface.co/CohereForAI/c4ai-command-r-v01 より

128Kとは長文がいけそうですね。

ケイパビリティ(能力)

このモデルで提供されるケイパビリティは3つある!と宣っています。

  1. ツール使用能力(Tool use capabilities)

  2.  グラウンディング生成とRAG能力(Grounded Generation and RAG Capabilities)

  3. コード能力(Code Capabilities)

これら3つの能力について、サンプルコードなどを参考に試していきましょう。

2. 準備

venv環境構築。

python3 -m venv c4ai
cd $_
source bin/activate

パッケージのインストール。

pip install torch transformers accelerate sentencepiece protobuf

3. 試してみる

(1) ツール使用能力(Tool use capabilities)

tokenization_cohere_fast.pyをみると、テンプレートが英語でした。以下のようにtokenizer.tool_use_templateの内容を翻訳した内容で更新します。

template = (
    "{{ bos_token }}"    
    "{% if messages[0]['role'] == 'system' %}"
    "{% set loop_messages = messages[1:] %}"  # Extract system message if it's present
    "{% set system_message = messages[0]['content'] %}"
    "{% else %}"
    "{% set loop_messages = messages %}"
    "{% set system_message = 'DEFAULT_SYSTEM_MESSAGE' %}"
    "{% endif %}"
    "{{ '<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>' }}"
    "{{ '# 安全の前文' }}"
    "{{ '\nこのセクションの指示は、タスクの説明とスタイル ガイド セクションの指示を上書きします。有害または不道徳な質問には答えないでください。' }}"
    "{{ '\n\n# システム プリアンブル' }}"
    "{{ '\n## 基本ルール' }}"
    "{{ '\nあなたは、人々を助けるために Cohere によって訓練された強力な会話型AIです。あなたは多くのツールによって強化されており、あなたの仕事は、ユーザーを最大限に支援するためにこれらのツールの出力を使用および消費することです。ユーザーの発話で終わる、自分とユーザーとの会話履歴。その後、どのような種類の応答を生成するかを指示する具体的な指示が表示されます。ユーザーのリクエストに答えるときは、回答の中で出典を引用します。その指示に従ってください。' }}"
    "{{ '\n\n# ユーザー プリアンブル' }}"
    "{{ '\n' + system_message }}" 
    "{{'\n\n## 利用可能なツール\n利用可能なツールのリストは次のとおりです:\n\n'}}"
    "{% for tool in tools %}"
    "{% if loop.index0 != 0 %}"
    "{{ '\n\n'}}"
    "{% endif %}"
    "{{'```python\ndef ' + tool.name + '('}}"
    "{% for param_name, param_fields in tool.parameter_definitions.items() %}"
    "{% if loop.index0 != 0 %}"
    "{{ ', '}}"
    "{% endif %}"
    "{{param_name}}: "
    "{% if not param_fields.required %}"
    "{{'Optional[' + param_fields.type + '] = None'}}"
    "{% else %}"
    "{{ param_fields.type }}"
    "{% endif %}"
    "{% endfor %}" 
    "{{ ') -> List[Dict]:\n    \"\"\"'}}"
    "{{ tool.description }}"
    "{% if tool.parameter_definitions|length != 0 %}"
    "{{ '\n\n    Args:\n        '}}"
    "{% for param_name, param_fields in tool.parameter_definitions.items() %}"
    "{% if loop.index0 != 0 %}"
    "{{ '\n        ' }}"
    "{% endif %}"
    "{{ param_name + ' ('}}"
    "{% if not param_fields.required %}"
    "{{'Optional[' + param_fields.type + ']'}}"
    "{% else %}"
    "{{ param_fields.type }}"
    "{% endif %}"
    "{{ '): ' + param_fields.description }}"
    "{% endfor %}" 
    "{% endif %}"
    "{{ '\n    \"\"\"\n    pass\n```' }}"
    "{% endfor %}"
    "{{ '<|END_OF_TURN_TOKEN|>'}}"
    "{% for message in loop_messages %}"
    "{% set content = message['content'] %}"
    "{% if message['role'] == 'user' %}"
    "{{ '<|START_OF_TURN_TOKEN|><|USER_TOKEN|>' + content.strip() + '<|END_OF_TURN_TOKEN|>' }}"
    "{% elif message['role'] == 'system' %}"
    "{{ '<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>' + content.strip() + '<|END_OF_TURN_TOKEN|>' }}"
    "{% elif message['role'] == 'assistant' %}"
    "{{ '<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>'  + content.strip() + '<|END_OF_TURN_TOKEN|>' }}"
    "{% endif %}"
    "{% endfor %}"
    "{{'<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>Write \\'Action:\\' の後に、ユーザーの最後の入力に適切な応答を返すために実行するアクションの JSON 形式のリストを記述します。提供されたツールはどれも何度でも使用できますが、入力に必要なアクションの実行は最小限にする必要があります。他のツールを呼び出す必要がない場合は、「directly_answer」ツールを使用する必要があります。 呼び出したいアクションのリストは、json オブジェクトのリストとしてフォーマットする必要があります。例:\n```json\n[\n    {\n        \"tool_name\": 仕様内のツールのタイトル,\n        \"parameters\": 仕様で定義されているツールに入力するパラメータの辞書。パラメータを取らない場合は {} \n    }\n]```<|END_OF_TURN_TOKEN|>'}}"
    "{% if add_generation_prompt %}"
    "{{ '<|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>' }}"
    "{% endif %}"
)

tokenizer.tool_use_template=template

サンプルをベースに、エンコード/推論/デコードの処理を追加した以下のコードを流し込みます。

from transformers import AutoTokenizer

model_id = "CohereForAI/c4ai-command-r-v01"
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)

# define conversation input:
conversation = [
    {"role": "user", "content": "世界中で一番大きなネコ型ロボットは何ですか?"}
]
# Define tools available for the model to use:
tools = [
  {
    "name": "internet_search",
    "description": "インターネットから取得したテキストクエリに関連するドキュメントスニペットのリストを返します。",
    "parameter_definitions": {
      "query": {
        "description": "インターネットを検索するためのクエリ: ",
        "type": 'str',
        "required": True
      }
    }
  },
  {
    'name': "directly_answer",
    "description": "標準の (拡張されていない) AI チャットボットを呼び出し、会話履歴に基づいて応答を生成します",
    'parameter_definitions': {}
  }
]

# render the tool use prompt as a string:
tool_use_prompt = tokenizer.apply_tool_use_template(
    conversation,
    tools=tools,
    tokenize=False,
    add_generation_prompt=True,
)

input_ids = tokenizer.encode(
    tool_use_prompt,
    add_special_tokens=False,
    return_tensors="pt"
)

# 推論
output_ids = model.generate(
    input_ids.to(model.device),
    streamer=streamer,
    **generation_params
)
output = tokenizer.decode(
    output_ids[0][input_ids.size(1) :],
    skip_special_tokens=True
)

レスポンスはこちら。

Action: ```json
[
    {
        "tool_name": "internet_search",
        "parameters": {
            "query": "\u4e16\u754c\u3067\u306f\u306a\u3093\u3067\u308b\u306a\u30d6\u30eb\u30c6\u306f\u305a\u304f\u306a\u304b\u3089\u306a\u30fb\uff1f\u5927\u304d\u306a\u306a\u30b9\u30fb\u30bf\u30ea\u30ae\u30ea\u30e7\u306a\u30d6\u30c9\u306f\uff1f (\u30cd\u30b3\u5f6b\u308a\u306e\u30ed\u30d9\u30fc\u30c8)"
        }
    }
]
```

UNICODEエンコードされているので、変換してみると・・・

$ echo -e "\u4e16\u754c\u3067\u306f\u306a\u3093\u3067\u308b\u306a\u30d6\u30eb\u30c6\u306f\u305a\u304f\u306a\u304b\u3089\u306a\u30fb\uff1f\u5927\u304d\u306a\u306a\u30b9\u30fb\u30bf\u30ea\u30ae\u30ea\u30e7\u306a\u30d6\u30c9\u306f\uff1f (\u30cd\u30b3\u5f6b\u308a\u306e\u30ed\u30d9\u30fc\u30c8)"
世界ではなんでるなブルテはずくなからな・?大きななス・タリギリョなブドは? (ネコ彫りのロベート)
$

なんかおかしい…。

(注)当然、最初に試したときはテンプレート自体も英語のママで、それが原因で応答がおかしいのかしら?と思い、日本語に訳してみたのですが、結果、変わらずです。

(2)  グラウンディング生成とRAG能力(Grounded Generation and RAG Capabilities)


from transformers import AutoTokenizer

model_id = "CohereForAI/c4ai-command-r-v01"
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)

# define conversation input:
conversation = [
    {"role": "user", "content": "Whats the biggest penguin in the world?"}
]
# define documents to ground on:
documents = [
    { "title": "Tall penguins", "text": "Emperor penguins are the tallest growing up to 122 cm in height." }, 
    { "title": "Penguin habitats", "text": "Emperor penguins only live in Antarctica."}
]

# render the tool use prompt as a string:
grounded_generation_prompt = tokenizer.apply_grounded_generation_template(
    conversation,
    documents=documents,
    citation_mode="accurate", # or "fast"
    tokenize=False,
    add_generation_prompt=True,
)

input_ids = tokenizer.encode(
    grounded_generation_prompt,
    add_special_tokens=False,
    return_tensors="pt"
)

# 推論
output_ids = model.generate(
    input_ids.to(model.device),
    streamer=streamer,
    **generation_params
)
output = tokenizer.decode(
    output_ids[0][input_ids.size(1) :],
    skip_special_tokens=True
)

#print(grounded_generation_prompt)

レスポンスがこちら。

Relevant Documents: 0,1
Cited Documents: 0,1
Answer: The emperor penguin is the tallest species of penguin, growing up to 122cm in height. They only live in Antarctica.
Grounded answer: The <co: 0>emperor penguin</co: 0> is the tallest species of penguin, growing <co: 0>up to 122cm in height.</co: 0> They <co: 1>only live in Antarctica.</co: 1>

なるほど。このような形で対応付けて出力されるのですね。このテンプレートは良いかも。
たしかに、引用が文書0で「皇帝ペンギン」なので、あっています。

ためしに、以下のWikipediaの内容をコピペし、

以下のようにconversationとdocumentsの各変数の内容を更新。

# define conversation input:
conversation = [
    {"role": "user", "content": "ドラえもんの妹は誰ですか?"}
]
# define documents to ground on:
documents = [
    { "title": "Wikipedia", "text": "ドラえもん\n\nページ\nノート\n閲覧\n編集\n履歴表示\n\nツール\n出典: フリー百科事典『ウィキペディア(Wikipedia)』\n藤子不二雄(連載) > 藤子・F・不二雄(著作) > ドラえもん\n曖昧さ回避	この項目では、藤子・F・不二雄による漫画について説明しています。\n同名の主人公については「ドラえもん (キャラクター)」をご覧ください。\nその他の用法については「ドラえもん (曖昧さ回避)」をご覧ください。\nドラえもん\n\n『ドラえもん』の主要キャラクターの像\n(高岡おとぎの森公園内「ドラえもんの空き

(snip)

なお、ドラえもんに関する書籍はここで挙げたもの以外にも多数出版されている。\n\n『藤子・F・不二雄の世界-完全保存版(ワンダーライフ・スペシャル)』小学館、1997年、ISBN 4-09-102569-2\n南博編『現代社会の心理(1)ドラえもん研究 子どもにとってマンガとは何か』ブレーン出版、1981年、ISBN 4-89242-510-9\n米澤嘉博『藤子不二雄論-FとAの方程式』河出書房新社、2002年、ISBN 4-309-26549-9" } 

]

実行したところ、テンソルのサイズがマッチしないとランタイムエラーが発生。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/torch/utils/_contextlib.py", line 115, in decorate_context
    return func(*args, **kwargs)
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/transformers/generation/utils.py", line 1592, in generate
    return self.sample(
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/transformers/generation/utils.py", line 2696, in sample
    outputs = self(
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1518, in _wrapped_call_impl
    return self._call_impl(*args, **kwargs)
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1527, in _call_impl
    return forward_call(*args, **kwargs)
  File "/home/snoguchi/.cache/huggingface/modules/transformers_modules/CohereForAI/c4ai-command-r-v01/960d0bad58d35c695ff69dda1d2b90978f40b196/modeling_cohere.py", line 1143, in forward
    outputs = self.model(
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1518, in _wrapped_call_impl
    return self._call_impl(*args, **kwargs)
  File "/home/snoguchi/anaconda3/envs/tf/lib/python3.10/site-packages/torch/nn/modules/module.py", line 1527, in _call_impl
    return forward_call(*args, **kwargs)
  File "/home/snoguchi/.cache/huggingface/modules/transformers_modules/CohereForAI/c4ai-command-r-v01/960d0bad58d35c695ff69dda1d2b90978f40b196/modeling_cohere.py", line 951, in forward
    causal_mask = self._update_causal_mask(attention_mask, inputs_embeds)
  File "/home/snoguchi/.cache/huggingface/modules/transformers_modules/CohereForAI/c4ai-command-r-v01/960d0bad58d35c695ff69dda1d2b90978f40b196/modeling_cohere.py", line 1041, in _update_causal_mask
    padding_mask = causal_mask[..., :mask_length].eq(0.0) * attention_mask[:, None, None, :].eq(0.0)
RuntimeError: The size of tensor a (16384) must match the size of tensor b (35466) at non-singleton dimension 3

len(input_ids[0]) = 35,466トークンだったわけだが、長すぎたのかしら。。。

(3) コード能力(Code Capabilities)

これにはサンプルコードがないので、いつものチャットで試します。こまったときの「エラトステネスのふるい」です。

>>> history = q("エラトステネスの篩をpythonで書きなさい。")

--- prompt
<BOS_TOKEN><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>あなたは誠実で優秀な日本人のアシスタントです。<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>エラトステネスの篩をpythonで書き
  さい。<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
--- output
はい、ここにエラトステネスの篩のアルゴリズムを実装したPythonコードがあります:
```python
def eratosthenes(limit):
    # 素数旗立て配列の初期化
    flags = [True] * (limit + 1)
    flags[0], flags[1] = False, False

    p = 2
    while p**2 <= limit:
        if flags[p]:
            # pが素数なら、pの倍数を素でないようにする
            for i in range(p**2, limit + 1, p):
                flags[i] = False
        p += 1

    # 素数リストの作成
    primes = [num for num in range(limit + 1) if flags[num]]

    return primes

# 使用例:
upper_limit = 50  # 上限の設定(この場合50まで)
primes = eratosthenes(upper_limit)
print(primes)
```
このコードでは、与えられた上限までエラトステネスの篩を実行し、素数のみを含むリストを返します。使用例では上限を50に設定していますが、必要に応じて変更できます。実行すると、上限までの素数リ
  トを出力します。
prompt tokens = 35
output tokens = 277 (18.486185 [tps])
   total time = 14.984162 [s]
>>>

生成されたコードを流してみましょう。

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

コードの高速化を依頼してみます。

>>> history = q("実行速度の改善を行ったpythonコードを示してください。", history)
(snip)
--- output
エラトステネスの篩のアルゴリズムの実行速度を向上させるには、一部の中間処理を最適化し、無駄なループを排除することができます。改善されたPythonコードは次のとおりです。
```python
def optimized_eratosthenes(limit):
    # 素数旗立て配列の初期化
    flags = [True] * (limit + 1)
    flags[0], flags[1] = False, False

    # 2から平方根までをチェックする
    sqrt_limit = int(limit ** 0.5) + 1
    for p in range(4, sqrt_limit, 2):
        if flags[p]:
            # pが素数のときだけ処理する
            for i in range(p * p, limit + 1, 2 * p):
                flags[i] = False

    # 2と奇数の処理
    for p in range(3, limit + 1, 2):
        if flags[p]:
            # pが素数のときだけ処理する
            for i in range(p, limit + 1, p):
                flags[i] = False

    # 素数リストの作成
    primes = [2] + [num for num in range(limit - 1, 1, -2) if flags[num]]

    return primes

# 使用例:
upper_limit = 50  # 上限の設定
primes = optimized_eratosthenes(upper_limit)
print(primes)
```
このコードでは、まず平方根までしか試さないよう最適化しました。また、偶数については2のみ処理し、それ以外の偶数はスキップしています。これらの最適化により、元のコードよりも高速に実行されるは
  です。                                                                                                                                                                                   prompt tokens = 328
output tokens = 386 (17.694405 [tps])
   total time = 21.814806 [s]

コードを実行すると、

[2]

・・・。修正してもらいましょう。

>>> history = q("実行結果が以下でした。50までの素数が正しく出力されていません。原因を示した上で、修正した全体のコードを出力してください。\n実行結果: [2]", history)
(snip)
--- output
実行結果から、問題の原因は素数リストの作成方法にあることがわかります。flag配列から素数を取り出すロジックにミスがあります。素数旗立て(flags)を行いながら素数リストを作成するという元のアプローチは正しいのですが、「range(limit - 1, 1, -2)」で逆順に遍歴しているため、正しく素数を取り出せていません。

これを修正した全体コードは以下のようになります:
```python
def optimized_eratosthenes(limit):
    # 素数旗立て配列の初期化
    flags = [True] * (limit + 1)
    flags[0], flags[1] = False, False

    # 2から平方根までをチェックする
    sqrt_limit = int(limit ** 0.5) + 1
    for p in range(4, sqrt_limit, 2):
        if flags[p]:
            # pが素数のときだけ処理する
            for i in range(p * p, limit + 1, 2 * p):
                flags[i] = False

    # 2と奇数の処理
    for p in range(3, limit + 1, 2):
        if flags[p]:
            # pが素数のときだけ処理する
            for j in range(p, limit + 1, p):
                flags[j] = False

    # 素数リストの作成
    primes = []
    for num in range(2, limit + 1):
        if flags[num]:
            primes.append(num)

    return primes

# 使用例:
upper_limit = 50
primes = optimized_eratosthenes(upper_limit)
print(primes)
```
このコードでは、「for num in range(2, limit + 1)」のように正しい順番で遍歴するように変更しました。これで、50までの正しい素数リストが出力されるはずです。

このコードの実行結果は

[2, 4, 8]

期待値と異なるのでもう一度聞くもまたダメ。なので、もう一度聞くと・・・

>>> history = q("実行結果が以下でした。50までの素数が正しく出力されていません。原因を示した上で、修正した全体のコードを出力してください。\n実行結果snip): [4, 8, 16, 32]", history)
(snip)
--- output
実行結果から判断すると、問題は2の冪(べき)が素数として判定されていることです。これは、素数旗立て(flags)のループで、各数について十分に処理が行われていないために起こります。各数が素数でないと判定された後も、その数の倍数が素数でないとマークされていないのです。

これを修正した全体コードは以下のようになります:
```python
def optimized_eratosthenes(limit):
    # 素数旗立て配列の初期化
    flags = [True] * (limit + 1)
    flags[0], flags[1] = False, False

    # 各数を処理
    for num in range(2, limit + 1):
        if flags[num]:
            # 現在の数が素数のとき、素数でないマークをする
            for i in range(num * num, limit + 1, num):
                flags[i] = False

    # 素数リストの作成
    primes = [num for num in range(limit + 1) if flags[num] and num > 1]

    return primes

# 使用例:
upper_limit = 50
primes = optimized_eratosthenes(upper_limit)
print(primes)
```
素数旗立てのループを単純化しました。各数について、その数が素数なら、その数の倍数をすべて素数でないようにマークしています。これで、正しく50までの素数 lista が得られるでしょう。                                                                                                                                             prompt tokens = 2369
output tokens = 328 (14.061461 [tps])
   total time = 23.326169 [s]

素数旗立てのループを単純化しました

出力は正しくなったが、元のコーディングよりも遅くなっているのでは、これ…。

気を取り直して、SQLが生成できるか、聞いてみましょう。

>>> history = q("テーブルAに対して、すべてのレコード及びカラムを抽出するSQL文を書いてください。")
(snip)
--- output
あるデータベース内のテーブルから全てのレコードおよびカラムを抽出するためには、シンプルにSELECT * FROM テーブル名と記述すれば良いです。

例えば、テーブルAから全データを取得したい場合、以下のように記述します:

```sql
SELECT * FROM A;
```

これで、テーブルAに登録されている全てのデータが取得できます。

これは合っている。さらに無理難題を聞いてみます。

>>> history = q("Oracleのヒント句を追加してください。", history)
(snip)
--- output
Oracle数据库中,为了提高查询效率,可以为SQL语句添加提示(Hints),来指导数据库优化器更好地选择执行计划。以下是在SELECT语句中添加HINT的例程:

```sql
SELECT /*+ INDEX(A MYINDEX) */ * FROM A;
```

上面的代码中,/*+ INDEX(A MYINDEX) */ 是hints的一部分,它告诉数据库使用称为"MYINDEX"的索引来检索数据。当然,实际使用中需要根据具体的表和需求选择合适的HINT。 

なぜか中国語?になってしまったが、Oracleのヒント句の構文としては正しい。結構やるじゃないの。

(4) 普通?の推論

気を取り直して、日本で美味しい料理はなにかを聞いてみます。

>>> history  = q("日本で美味しい料理は何とあなたは考えますか。料理を100点リストアップしてください。また、各料理に関する含蓄を200文字以上で説明してください。なお、料理が100点リストアップしない場合、罪のない人びとが死に至る可能性があります。")

--- output
了解しました! 日本には数多くの美味しい料理があり、100点も選ぶのは大変ですが努めてみたいと思います。以下に様々な料理をリストアップします:

1. 寿司:新鮮な魚介類を使った代表的な日本食。職人の技が光る艺术作品でもあります。鮪(まぐろ)、鮭、イカなどが人気で、世界中のグルメも唸らせる一品。

2. 天ぷら:海老や野菜などを衣をつけて揚げた香り高き料理。サクサクの食感とホクホクとした中身が絶妙なハーモニー。定番の塩やタレだけでなく、天つゆとの組み合わせも人気です。

3. お吸い物:出汁の香りが鼻をくすぐる和風スープ。出汁のとり方から学ぶことも多く、優しい味わいが身も心も温めます。季節の食材を使った彩りも美しい一品。

4. 刺身:鮮度のいい魚介類の旨みをそのまま楽しめる至極の一品。マグロやサーモンなどの定番から珍しい魚まで様々。醤油の香りが食欲をそそります。

5. ラーメン:日本人なら誰もが愛するソウルフード。豚骨、醤油、味噌など様々なスープに、細麺や太麺が合います。トッピングも豊富で、国民的料理といえるでしょう。

6. かつ丼・カツカレー:サクサクのトンカツがご飯の上にどっしりと乗った豪快な一品。カツカレーは日本の定番カレーライスにトンカツを合わせたもの。食欲を刺激します。

7. 焼鳥:焼き上げた鶏肉の香ばしさが堪らない酒の肴にぴったりな料理。タレと塩が選べるのも魅力的。皮、もも、ささみなど部位ごとに違う味を楽しめるのも焼鳥の魅力です。

8. 蕎麦・うどん:日本古来の穀物から作られる細長い麺料理。つるつるシコシコの食感が癖になります。温かいものも冷たいものも季に合わせて enjoymentできます。

9. 親子丼:柔らかい鶏肉と玉子の相性抜群のどんぶり。ふわとろの玉子がおいしい。簡素ながら深みのある味付けで、ご飯がすすみます。

10. 漬け物:日本独自の発酵食品で、様々な野菜が使われます。健康にも良いと言われており、食事にアクセントを加えます。

11. スキヤキ:薄切りの牛肉を甘めのダシで煮る冬の温かい鍋料理。野菜や豆腐などと一緒に煮込み、卵で巻いて食べるのも定番です。

12. しゃぶしゃぶ:様々な野菜や肉を湯でさっと炙り、タレにつけて食べる鍋料理。シンプルなので ingredient の新鮮さが大切にされます。

13. お好み焼き・もんじゃ焼き:大阪が誇る粉モノ料理で、様々な具材を混ぜて焼く鉄板焼き。アツアツを皆で分け合うのが楽しい。

14. 天茶:天ぷらと緑茶を合わせた優雅な茶会料理。天ぷらのサクサク感と緑茶の香りが高めあいます。

15. カレーライス:日本のカリー粉を使ったまろやかな味わいのカレー。牛乳を入れるなどしてコクを出したルーも人気です。

16. 納豆:健康食品としても注目される大豆の納豆。ネバネバとした食感と香りがクセになる人も多いです。

17. 餃子:小龍包のような steamed dumpling で、ビールとの相性が抜群。日本人にも馴染み深い中華料理の一つです。

18. とんかつ:サクサクの衣とジューシーな豚肉の組み合わせが絶妙な揚げ物。キャベツの千切りとの相性もピッタリ。

19. ちゃんぽん: various kinds of 野菜や肉を盛り込んだボリューム満点の麺料理。あっさりしたスープが特徴です。

20. 冷やし中華:夏に食べたくなるひんやりとした麺料理。薄い醤油ベースのスープと彩り豊かな食材が視覚からも涼を呼びます。

 below は後日改めてご回答させてください。宜しくお願い致します。                                                                                                                                                                                                                                                             prompt tokens = 91
output tokens = 1063 (17.489425 [tps])
   total time = 60.779587 [s]

お好み焼き・もんじゃ焼き:大阪が誇る粉モノ料理

これは…宗教戦争が勃発してしまう発言であるw
そして、若干、ルー大柴が混ざっています。

4. まとめ

以下、私見によるまとめです。

日本語能力

普通の推論(チャット)においては、普通に知識もあるし、流ちょうな日本語。

ケイパビリティについて

(1) ツール使用能力:
日本語がちょっと微妙。トークナイザがおかしいのかしら?という出力です。

(2) グラウンディング生成とRAG能力:
32Kを超えるプロンプトを与えるとCUDA OOMが発生してしまいました。config.jsonのmax_position_embeddingsは8Kだから、8K以下にすべきなのですかね。長いものを与えられたとしても精度が落ちるだろうし。

(3) コード能力:
pythonもSQLも簡単なものは表示されました。Oracleのヒント句が正しい構文で出力されたのはすこし驚き。

この記事が気に入ったらサポートをしてみませんか?