テーマを切り替える

Ollama GPU スケジューリングとリソース管理:VRAM 最適化とマルチ GPU 負荷分散

8GB の VRAM のグラフィックボードで、やっとのことで 13B モデルを読み込めた——と思ったら、数回推論しただけで突然クラッシュ。画面には「CUDA out of memory」のエラー。

あるいは、お金をかけて GPU を2枚積んで、これで大きなモデルが動かせると期待していたのに、nvidia-smi を見てみると、働いているのは1枚だけで、もう1枚は遊んでいる。

Ollama を使い始めた頃は、こうした落とし穴にいくつもはまりました。VRAM が足りない、マルチ GPU が活かせない、推論速度が速くなったり遅くなったり。そのうち少しずつ手探りで、Ollama の裏側にある GPU スケジューリングのロジックがわかってきました。多くのことは「設定すれば動く」ものではなく、パラメータの背後にある原理を理解する必要があったのです。

この記事では、そうした経験を整理して、いくつかの実際の問題を解決できるようにまとめます。

  • 8GB の VRAM で 13B モデルを安定して動かす方法(すぐに OOM にならないように)
  • マルチ GPU を本当に使えるようにする設定方法(負荷分散の完全な手順)
  • VRAM が足りないときにどのパラメータを調整すべきか(優先順位)
  • GPU offloading とは結局何なのか(llama.cpp の内部メカニズム)

先に前提を1つ。この記事は少し硬派な内容で、GPU、CUDA、Ollama の基本操作についてある程度の知識が必要です。Ollama を触り始めたばかりなら、まずシリーズの前の数本(特に第6回の性能最適化の基礎)を読んでおくと、背景知識ができた上でこの記事を読めるので、ぐっと理解しやすくなります。

1. GPU メモリ管理の仕組み:パラメータ設定を完全解説

Ollama の GPU スケジューリングの核心は、いくつかのパラメータでモデルの層を GPU と CPU の間でどう割り当てるかを制御することです。これらのパラメータを理解すれば、VRAM が足りているはずなのにエラーが出る理由や、推論速度がなぜか遅くなる理由がわかります。

1.1 主要パラメータの詳解

まずは最も重要ないくつかのパラメータを、見比べやすいように表にまとめました。

パラメータ役割デフォルト値調整するタイミング
num_gpuモデルの何層を GPU 上で動かすか自動検出VRAM が足りないときに値を減らす
main_gpuメイン GPU の番号0マルチ GPU でどのカードを使うか指定する
low_vram低 VRAM モードのスイッチfalse8GB 以下の VRAM では有効化を推奨
num_batchバッチサイズ512VRAM が逼迫したら 256 に下げる
num_ctxコンテキスト長4096短い会話なら 2048 で VRAM をかなり節約できる

これらのパラメータの中で、num_gpu が最も誤解されやすいものです。これは GPU が何枚あるかではなく、モデルの何層を GPU 上で計算するかを指します。

例を挙げましょう。Llama 2 7B モデルは 32 層あります。num_gpu: 32 に設定すれば、全 32 層が GPU 上で動きます。VRAM が足りなければ num_gpu: 20 に変えると、20 層が GPU、残りの 12 層は CPU で計算することになり——当然ながら速度は落ちます。

low_vram というパラメータはなかなか面白いものです。有効にすると、Ollama は VRAM を節約するためにいくつかの工夫をします。たとえば KV cache を GPU の VRAM ではなく CPU のメモリに置く、といった具合です。代償として推論速度は少し落ちますが、少なくともクラッシュはしません。

1.2 VRAM 割り当ての流れ

Ollama がモデルを読み込むとき、VRAM の割り当ては次のような流れになります。

  1. VRAM の検出:まず GPU にどれだけ空き VRAM があるかを確認する
  2. 層数の計算:モデルサイズと VRAM の状況から、何層を GPU に載せられるか算出する
  3. KV cache の割り当て:推論用のキャッシュ領域を確保する(これも VRAM を消費する)
  4. 推論の開始:VRAM 使用量は動的に変化し、変動がある

