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

※本記事にはプロモーション(広告・アフィリエイトリンク)を含みます。
「モデルは動くのに、返答がやたら遅い」——その多くはVRAMが足りず、モデルの一部がCPU側に載っている(CPUフォールバック)状態です。この記事は、Ollamaで推論が急に遅くなった人向けに、(1)どこにオフロードされているかを確認し、(2)num_gpuでGPUに載せる層数を制御し、(3)VRAMが足りないときに取れる打ち手を並べる、という手順をまとめます。GPUを複数ツールで共有している環境(たとえば12GBクラスのGPUを画像生成ツールなどと共用する構成)での取り分の決め方まで扱います。値はモデル・量子化・コンテキスト長で変わるため、具体的な層数はご自身の環境で確認してください。
まず「どこにオフロードされているか」を確認する
遅さの原因を推測で潰すと沼にはまります。最初に事実を見ます。
- モデルをロードした状態で
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で走っています。
- VRAMの空きを見ます。NVIDIA GPUなら
nvidia-smiでVRAMの使用量と空きを確認できます。
nvidia-smi --query-gpu=memory.used,memory.free --format=csv
- さらに詳しく層の割り当てを見たいときは、デバッグログを有効にしてサーバーを起動します。公式ドキュメントによると
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側を動かします。
- 量子化を下げる: 同じモデルでも
q8_0よりq4_K_Mの方がVRAMを食いません。まず軽い量子化のタグを引き直すのが効果的です(品質とのトレードオフはあります)。 - コンテキスト長を絞る:
num_ctxを大きくするとKVキャッシュぶんVRAM消費が増えます。長文を扱わないなら既定より小さくすると層をGPUに回せます。
>>> /set parameter num_ctx 4096
- モデルを一段小さくする: 8Bで溢れるなら、用途次第で3B〜4Bクラスに変えると全層GPUに載せやすくなります。
- 常駐を切ってVRAMを解放する:
OLLAMA_KEEP_ALIVEでロード保持時間を制御できます。公式ドキュメントによると既定は5分(執筆時点)。使い終わったらすぐ解放したいなら短く、または0にします。
OLLAMA_KEEP_ALIVE=30s ollama serve
- 他プロセスの占有を疑う: 画像生成ツールなどが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を解放する、のいずれかで載る層を増やせます。環境によって最適解は異なります。