mcpField
G
gpu-optimizer

gpu-optimizer

github.com/mathews-tom開発337131 回インストール2 日前に更新
リポジトリ

gpu-optimizer について

GPU Optimizerは、コンシューマー向けNVIDIA GPUを最適化するスキルで、PyTorch、XGBoost、RAPIDSを使う開発者向けです。8~24GB VRAMの単一GPU環境を対象に、コード例、メモリ管理、診断方法を示します。

主な機能

  1. 01XGBoostのGPUトレーニングを最適化
  2. 02PyTorchの混合精度とコンパイルの指針
  3. 03VRAMの管理と使用量の監視
  4. 04NumPyやPandasの処理をGPUへ移行
  5. 05性能分析とトラブルシューティング

活用シーン

  1. 01モデル学習時のVRAM使用量を削減
  2. 02XGBoostの学習と推論を高速化
  3. 03大規模な配列や表データ処理をGPUへ移行
  4. 04GPU学習のボトルネックを特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mathews-tom/armory --skill gpu-optimizer

インストール後、Claude Code で/gpu-optimizerを入力して読み込まれたか確認します。

同梱ファイルevals/cases.yaml

詳細

GPU オプティマイザー

VRAM が 8~24GB のコンシューマー向け GPU に特化した GPU 最適化。エビデンスに基づくパターンのみを紹介します。

ハードウェアプロファイル

最適化を適用する前に、お使いのハードウェア情報を入力してください。

プロパティ値
GPU モデル(例:RTX 4080 Mobile、RTX 3090、RTX 4090)
VRAM(例:12GB、16GB、24GB)
CUDA バージョン(nvidia-smi → 右上)
TDP/電力制限(ノート PC とデスクトップ PC では持続的なスループットに影響します)
ドライバーバージョン(nvidia-smi → 左上)

重要な制約:VRAM 容量によって、適用できる戦略が決まります。該当する場合は、以下のパターンに必要な最小 VRAM を記載しています。

最適化カテゴリー

1. XGBoost GPU アクセラレーション

DMatrix と QuantileDMatrix の比較:

# GPU-optimized: QuantileDMatrix is 1.8x faster
dtrain = xgb.QuantileDMatrix(X_train.astype(np.float32))
dval = xgb.QuantileDMatrix(X_val.astype(np.float32))

# Standard: DMatrix (use for inference only)
dtest = xgb.DMatrix(X_test.astype(np.float32))

重要なパラメーター:

params = {
    'tree_method': 'hist',        # GPU-accelerated histogram
    'device': 'cuda:0',           # Explicit GPU device
    'max_bin': 256,               # Higher bins = better splits (VRAM permitting)
    'grow_policy': 'depthwise',   # vs 'lossguide' for imbalanced data
    'predictor': 'gpu_predictor', # GPU inference
}

# Training with explicit device
model = xgb.train(params, dtrain, num_boost_round=100)

GPU の検証(即時失敗):

def verify_gpu():
    """Verify XGBoost GPU availability. Raises if unavailable."""
    import subprocess
    try:
        result = subprocess.run(["nvidia-smi"], capture_output=True, text=True)
        if result.returncode != 0:
            raise RuntimeError("nvidia-smi failed - no GPU available")
    except FileNotFoundError:
        raise RuntimeError("nvidia-smi not found - no GPU available")

    build_info = xgb.build_info()
    if not build_info.get("USE_CUDA"):
        raise RuntimeError("XGBoost not compiled with CUDA support")

メモリー管理:

# Single-pass training (reuse QuantileDMatrix across slots)
dtrain = xgb.QuantileDMatrix(X_train.astype(np.float32))
for slot_idx in range(num_slots):
    dtrain.set_label(y_train[:, slot_idx])  # Reuse matrix
    model = xgb.train(params, dtrain, num_boost_round=100)
2. PyTorch 混合精度

BF16(推奨)と FP16 の比較:

from torch.amp import autocast, GradScaler

# Auto-detect best precision
if torch.cuda.is_bf16_supported():
    amp_dtype = torch.bfloat16  # Ampere+ GPUs support BF16
else:
    amp_dtype = torch.float16