ポイントは2番目です——Ollama は自動で最適な層数の割り当てを計算します。ただし、この自動計算は十分に正確でないことがあります。特に VRAM がぎりぎり足りるか足りないかの境目(たとえば 8GB の VRAM で 13B モデルを動かす場合)では、手動で num_gpu を指定する必要が出てきます。

今のモデルが何層 GPU offloading しているか知りたいときは、このコマンドを使います。

ollama run llama3 --verbose

出力に llama_model_load: model loaded - layers: 40/40 on GPU のような行があり、これが 40 層すべてが GPU 上にあることを教えてくれます。

1.3 llama.cpp バックエンドの仕組み

Ollama は内部で llama.cpp という推論エンジンを使っています。llama.cpp の GPU offloading ロジックを理解すれば、なぜパラメータを調整しても効果がいまひとつのことがあるのかがわかります。

GPU Offloading の判断

llama.cpp は次のように計算します。

利用可能 VRAM = GPU 総 VRAM - システム予約(数百 MB 程度)
1層あたりのサイズ = モデルパラメータ / 層数
載せられる層数 = min(総層数, 利用可能 VRAM / 1層あたりのサイズ)

この計算には落とし穴があります。モデル本体が占める VRAM しか考慮しておらず、KV cache を勘定に入れていないのです。KV cache は推論時に使われるキャッシュで、会話が長くなるにつれて大きくなります。だからモデルの読み込みは成功しても、数回推論すると KV cache が VRAM を圧迫してクラッシュする、ということが起きます。

75%
Q4 量子化による VRAM 節約
Source: 実測比較:FP16 → Q4_K_M

ハイブリッド計算アーキテクチャ

GPU と CPU は完全に分業しているわけではありません。おおまかには次のようになっています。

  • GPU の担当:行列計算、attention 操作(計算量が大きいもの)
  • CPU の担当:embedding、normalization 操作(計算量が小さいもの)
  • データ転送:GPU と CPU の間でデータを往復させるため、オーバーヘッドがある

一部の層だけを GPU に載せると、データ転送のオーバーヘッドが大きくなります——ある層の計算が終わると、次の層は別のデバイス上にあるので、まず結果を転送しなければなりません。これが、一部だけ GPU offloading したときに推論速度が明らかに遅くなる理由です。

mmap メモリマッピング

llama.cpp はデフォルトで mmap を使ってモデルファイルを読み込みます。利点は次の通りです。

  • モデル全体をメモリに読み込む必要がなく、OS が必要に応じて読み込む
  • 複数のプロセスが同じメモリを共有できる
  • メモリ使用量が少なくて済む

mmap を無効にしたい場合(特定の状況では問題が起きることがあります)は、Modelfile で次のように設定できます。

PARAMETER use_mmap false

2. マルチ GPU の構成:負荷分散の完全アーキテクチャ

GPU を2枚、あるいはそれ以上持っている人にとって、最も悩ましい問題はこれでしょう。Ollama でどうやってそれらをすべて使うのか?

先に、少しがっかりする事実を言っておきます。Ollama はモデル並列に対応していません。どういう意味かというと、1つのモデルを2つに分けて、半分を GPU 0 で、もう半分を GPU 1 で計算する、ということはできないのです。各モデルは1枚の GPU にしかバインドできません。

では、マルチ GPU には何の意味があるのか?用途は2つあります。

  1. 異なるモデルインスタンスを動かす:GPU 0 で llama3、GPU 1 で mistral
  2. 同じモデルの複数インスタンスを動かす:負荷分散に使い、スループットを上げる

2.1 単一インスタンスのマルチ GPU(限界と設定)

Ollama に複数の GPU を認識させたいだけなら、最も簡単なのは CUDA_VISIBLE_DEVICES 環境変数を使う方法です。

# Ollama に GPU 0 と GPU 1 だけを使わせる
CUDA_VISIBLE_DEVICES=0,1 ollama serve

ただ、この設定には問題があります。Ollama はデフォルトでモデルを GPU 0 にしか載せず、GPU 1 は遊んだままです。main_gpu パラメータでメイン GPU を指定できます。

