0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ollamaの生成速度を実測比較:tok/sの読み方とCPU/GPU分割の落とし穴

0
Posted at

はじめに

「8Bクラスのモデルをローカルで動かすと遅い」——その遅さは、実は設定次第で3倍以上変わります。本記事では /api/generate のレスポンスに含まれる計測値で生成速度(tok/s)を正しく測り、同じ qwen3:8b が 9.1 tok/s → 33.3 tok/s に改善した実測を紹介します。

環境

  • Windows 11(ビルド 10.0.26200)
  • GPU: RTX 4060(VRAM 8GB)
  • Ollama 0.40.4(既定の http://127.0.0.1:11434)
  • モデル: qwen2.5:0.5b / qwen3:8b
  • Python 3.11(標準ライブラリのみ。OllamaのPythonライブラリ不要)

やったこと

1. 計測スクリプト

/api/generate のJSONレスポンスには計測値が含まれている。ここから eval_count(生成トークン数)と eval_duration(生成にかかった時間)を取り出して tok/s を計算する。

import json
import time
import urllib.request

def gen(model, num_ctx=None, think=None):
    options = {"num_predict": 32, "temperature": 0}
    if num_ctx:
        options["num_ctx"] = num_ctx
    payload = {
        "model": model,
        "prompt": "1から10まで数えて。数字だけをスペース区切りで。",
        "stream": False,
        "options": options,
    }
    if think is not None:
        payload["think"] = think
    req = urllib.request.Request(
        "http://127.0.0.1:11434/api/generate",
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=600) as res:
        d = json.loads(res.read())
    ev, ev_s = d["eval_count"], d["eval_duration"] / 1e9
    print(f"{model} ctx={num_ctx}: load {d['load_duration'] / 1e9:.1f}s / "
          f"{ev} tok を {ev_s:.2f}s → {ev / ev_s:.1f} tok/s")

gen("qwen2.5:0.5b")              # 1回目: ロード込み
gen("qwen2.5:0.5b")              # 2回目: ウォーム
gen("qwen3:8b")                  # 既定コンテキスト
gen("qwen3:8b", num_ctx=4096)   # コンテキストを絞る

2. 計測結果

構成 ollama ps のサイズ PROCESSOR 生成速度(2回目以降)
qwen2.5:0.5b(既定 ctx 32768) 865 MB 100% GPU 193.6 tok/s
qwen3:8b(既定 ctx 40960) 11 GB 46%/54% CPU/GPU 9.1 tok/s
qwen3:8b(num_ctx=4096) 5.6 GB 100% GPU 33.3 tok/s

コールドスタート(モデルのロード)は 0.5b で約3.3秒、8b(ctx 4096)で約16.6秒だった。

3. なぜ qwen3:8b が 9 tok/s だったのか

実行中に ollama ps を見ると、qwen3:8b は 46%/54% CPU/GPU と表示された。VRAM 8GBのGPUに対して、既定コンテキスト 40960 のKVキャッシュを含むサイズが 11GB あり、全部をGPUに載せられず一部がCPUに落ちていた。

同じモデルでも num_ctx を 4096 に絞ると 5.6GB に収まり、100% GPU で動くようになる。生成速度は 9.1 → 33.3 tok/s(約3.7倍)になった。

gen("qwen3:8b", num_ctx=4096)

長文コンテキストが必要なタスク以外は、num_ctx を必要な分だけ指定するのが効率的、という実感が得られた。

4. thinkingモデル(qwen3)の速度の見え方

qwen3系は既定で「思考トークン」を生成する。num_predict=32 のような短い上限だと、32トークン全部が思考に使われて response が空に見えることがある。思考を切って比べると動きが分かりやすい。

gen("qwen3:8b", num_ctx=4096, think=None)   # 既定: 思考あり
gen("qwen3:8b", num_ctx=4096, think=False)  # 思考なし: 直接回答

ハマった点

  1. total_duration で測ると遅く見える。total_duration にはロード時間(load_duration)やプロンプト評価が含まれる。純粋な生成速度は eval_count ÷ eval_duration で出す。初回計測ほどこの差が大きい。
  2. ollama ps の PROCESSOR 列を見ないと気づけない。「GPUに載っているか」はタスクマネージャの使用量では判断しづらい。まず ollama ps で 100% GPU か分割かを確認するのが早い。
  3. 計測と同じマシンで重い処理を並行させると数字が汚染される。筆者は計測中に別ウィンドウでビルド処理を走らせてしまい、初回計測が 2.3 tok/s と出た。条件を揃えて測り直したら 9.1 tok/s だった。ベンチは静かな状態で。
  4. 思考トークンも eval_count に含まれる。think のオン/オフで「同じ土俵」にならないので、比較するなら条件を揃える。

まとめ

  • 生成速度は eval_count ÷ eval_duration で測る。total_duration はロード込みなので比較に使わない。
  • ollama ps の PROCESSOR 列で 100% GPU か CPU/GPU 分割かを必ず確認する。
  • VRAMに収まらない場合は num_ctx を絞る。実測では 9.1 → 33.3 tok/s(3.7倍)に改善した。
  • ベンチマークは「ウォーム状態・同一条件・静かなマシン」で。

関連する本

速度計測の手順を含む実測ガイドを一冊にまとめました。第1章・第2章は無料で読めます。

Windowsで動かすローカルLLM自動化:Ollama実測ガイド

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?