Ollama vs llama.cpp直接実行、同じGGUFなのに速度が2.7倍違った話

きっかけ:Ollamaは中身llama.cppなのに、直接使うとどれくらい違うのか

Ollamaは内部的にllama.cpp(ggml)を使っている、というのはよく知られた話。実際、Ollamaのインストールフォルダの中にはllama-server.exeがそのまま同梱されている。

じゃあ「Ollama経由」と「llama.cppを直接叩く」で、同じGGUFファイルを使った場合にどれくらい速度が変わるのか、実際に検証してみた。今回はこれまでの比較で最速だったGemma4-12B-Hereticを使い、Ollamaのモデルストレージにある実体ファイル(.gguf)をそのままllama.cppに読み込ませて比較している。

最初の落とし穴:同梱バイナリはCPU専用だった

最初、Ollamaに同梱されているllama-server.exeをそのまま使おうとしたら、いきなり躓いた。

warning: no usable GPU found, --gpu-layers option will be ignored

Ollamaに同梱されているこのバイナリ、GPUサポート無しでビルドされたものだった。Ollama自体はきちんとVulkanでGPU推論しているのに、同梱のllama-server.exe単体では動かないという、地味に紛らわしい罠。この状態で生成速度を測ったら4.1 tok/sしか出ず、当然ながらCPU実行だとこうなる。

正しく比較するため、llama.cpp公式のVulkan対応Windows版バイナリ(GitHub Releases)を別途取得して検証し直した。

本題:GPU対応版でも、Ollamaには届かなかった

Ollama vs llama.cpp直接実行の速度比較グラフ

Vulkan対応版のllama.cppで、同じGGUFファイル・同じGPU2枚環境で計測した結果:

  • Ollama(既定設定): 33.1 tok/s
  • llama.cpp直接(既定設定): 12.1 tok/s
  • llama.cpp直接(--split-mode none --main-gpu 0、GPU1枚に固定してパイプライン分割を無効化): 18.4 tok/s

既定設定のままだと、Ollamaの方が約2.7倍速いという結果になった。llama.cppの既定の--split-mode(layer、GPU間でレイヤーをパイプライン分割する方式)をnone(単一GPUのみ使用)に変えると18.4 tok/sまで改善したが、それでもOllamaには届かなかった。

前回の記事で「GPU1枚に余裕で収まるモデルは複数GPUの恩恵がない」という結果を出したばかりだが、llama.cpp側の既定設定(layer分割)では、逆に複数GPUへの分割自体がオーバーヘッドになって遅くなっていた、という点は興味深い。Ollamaはおそらく、モデルサイズとGPU容量を見て「1枚に収まるなら1枚だけ使う」という判断を内部で自動的にやってくれているのだと思われる。

結論

  1. Ollama同梱のllama-server.exeはCPU専用ビルド — そのまま使うと不当に遅い比較になるので要注意。GPU版で検証し直す必要があった
  2. 既定設定同士の比較では、Ollamaがllama.cpp直接実行より約2.7倍速い — 同じエンジン・同じGGUFでもラッパー側のチューニングでここまで差が出る
  3. llama.cppの既定の--split-mode(layer)は、1枚に収まるモデルには不利に働く--split-mode noneで単一GPU固定にすると速度は改善するが、それでもOllamaには届かなかった
  4. 「中身は同じllama.cppだから同じ速度のはず」は誤り — Ollamaは単なるラッパーではなく、実行時のGPU割り当てやバッチ設定などで実質的なチューニングを行っている

「速度で困ったらOllamaをやめて生のllama.cppを使えばいい」という発想は、少なくとも今回の環境・条件では成り立たなかった。むしろOllama側のデフォルトの賢さを再確認する結果になった。次はllama.cpp側のバッチサイズやスレッド数など、さらに細かいパラメータチューニングでOllamaに追いつけるか試してみたい。