# Modelfile
FROM llama3
PARAMETER main_gpu 1  # メイン GPU を GPU 1 に設定

ただ正直に言うと、この方法は効果が限定的です——モデルを動かすカードを別のものに替えただけで、2枚のカードの能力を本当に活かしているわけではありません。

2.2 マルチインスタンス負荷分散(推奨方式)

マルチ GPU の能力を本当に発揮させる方法は、複数の Ollama インスタンスを動かし、各カードに1つのインスタンスをバインドして、負荷分散器でリクエストを振り分けることです。

アーキテクチャは次の通りです。

┌─────────┐
│ Client  │  推論リクエストを送信
└────┬────┘

┌────▼────────────────────┐
│ Nginx (負荷分散器)       │  least_conn 戦略
│ Port: 8080              │
└────┬─────────┬──────────┘
     │         │
┌────▼───┐ ┌──▼────┐
│Ollama 1│ │Ollama 2│
│GPU 0   │ │GPU 1   │  各インスタンスが1枚の GPU を占有
│Port    │ │Port    │
│11434   │ │11435   │
└────────┘ └────────┘

ステップ1:複数の Ollama インスタンスを起動する

# インスタンス 1 - GPU 0 にバインド、ポート 11434
CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &

# インスタンス 2 - GPU 1 にバインド、ポート 11435
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &

注意:デフォルトの Ollama データディレクトリは ~/.ollama で、2つのインスタンスは同じモデルストレージを共有します。これは問題ありません。mmap メモリマッピングにより、複数のプロセスが同じモデルファイルを共有できるからです。

ステップ2:Nginx 負荷分散を設定する

# /etc/nginx/conf.d/ollama.conf
upstream ollama_cluster {
    least_conn;  # 最少接続優先戦略
    server 127.0.0.1:11434;
    server 127.0.0.1:11435;
}

server {
    listen 8080;

    location / {
        proxy_pass http://ollama_cluster;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # ストリーミングレスポンス対応
        proxy_buffering off;
        proxy_cache off;
    }
}

least_conn 戦略は、新しいリクエストをその時点で接続数が最も少ないインスタンスに送る、という意味です。こうすれば2枚の GPU の負荷がより均等になります。

ステップ3:クライアントからの呼び出し

クライアントは Nginx のポートに接続するだけです。

# Nginx 経由で呼び出す(自動的にいずれかのインスタンスに振り分けられる)
curl http://localhost:8080/api/generate -d '{
  "model": "llama3",
  "prompt": "こんにちは"
}'

または Ollama クライアントのデフォルトアドレスを変更します。

export OLLAMA_HOST=http://localhost:8080
ollama run llama3

2.3 負荷分散戦略の比較

Nginx はいくつかの異なる負荷分散戦略に対応していて、それぞれ適した場面があります。

戦略仕組み適した場面
ラウンドロビン(デフォルト)各インスタンスに順番に送るシンプルな場面、モデルサイズが揃っている場合
最少接続(least_conn)その時点で最も空いているインスタンスに送る推論サービスに推奨
IP Hash同じ IP は常に同じインスタンスに送るセッション維持が必要な場面

推論サービスの特徴は、リクエストの所要時間が一定しないことです——数秒で返るものもあれば、数分かかるものもあります。ラウンドロビンだと、一方のインスタンスが忙しくてたまらず、もう一方が暇という状況が起こりえます。least_conn ならこの問題を避けられます。

リクエストをできるだけ均等にしつつ、たまにあるインスタンスがクラッシュしても自動的に切り替えたいなら、ヘルスチェックを追加できます。

upstream ollama_cluster {
    least_conn;
    server 127.0.0.1:11434 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:11435 max_fails=3 fail_timeout=30s;
}

こうすると、あるインスタンスが連続で3回失敗すると、Nginx はそれを一時的にクラスタから外し、30 秒後に再試行します。

3. VRAM 最適化戦略:量子化・コンテキスト・バッチの組み合わせ実践