# Training step
scaler = GradScaler('cuda') if amp_dtype == torch.float16 else None

with autocast('cuda', dtype=amp_dtype):
    output = model(input_ids, attention_mask)
    loss = criterion(output, targets)

# Backward with scaling (FP16 only)
if scaler:
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()
else:
    loss.backward()
    optimizer.step()

BF16 が FP16 より優れている理由:

  • FP32 と同じ指数範囲(オーバーフロー/アンダーフローが発生しません)
  • GradScaler が不要(コードがシンプルになります)
  • Ampere 世代以降の GPU にはネイティブの BF16 Tensor コアが搭載されています
3. VRAM 管理

勾配チェックポイント:

# Saves ~40% VRAM, adds ~20% compute time
model.gradient_checkpointing_enable()

# For transformers:
model.base_model.model.gradient_checkpointing_enable()

VRAM のモニタリング:

import torch

torch.cuda.reset_peak_memory_stats()
# ... training ...
peak_vram_gb = torch.cuda.max_memory_allocated() / 1024**3
print(f"Peak VRAM: {peak_vram_gb:.2f} GB")

# Clear cache between experiments
torch.cuda.empty_cache()

勾配蓄積:

# Simulate larger batch size without OOM
grad_accum_steps = max(1, target_batch_size // actual_batch_size)

for i, batch in enumerate(dataloader):
    loss = model(batch) / grad_accum_steps
    loss.backward()

    if (i + 1) % grad_accum_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

VRAM 最適化の実験計画法(DoE):

EXPERIMENTS = [
    {"batch_size": 2,  "seq_len": 128, "grad_ckpt": True,  "amp": "bf16"},
    {"batch_size": 4,  "seq_len": 256, "grad_ckpt": True,  "amp": "bf16"},
    {"batch_size": 8,  "seq_len": 512, "grad_ckpt": False, "amp": "bf16"},
    {"batch_size": 16, "seq_len": 256, "grad_ckpt": False, "amp": "bf16"},
]
4. 積極的なベクトル化

テンソル検索(Python ループではなく):

# Slow: Python loop
for i, token_id in enumerate(input_ids):
    type_id = token_to_type[token_id]
    embeddings[i] = type_embeddings[type_id]

# Fast: Vectorized
type_ids = token_to_type[input_ids]  # Broadcast lookup
embeddings = type_embeddings[type_ids]  # Single GPU kernel

登録済みバッファー(GPU 上にデータを保持):

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        # Build lookup tensors once
        type_ids = torch.zeros(vocab_size, dtype=torch.long)
        self.register_buffer('_type_ids', type_ids)  # Stays on GPU

    def forward(self, input_ids):
        return self._type_ids[input_ids]  # Vectorized lookup

バッチ処理:

# Slow: Per-sample processing
outputs = [model(x.unsqueeze(0)) for x in batch]

# Fast: Batched
outputs = model(batch)  # Single forward pass
5. CuPy への移行(NumPy → GPU)

CuPy を使う場面:

  • 大きな配列の処理(>1M 要素)
  • タイトなループ内で NumPy を繰り返し呼び出す場合
  • PyTorch/XGBoost の前処理パイプライン

移行パターン:

import cupy as cp
import numpy as np

# NumPy (CPU)
x = np.random.randn(10000, 1000)
y = np.dot(x, x.T)

# CuPy (GPU) - SAME API
x_gpu = cp.random.randn(10000, 1000)
y_gpu = cp.dot(x_gpu, x_gpu.T)

# Transfer back if needed
y_cpu = cp.asnumpy(y_gpu)

PyTorch との相互運用:

# CuPy → PyTorch (zero-copy)
x_cupy = cp.random.randn(1000, 1000)
x_torch = torch.as_tensor(x_cupy, device='cuda')

# PyTorch → CuPy (zero-copy)
x_torch = torch.randn(1000, 1000, device='cuda')
x_cupy = cp.asarray(x_torch)

インストール:

uv pip install cupy-cuda12x  # For CUDA 12.x
6. cuDF への移行(Pandas → GPU)

cuDF を使う場面:

  • 1GB を超える DataFrame
  • 大規模データでの Groupby/集計
  • モデルトレーニング前の ETL パイプライン

移行パターン:

import cudf
import pandas as pd

# Pandas (CPU)
df = pd.read_csv('large.csv')
grouped = df.groupby('category')['value'].mean()

# cuDF (GPU) - SAME API
df_gpu = cudf.read_csv('large.csv')
grouped_gpu = df_gpu.groupby('category')['value'].mean()

# Transfer back
grouped_cpu = grouped_gpu.to_pandas()

XGBoost との統合:

import cudf
import xgboost as xgb

# Load data on GPU
df = cudf.read_csv('train.csv')
X = df[feature_cols]
y = df['target']

# Create DMatrix directly from cuDF (no CPU copy)
dtrain = xgb.DMatrix(X, label=y)

インストール:

# RAPIDS (includes cuDF, cuML, cuGraph)
uv pip install cudf-cu12 --extra-index-url=https://pypi.nvidia.com
7. PyTorch のコンパイルと最適化

融合オプティマイザー:

# Check availability
use_fused = (
    torch.cuda.is_available()
    and "fused" in torch.optim.AdamW.__init__.__code__.co_varnames
)

optimizer = torch.optim.AdamW(
    model.parameters(),
    lr=1e-3,
    fused=use_fused,  # Single GPU kernel (2-3x faster)
)

Torch Compile:

# PyTorch 2.0+ compile
if hasattr(torch, "compile"):
    model = torch.compile(model, mode="reduce-overhead")

cuDNN ベンチマーク:

# Auto-tune kernels (slower startup, faster training)
torch.backends.cudnn.benchmark = True

# Disable for determinism
torch.backends.cudnn.deterministic = True
8. 高度な損失関数

重み付きスロット損失:

class WeightedSlotLoss(nn.Module):
    def __init__(self, slot_weights):
        super().__init__()
        self.slot_weights = torch.tensor(slot_weights)

    def forward(self, logits_list, targets):
        weighted_losses = []
        for i, logits in enumerate(logits_list):
            loss = F.cross_entropy(logits, targets[:, i])
            weighted_losses.append(loss * self.slot_weights[i])
        return torch.stack(weighted_losses).sum() / self.slot_weights.sum()

Focal Loss(難しいサンプルのマイニング):

class FocalLoss(nn.Module):
    def __init__(self, gamma=2.0):
        super().__init__()
        self.gamma = gamma

    def forward(self, logits, targets):
        ce_loss = F.cross_entropy(logits, targets, reduction='none')
        pt = torch.exp(-ce_loss)
        focal_loss = ((1 - pt) ** self.gamma) * ce_loss
        return focal_loss.mean()
9. キャッシュと事前計算

位置埋め込みキャッシュ:

class Model(nn.Module):
    def __init__(self):
        super().__init__()
        self._pos_cache = {}  # {seq_len: positions}

    def forward(self, x):
        T = x.size(1)
        if T not in self._pos_cache:
            self._pos_cache[T] = torch.arange(T, device=x.device)
            # Limit cache size
            if len(self._pos_cache) > 10:
                self._pos_cache.pop(next(iter(self._pos_cache)))
        return self.pos_embed(self._pos_cache[T])

アテンションマスクキャッシュ:

def _create_causal_mask(self, T, device):
    if T not in self._mask_cache:
        mask = torch.triu(torch.ones(T, T), diagonal=1).bool()
        self._mask_cache[T] = mask.to(device)
    return self._mask_cache[T]

クイック診断

GPU 使用率を確認する:

watch -n 1 nvidia-smi  # Monitor in real-time

PyTorch のプロファイリング:

with torch.profiler.profile(
    activities=[torch.profiler.ProfilerActivity.GPU],
    with_stack=True,
) as prof:
    model(batch)

print(prof.key_averages().table(sort_by="cuda_time_total"))

ボトルネックの検出:

import torch.utils.bottleneck as bottleneck
bottleneck.main(['script.py'])

移行チェックリスト

  • XGBoost:QuantileDMatrix を使用し、device='cuda:0' を設定する
  • PyTorch:BF16/FP16、融合オプティマイザー、torch.compile を有効にする
  • VRAM:VRAM の上限に近づいた場合は勾配チェックポイントを使用する
  • NumPy→CuPy:100 万要素を超える前処理に使用する
  • Pandas→cuDF:1GB を超える DataFrame に使用する
  • ベクトル化:Python ループをテンソル演算に置き換える
  • キャッシュ:位置、マスク、埋め込みを事前計算する
  • モニタリング:VRAM 使用量を追跡し、GPU カーネルをプロファイリングする

避けるべきパターン

避けてください:

  • トレーニングループ内で .cpu() を使用する(GPU パイプラインが停止します)
  • CPU 上でテンソルを作成してから GPU に移動する(最初から GPU 上で作成してください)
  • テンソルに対して Python ループを使用する(ベクトル化してください)
  • VRAM のモニタリングを無視する(OOM クラッシュにつながります)
  • BF16/FP16 が使えるのに FP32 を使用する(帯域幅を無駄にします)
  • 不要に torch.cuda.synchronize() を呼び出す(非同期処理が中断されます)

参考資料

ドキュメント:

エラー処理

  • 実行時に CUDA を利用できない場合:まず nvidia-smi を実行して GPU が認識されていることを確認します。コマンドが失敗する場合は、続行する前に sudo nvidia-smi でドライバーのインストール状況を確認するか、ドライバーを再インストールしてください。
  • XGBoost で RuntimeError: XGBoost not compiled with CUDA support が発生する場合:CUDA 対応環境から uv pip install xgboost を実行して CUDA ビルドをインストールするか、-DUSE_CUDA=ON を指定してソースからビルドしてください。
  • トレーニング中に OOM が発生する場合:まずバッチサイズを半分に減らし、次に勾配チェックポイントを有効にしてください。両方を適用しても OOM が解消しない場合は、勾配累積を有効にして元のバッチサイズを再現してください。
  • CuPy のインポートに失敗する場合(ImportError またはバージョン不一致):nvcc --version で CUDA ツールキットのバージョンを確認し、対応する CuPy ホイールをインストールしてください(例:CUDA 12.x には cupy-cuda12x)。
  • cuDF のインストールが失敗する、または CUDA バージョンエラーが発生する場合:NVIDIA の PyPI インデックス(--extra-index-url=https://pypi.nvidia.com)を使用し、cudf-cu12 の接尾辞を CUDA のメジャーバージョンに合わせてください。
  • torch.compile で誤った結果が出る、またはクラッシュする場合:原因を切り分けるため、model = model(コンパイルなし)にして無効化してください。一部のカスタム演算では失敗することが知られているため、そのようなレイヤーではイーガーモードに切り替えてください。

制限事項

  • NVIDIA GPU のみが対象です。AMD(ROCm)および Intel Arc GPU には、これらのパターンは適用されません。
  • シングル GPU 構成を前提としています。マルチ GPU(DDP、FSDP)には追加の設定が必要ですが、ここでは扱いません。
  • これらのパターンはコンシューマー向け GPU(VRAM 8~24GB)を基準に調整されています。データセンター向け GPU(A100、H100)はメモリ階層が異なるため、別の戦略が有効な場合があります。
  • 対象フレームワークは PyTorch、XGBoost、RAPIDS(CuPy/cuDF)のみです。JAX、TensorFlow、MXNet は対象外です。
  • ノート PC の GPU では TDP により持続的なスループットに制限がかかります。同じ VRAM 容量でも、電力制限によるパフォーマンスはデスクトップのベンチマークと大きく異なる場合があります。

出力形式

各最適化の推奨には、元のパターンと GPU 向けに最適化したパターンを示す変更前・変更後のコードペアが含まれます。 パフォーマンス向上の推定値は、一般的なコンシューマー向け GPU のベンチマークに基づき、範囲(例:「1.8 倍高速」「VRAM を約 40%削減」)で示されます。実際の効果はワークロードとハードウェアによって異なります。 変更によってトレードオフが生じる場合(例:勾配チェックポイントによって計算時間が増加する場合)は、その内容を本文中に明記します。

コメント