Ollamaが遅い原因はCPU fallback|num_gpuでVRAM分割を制御する

Ollamaが遅い原因はCPU fallback|num_gpuでVRAM分割を制御する

※本記事にはプロモーション(広告・アフィリエイトリンク)を含みます。

「モデルは動くのに、返答がやたら遅い」——その多くはVRAMが足りず、モデルの一部がCPU側に載っている(CPUフォールバック)状態です。この記事は、Ollamaで推論が急に遅くなった人向けに、(1)どこにオフロードされているかを確認し、(2)num_gpuでGPUに載せる層数を制御し、(3)VRAMが足りないときに取れる打ち手を並べる、という手順をまとめます。GPUを複数ツールで共有している環境(たとえば12GBクラスのGPUを画像生成ツールなどと共用する構成)での取り分の決め方まで扱います。値はモデル・量子化・コンテキスト長で変わるため、具体的な層数はご自身の環境で確認してください。

まず「どこにオフロードされているか」を確認する

遅さの原因を推測で潰すと沼にはまります。最初に事実を見ます。

  1. モデルをロードした状態で ollama ps を実行します。PROCESSOR 列に処理の分担が出ます。
ollama ps
# NAME           ...   PROCESSOR
# llama3.1:8b    ...   100% GPU        ← 全部GPUに載っている(理想)
# llama3.1:8b    ...   47%/53% CPU/GPU ← 47%がCPU。ここが遅さの正体

CPU/GPU の分割が出ていたら、その割合ぶんの計算がCPUで走っています。

  1. VRAMの空きを見ます。NVIDIA GPUなら nvidia-smi でVRAMの使用量と空きを確認できます。
nvidia-smi --query-gpu=memory.used,memory.free --format=csv
  1. さらに詳しく層の割り当てを見たいときは、デバッグログを有効にしてサーバーを起動します。公式ドキュメントによると OLLAMA_DEBUG=1 で詳細ログが出ます。
OLLAMA_DEBUG=1 ollama serve
# ログに offloaded 24/33 layers to GPU のような行が出る

24/33 のように「一部の層だけGPU」になっていれば、残りはCPUで処理されています。

なぜCPUフォールバックで遅くなるのか

Ollamaは起動時に空きVRAMを見積もり、モデルの層(layer)を「入るだけGPUに載せ、残りをCPUに置く」という部分オフロードを自動で行います。全層がGPUに載れば高速ですが、1層でもCPUに落ちると、その層の計算のたびにCPU側の演算が挟まります。LLMは全層を毎トークン通過するため、CPUに落ちた層の割合がそのまま速度低下として効いてきます。

つまり狙いはシンプルで、できるだけ全層をGPUに載せること、それが無理ならCPUに落ちる層を最小化することです。逆に、GPUを他ツールと共有していて意図的にVRAMを空けたい場合は、あえてGPUへの層数を絞る、という制御も必要になります。その両方を握るのが num_gpu です。

num_gpu でGPUに載せる層数を決める

公式ドキュメントによると、num_gpu は「GPUに送る層の数(The number of layers to send to the GPU(s))」を指定するパラメータです。名前から「GPUの枚数」と誤解しがちですが、実際は層数です。設定方法は3通りあります。

方法 使いどころ 例
対話(REPL) その場で試したい /set parameter num_gpu 24
API options アプリから制御 "options": {"num_gpu": 24}
Modelfile 恒久設定にする PARAMETER num_gpu 24

対話で当たりを探す例:

ollama run llama3.1:8b
>>> /set parameter num_gpu 24
>>> こんにちは

設定を固定したいときはModelfileにして作り直します。

FROM llama3.1:8b
PARAMETER num_gpu 24
ollama create llama3.1-8b-g24 -f Modelfile

APIから叩く場合:

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.1:8b",
  "prompt": "要約して: ...",
  "options": { "num_gpu": 24 }
}'