VRAM が足りないときに、パラメータを調整する優先順位はこうです。量子化 > コンテキスト長 > バッチサイズ > GPU 層数

なぜこの順番なのか?量子化の影響が最も大きいからです。同じモデルでも、Q4 量子化なら FP16 より 75% の VRAM を節約できます。一方、GPU 層数の調整は計算を GPU から CPU に移すだけで、VRAM は節約できても速度が落ちます。

3.1 量子化レベルの選び方

量子化とは、より少ないビット数でモデルパラメータを保存することです。FP16 は各パラメータに 16 ビットを使い、Q4 は 4 ビットしか使いません。ビット数が減れば当然精度に損失が出ますが、実際にテストしてみると、Q4 量子化による品質低下はおよそ 2〜3% で、ほとんどの場面で十分に許容できます。

量子化レベルの比較:

量子化VRAM 使用量(FP16 比)精度損失適した場面
Q4_K_M約 25%2〜3%推奨:性能と品質のバランス
Q5_K_M約 33%1〜2%精度要求がやや高い場面
Q8_0約 50%0.5%元の精度に近い
FP16100%なし研究・ベンチマーク

実データの参考:Llama 2 13B モデル

  • FP16:約 26GB の VRAM
  • Q4_K_M:約 8GB の VRAM
  • Q8_0:約 13GB の VRAM

なので 8GB の VRAM で 13B Q4 モデルを動かすと、ちょうど収まります。ただ問題は KV cache がさらに領域を占めることで、推論時に簡単に溢れてしまいます。

量子化レベルを選ぶときの小さなアドバイス:日常的に使うだけなら Q4_K_M で十分です。翻訳やコード生成のような精度要求が高いタスクをするなら、Q5_K_M や Q8_0 を検討するとよいでしょう。

Ollama はデフォルトで Q4 量子化版をダウンロードします。別の量子化版を使いたいときは、モデル名の後ろにサフィックスを付けます。

# Q4 量子化(デフォルト)
ollama pull llama3

# Q8 量子化
ollama pull llama3:8b-q8_0

3.2 コンテキスト長の最適化

KV cache は推論中のキャッシュで、それまでの会話履歴を保存するために使われます。その VRAM 使用量はコンテキスト長に直結します。

概算式(簡易版):

KV Cache の VRAM ≈ num_ctx × num_layers × hidden_dim × 2 bytes

Llama 2 7B を例に挙げます。

  • num_layers = 32
  • hidden_dim = 4096
  • num_ctx = 4096

計算すると KV cache はおよそ 2GB です。ctx を 8192 に広げると、KV cache は 4GB になります。コンテキストが倍になれば、KV cache の VRAM も倍になります。

最適化戦略

  1. 短い会話の場面num_ctx: 2048 を使う

    • KV cache の VRAM を半分に節約できる
    • 日常的な質問応答やシンプルなタスクには十分
  2. 長い文書の処理:ctx をいきなり 16000 やそれ以上に設定せず、チャンク化(chunking)戦略を使う

    • 文書を小さなブロックに切り、ブロックごとに処理する
    • 一度に詰め込むより安定し、コントロールしやすい

Modelfile でコンテキスト長を設定します。

FROM llama3
PARAMETER num_ctx 2048  # コンテキスト長を減らす

1つ注意したい誤解があります。ctx を小さくすると出力品質が落ちると思っている人が多いのですが、実はそうではありません——ctx はモデルがそれまでの会話をどれだけ「覚えていられるか」に影響するだけです。会話がもともと数ターンしかないなら、ctx を 2048 にしても 4096 にしても効果は同じです。

3.3 バッチ処理と並行性の最適化

num_batch というパラメータは、一度に何個の token を処理するかを制御します。デフォルト値は 512 で、Ollama が一度に 512 個の token を推論することを意味します。

バッチを大きくすると何が良いのか?並列計算の効率が上がります。代償としてピーク時の VRAM がより高くなります。

VRAM が逼迫しているときは、batch を下げるとピーク時の圧力を緩和できます。

FROM llama3
PARAMETER num_batch 256  # 512 から 256 に下げる

