【Ollama】GPUレイヤー数設定エラーを解決!モデルごとの最適化で推論速度を向上させる方法

問題の概要:Ollamaで特定モデルを実行するとGPUメモリ不足エラーが発生する

Ollamaを使用してLLM(大規模言語モデル)をローカル環境で実行する際、特にパラメータ数の多いモデル(例:llama2:70b, mixtral:8x7b)をGPUで動作させようとすると、以下のようなエラーメッセージが表示され、実行に失敗することがあります。

Error: failed to load model: CUDA out of memory. Tried to allocate 2.00 GiB (GPU 0; 8.00 GiB total capacity; 5.21 GiB already allocated; 0 bytes free; 5.93 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

あるいは、モデルは起動するものの、推論速度が異常に遅く、以下のようなログでCPUへのフォールバックが確認される場合もあります。

ollama run llama2:13b
>>> こんにちは
(応答が非常に遅い)
ollama logs
...
llama_model_load_internal: offloaded 35/43 layers to GPU
llama_model_load_internal: total VRAM used: 5120 MB

この問題の核心は、OllamaがモデルをGPUに完全にロードできず、一部のレイヤーをCPUで処理していることにあります。これにより、GPUのメモリ容量を超えてモデルをロードしようとするとエラーが発生し、あるいはパフォーマンスが大幅に低下します。

原因の解説:GPUレイヤー数とメモリ割り当ての関係

Ollamaは、LLMの計算を高速化するため、モデルの「レイヤー」をGPUのVRAM(ビデオメモリ)にロードします。しかし、モデルのサイズ(パラメータ数)と使用するGPUのVRAM容量には限界があります。

主な原因

1. デフォルト設定の不適合: Ollamaは利用可能なGPUメモリを自動検出し、モデルをロードするレイヤー数を決定しますが、この推定が正確でない場合や、他のアプリケーションがVRAMを使用している場合、最適な設定にならないことがあります。

2. モデルとGPUのミスマッチ: 例えば、24GBのVRAMを持つGPUで70Bパラメータのモデルを完全にロードすることは物理的に不可能です。この場合、ロードするレイヤー数を手動で調整(削減)する必要があります。

3. システム全体のメモリ競合: Dockerコンテナ内で実行している場合、コンテナに割り当てられたメモリ制限が原因で、GPUレイヤー数の設定が正しく機能しないことがあります。

解決方法:モデルごとにGPUレイヤー数を最適化する手順

Ollamaでは、モデルごとにGPUにロードするレイヤー数を明示的に指定することで、この問題を解決できます。以下に、ステップバイステップの手順を説明します。

ステップ1: 現在のシステム環境とモデル情報を確認する

まず、使用しているGPUのVRAM容量と、対象モデルのおおよそのメモリ要件を把握します。

# NVIDIA GPUの場合
nvidia-smi

# 出力例:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.105.17   Driver Version: 525.105.17   CUDA Version: 12.0    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:01:00.0  On |                  N/A |
| 30%   50C    P2    70W / 200W |   5321MiB /  8192MiB |     45%      Default |

この例では、GPUメモリは合計8GB(8192MiB)で、現在約5.3GBを使用中であることがわかります。

ステップ2: モデルファイルの修正(Modelfileの作成)

Ollamaでは、Modelfileという設定ファイルを使用して、モデルのカスタマイズを行います。既存のモデルをベースに、GPUレイヤー数を指定した新しいモデルを作成します。

# 例:llama2:13bモデルをベースに、GPUレイヤー数を20に設定するModelfile
FROM llama2:13b

# GPUにロードするレイヤー数を指定(この数値は調整が必要)
PARAMETER num_gpu 20

# オプション:コンテキストウィンドウサイズを小さくしてメモリ使用量を削減することも可能
# PARAMETER num_ctx 2048

num_gpuパラメータが、GPUにオフロードするレイヤー数を直接制御します。モデルの総レイヤー数はモデルアーキテクチャによって異なります(例:LLaMA2 13Bは約40層)。

ステップ3: カスタムモデルの作成と実行

作成したModelfileを使って、新しいモデルをビルドします。

# Modelfileからカスタムモデルを作成
ollama create my-llama2-13b -f ./Modelfile

# 作成したカスタムモデルを実行
ollama run my-llama2-13b

実行後、ログを確認して、指定したレイヤー数が正しくGPUにオフロードされているか確認します。

# 別のターミナルでログを監視
ollama logs

# 正常に設定されていれば、以下のようなログが出力される
# llama_model_load_internal: offloaded 20/43 layers to GPU
# llama_model_load_internal: total VRAM used: 4200 MB

ステップ4: 最適なレイヤー数の見つけ方(試行錯誤)

最適なnum_gpuの値は、モデルサイズ、GPUのVRAM容量、他のアプリケーションの使用状況によって異なります。以下の手順で見つけます。

1. まず控えめな値(例:総レイヤー数の50%)から始めます。
2. モデルを実行し、エラーが発生しないか、パフォーマンスが許容範囲内か確認します。
3. エラー(メモリ不足)が発生する場合は値を減らし、VRAMに余裕がありそうなら値を増やして再試行します。
4. nvidia-smiでVRAM使用量を監視し、安全マージン(少なくとも500MB-1GB)を残すように調整します。

コード例・コマンド例

例1: 8GB VRAM GPUでのllama2:13b最適化

総レイヤー数約40層のモデルに対して、安全に動作する設定例です。

# Modelfile (llama2-13b-8gb-gpu.txt)
FROM llama2:13b
PARAMETER num_gpu 28
PARAMETER num_ctx 2048  # デフォルトの4096から削減してメモリ節約

# モデル作成
ollama create llama2-13b-optimized -f ./llama2-13b-8gb-gpu.txt

例2: メモリ不足エラー発生時のトラブルシューティングスクリプト

以下のシェルスクリプトで、段階的にレイヤー数を減らしてテストできます。

#!/bin/bash
MODEL_BASE="llama2:13b"
CUSTOM_NAME="test-gpu-layers"

for layers in 35 30 25 20 15; do
  echo "Testing with num_gpu=${layers}..."
  
  # Modelfileを動的に生成
  cat > /tmp/test_modelfile.txt </dev/null || true
  
  # モデル作成
  if ollama create ${CUSTOM_NAME} -f /tmp/test_modelfile.txt; then
    echo "  → Creation successful. Testing run..."
    # 簡単な推論テスト(タイムアウト付き)
    timeout 30s ollama run ${CUSTOM_NAME} "Hello" > /tmp/test_output.txt 2>&1
    if [ $? -eq 0 ]; then
      echo "  → Run successful with ${layers} layers!"
      echo "Optimal layer count found: ${layers}"
      break
    else
      echo "  → Run failed with ${layers} layers."
    fi
  else
    echo "  → Creation failed with ${layers} layers."
  fi
  echo ""
done

例3: 既存モデルの設定確認と更新

# モデルの詳細情報を表示(設定確認)
ollama show llama2:13b --modelfile

# 既存のカスタムモデルを削除して再作成
ollama rm my-llama2-13b
ollama create my-llama2-13b -f ./新しいModelfile.txt

# システム全体のOllama設定(OLLAMA_NUM_GPUなど)は環境変数でも設定可能
export OLLAMA_NUM_GPU=30
ollama run llama2:13b

まとめ・補足情報

Ollamaで特定モデルのGPUレイヤー数を最適化することは、限られたハードウェアリソースでより大きなモデルを実行したり、推論速度を最大化したりするための重要な手法です。

重要なポイント

1. モデルごとの特性理解: 異なるモデルファミリー(LLaMA, Mistral, Gemmaなど)はアーキテクチャが異なり、レイヤー数やメモリ使用パターンも変わります。公式ドキュメントやモデルカードで情報を確認しましょう。

2. 環境変数によるグローバル設定: システム全体でデフォルトのGPUレイヤー数を設定したい場合は、環境変数OLLAMA_NUM_GPUを使用できます。ただし、モデルごとのModelfile設定が優先されます。

# Linux/macOS
export OLLAMA_NUM_GPU=40

# Windows (PowerShell)
$env:OLLAMA_NUM_GPU=40

3. 他のメモリ最適化手法との組み合わせ:

  • num_ctx(コンテキスト長)を短くする
  • 量子化版モデル(例: llama2:7b-text-q4_K_M)を使用する
  • バッチサイズを調整する(OLLAMA_NUM_PARALLEL

4. モニタリングの継続: 最適な設定を見つけた後も、nvidia-smiollama logsを定期的に確認し、システムの更新やワークロードの変化に応じて設定を見直すことが重要です。

GPUレイヤー数の最適化は、ハードウェアの制約とモデルの性能の間で適切なバランスを見つける作業です。このガイドを参考に、ご自身の環境に最適な設定を見つけ、Ollamaをより効率的に活用してください。

この記事は役に立ちましたか?