言語を切り替える
テーマを切り替える

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

8GB の VRAM しかないグラフィックカードで、なんとか 13B モデルをロードできたのに、数回推論しただけでクラッシュ——画面に “CUDA out of memory” のエラーが表示されて、がっかりした経験はありませんか?

あるいは、お金をかけて 2 枚の GPU を用意して、いよいよ大規模モデルを動かせると思ったら、nvidia-smi を見ると、1 枚のカードだけが仕事をしていて、もう 1 枚は暇している、ということも。

正直なところ、私も Ollama を使い始めた頃は、これらの落とし穴にはまりました。VRAM が足りない、マルチ GPU が使えない、推論速度が不安定——これらの問題に数晩悩まされました。その後、少しずつ試行錯誤して、Ollama の背後にある GPU スケジューリングロジックを理解しました。「設定すれば動く」だけでなく、パラメータの背後にある原理を理解する必要があることがわかったのです。

この記事では、これらの経験を整理して、いくつかの実践的な問題を解決するお手伝いをします:

  • 8GB VRAM で 13B モデルを安定して実行する方法(突然の OOM を防ぐ)
  • マルチ GPU を真に活用するための設定方法(負荷分散の完全なソリューション)
  • VRAM が足りない時に調整すべきパラメータ(優先順位付け)
  • GPU オフローディングとは何か(llama.cpp の基盤メカニズム)

まず前提として:この記事は少し技術的に高度です。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 オフローディングしているかを知るには、このコマンドを使います:

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 オフローディングロジックを理解すると、なぜパラメータ調整の効果が薄い場合があるかがわかります。

GPU オフローディングの決定

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

利用可能 VRAM = GPU 総 VRAM - システム予約(数百MB程度)
各層のサイズ = モデルパラメータ / 層数
配置可能層数 = min(総層数, 利用可能 VRAM / 各層のサイズ)

この計算には落とし穴があります:モデル自体が占有する VRAM だけを考慮し、KV cache を計算に入れていません。KV cache は推論時に使用するキャッシュで、会話の長さとともに大きくなります。そのため、モデルのロードには成功しても、数回推論した後に KV cache で VRAM がいっぱいになり、クラッシュすることがあります。

75%
Q4 量子化の VRAM 節約
来源: 実測比較:FP16 → Q4_K_M

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

GPU と CPU は完全に分担しているわけではありません。概ね次のようになります:

  • GPU 担当:行列計算、アテンション操作(これらは計算量が多い)
  • CPU 担当:エンベディング、正規化操作(計算量が少ない)
  • データ転送:GPU と CPU の間でデータをやり取りする必要があり、オーバーヘッドがある

一部の層だけを GPU に配置すると、データ転送のオーバーヘッドが大きくなります——各層の計算後、次の層が別のデバイスにある場合、結果を転送する必要があります。これが、部分的な GPU オフローディングの推論速度が明らかに遅くなる理由です。

mmap メモリマッピング

llama.cpp はデフォルトで mmap を使用してモデルファイルをロードします。メリットは:

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

mmap を無効にしたい場合(特定の状況で問題が発生する場合)、Modelfile で設定できます:

PARAMETER use_mmap false

2. マルチ GPU 設定方法:負荷分散の完全なアーキテクチャ

2 枚以上の GPU を持っている人の多くが直面する最大の問題は: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 を半分節約
    • 日常的な Q&A や単純なタスクには十分
  2. 長文書処理:ctx を 16000 やそれ以上に直接設定せず、チャンキングストラテジーを使用

    • 文書を小さなチャンクに分割し、順次処理
    • 一度に詰め込むよりも安定しており、制御もしやすい

Modelfile でコンテキスト長を設定:

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

よくある誤解を解消しておきます:ctx を小さくすると出力品質に影響すると思っている人が多いです。実際はそうではありません——ctx はモデルが「記憶」できる以前の会話の量に影響するだけです。会話がそもそも数回しかない場合、ctx を 2048 に設定しても 4096 に設定しても効果は同じです。

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

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

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

VRAM が厳しい時、バッチサイズを下げるとピーク時の負荷を軽減できます:

FROM llama3
PARAMETER num_batch 256  # 512 から 256 に削減

実測では、バッチを 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)

# バックグラウンドワーカーがキューからリクエストを取得して処理
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 使用量
来源: 8GB から 6GB に削減、OOM 解消
  • VRAM 使用量:約 8GB から約 6GB に削減(安定動作)
  • 推論速度:約 8 tokens/s(完全 GPU より遅いが、CPU よりはるかに速い)
  • 安定性:OOM クラッシュが発生しなくなった

代償として推論速度は少し低下しました。10 層が CPU で計算されるため、GPU-CPU 間のデータ転送オーバーヘッドが毎回発生するからです。しかし、少なくとも使用できるようになり、突然クラッシュすることはなくなりました。

4.2 シナリオ 2:デュアル GPU ロードバランシングでスループット向上

問題

ユーザーは 2 枚の RTX 3090(各 24GB VRAM)を持ち、外部向け API サービスとして Ollama をデプロイしています。問題は、単一インスタンスがシリアルでリクエストを処理するため、並行処理能力が低く、ピーク時にリクエストがキューで待機することです。

nvidia-smi で見ると、2 枚のカードの利用率に大きな差があります——1 枚は常に 70% 以上、もう 1 枚は 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%
スループット向上
来源: デュアルインスタンス並列 vs 単一インスタンスシリアル
  • 全体スループット:約 80% 向上(単一インスタンスシリアルからデュアルインスタンス並列へ)
  • 単 GPU 利用率:平均 40% → 平均 80%(両方のカードが稼働)
  • レスポンス遅延:ピーク時約 50% 削減(キュー待ちなし)

実測データ:単一インスタンスで 100 リクエストを処理するのに約 10 分かかりますが、デュアルインスタンスロードバランシングでは 5 分強です。

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

問題

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

解決策

現在の VRAM 状況に基づいて適切な Modelfile 設定を自動選択するスクリプトを作成します。

#!/bin/bash
# auto_offload.sh - 自動 GPU オフローディング設定

# 現在の 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 オフローディング
    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 モードに切り替える、あるいは cron ジョブと組み合わせて、深夜誰も使用していない時にモデルをプリロードするなど。

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 オフローディング層数
  • モデルメモリ使用量
  • 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 オフローディング層数が十分かどうか確認:

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 オフローディングは魔法ではなく、レイヤー単位の計算で、データ転送オーバーヘッドがある

すぐに使える設定をいくつか提示します:

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 が足りない時、どのパラメータから調整すべきですか?
優先順位:量子化 &gt; コンテキスト長 &gt; バッチ処理 &gt; GPU 層数 &gt; low_vram。量子化の影響が最も大きく、Q4 で 75% の VRAM を節約でき、精度低下はわずか 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 オフローディングが必要

10 min read · 公開日: 2026年4月11日 · 更新日: 2026年4月11日

コメント

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

関連記事