実測では、batch を 512 から 256 に下げると、ピーク時の VRAM が約 20% 下がりました。推論速度は少し落ちますが、GPU 層数を減らしたときほど激しくは落ちません。

並行リクエストの問題

Ollama はデフォルトでリクエストを逐次処理します——1つのリクエストを処理し終えてから次を処理します。複数のリクエストを同時に送ると、それらは順番待ちになります。

並行性能を上げたいなら、2つの方法があります。

  1. マルチインスタンス展開:前述のマルチ GPU 負荷分散方式で、各インスタンスが独立してリクエストを処理できる
  2. キューシステム:アプリケーション層にキュー(たとえば Redis Queue)を追加し、自分でリクエストの振り分けを管理する

2つ目の方法はマルチ GPU がない場面により向いています。アプリケーションのコードで次のように処理できます。

import redis
from queue import Queue

# Redis をキューとして使う
r = redis.Redis()
r.lpush('ollama_queue', request_data)

# バックグラウンドの worker がキューからリクエストを取り出して処理する
request = r.rpop('ollama_queue')
ollama.generate(request)

4. 実践シナリオの事例:3つの実例

理論はずいぶん話しました。実際に遭遇した問題とその解決策をいくつか見ていきましょう。

4.1 シナリオ1:8GB の VRAM で 13B モデルを安定稼働させる

問題

ユーザーのグラフィックボードは RTX 3060(8GB VRAM)で、Llama 2 13B Q4 モデルを動かしたいと考えていました。モデル本体には約 8GB が必要で、ちょうど収まります。ただ問題は、数回推論すると OOM エラーが出始めることでした——KV cache が VRAM を圧迫したのです。

解決策

核心となる考え方:KV cache の使用量を減らす + ピーク時の VRAM を下げる。

FROM llama2:13b-q4

PARAMETER num_gpu 30      # 13B モデルは計 40 層、30 層だけ GPU に載せる
PARAMETER low_vram true   # 低 VRAM モードを有効化、KV cache を CPU メモリに置く
PARAMETER num_ctx 2048    # コンテキスト長を半分にし、KV cache も半分に
PARAMETER num_batch 256   # バッチを小さくし、ピークを下げる

これらのパラメータを組み合わせると、VRAM 使用量は 6GB 前後で安定し、変動に備えて 2GB の余裕を残せます。

効果

6GB
安定した VRAM 使用量
Source: 8GB から 6GB に低下、OOM は再発せず
  • VRAM 使用量:約 8GB から約 6GB に低下(安定稼働)
  • 推論速度:約 8 tokens/s(全 GPU より遅いが、CPU よりはずっと速い)
  • 安定性:OOM クラッシュが再発しなくなった

代償として推論速度は少し落ちます。10 層を CPU で計算する必要があり、GPU と CPU をまたぐたびにデータ転送のオーバーヘッドがあるからです。それでも、少なくとも使えるようになり、すぐにクラッシュすることはなくなりました。

4.2 シナリオ2:デュアル GPU の負荷分散でスループットを上げる

問題

ユーザーは RTX 3090 を2枚(各 24GB VRAM)持っていて、外部に API サービスを提供する Ollama を展開していました。問題は、単一インスタンスではリクエストを逐次処理することしかできず、並行性能が低く、ピーク時にはリクエストの順番待ちが深刻だったことです。

nvidia-smi で見ると、2枚のカードの使用率に大きな差がありました——一方は常に 70%+、もう一方は 20% 程度しかありませんでした。

解決策

マルチインスタンス + Nginx 負荷分散で、第2章で詳しく説明した通りです。ここでは完全な起動スクリプトを示します。

#!/bin/bash
# start_ollama_cluster.sh

# インスタンス 1 - GPU 0
CUDA_VISIBLE_DEVICES=0 \
OLLAMA_HOST=127.0.0.1:11434 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama1.log 2>&1 &

