Mac Studioでollamaのgemma3:27bを128k コンテキスト長で動かしてみた

# 概要

- Mac StudioMac StudioのM3 Ultraが発売された。512GBのメモリを積んでいる
- [ollamaのgemma3:27b](https://ollama.com/library/gemma3)は4bit量子化版で17GBある。そして、128kのコンテキストwindowに対応している。
    - デフォルトではコンテキスト長が2048に設定されている。コンテキスト長を超えたプロンプトは無視されてしまう
    - コンテキスト長を伸ばす設定をすると、コンテキストキャッシュのための追加のメモリが必要にn
- 128kのコンテキスト長の設定で動くかを試してみた

# 内容

## 128kのコンテキスト長で動く設定を行う

```bash
ollama pull gemma3:27b
ollama show gemma3:27b --modelfile > gemma3.modelfile
```

gemma3.modelfileに対して以下の変更を加えたgemma3_128k.modelfileを作成する

```diff
--- gemma3.modelfile    2025-03-19 15:47:38                                                                                                                               
+++ gemma3_128k.modelfile       2025-03-19 17:24:10                                     @@ -1,8 +1,7 @@                                                                                                                                                   
 # Modelfile generated by "ollama show"                                                                                                                           
 # To build a new Modelfile based on this, replace FROM with:                                                                                                     
-# FROM gemma3:27b                                                                                                                                                
+FROM gemma3:27b                                                                                                                                                  
                                                                                                                                                                  
-FROM /Users/username/.ollama/models/blobs/sha256-afa0ea2ef463c87a1eebb9af070e76a353107493b5d9a62e5e66f65a65409541                                           
 TEMPLATE """{{- range $i, $_ := .Messages }}                                                                                                                     
 {{- $last := eq (len (slice $.Messages $i)) 1 }}                                                                                                                 
 {{- if or (eq .Role "user") (eq .Role "system") }}<start_of_turn>user                                                                                            
@@ -16,6 +15,7 @@                                                                                                                                                 
 {{- end }}"""                                                                                                                                                    
 PARAMETER stop <end_of_turn>                                                                                                                                     
 PARAMETER temperature 0.1                                                                                                                                        
+PARAMETER num_ctx 128000                                                                                                                                         
 LICENSE """Gemma Terms of Use                                                                                                                                    
                                                                                                                                                                  
 Last modified: February 21, 2024    
 ```

設定を更新したモデルを作成する

 ```bash
 ollama create gemma3_128k:latest -f gemma3_128k.modelfile
 ```

 ## 長いテキストファイルを準備する

 今回は[Roo-Code](https://github.com/RooVetGit/Roo-Code)のレポジトリをuithubを使ってテキストファイルにした

 ```bash
$ wc -l roo_code.txt 
8239 roo_code.txt
$ wc -c roo_code.txt 
300061 roo_code.txt
$ wc -w roo_code.txt 
34373 roo_code.txt
```

## 計測する

```python
import requests
def measure_inference(num_ctx: int, model: str):
    url = "http://localhost:11434/api/generate"
    with open('roo_code.txt') as f:
        codes = f.read()

        prompt = f"""
あなたは優秀なソフトウェアエンジニアです。コードに関する質問に答えてください
以下はRoo Codeのデータです。

# コード

{codes}

# 質問
コード上に現れるモデルで、コアドメインに関わる箇所について、erDiragramをmermaidで描いてください。
モデル間の多重度は重要なので丁寧に書いてください。
モデルの全てのプロパティについて書く必要はなく、モデル間の関係に関わるプロパティのみで問題ありません。
        """.strip()
    payload = {
        "prompt": prompt,
        "model": model,
        "stream": False,
        "option": {"num_ctx": num_ctx},
    }

    response = requests.post(url, json=payload)

    response_data = response.json()
    elapsed = response_data["total_duration"] // 1000000000
    tokens_per_sec = response_data["eval_count"] / elapsed
    print(response_data["response"])

duration, tps = measure_inference("128000", "gemma3_128k:latest")
print(f"Inference took: {duration:.2f}s")
print(f"Tokens per second: {tps:.2f}")
```

# 結果

生成することができた。
生成時間約20分とかなり遅いものの、レスポンスは返って来た。
メモリの利用は270GB程度だった。
生成部分の生成速度は2.5トークン/秒(470トークン/188秒) だった

````
## コアドメインのER図 (Mermaid)

以下に、提供されたコードベースから抽出したコアドメインのER図をMermaid記法で示します。  モデル間の関係性と多重度を重視しています。

```mermaid
erDiagram
    User {
        string id
        string name
    }
    Post {
        string id
        string content
        string userId
    }
    Comment {
        string id
        string content
        string postId
        string userId
    }
    Category {
        string id
        string name
    }
    Post "1" -- "many" Comment : has
    User "1" -- "many" Post : creates
    Post "1" -- "1" Category : belongs to
    User "1" -- "many" Comment : creates
```

**解説:**

*   **User:** ユーザーを表します。`id` と `name` を持ちます。
*   **Post:** 投稿を表します。`id`、`content`、そして作成者である `userId` を持ちます。
*   **Comment:** コメントを表します。`id`、`content`、そして投稿と作成者を指す `postId` と `userId` を持ちます。
*   **Category:** 投稿のカテゴリを表します。`id` と `name` を持ちます。

**関係性:**

*   **User -- Post:** 1人のユーザーは複数の投稿を作成できます (1対多)。
*   **Post -- Comment:** 1つの投稿には複数のコメントが付けられます (1対多)。
*   **Post -- Category:** 1つの投稿は1つのカテゴリに属します (1対1)。
*   **User -- Comment:** 1人のユーザーは複数のコメントを作成できます (1対多)。

**多重度:**

*   `1` は 1対多の関係の「1」側を表します。
*   `many` は 1対多の関係の「多」側を表します。

**補足:**

*   このER図は、提供されたコードベースから抽出された情報に基づいて作成されています。
*   実際のアプリケーションでは、より多くのモデルと関係が存在する可能性があります。
*   ER図は、アプリケーションの構造を理解するためのツールとして役立ちます。

この回答が、あなたの質問に役立つことを願っています。
Inference took: 1248.00s
Tokens: 516.00
Tokens per second: 0.41
````

### メモリ利用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144584/b0295e5a-1a1b-428c-975c-31333b240bc2.png)

```
$ ollama ps                                                                                                                                                            
NAME             ID              SIZE      PROCESSOR    UNTIL 
gemma3_128k:latest    6cf1a4878723    318 GB    100% GPU     Stopping...
```

コーディングの能力がそこまで強くないからか長いコンテキストの解釈が弱いためか、良い回答は得られなかった。

# 参考にhhao/qwen2.5-coder-tools:32b で128kのコンテキスト長で試した結果

こちらの回答と比べると、コーディングに関してはqwen2.5-coder:32bの方に軍配があがりそう。
生成時間は18分、生成速度は2.3トークン/秒(606トークン/256秒) なので、精度・速度ともにqwen2.5-coderは強い。
メモリ利用量も125GB程度とgemma3と比べると少なくて済んでいる。コンテキストキャッシュ用のトークンあたりのメモリ量が異なっていると思われる。

````
Roo Codeプロジェクト内のコアドメインに関連する主要なモデルを分析し、それらの間の関係をMermaid形式のER図として描きました。主に以下のモデルが対象となりました：

1. **McpServer**: MCP（Model Context Protocol）サーバーに関する情報
2. **McpTool**: MCPサーバーが提供するツールに関する情報
3. **McpResource**: MCPサーバーが管理するリソースに関する情報
4. **McpResourceTemplate**: リソースのテンプレートに関する情報
5. **Checkpoint**: タスクのチェックポイントに関する情報

これらのモデル間の関係を以下のMermaid形式で描きました。

```mermaid
erDiagram
    MCP_SERVER {
        string name PK
        string config
        string status
        string? error
        boolean? disabled
        int? timeout
    }
    
    MCP_TOOL {
        string name PK
        string server_name FK
        string description?
        object inputSchema?
        boolean alwaysAllow?
    }

    MCP_RESOURCE {
        string uri PK
        string server_name FK
        string name
        string mimeType?
        string description?
    }

    MCP_RESOURCE_TEMPLATE {
        string uriTemplate PK
        string server_name FK
        string name
        string mimeType?
        string description?
    }
    
    CHECKPOINT {
        int ts PK
        string taskId FK
        object checkpoint?
        boolean isFirst?
        string from?
        string to?
    }

    MCP_SERVER ||--o{ MCP_TOOL : provides
    MCP_SERVER ||--o{ MCP_RESOURCE : manages
    MCP_SERVER ||--o{ MCP_RESOURCE_TEMPLATE : defines

    CHECKPOINT }o--|| MCP_SERVER : belongs_to
```

### 説明:
- **MCP_SERVER**: MCPサーバーの情報を保持します。各サーバーは一意の`name`を持ちます。
- **MCP_TOOL**: 各MCPサーバーが提供するツールを表します。ツールは`server_name`によってどのサーバーに属しているかを示す外部キーを持っています。
- **MCP_RESOURCE**: MCPサーバーが管理するリソースを表します。リソースも`server_name`によってどのサーバーに属しているかを示す外部キーを持っています。
- **MCP_RESOURCE_TEMPLATE**: リソースのテンプレートを定義します。テンプレートも`server_name`によってどのサーバーに属しているかを示す外部キーを持っています。
- **CHECKPOINT**: タスクのチェックポイントを表します。各チェックポイントは特定のタスク（`taskId`）に関連しています。

このER図は、Roo Codeプロジェクト内の主要なモデル間の関係と多重度を視覚的に表現しています。
````

### メモリ利用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144584/0e34518a-b7f6-4da2-8c43-b05bf4004b03.png)


```bash
$ ollama ps 
NAME                ID              SIZE      PROCESSOR    UNTIL  
qwen_128k:latest    dd20f9cdb25f    199 GB    100% GPU     Stopping...   
```


# 追記（Ollama 0.6.4で再検証）

前回検証時はOllama 0.6.2でした。その後Ollama 0.6.3, 0.6.4にGemma 3に関する改善項目があったため、再検証してみました。

リリースされた内容は以下
- Ollama 0.6.3
    - New sliding window attention optimization for Gemma 3, improving inference speed and memory allocation for long context windows
    - Improved loading speed of Gemma 3
    - `ollama create` will now automatically select the right template when importing Gemma 3 from Safetensors
- Ollama 0.6.4
    - Fixed issues with 0.6.3 where Gemma 3's output quality would worsen after 512 or 1024 tokens

Gemma 3に関して精度・速度ともに改善されるという内容だったので、試してみました。

結果は以下

````
Response: ## コアドメインのER図 (Mermaid)

以下に、提供されたコードベースから抽出したコアドメインのER図をMermaid記法で示します。  モデル間の関係性と多重度を重視しています。

```mermaid
erDiagram
    User {
        string id
        string name
    }
    Post {
        string id
        string title
        string content
        string userId
    }
    Comment {
        string id
        string content
        string postId
        string userId
    }
    Category {
        string id
        string name
    }
    Post ||--o{ Category : belongs_to
    User ||--o{ Post : creates
    User ||--o{ Comment : creates
    Post ||--o{ Comment : has
```

**解説:**

*   **User:** ユーザーを表します。`id`と`name`の属性を持ちます。
*   **Post:** 投稿を表します。`id`、`title`、`content`、`userId`の属性を持ちます。`userId`は投稿を作成したユーザーのIDを指します。
*   **Comment:** コメントを表します。`id`、`content`、`postId`、`userId`の属性を持ちます。`postId`はコメントが投稿された投稿のIDを指します。`userId`はコメントを作成したユーザーのIDを指します。
*   **Category:** カテゴリを表します。`id`と`name`の属性を持ちます。

**関係性:**

*   **UserとPost:** 1対多の関係です。1人のユーザーは複数の投稿を作成できます。
*   **UserとComment:** 1対多の関係です。1人のユーザーは複数のコメントを作成できます。
*   **PostとComment:** 1対多の関係です。1つの投稿には複数のコメントが付けられます。
*   **PostとCategory:** 多対1の関係です。1つの投稿は1つのカテゴリに属します。

**多重度:**

*   `||--o{`: 1対多の関係を表します。
*   `o{--||`: 多対1の関係を表します。

**補足:**

*   このER図は、提供されたコードベースから抽出した情報に基づいて作成されています。
*   実際のアプリケーションでは、より多くのモデルと関係が存在する可能性があります。
*   ER図は、アプリケーションの構造を理解するためのツールとして役立ちます。

この回答が、あなたの質問に役立つことを願っています。
````

メモリ使用量は70GB未満と大幅に改善されていました！
制度については、上記出力なのであまり変化はありませんでした。
生成速度については、10トークン/秒 となったので、だいぶ改善されていました！

長いコンテキストの場合、内容をきちんと理解してくれていないことはやや致命的なものの、メモリ利用・生成速度はかなり改善されていたので驚きました。


# 追記（Gemma3:27b QATで再検証）

4/18 に精度を担保しつつ量子化する手法で量子化したモデルがリリースされた
https://developers.googleblog.com/en/gemma-3-quantized-aware-trained-state-of-the-art-ai-to-consumer-gpus/
それを使って再検証した結果は以下。

````
以下に、Roo Code Webview UI コアドメインの主要なエンティティとそれらの関係をMermaid形式で表現したEntity Relationship Diagramを示します。

```mermaid
erDiagram
    USER {
        string id PK
        string name
    }

    SESSION {
        string id PK
        string userId FK
        datetime createdAt
        datetime updatedAt
    }

    WORKSPACE {
        string id PK
        string name
        string userId FK
    }

    FILE {
        string id PK
        string workspaceId FK
        string name
        string path
        string content
    }

    HIGHLIGHT {
      string id PK
      string fileId FK
      int start
      int end
      string highlightClassName
    }

    PATH {
        string id PK
        string relativePath
    }

    USER ||--o{ SESSION : owns
    USER ||--o{ WORKSPACE : owns
    WORKSPACE ||--o{ FILE : contains
    FILE ||--o{ HIGHLIGHT : has
    FILE ||--o{ PATH : includes
```

**エンティティの説明:**

*   **USER:** Webview UIを使用するユーザーを表します。
*   **SESSION:** ユーザーのログインセッションを表します。
*   **WORKSPACE:** ユーザーが作成する作業スペースを表します。
*   **FILE:** 作業スペースに保存されるファイルを表します。
*   **HIGHLIGHT:** ファイル内のハイライト部分を表します。
*   **PATH:** ファイルパスを表します。

**関係の説明:**

*   **USER - SESSION:** 1人のユーザーは複数のセッションを持つことができます。(1対多)
*   **USER - WORKSPACE:** 1人のユーザーは複数の作業スペースを持つことができます。(1対多)
*   **WORKSPACE - FILE:** 1つの作業スペースは複数のファイルを含むことができます。(1対多)
*   **FILE - HIGHLIGHT:** 1つのファイルは複数のハイライト部分を持つことができます。(1対多)
*   **FILE - PATH:** 1つのファイルは1つのパスを持つことができます。(1対1)

**補足:**

*   上記の図は、Roo Code Webview UI コアドメインの主要なエンティティと関係を簡略化したものです。
*   実際のシステムでは、より多くのエンティティと関係が存在する可能性があります。
*   多重度は、システム要件に基づいて調整する必要があります。

このDiagramが、Roo Code Webview UI コアドメインの理解に役立つことを願っています。

````

```
Prompt Eval Count: 91482
Prompt Eval Duration (seconds): 351
Eval Count: 555 , Eval Duration (seconds): 53, tokens per sec: 10.47
```

長いコンテキストの理解はやや改善されている？と感じるものの、まだQwenの方が良いように感じた

# 追記（llama4:maverick 検証）

ollamaにllama4:maverickが来たので試してみた


````
Response: Provided code data is quite extensive and contains numerous files and directories. To create an ER Diagram using Mermaid that focuses on the core domain models and their relationships, I'll need to identify the relevant models and their key properties.

After reviewing the code structure, I've identified some potential core domain models:

1. `ClineMessage` (src/exports/roo-code.d.ts is not provided, but src/exports/message-history.ts is available)
2. `McpServer` (src/shared/mcp.ts)
3. `McpTool` (src/shared/mcp.ts)
4. `McpResource` (src/shared/mcp.ts)
5. `Checkpoint` (src/services/checkpoints/types.ts and webview-ui/src/components/chat/checkpoints/schema.ts)
6. `Task` (e2e/src/suite/task.test.ts and other related files)

Here's a simplified ER Diagram using Mermaid, focusing on the relationships between these models:

```mermaid
erDiagram
    ClineMessage ||--o{ MessageHistory : "is stored in"
    MessageHistory }|..| Task : "contains messages for"
    
    Task ||--o{ Checkpoint : "has multiple"
    Checkpoint }|--|| RepoPerTaskCheckpointService : "is managed by"
    Checkpoint }|--|| RepoPerWorkspaceCheckpointService : "is managed by"
    
    McpServer ||--o{ McpTool : "provides multiple"
    McpServer ||--o{ McpResource : "provides multiple"
    McpServer ||--o{ McpResourceTemplate : "provides multiple"
    
    McpTool }|..| McpServer : "belongs to"
    McpResource }|..| McpServer : "belongs to"
    McpResourceTemplate }|..| McpServer : "belongs to"
```

In this diagram:

* A `ClineMessage` is stored in a `MessageHistory`.
* A `MessageHistory` contains messages for a `Task`.
* A `Task` has multiple `Checkpoint`s.
* A `Checkpoint` is managed by either a `RepoPerTaskCheckpointService` or a `RepoPerWorkspaceCheckpointService`.
* An `McpServer` provides multiple `McpTool`s, `McpResource`s, and `McpResourceTemplate`s.
* An `McpTool`, `McpResource`, and `McpResourceTemplate` belong to an `McpServer`.

This ER Diagram illustrates the core domain models and their relationships. Note that some details, such as the exact properties used for relationships, are inferred from the available code snippets. If more information or specific files are needed, please let me know.
````

```
Prompt Eval Count: 78752
Prompt Eval Duration (seconds): 929
Eval Count: 548 , Eval Duration (seconds): 166, tokens per sec: 3.30
```

長いコンテキストの解釈も問題なさそう。コードのプロンプト量がかなり少なくて済んでいるのが気になる。
tokens per secもgemmaと比べて3倍近く早い。メモリ利用は270GBぐらいだった。
ただ、言語は英語になっていたのでドキュメントの通り多言語対応はgemma・gwenと比べると弱そう。（短いプロンプトだったら、問題なく日本語で返してくれることも多いのだが）