進め方は、num_gpu を少しずつ上げながら ollama ps が 100% GPU になる、かつ nvidia-smi でVRAMが溢れない上限を探す、という往復です。上げすぎるとロード時にVRAM不足で失敗するので、nvidia-smi の空きを見ながら調整してください。適正値はモデルサイズ・量子化・コンテキスト長で変わるため、環境によって異なります。

VRAMが足りないときの打ち手

num_gpu を最大まで上げても全層が載らないなら、モデル側かVRAM側を動かします。

  1. 量子化を下げる: 同じモデルでも q8_0 より q4_K_M の方がVRAMを食いません。まず軽い量子化のタグを引き直すのが効果的です(品質とのトレードオフはあります)。
  2. コンテキスト長を絞る: num_ctx を大きくするとKVキャッシュぶんVRAM消費が増えます。長文を扱わないなら既定より小さくすると層をGPUに回せます。
>>> /set parameter num_ctx 4096
  1. モデルを一段小さくする: 8Bで溢れるなら、用途次第で3B〜4Bクラスに変えると全層GPUに載せやすくなります。
  2. 常駐を切ってVRAMを解放する: OLLAMA_KEEP_ALIVE でロード保持時間を制御できます。公式ドキュメントによると既定は5分(執筆時点)。使い終わったらすぐ解放したいなら短く、または 0 にします。
OLLAMA_KEEP_ALIVE=30s ollama serve
  1. 他プロセスの占有を疑う: 画像生成ツールなどがVRAMを掴んだままだと、Ollamaが載せられる層が減ります。nvidia-smi で占有プロセスを確認してから対処します。

共有GPUでは num_gpu で「取り分」を決める

GPUが1枚しかなく、Ollama以外のツール(画像生成など)と同時に使う環境では、Ollamaに全VRAMを取らせない設計が要ります。ここで num_gpu は「速度を上げる」ためだけでなく「わざとGPUへの層数を抑えて、他ツールぶんのVRAMを空ける」用途にも使えます。

あわせて OLLAMA_GPU_OVERHEAD(GPUごとに確保をやめておく予約バイト数を指定する環境変数)で余白を持たせると、見積もりミスによるロード失敗や、他ツールとのVRAM取り合いによる強制解放を避けやすくなります。

# 例: 予約を多めに取り、他ツールぶんのVRAMを残す
OLLAMA_GPU_OVERHEAD=1073741824 ollama serve  # 1GiBを予約

なお、共有GPUで複数プロセスを乱暴に pkill すると自分のセッションごと巻き込みかねません。占有の確認と解放は、ポートやPIDを名指しして慎重に行うのが安全だと考えられます。

まとめ

Ollamaの遅さは「全層がGPUに載っているか」でほぼ決まります。次の一手はこれです——まず ollama ps を実行して PROCESSOR 列を見る。100% GPU なら別要因、CPU/GPU 分割が出ていたら num_gpu を上げて全層GPUを目指し、載りきらないなら量子化・num_ctx・モデルサイズ・KEEP_ALIVE の順で削っていきます。数値は環境で変わるので、nvidia-smi と ollama ps を見ながら自分の一台で当たりを取ってください。

よくある質問

num_gpu はGPUの枚数を指定するのですか?

いいえ。公式ドキュメントによると num_gpu は「GPUに送る層(layer)の数」を指定するパラメータで、GPUの枚数ではありません。数を増やすほど多くの層がGPUに載り、VRAMを超えるとロードに失敗します。

CPUフォールバックしているか確認する方法は?

モデルをロードした状態で ollama ps を実行し、PROCESSOR 列を見ます。100% GPU なら全層GPU、47%/53% CPU/GPU のような表示が出ていれば、その割合ぶんがCPUで処理されて遅くなっています。

num_gpu を上げても全層がGPUに載りません。

VRAMが不足しています。より軽い量子化タグに変える、num_ctx を下げてKVキャッシュを減らす、モデルを一段小さくする、他ツールの占有VRAMを解放する、のいずれかで載る層を増やせます。環境によって最適解は異なります。