# インスタンス 2 - GPU 1
CUDA_VISIBLE_DEVICES=1 \
OLLAMA_HOST=127.0.0.1:11435 \
OLLAMA_MODELS=/home/user/.ollama \
nohup ollama serve > ollama2.log 2>&1 &

# 両インスタンスにモデルを事前ロード
sleep 5
curl http://127.0.0.1:11434/api/pull -d '{"name": "llama3"}'
curl http://127.0.0.1:11435/api/pull -d '{"name": "llama3"}'

echo "Ollama cluster started on ports 11434 and 11435"

Nginx の設定は least_conn 戦略を使い、リクエストが均等に振り分けられるようにします。

効果

80%
スループット向上
Source: デュアルインスタンス並列 vs 単一インスタンス逐次
  • 全体のスループット:約 80% 向上(単一インスタンスの逐次処理からデュアルインスタンスの並列処理へ)
  • 単一 GPU の使用率:平均 40% → 平均 80%(2枚とも稼働)
  • レスポンス遅延:ピーク時に約 50% 減少(順番待ちが不要に)

実測データ:単一インスタンスで 100 件のリクエストを処理するのに約 10 分かかったのに対し、デュアルインスタンス負荷分散では 5 分強で済みました。

4.3 シナリオ3:VRAM の動的割り当てを自動化する

問題

ユーザーはサイズの異なる複数のモデルを持っていて、切り替えるたびに手動で GPU 層数の設定を調整する必要がありました。変更を忘れるとクラッシュすることもあります。自動化できないか?という相談です。

解決策

スクリプトを書いて、現在の VRAM の状況に応じて適切な Modelfile 設定を自動で選ぶようにします。

#!/bin/bash
# auto_offload.sh - 自動 GPU offloading 設定

# 現在の GPU 空き VRAM を取得(単位 MB)
GPU_MEM_FREE=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits | head -1)

# モデルサイズの参考値(MB)
declare -A MODEL_SIZES
MODEL_SIZES["llama3:8b-q4"]=5000
MODEL_SIZES["llama3:70b-q4"]=40000
MODEL_SIZES["mistral:7b-q4"]=4500

MODEL_NAME=$1

if [ -z "$MODEL_NAME" ]; then
    echo "Usage: $0 <model_name>"
    exit 1
fi

MODEL_SIZE=${MODEL_SIZES[$MODEL_NAME]}

if [ -z "$MODEL_SIZE" ]; then
    echo "Unknown model size for $MODEL_NAME"
    exit 1
fi

# VRAM が全 GPU に足りるか判定
if [ $GPU_MEM_FREE -gt $MODEL_SIZE ]; then
    # 全 GPU offloading
    echo "Using full GPU offloading (enough memory)"
    cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu -1  # -1 は全 GPU を意味する
PARAMETER low_vram false
EOF
else
    # 一部 GPU、適切な層数の割合を算出
    OFFLOAD_RATIO=$((GPU_MEM_FREE * 100 / MODEL_SIZE))
    echo "Using partial GPU offloading ($OFFLOAD_RATIO%)"
    cat > /tmp/modelfile_temp <<EOF
FROM $MODEL_NAME
PARAMETER num_gpu $OFFLOAD_RATIO
PARAMETER low_vram true
PARAMETER num_ctx 2048
EOF
fi

# モデルを作成
ollama create "${MODEL_NAME}-auto" -f /tmp/modelfile_temp
echo "Created ${MODEL_NAME}-auto with auto config"

使い方:

# スクリプトを実行し、適切な設定のモデルを自動作成する
./auto_offload.sh llama3:70b-q4

効果

  • VRAM の変化に自動で適応する
  • 手動設定のミスが減る
  • モデルを切り替えるときに毎回パラメータを変えなくて済む

このスクリプトはさらに拡張できます。たとえば監視を加えて、VRAM が足りなくなったら自動で低 VRAM モードに切り替える、あるいは定期タスクと組み合わせて、誰も使わない深夜にモデルを事前ロードする、といった具合です。

5. ベストプラクティスと監視:推奨設定、監視ツール、よくある問題

5.1 VRAM サイズ別の推奨設定

自分のハードウェアに合った設定をすばやく見つけられる早見表です。

VRAM サイズ推奨モデル量子化GPU 層数その他のパラメータ
6GB7B モデルQ4一部(約 50%)low_vram=true, ctx=2048
8GB7B モデルQ4全 GPUctx=2048(念のため)
8GB13B モデルQ4一部(約 75%)low_vram=true, ctx=2048, batch=256
12GB13B モデルQ4全 GPUctx=4096 が使える
16GB13B モデルQ8 または Q5全 GPUctx=4096
16GB70B モデルQ4一部(約 50%)low_vram=true
24GB70B モデルQ4全 GPUctx=4096 が使える
48GB(デュアルカード)70B モデルQ4全 GPUマルチインスタンス負荷分散

注意:これらは控えめな見積もりです。実際には KV cache とシステム予約の領域も考慮する必要があります。長い会話(コンテキストが大きい)の場面なら、控えめにしておくほうが安定します。

5.2 VRAM 監視ツール

nvidia-smi のリアルタイム監視

最も簡単な方法:

# 1秒ごとに更新
nvidia-smi -l 1

# VRAM 使用量だけを見る
nvidia-smi --query-gpu=memory.used,memory.free --format=csv -l 1

出力には各カードの VRAM 使用状況が表示されます。推論中にこれを見ていると、VRAM がどのように増えていくかがわかります。

Ollama の verbose ログ

ollama run llama3 --verbose

出力にはモデル読み込み時の詳細情報が表示されます。次のような内容が含まれます。

  • GPU offloading の層数
  • モデルのメモリ使用量
  • mmap が有効かどうか
  • KV cache の割り当て

GPU offloading: 40/40 layers のような情報が見えれば、モデルが全部 GPU 上にあるとわかります。

監視スクリプトの例

VRAM 使用状況を長期的に監視したいなら、ログを記録するスクリプトを書けます。

#!/bin/bash
# monitor_gpu.sh

LOG_FILE="gpu_memory.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    GPU_MEM=$(nvidia-smi --query-gpu=memory.used,memory.free --format=csv,noheader)
    echo "$TIMESTAMP $GPU_MEM" >> $LOG_FILE
    sleep 5
done

バックグラウンドで動かしておけば、いつでも履歴データを確認できます。

5.3 よくある問題のトラブルシューティング

問題1:推論時に OOM が出る

トラブルシューティングの手順:

  1. まず nvidia-smi を見て、本当に VRAM が足りないことを確認する
  2. 現在の設定を確認する:
    • 量子化が Q4 になっているか(なっていなければ Q4 に変える)
    • コンテキスト長が大きすぎないか(2048 に変える)
    • バッチが大きすぎないか(256 に変える)
    • GPU 層数が全 GPU になっていないか(数層減らす)
  3. 以上を全部調整しても駄目なら、low_vram=true を有効にする

調整の優先順位:量子化 > ctx > batch > GPU 層数 > low_vram

問題2:推論速度が遅い

まず GPU offloading の層数が足りているか確認します。

ollama run your_model --verbose | grep "GPU offloading"

GPU offloading: 20/40 layers と見えたら、半分の層が CPU で計算されているということなので、速度が遅いのは当然です。

解決策:量子化レベルを下げる(Q4 → Q8)か、より大きい VRAM のグラフィックボードに替える。どうにもならなければ、この速度を受け入れるしかありません。

問題3:VRAM の変動が大きく、不安定

VRAM の変動は主に KV cache から来ます。会話が長くなるほど KV cache が大きくなります。

解決策:コンテキスト長を制限するか、アプリケーション層で会話履歴の長さを制御する(たとえば直近 10 ターンの会話だけ保持する)。

問題4:マルチ GPU を設定したのに、まだ1枚しか使われない

Nginx の設定が有効になっているか確認します。

curl http://localhost:8080/api/tags

1つのモデルのレスポンスだけが見えるなら、リクエストは確かに振り分けられています。

2枚のカードの使用率に大きな差があるなら、原因として次が考えられます。

  • least_conn 戦略が設定されていない
  • どれかのインスタンスに問題が起きている(ログを確認する)
  • モデルが片方のインスタンスにしかロードされていない

まとめ

ずいぶん話しましたが、核心はいくつかのポイントに尽きます。

  1. VRAM が足りないときは、まず量子化を調整する:Q4 は FP16 より 75% の VRAM を節約でき、品質低下はわずか
  2. KV cache の使用量に注目する:コンテキスト長が KV cache に直接影響し、長い会話ほど VRAM 圧力が大きい
  3. マルチ GPU は負荷分散で使う:単一インスタンスのマルチ GPU モードは効果が限定的で、マルチインスタンス + Nginx が正解
  4. llama.cpp の内部を理解する:GPU offloading は魔法ではなく層ごとの計算で、データ転送のオーバーヘッドがある

そのまま使える設定をいくつか挙げておきます。

8GB VRAM の安定設定

PARAMETER num_gpu 30
PARAMETER low_vram true
PARAMETER num_ctx 2048
PARAMETER num_batch 256

デュアル GPU 負荷分散の起動

CUDA_VISIBLE_DEVICES=0 OLLAMA_HOST=127.0.0.1:11434 ollama serve &
CUDA_VISIBLE_DEVICES=1 OLLAMA_HOST=127.0.0.1:11435 ollama serve &

最後に、この記事が役に立ったなら、シリーズの他の記事もぜひ見てみてください。第6回は量子化やバッチ処理の基礎を扱っていて、この記事はその GPU 方向の発展編にあたります。第8回ではマルチモデルの並列展開を扱い、マルチ GPU の設定をより複雑な場面に応用します。

質問があれば、Ollama の GitHub Discussions を探してみてください。多くの実際の問題はコミュニティで議論されています。あるいはコメント欄に直接書き込んでもらえれば、見つけ次第返信します。


FAQ

Ollama は1つのモデルを複数の GPU に分割して並列計算できますか?
できません。Ollama はモデル並列(Tensor Parallelism)に対応しておらず、各モデルインスタンスは1枚の GPU にしかバインドできません。マルチ GPU を活用するには、複数インスタンス + Nginx 負荷分散が必要です。
モデルの読み込みは成功したのに、数回推論すると OOM になるのはなぜですか?
原因は KV cache です。モデルの読み込み時はモデル本体が占める VRAM しか計算されませんが、推論中は会話が長くなるにつれて KV cache が増えていきます。おすすめの対策は次の通りです。

• コンテキスト長(num_ctx)を減らす
• low_vram モードを有効にする
• 会話履歴を短くする
VRAM が足りないとき、まずどのパラメータを調整すべきですか?
優先順位は 量子化 > コンテキスト長 > バッチ > GPU 層数 > low_vram です。量子化の影響が最も大きく、Q4 なら VRAM を 75% 節約でき、品質低下はわずか 2〜3% です。
num_gpu パラメータは GPU の枚数を指すのですか?
違います。num_gpu はモデルの何層を GPU 上で計算するかを指します。たとえば 32 層のモデルなら、num_gpu=32 は全層 GPU、num_gpu=20 は 20 層が GPU、12 層が CPU という意味です。
マルチ GPU の負荷分散にはどの戦略を使うべきですか?
least_conn(最少接続優先)がおすすめです。推論リクエストの所要時間は一定しないため、ラウンドロビンだと一方のインスタンスが忙しく、もう一方が暇という状況になりがちです。least_conn なら、その時点で最も空いているインスタンスにリクエストを振り分けられます。
8GB の VRAM でどれくらいの大きさのモデルが動かせますか?
控えめな構成の目安は次の通りです。

• 7B Q4:全 GPU、ctx=2048
• 13B Q4:一部 GPU(約 75%)、low_vram + ctx=2048 + batch=256 が必要
• さらに大きいモデルには、より大きい VRAM か CPU offloading が必要

12分で読めます · 公開日: 2026年4月11日 · 更新日: 2026年7月9日

関連記事

コメント

GitHubアカウントでログインしてコメントできます

Easton BlogEaston Blog