T-CREATOR

gpt-oss を最短デプロイ:CPU/単一 GPU/マルチ GPU 別インフラ設計テンプレ

gpt-oss を最短デプロイ:CPU/単一 GPU/マルチ GPU 別インフラ設計テンプレ

近年、大規模言語モデル(LLM)の活用が急速に広がる中、オープンソースの GPT-OSS プロジェクトは、自社環境でカスタマイズ可能な AI システムを構築したい開発者にとって魅力的な選択肢となっています。しかし、GPT-OSS のデプロイには複数の環境選択肢があり、それぞれ異なるパフォーマンス特性とコスト構造を持っているため、最適なインフラ設計を選択することが成功の鍵となります。

本記事では、CPU 環境、単一 GPU 環境、マルチ GPU 環境という 3 つの主要なデプロイパターンについて、最短でプロダクション環境を構築するためのテンプレートと実装手順を詳しく解説します。各環境の特性を理解し、プロジェクトの要件に応じて最適な選択ができるよう、実践的なガイドを提供いたします。

背景

GPT-OSS とは何か

GPT-OSS(Generative Pre-trained Transformer - Open Source Software)は、オープンソースライセンスで提供される大規模言語モデルの実装プロジェクトです。商用の GPT モデルとは異なり、完全にオンプレミス環境で動作させることができ、データのプライバシーやカスタマイズの自由度において大きなメリットを提供します。

GPT-OSS の主な特徴として、以下のような点が挙げられます。

  • 完全なオンプレミス動作: 外部 API に依存せず、自社インフラで完結
  • モデルのカスタマイズ性: 独自データでのファインチューニングが可能
  • 透明性: ソースコードが公開されており、アルゴリズムの詳細を把握可能
  • コスト効率: 長期運用において外部 API 利用料が不要

このような特徴により、金融機関、医療機関、政府機関など、高いセキュリティ要件を持つ組織での導入が進んでおります。

デプロイ環境の選択肢

GPT-OSS のデプロイ環境は、利用可能なハードウェアリソースに応じて大きく 3 つのカテゴリに分類されます。

mermaidflowchart TB
    start[GPT-OSS デプロイ環境選択] --> cpu[CPU環境]
    start --> single[単一GPU環境]
    start --> multi[マルチGPU環境]

    cpu --> cpu_detail[低コスト<br/>中程度レスポンス<br/>スケールアウト可能]
    single --> single_detail[中コスト<br/>高速レスポンス<br/>メモリ制約あり]
    multi --> multi_detail[高コスト<br/>超高速レスポンス<br/>複雑な管理]

図で理解できる要点:

  • 環境選択はコストとパフォーマンスのトレードオフ関係
  • 各環境には固有の制約と利点が存在
  • プロジェクト要件に応じた最適解の選択が重要

CPU 環境

CPU 環境は初期投資を抑えながら GPT-OSS を導入したい場合に適しています。GPU に比べて推論速度は劣りますが、一般的なサーバーで動作するため導入のハードルが低く、水平スケールによる性能向上も期待できます。

単一 GPU 環境

単一 GPU を搭載した環境は、コストと性能のバランスが良く、多くの企業で採用されているパターンです。NVIDIA RTX 4090 や A100 といった高性能 GPU を使用することで、CPU 環境の 10〜100 倍の推論速度を実現できます。

マルチ GPU 環境

複数の GPU を並列動作させるマルチ GPU 環境は、最高レベルの性能を求める場合に選択されます。大規模なモデルを扱う場合や、同時に多数のリクエストを処理する必要がある場合に威力を発揮しますが、インフラの複雑性とコストが大幅に増加します。

インフラ設計の重要性

GPT-OSS の成功は、適切なインフラ設計にかかっています。なぜなら、言語モデルは大量のメモリと計算リソースを必要とし、わずかな設定ミスがパフォーマンスの大幅な低下や、最悪の場合システムの停止を引き起こす可能性があるからです。

インフラ設計で特に重要な要素は以下の通りです。

要素重要度影響範囲
リソース配分★★★★★推論速度、同時処理数
ネットワーク設計★★★★☆レスポンス時間、可用性
ストレージ設計★★★☆☆モデル読み込み速度
監視・ログ設計★★★★☆運用保守性、トラブル対応
セキュリティ設計★★★★★データ保護、アクセス制御

適切なインフラ設計により、システムの安定性、拡張性、保守性を確保しながら、ビジネス要件を満たす性能を実現することができます。

課題

各環境でのパフォーマンス制約

GPT-OSS の各デプロイ環境には、それぞれ固有のパフォーマンス制約が存在し、これらを理解せずに実装を進めると期待する性能を得られない場合があります。

mermaidgraph LR
    subgraph CPU_Issues[CPU環境の制約]
        cpu_speed[処理速度の限界]
        cpu_memory[メモリ帯域幅]
        cpu_parallel[並列処理効率]
    end

    subgraph GPU_Issues[単一GPU環境の制約]
        gpu_memory[VRAM容量制限]
        gpu_heat[発熱管理]
        gpu_power[電力消費]
    end

    subgraph Multi_Issues[マルチGPU環境の制約]
        multi_sync[GPU間同期]
        multi_network[ネットワーク帯域]
        multi_balance[負荷分散]
    end

図で理解できる要点:

  • 各環境には異なる種類の制約が存在
  • 制約の種類により対策方法が大きく異なる
  • 事前の制約理解が性能最適化の基礎

CPU 環境の制約

CPU 環境では、浮動小数点演算の性能が GPU に比べて大幅に劣るため、大規模なモデルの推論に時間がかかります。特に、Transformer アーキテクチャで多用される行列計算において、この差は顕著に現れます。

例えば、7B パラメータのモデルの場合、CPU 環境では 1 つのクエリに対する応答時間が 30〜60 秒程度かかることがありますが、GPU 環境では 1〜3 秒程度で済むケースが多いです。

また、CPU のメモリ帯域幅の制限により、大きなモデルをメモリに読み込む際のオーバーヘッドも無視できません。

単一 GPU 環境の制約

単一 GPU 環境の最大の制約は、VRAM(ビデオメモリ)の容量制限です。大規模なモデルほど多くの VRAM を必要とし、モデルサイズが VRAM 容量を超える場合、メインメモリとの間でデータのスワップが発生し、性能が大幅に低下します。

一般的な GPU の VRAM 容量と対応可能なモデルサイズの目安は以下の通りです。

GPU モデルVRAM 容量推奨モデルサイズ備考
RTX 409024GB13B 以下コンシューマー最高峰
A10040GB/80GB30B/70B 以下エンタープライズ向け
H10080GB70B 以下最新世代

マルチ GPU 環境の制約

マルチ GPU 環境では、複数の GPU 間でのデータ同期とワークロード分散が主要な課題となります。特に、GPU 間の通信帯域幅がボトルネックとなり、理論的な性能向上を実現できないケースが頻繁に発生します。

また、各 GPU の負荷を均等に分散させることも技術的に困難で、一部の GPU にボトルネックが発生すると、全体のパフォーマンスが低下してしまいます。

リソース配分の最適化問題

GPT-OSS の運用において、限られたハードウェアリソースを最適に配分することは、性能とコストの両面で重要な課題です。

メモリ配分の最適化

言語モデルの動作には、モデルパラメータの格納、推論時の中間データ保持、バッチ処理用のバッファなど、様々な用途でメモリが必要となります。これらの用途間でメモリを適切に配分しないと、メモリ不足によるエラーや、過度なスワップによる性能低下が発生します。

CPU/GPU リソースの競合

多くの環境では、GPT-OSS 以外のアプリケーションも同時に動作しているため、リソースの競合が発生しやすくなります。特に、データベースや Web サーバーなどの I/O 集約的なアプリケーションと GPU 集約的な GPT-OSS が同一サーバー上で動作する場合、適切な優先度設定とリソース分離が必要です。

ネットワーク帯域幅の管理

マルチ GPU 環境や分散環境では、GPU 間通信やノード間通信が頻繁に発生します。ネットワーク帯域幅が不足すると、計算資源が十分にあってもデータ転送がボトルネックとなり、全体のパフォーマンスが低下してしまいます。

デプロイ時間とコストのトレードオフ

GPT-OSS のデプロイにおいて、迅速な導入と長期的なコスト効率のバランスを取ることは、多くの組織が直面する重要な課題です。

初期構築時間 vs 運用効率

迅速なデプロイを重視する場合、既存のクラウドサービスやマネージドサービスを活用することで構築時間を短縮できますが、長期的な運用コストが高くなる傾向があります。

一方、オンプレミス環境で最適化されたインフラを構築する場合、初期の設計・構築に時間がかかりますが、運用コストを大幅に抑制できます。

ハードウェア投資 vs クラウド利用

自社で GPU サーバーを購入する場合、初期投資は大きくなりますが、長期間の利用により 1 時間あたりのコストは削減されます。クラウド GPU インスタンスを利用する場合、初期投資は不要ですが、利用時間に応じたコストが継続的に発生します。

一般的な損益分岐点は、連続稼働の場合 6〜12 ヶ月程度とされており、利用パターンに応じた適切な選択が重要になります。

解決策

CPU 環境向けテンプレート設計

CPU 環境での GPT-OSS デプロイにおいて、限られた計算資源を最大限活用するためのテンプレート設計をご紹介します。

アーキテクチャ設計の基本方針

CPU 環境では、並列処理の最適化とメモリ効率の向上が性能改善の鍵となります。以下の設計原則に基づいてテンプレートを構築します。

mermaidflowchart TD
    request[リクエスト] --> lb[ロードバランサー]
    lb --> worker1[Worker 1<br/>CPU集約処理]
    lb --> worker2[Worker 2<br/>CPU集約処理]
    lb --> worker3[Worker 3<br/>CPU集約処理]

    worker1 --> cache[共有キャッシュ<br/>Redis]
    worker2 --> cache
    worker3 --> cache

    cache --> storage[モデルストレージ<br/>高速SSD]

図で理解できる要点:

  • 水平スケールによる処理能力向上
  • 共有キャッシュによる重複処理の回避
  • 高速ストレージによる I/O ボトルネック解消

コンテナ設計とリソース配分

CPU 環境向けのコンテナ設計では、以下の要素を重点的に最適化します。

CPU アフィニティの設定 各ワーカープロセスを特定の CPU コアに固定することで、コンテキストスイッチのオーバーヘッドを削減し、キャッシュ効率を向上させます。

メモリプールの最適化 推論処理で頻繁に使用される中間データ用のメモリプールを事前に確保し、ガベージコレクションの頻度を抑制します。

I/O 多重化の活用 非同期 I/O を活用して、モデル読み込み中も他の処理を継続できるよう設計します。

単一 GPU 環境向けテンプレート設計

単一 GPU 環境では、限られた VRAM 容量を効率的に活用し、GPU 計算資源を最大限に引き出すテンプレート設計が重要です。

VRAM 最適化戦略

VRAM の制約を克服するため、以下の最適化手法を組み合わせます。

モデル量子化 FP32 から FP16、さらには INT8 への量子化により、メモリ使用量を 50〜75%削減できます。精度の低下は最小限に抑えながら、より大きなモデルの実行を可能にします。

動的バッチサイズ調整 利用可能な VRAM 容量に応じて、バッチサイズを動的に調整する仕組みを実装します。これにより、メモリ不足エラーを回避しながら、スループットを最大化できます。

GPU 監視と負荷制御

mermaidsequenceDiagram
    participant Client as クライアント
    participant Monitor as GPU監視
    participant Scheduler as スケジューラー
    participant GPU as GPU処理

    Client->>Monitor: リクエスト受信
    Monitor->>Monitor: VRAM使用率確認
    Monitor->>Scheduler: 処理可否判定
    Scheduler->>GPU: 推論実行
    GPU->>Monitor: リソース状況更新
    Monitor->>Client: レスポンス返却

図で理解できる要点:

  • リアルタイムリソース監視による安定性確保
  • 動的スケジューリングによる効率最大化
  • 予防的負荷制御によるシステム保護

冷却と電力管理

GPU の安定動作のため、適切な冷却システムと電力管理が不可欠です。

温度監視システム GPU 温度をリアルタイムで監視し、設定閾値を超過した場合に自動的に処理負荷を調整する仕組みを実装します。

電力効率最適化 GPU の動作クロックを需要に応じて調整し、不要な電力消費を抑制しながら必要な性能を確保します。

マルチ GPU 環境向けテンプレート設計

マルチ GPU 環境は最高の性能を実現できる一方、複雑な分散処理の管理が必要となります。安定性と性能を両立するテンプレート設計をご紹介します。

分散処理アーキテクチャ

モデル並列化戦略 大規模モデルを複数の GPU に分割して配置する「モデル並列化」と、複数のリクエストを並行処理する「データ並列化」を組み合わせます。

mermaidgraph TB
    subgraph Model_Parallel[モデル並列化]
        layer1[Layer 1-4<br/>GPU 1] --> layer2[Layer 5-8<br/>GPU 2]
        layer2 --> layer3[Layer 9-12<br/>GPU 3]
        layer3 --> layer4[Layer 13-16<br/>GPU 4]
    end

    subgraph Data_Parallel[データ並列化]
        batch1[Batch 1] --> Model_Parallel
        batch2[Batch 2] --> Model_Parallel
        batch3[Batch 3] --> Model_Parallel
    end

図で理解できる要点:

  • モデル並列化による大規模モデル対応
  • データ並列化による同時処理数向上
  • 階層的分散による効率的リソース活用

GPU 間通信最適化

高速インターコネクトの活用 NVLink や InfiniBand などの高速インターコネクトを活用し、GPU 間のデータ転送を最適化します。

通信パターンの最適化 All-Reduce や Ring All-Reduce などの効率的な通信パターンを選択し、ネットワーク帯域幅の使用効率を向上させます。

障害対応とフェイルオーバー

マルチ GPU 環境では、一部の GPU に障害が発生した場合でも、システム全体の可用性を維持する仕組みが重要です。

動的リソース再配分 GPU 障害を検出した際、残りの GPU に処理を再分散し、性能は低下するものの継続的なサービス提供を実現します。

チェックポイント機能 長時間の推論処理中に障害が発生した場合、途中状態から処理を再開できるチェックポイント機能を実装します。

具体例

Docker Compose による CPU デプロイ

CPU 環境での GPT-OSS デプロイを、Docker Compose を使用して実装する具体例をご紹介します。

基本的な Docker Compose 設定

まず、プロジェクトの基本構造を構築します。以下のディレクトリ構成を作成してください。

cssgpt-oss-cpu/
├── docker-compose.yml
├── app/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── main.py
├── nginx/
│   └── nginx.conf
└── redis/
    └── redis.conf

Docker Compose ファイルの作成

システム全体の構成を定義する Docker Compose ファイルを作成します。

yamlversion: '3.8'

services:
  # GPT-OSS アプリケーションサービス
  gpt-app:
    build:
      context: ./app
      dockerfile: Dockerfile
    ports:
      - '8000:8000'
    environment:
      - WORKERS=4
      - MODEL_PATH=/models
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./models:/models:ro
      - ./logs:/app/logs
    depends_on:
      - redis
    deploy:
      resources:
        limits:
          cpus: '8.0'
          memory: 16G
        reservations:
          cpus: '4.0'
          memory: 8G
    restart: unless-stopped

  # Redis キャッシュサービス
  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'
    volumes:
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
      - redis-data:/data
    command: redis-server /usr/local/etc/redis/redis.conf
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 2G
    restart: unless-stopped

  # Nginx ロードバランサー
  nginx:
    image: nginx:alpine
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - gpt-app
    restart: unless-stopped

volumes:
  redis-data:
    driver: local

この設定では、CPU リソースを効率的に分散し、Redis による結果キャッシュと Nginx による負荷分散を実現しています。

アプリケーションコンテナの構築

GPT-OSS を動作させる Python アプリケーションの Dockerfile を作成します。

dockerfileFROM python:3.11-slim

# システムパッケージの更新とビルドツールのインストール
RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    software-properties-common \
    && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリの設定
WORKDIR /app

# Python依存関係のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションコードのコピー
COPY . .

# 非rootユーザーの作成
RUN useradd --create-home --shell /bin/bash app
RUN chown -R app:app /app
USER app

# ヘルスチェックの設定
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# アプリケーションの起動
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

Python アプリケーションの実装

GPT-OSS の API サーバーを実装するメインアプリケーションを作成します。

pythonfrom fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import asyncio
import redis
import json
import hashlib
import logging
from typing import Optional
import multiprocessing as mp

# ログ設定
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = FastAPI(title="GPT-OSS CPU Deployment", version="1.0.0")

# Redis接続設定
redis_client = redis.Redis.from_url("redis://redis:6379", decode_responses=True)

class QueryRequest(BaseModel):
    prompt: str
    max_tokens: Optional[int] = 512
    temperature: Optional[float] = 0.7

class QueryResponse(BaseModel):
    response: str
    processing_time: float
    cached: bool

CPU 最適化処理の実装

CPU 環境での推論処理を最適化した実装を追加します。

pythonimport torch
import torch.nn.functional as F
from transformers import AutoTokenizer, AutoModelForCausalLM
import time
from concurrent.futures import ThreadPoolExecutor
import psutil

class CPUOptimizedInference:
    def __init__(self, model_path: str):
        self.model_path = model_path
        self.tokenizer = None
        self.model = None
        self.load_model()

        # CPU最適化設定
        torch.set_num_threads(mp.cpu_count())
        torch.set_num_interop_threads(mp.cpu_count())

    def load_model(self):
        """モデルとトークナイザーの読み込み"""
        logger.info(f"Loading model from {self.model_path}")

        # トークナイザーの読み込み
        self.tokenizer = AutoTokenizer.from_pretrained(self.model_path)

        # モデルの読み込み(CPU最適化)
        self.model = AutoModelForCausalLM.from_pretrained(
            self.model_path,
            torch_dtype=torch.float32,  # CPUではfloat32が最適
            device_map="cpu",
            low_cpu_mem_usage=True,
            trust_remote_code=True
        )

        # 推論モードに設定
        self.model.eval()
        logger.info("Model loaded successfully")

    async def generate_response(self, prompt: str, max_tokens: int = 512, temperature: float = 0.7) -> str:
        """テキスト生成処理"""
        start_time = time.time()

        # 入力のトークン化
        inputs = self.tokenizer.encode(prompt, return_tensors="pt")

        # CPUでの推論実行
        with torch.no_grad():
            outputs = self.model.generate(
                inputs,
                max_new_tokens=max_tokens,
                temperature=temperature,
                do_sample=True,
                pad_token_id=self.tokenizer.eos_token_id,
                num_beams=1,  # CPUでは計算効率を重視
                early_stopping=True
            )

        # 出力のデコード
        response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
        response = response[len(prompt):].strip()

        processing_time = time.time() - start_time
        logger.info(f"Response generated in {processing_time:.2f} seconds")

        return response, processing_time

# グローバルインスタンス
inference_engine = CPUOptimizedInference("/models/gpt-oss-model")

キャッシュと API 実装

レスポンス時間向上のためのキャッシュ機能と API エンドポイントを実装します。

python@app.post("/generate", response_model=QueryResponse)
async def generate_text(request: QueryRequest):
    """テキスト生成API"""
    try:
        # リクエストのハッシュ化(キャッシュキー生成)
        cache_key = hashlib.md5(
            f"{request.prompt}_{request.max_tokens}_{request.temperature}".encode()
        ).hexdigest()

        # キャッシュ確認
        cached_result = redis_client.get(cache_key)
        if cached_result:
            logger.info("Returning cached response")
            cached_data = json.loads(cached_result)
            return QueryResponse(
                response=cached_data["response"],
                processing_time=cached_data["processing_time"],
                cached=True
            )

        # 新規推論実行
        response, processing_time = await inference_engine.generate_response(
            request.prompt,
            request.max_tokens,
            request.temperature
        )

        # 結果をキャッシュに保存(24時間)
        cache_data = {
            "response": response,
            "processing_time": processing_time
        }
        redis_client.setex(cache_key, 86400, json.dumps(cache_data))

        return QueryResponse(
            response=response,
            processing_time=processing_time,
            cached=False
        )

    except Exception as e:
        logger.error(f"Error in text generation: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
async def health_check():
    """ヘルスチェックエンドポイント"""
    return {
        "status": "healthy",
        "cpu_usage": psutil.cpu_percent(),
        "memory_usage": psutil.virtual_memory().percent,
        "redis_connected": redis_client.ping()
    }

@app.get("/metrics")
async def get_metrics():
    """システムメトリクス取得"""
    return {
        "cpu_count": mp.cpu_count(),
        "cpu_usage": psutil.cpu_percent(interval=1),
        "memory_total": psutil.virtual_memory().total,
        "memory_available": psutil.virtual_memory().available,
        "disk_usage": psutil.disk_usage('/').percent
    }

システム起動と動作確認

すべての設定ファイルを作成した後、以下のコマンドでシステムを起動します。

bash# Docker Composeでサービス起動
docker-compose up -d

# ログ確認
docker-compose logs -f gpt-app

# ヘルスチェック実行
curl http://localhost/health

# テスト推論実行
curl -X POST http://localhost/generate \
  -H "Content-Type: application/json" \
  -d '{"prompt": "人工知能の未来について教えてください", "max_tokens": 200}'

この CPU 環境のデプロイでは、多重プロセシング、結果キャッシュ、負荷分散により、限られた CPU リソースを最大限活用しています。

Kubernetes + GPU Operator による単一 GPU デプロイ

単一 GPU 環境での GPT-OSS デプロイを、Kubernetes と NVIDIA GPU Operator を使用して実装する方法をご紹介します。

Kubernetes クラスター環境の準備

まず、GPU 対応の Kubernetes クラスターを構築します。

yaml# gpu-node-setup.yaml
apiVersion: v1
kind: Node
metadata:
  name: gpu-worker-01
  labels:
    kubernetes.io/arch: amd64
    kubernetes.io/os: linux
    nvidia.com/gpu.present: 'true'
    node-type: gpu-worker
spec:
  capacity:
    nvidia.com/gpu: '1'
    cpu: '16'
    memory: '64Gi'

NVIDIA GPU Operator のインストール

GPU リソースの管理とスケジューリングを自動化する GPU Operator をインストールします。

yaml# gpu-operator-values.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: gpu-operator-config
  namespace: gpu-operator
data:
  values.yaml: |
    operator:
      defaultRuntime: containerd

    driver:
      enabled: true
      version: "535.129.03"

    toolkit:
      enabled: true

    devicePlugin:
      enabled: true
      
    dcgmExporter:
      enabled: true
      
    gfd:
      enabled: true
      
    migManager:
      enabled: false
      
    nodeStatusExporter:
      enabled: true
      
    gds:
      enabled: false
      
    vgpuManager:
      enabled: false
      
    vgpuDeviceManager:
      enabled: false
      
    sandboxWorkloads:
      enabled: false
      
    cdi:
      enabled: false

GPT-OSS アプリケーションの Deployment

GPU を活用する GPT-OSS アプリケーションの Kubernetes マニフェストを作成します。

yaml# gpt-oss-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gpt-oss-gpu
  namespace: gpt-oss
  labels:
    app: gpt-oss
    tier: inference
spec:
  replicas: 1 # 単一GPU環境では1つのPodのみ
  selector:
    matchLabels:
      app: gpt-oss
      tier: inference
  template:
    metadata:
      labels:
        app: gpt-oss
        tier: inference
    spec:
      nodeSelector:
        nvidia.com/gpu.present: 'true'
      containers:
        - name: gpt-oss
          image: gpt-oss:gpu-latest
          ports:
            - containerPort: 8000
              name: http
            - containerPort: 8080
              name: metrics
          env:
            - name: CUDA_VISIBLE_DEVICES
              value: '0'
            - name: NVIDIA_VISIBLE_DEVICES
              value: 'all'
            - name: NVIDIA_DRIVER_CAPABILITIES
              value: 'compute,utility'
            - name: MODEL_PATH
              value: '/app/models'
            - name: GPU_MEMORY_FRACTION
              value: '0.9'
          resources:
            requests:
              nvidia.com/gpu: 1
              cpu: '4'
              memory: '16Gi'
            limits:
              nvidia.com/gpu: 1
              cpu: '8'
              memory: '32Gi'
          volumeMounts:
            - name: model-storage
              mountPath: /app/models
              readOnly: true
            - name: cache-volume
              mountPath: /app/cache
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 60
            periodSeconds: 30
            timeoutSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 8000
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
      volumes:
        - name: model-storage
          persistentVolumeClaim:
            claimName: gpt-oss-model-pvc
        - name: cache-volume
          emptyDir:
            sizeLimit: 8Gi
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule

GPU 最適化されたアプリケーション実装

CUDA を活用した GPU 最適化の推論エンジンを実装します。

python# gpu_inference.py
import torch
import torch.cuda
from transformers import (
    AutoTokenizer,
    AutoModelForCausalLM,
    BitsAndBytesConfig
)
import logging
import time
import gc
from typing import Optional, Tuple
import psutil
import pynvml

logger = logging.getLogger(__name__)

class GPUOptimizedInference:
    def __init__(self, model_path: str, gpu_memory_fraction: float = 0.9):
        self.model_path = model_path
        self.gpu_memory_fraction = gpu_memory_fraction
        self.device = "cuda:0" if torch.cuda.is_available() else "cpu"

        # NVIDIA-ML初期化
        pynvml.nvmlInit()
        self.gpu_handle = pynvml.nvmlDeviceGetHandleByIndex(0)

        # GPU メモリ設定
        if torch.cuda.is_available():
            torch.cuda.set_per_process_memory_fraction(gpu_memory_fraction)
            torch.cuda.empty_cache()

        self.tokenizer = None
        self.model = None
        self.load_model()

    def get_gpu_memory_info(self) -> dict:
        """GPU メモリ使用状況を取得"""
        if torch.cuda.is_available():
            memory_info = pynvml.nvmlDeviceGetMemoryInfo(self.gpu_handle)
            return {
                "total": memory_info.total,
                "used": memory_info.used,
                "free": memory_info.free,
                "usage_percent": (memory_info.used / memory_info.total) * 100
            }
        return {}

    def load_model(self):
        """GPU最適化されたモデル読み込み"""
        logger.info(f"Loading model on {self.device}")

        # 量子化設定(VRAM節約)
        quantization_config = BitsAndBytesConfig(
            load_in_4bit=True,
            bnb_4bit_compute_dtype=torch.float16,
            bnb_4bit_use_double_quant=True,
            bnb_4bit_quant_type="nf4"
        )

        # トークナイザー読み込み
        self.tokenizer = AutoTokenizer.from_pretrained(
            self.model_path,
            trust_remote_code=True,
            padding_side="left"
        )

        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token

        # モデル読み込み(GPU最適化)
        self.model = AutoModelForCausalLM.from_pretrained(
            self.model_path,
            quantization_config=quantization_config,
            device_map="auto",
            torch_dtype=torch.float16,
            trust_remote_code=True,
            attn_implementation="flash_attention_2"  # メモリ効率向上
        )

        # 推論モード設定
        self.model.eval()

        # メモリ使用状況ログ
        gpu_memory = self.get_gpu_memory_info()
        logger.info(f"Model loaded. GPU memory usage: {gpu_memory.get('usage_percent', 0):.1f}%")

    async def generate_response(
        self,
        prompt: str,
        max_tokens: int = 512,
        temperature: float = 0.7,
        batch_size: int = 1
    ) -> Tuple[str, float, dict]:
        """GPU最適化推論実行"""
        start_time = time.time()

        try:
            # GPU メモリ監視
            initial_memory = self.get_gpu_memory_info()

            # 入力準備
            inputs = self.tokenizer(
                prompt,
                return_tensors="pt",
                padding=True,
                truncation=True,
                max_length=2048
            ).to(self.device)

            # 推論実行
            with torch.no_grad():
                with torch.cuda.amp.autocast():  # 混合精度で高速化
                    outputs = self.model.generate(
                        **inputs,
                        max_new_tokens=max_tokens,
                        temperature=temperature,
                        do_sample=True,
                        top_p=0.9,
                        top_k=50,
                        pad_token_id=self.tokenizer.eos_token_id,
                        use_cache=True,  # KVキャッシュ使用
                        repetition_penalty=1.1
                    )

            # 出力デコード
            response = self.tokenizer.decode(
                outputs[0][inputs['input_ids'].shape[-1]:],
                skip_special_tokens=True
            ).strip()

            # メモリクリーンアップ
            del inputs, outputs
            torch.cuda.empty_cache()
            gc.collect()

            processing_time = time.time() - start_time
            final_memory = self.get_gpu_memory_info()

            metrics = {
                "processing_time": processing_time,
                "initial_memory_usage": initial_memory.get('usage_percent', 0),
                "final_memory_usage": final_memory.get('usage_percent', 0),
                "gpu_utilization": self.get_gpu_utilization()
            }

            logger.info(f"Generated response in {processing_time:.2f}s")

            return response, processing_time, metrics

        except Exception as e:
            logger.error(f"GPU inference error: {str(e)}")
            torch.cuda.empty_cache()
            raise

    def get_gpu_utilization(self) -> float:
        """GPU使用率取得"""
        try:
            util = pynvml.nvmlDeviceGetUtilizationRates(self.gpu_handle)
            return util.gpu
        except:
            return 0.0

サービスと Ingress 設定

外部からのアクセスを管理する Service と Ingress を設定します。

yaml# gpt-oss-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: gpt-oss-gpu-service
  namespace: gpt-oss
  labels:
    app: gpt-oss
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 8000
      protocol: TCP
      name: http
    - port: 8080
      targetPort: 8080
      protocol: TCP
      name: metrics
  selector:
    app: gpt-oss
    tier: inference

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gpt-oss-ingress
  namespace: gpt-oss
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
    nginx.ingress.kubernetes.io/proxy-read-timeout: '300'
    nginx.ingress.kubernetes.io/proxy-send-timeout: '300'
spec:
  tls:
    - hosts:
        - gpt-oss.example.com
      secretName: gpt-oss-tls
  rules:
    - host: gpt-oss.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gpt-oss-gpu-service
                port:
                  number: 80

監視とオートスケーリング設定

GPU 使用率に基づく監視とアラート設定を実装します。

yaml# gpu-monitoring.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: gpu-monitoring-config
  namespace: monitoring
data:
  gpu-rules.yaml: |
    groups:
    - name: gpu.rules
      rules:
      - alert: GPUMemoryHigh
        expr: DCGM_FI_DEV_MEM_COPY_UTIL > 90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "GPU memory usage is high"
          description: "GPU memory usage is {{ $value }}% for more than 5 minutes"
      
      - alert: GPUTemperatureHigh
        expr: DCGM_FI_DEV_GPU_TEMP > 85
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "GPU temperature is high"
          description: "GPU temperature is {{ $value }}°C"

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: gpt-oss-hpa
  namespace: gpt-oss
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: gpt-oss-gpu
  minReplicas: 1
  maxReplicas: 1 # 単一GPU環境では1つのPodのみ
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

この単一 GPU 環境のデプロイでは、VRAM 最適化、混合精度計算、メモリ監視により、限られた GPU リソースを最大限活用できる設計となっています。

分散処理によるマルチ GPU デプロイ

マルチ GPU 環境での分散処理を活用した GPT-OSS デプロイ方法をご紹介します。

分散アーキテクチャ設計

マルチ GPU 環境では、複数の処理戦略を組み合わせた分散アーキテクチャを構築します。

mermaidgraph TB
    subgraph LoadBalancer[ロードバランサー層]
        nginx[Nginx Ingress]
    end

    subgraph APIGateway[API Gateway層]
        gateway[API Gateway<br/>リクエスト振り分け]
    end

    subgraph ModelServing[モデルサービング層]
        subgraph Node1[ノード1]
            gpu1[GPU 1<br/>Layer 1-8]
            gpu2[GPU 2<br/>Layer 9-16]
        end
        subgraph Node2[ノード2]
            gpu3[GPU 3<br/>Layer 17-24]
            gpu4[GPU 4<br/>Layer 25-32]
        end
    end

    subgraph Storage[ストレージ層]
        modelstore[分散モデルストレージ]
        cache[分散キャッシュ]
    end

    nginx --> gateway
    gateway --> Node1
    gateway --> Node2
    Node1 --> modelstore
    Node2 --> modelstore
    Node1 --> cache
    Node2 --> cache

図で理解できる要点:

  • 階層化された分散アーキテクチャによる高可用性
  • モデル並列化とデータ並列化の組み合わせ
  • 分散ストレージによるスケーラビリティ確保

Docker Swarm を使用した分散環境構築

複数ノードにまたがるマルチ GPU 環境を Docker Swarm で構築します。

yaml# docker-compose.distributed.yml
version: '3.8'

services:
  # API Gateway
  api-gateway:
    image: gpt-oss-gateway:latest
    ports:
      - '80:80'
      - '443:443'
    environment:
      - BACKEND_NODES=node1:8000,node2:8000,node3:8000,node4:8000
      - LOAD_BALANCE_STRATEGY=round_robin
    deploy:
      replicas: 2
      placement:
        constraints:
          - node.role == manager
      restart_policy:
        condition: on-failure
    networks:
      - gpt-network

  # GPU ワーカーノード 1
  gpu-worker-1:
    image: gpt-oss-worker:latest
    environment:
      - NODE_ID=1
      - CUDA_VISIBLE_DEVICES=0,1
      - MODEL_PARALLEL_SIZE=4
      - DATA_PARALLEL_SIZE=1
      - MASTER_ADDR=gpu-worker-1
      - MASTER_PORT=29500
      - WORLD_SIZE=4
      - RANK=0
    volumes:
      - /mnt/shared/models:/app/models:ro
      - gpu1-cache:/app/cache
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.gpu.count == 2
          - node.labels.node.id == 1
      resources:
        reservations:
          generic_resources:
            - discrete_resource_spec:
                kind: 'NVIDIA-GPU'
                value: 2
    networks:
      - gpt-network

  # GPU ワーカーノード 2
  gpu-worker-2:
    image: gpt-oss-worker:latest
    environment:
      - NODE_ID=2
      - CUDA_VISIBLE_DEVICES=0,1
      - MODEL_PARALLEL_SIZE=4
      - DATA_PARALLEL_SIZE=1
      - MASTER_ADDR=gpu-worker-1
      - MASTER_PORT=29500
      - WORLD_SIZE=4
      - RANK=2
    volumes:
      - /mnt/shared/models:/app/models:ro
      - gpu2-cache:/app/cache
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.gpu.count == 2
          - node.labels.node.id == 2
      resources:
        reservations:
          generic_resources:
            - discrete_resource_spec:
                kind: 'NVIDIA-GPU'
                value: 2
    networks:
      - gpt-network

  # 分散キャッシュ
  redis-cluster:
    image: redis:7-alpine
    command: redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
    volumes:
      - redis-data:/data
    deploy:
      replicas: 6
      placement:
        max_replicas_per_node: 2
    networks:
      - gpt-network

  # 監視システム
  prometheus:
    image: prom/prometheus:latest
    ports:
      - '9090:9090'
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.role == manager
    networks:
      - gpt-network

volumes:
  gpu1-cache:
    driver: local
  gpu2-cache:
    driver: local
  redis-data:
    driver: local
  prometheus-data:
    driver: local

networks:
  gpt-network:
    driver: overlay
    attachable: true

分散推論エンジンの実装

PyTorch の分散処理機能を活用した推論エンジンを実装します。

python# distributed_inference.py
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP
from transformers import AutoTokenizer, AutoModelForCausalLM
import logging
import time
import os
from typing import List, Dict, Any
import asyncio
import numpy as np

logger = logging.getLogger(__name__)

class DistributedGPTInference:
    def __init__(self,
                 model_path: str,
                 world_size: int,
                 rank: int,
                 master_addr: str = "localhost",
                 master_port: str = "29500"):

        self.model_path = model_path
        self.world_size = world_size
        self.rank = rank
        self.master_addr = master_addr
        self.master_port = master_port

        # 分散環境初期化
        self.setup_distributed()

        # デバイス設定
        self.device = f"cuda:{rank % torch.cuda.device_count()}"
        torch.cuda.set_device(self.device)

        self.tokenizer = None
        self.model = None
        self.load_distributed_model()

    def setup_distributed(self):
        """分散処理環境の初期化"""
        os.environ['MASTER_ADDR'] = self.master_addr
        os.environ['MASTER_PORT'] = self.master_port

        # NCCLバックエンドで初期化
        dist.init_process_group(
            backend="nccl",
            rank=self.rank,
            world_size=self.world_size,
            timeout=timedelta(minutes=10)
        )

        logger.info(f"Initialized distributed process group. Rank: {self.rank}/{self.world_size}")

    def load_distributed_model(self):
        """分散モデルの読み込み"""
        logger.info(f"Loading distributed model on rank {self.rank}")

        # トークナイザー読み込み(全ランクで同じ)
        self.tokenizer = AutoTokenizer.from_pretrained(
            self.model_path,
            trust_remote_code=True
        )

        if self.tokenizer.pad_token is None:
            self.tokenizer.pad_token = self.tokenizer.eos_token

        # モデル読み込み(モデル並列化)
        with torch.device(self.device):
            self.model = AutoModelForCausalLM.from_pretrained(
                self.model_path,
                torch_dtype=torch.float16,
                trust_remote_code=True,
                device_map=self.get_device_map()
            )

        # DDP でラップ
        self.model = DDP(
            self.model,
            device_ids=[self.device],
            output_device=self.device,
            find_unused_parameters=False
        )

        self.model.eval()

        # 分散同期
        dist.barrier()
        logger.info(f"Model loaded and synchronized on rank {self.rank}")

    def get_device_map(self) -> Dict[str, int]:
        """モデル並列化のデバイスマップを生成"""
        # 簡単なレイヤー分散戦略
        device_map = {}

        # トランスフォーマーレイヤーを分散
        layers_per_gpu = 32 // self.world_size
        start_layer = self.rank * layers_per_gpu
        end_layer = min((self.rank + 1) * layers_per_gpu, 32)

        for i in range(start_layer, end_layer):
            device_map[f"transformer.h.{i}"] = self.device

        # 最初のランクに埋め込み層、最後のランクに出力層を配置
        if self.rank == 0:
            device_map["transformer.wte"] = self.device
            device_map["transformer.wpe"] = self.device

        if self.rank == self.world_size - 1:
            device_map["transformer.ln_f"] = self.device
            device_map["lm_head"] = self.device

        return device_map

分散処理の協調制御実装

複数 GPU での協調処理を管理するコーディネーターを実装します。

pythonclass DistributedCoordinator:
    def __init__(self, inference_engines: List[DistributedGPTInference]):
        self.engines = inference_engines
        self.request_queue = asyncio.Queue()
        self.response_cache = {}

    async def distributed_generate(
        self,
        prompt: str,
        max_tokens: int = 512,
        temperature: float = 0.7
    ) -> Dict[str, Any]:
        """分散推論の実行"""
        start_time = time.time()

        try:
            # リクエストID生成
            request_id = f"req_{int(time.time() * 1000)}_{np.random.randint(10000)}"

            # 各エンジンでの並列処理
            tasks = []
            for engine in self.engines:
                task = asyncio.create_task(
                    self._engine_generate(engine, prompt, max_tokens, temperature, request_id)
                )
                tasks.append(task)

            # 最初に完了した結果を使用
            done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)

            # 完了したタスクから結果取得
            result = None
            for task in done:
                try:
                    result = await task
                    break
                except Exception as e:
                    logger.error(f"Task failed: {e}")
                    continue

            # 残りのタスクをキャンセル
            for task in pending:
                task.cancel()

            if result is None:
                raise Exception("All inference engines failed")

            processing_time = time.time() - start_time

            return {
                "response": result["response"],
                "processing_time": processing_time,
                "engine_metrics": result["metrics"],
                "request_id": request_id
            }

        except Exception as e:
            logger.error(f"Distributed generation failed: {e}")
            raise

    async def _engine_generate(
        self,
        engine: DistributedGPTInference,
        prompt: str,
        max_tokens: int,
        temperature: float,
        request_id: str
    ) -> Dict[str, Any]:
        """個別エンジンでの推論実行"""
        try:
            # トークン化(分散同期)
            inputs = engine.tokenizer(
                prompt,
                return_tensors="pt",
                padding=True,
                truncation=True,
                max_length=2048
            ).to(engine.device)

            # 分散推論実行
            with torch.no_grad():
                torch.distributed.barrier()  # 同期点

                outputs = engine.model.module.generate(
                    **inputs,
                    max_new_tokens=max_tokens,
                    temperature=temperature,
                    do_sample=True,
                    top_p=0.9,
                    use_cache=True,
                    pad_token_id=engine.tokenizer.eos_token_id
                )

                torch.distributed.barrier()  # 同期点

            # レスポンス生成
            response = engine.tokenizer.decode(
                outputs[0][inputs['input_ids'].shape[-1]:],
                skip_special_tokens=True
            ).strip()

            return {
                "response": response,
                "metrics": {
                    "rank": engine.rank,
                    "device": str(engine.device),
                    "gpu_memory_used": torch.cuda.memory_allocated(engine.device),
                    "request_id": request_id
                }
            }

        except Exception as e:
            logger.error(f"Engine {engine.rank} generation failed: {e}")
            raise

負荷分散とフェイルオーバー機能

高可用性を実現する負荷分散とフェイルオーバー機能を実装します。

python# load_balancer.py
import asyncio
import aiohttp
import time
import logging
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum

logger = logging.getLogger(__name__)

class NodeStatus(Enum):
    HEALTHY = "healthy"
    UNHEALTHY = "unhealthy"
    MAINTENANCE = "maintenance"

@dataclass
class GPUNode:
    id: str
    host: str
    port: int
    gpu_count: int
    status: NodeStatus = NodeStatus.HEALTHY
    last_health_check: float = 0
    request_count: int = 0
    average_response_time: float = 0

class MultiGPULoadBalancer:
    def __init__(self, nodes: List[GPUNode], health_check_interval: int = 30):
        self.nodes = {node.id: node for node in nodes}
        self.health_check_interval = health_check_interval
        self.session = None
        self._health_check_task = None

    async def start(self):
        """ロードバランサー開始"""
        self.session = aiohttp.ClientSession()
        self._health_check_task = asyncio.create_task(self._health_check_loop())
        logger.info("Load balancer started")

    async def stop(self):
        """ロードバランサー停止"""
        if self._health_check_task:
            self._health_check_task.cancel()
        if self.session:
            await self.session.close()
        logger.info("Load balancer stopped")

    async def route_request(
        self,
        prompt: str,
        max_tokens: int = 512,
        temperature: float = 0.7
    ) -> Dict:
        """リクエストのルーティング"""
        # 利用可能ノード選択
        available_node = self._select_node()
        if not available_node:
            raise Exception("No healthy nodes available")

        # リクエスト実行
        start_time = time.time()
        try:
            response = await self._send_request(
                available_node, prompt, max_tokens, temperature
            )

            # メトリクス更新
            response_time = time.time() - start_time
            self._update_node_metrics(available_node.id, response_time, success=True)

            return response

        except Exception as e:
            # エラー時ノードステータス更新
            self._update_node_metrics(available_node.id, 0, success=False)

            # リトライ(別ノード)
            retry_node = self._select_node(exclude=[available_node.id])
            if retry_node:
                logger.warning(f"Retrying request on node {retry_node.id}")
                response = await self._send_request(
                    retry_node, prompt, max_tokens, temperature
                )
                response_time = time.time() - start_time
                self._update_node_metrics(retry_node.id, response_time, success=True)
                return response

            raise e

    def _select_node(self, exclude: List[str] = None) -> Optional[GPUNode]:
        """最適ノード選択(重み付きラウンドロビン)"""
        exclude = exclude or []
        healthy_nodes = [
            node for node in self.nodes.values()
            if node.status == NodeStatus.HEALTHY and node.id not in exclude
        ]

        if not healthy_nodes:
            return None

        # GPU数と平均レスポンス時間を考慮した重み計算
        weights = []
        for node in healthy_nodes:
            # GPU数が多く、レスポンス時間が短いノードほど高い重み
            weight = node.gpu_count / max(node.average_response_time, 0.1)
            weights.append(weight)

        # 重み付きランダム選択
        total_weight = sum(weights)
        if total_weight == 0:
            return healthy_nodes[0]

        import random
        r = random.uniform(0, total_weight)
        current_weight = 0

        for i, weight in enumerate(weights):
            current_weight += weight
            if r <= current_weight:
                return healthy_nodes[i]

        return healthy_nodes[-1]

    async def _send_request(
        self,
        node: GPUNode,
        prompt: str,
        max_tokens: int,
        temperature: float
    ) -> Dict:
        """ノードへのリクエスト送信"""
        url = f"http://{node.host}:{node.port}/generate"
        payload = {
            "prompt": prompt,
            "max_tokens": max_tokens,
            "temperature": temperature
        }

        timeout = aiohttp.ClientTimeout(total=300)  # 5分タイムアウト

        async with self.session.post(url, json=payload, timeout=timeout) as response:
            if response.status != 200:
                raise Exception(f"HTTP {response.status}: {await response.text()}")

            return await response.json()

    def _update_node_metrics(self, node_id: str, response_time: float, success: bool):
        """ノードメトリクス更新"""
        node = self.nodes[node_id]

        if success:
            node.request_count += 1
            # 移動平均でレスポンス時間更新
            alpha = 0.1
            node.average_response_time = (
                alpha * response_time + (1 - alpha) * node.average_response_time
            )
        else:
            # 失敗時はステータス更新
            node.status = NodeStatus.UNHEALTHY
            logger.warning(f"Node {node_id} marked as unhealthy")

    async def _health_check_loop(self):
        """定期ヘルスチェック"""
        while True:
            try:
                await asyncio.sleep(self.health_check_interval)
                await self._perform_health_checks()
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Health check error: {e}")

    async def _perform_health_checks(self):
        """全ノードのヘルスチェック実行"""
        tasks = []
        for node in self.nodes.values():
            task = asyncio.create_task(self._check_node_health(node))
            tasks.append(task)

        await asyncio.gather(*tasks, return_exceptions=True)

    async def _check_node_health(self, node: GPUNode):
        """個別ノードヘルスチェック"""
        try:
            url = f"http://{node.host}:{node.port}/health"
            timeout = aiohttp.ClientTimeout(total=10)

            async with self.session.get(url, timeout=timeout) as response:
                if response.status == 200:
                    health_data = await response.json()

                    # GPU使用率チェック
                    if health_data.get("gpu_memory_usage", 0) < 95:
                        node.status = NodeStatus.HEALTHY
                        node.last_health_check = time.time()
                    else:
                        node.status = NodeStatus.UNHEALTHY
                        logger.warning(f"Node {node.id} GPU memory usage too high")
                else:
                    node.status = NodeStatus.UNHEALTHY

        except Exception as e:
            node.status = NodeStatus.UNHEALTHY
            logger.error(f"Health check failed for node {node.id}: {e}")

このマルチ GPU 環境のデプロイでは、分散処理、動的負荷分散、自動フェイルオーバーにより、高性能と高可用性を両立したシステムを実現しています。

まとめ

各環境の選択指針

GPT-OSS の最短デプロイを実現するためには、プロジェクトの要件と利用可能なリソースに応じて適切な環境を選択することが重要です。

環境選択のマトリックス

選択基準CPU 環境単一 GPU 環境マルチ GPU 環境
初期投資コスト★★★★★★★★☆☆★☆☆☆☆
運用コスト★★★★☆★★★☆☆★★☆☆☆
推論速度★★☆☆☆★★★★☆★★★★★
同時処理数★★★☆☆★★★☆☆★★★★★
実装の複雑さ★★★★★★★★★☆★★☆☆☆
保守性★★★★★★★★★☆★★★☆☆
スケーラビリティ★★★★☆★★★☆☆★★★★★

具体的な選択指針

CPU 環境を選ぶべき場合

  • 初期費用を抑えて PoC(概念実証)を行いたい場合
  • リアルタイム性よりもコスト効率を重視する場合
  • 既存のサーバーインフラを活用したい場合
  • 開発・テスト環境として使用する場合

単一 GPU 環境を選ぶべき場合

  • コストと性能のバランスを重視する場合
  • 中程度の同時ユーザー数(10〜100 人程度)に対応したい場合
  • 運用の複雑さを抑えながら高速な推論を実現したい場合
  • 本格運用前の検証環境として使用する場合

マルチ GPU 環境を選ぶべき場合

  • 最高レベルの性能が要求される場合
  • 大量の同時ユーザー(100 人以上)に対応する必要がある場合
  • 大規模モデル(70B 以上のパラメータ)を使用する場合
  • 24 時間 365 日の安定稼働が要求される場合

最短デプロイのベストプラクティス

GPT-OSS の迅速で確実なデプロイを実現するために、以下のベストプラクティスを実践することをお勧めします。

段階的デプロイアプローチ

フェーズ 1: 最小構成での動作確認 まず最小限の構成でシステムを構築し、基本的な動作を確認します。これにより、早期に問題を発見し、修正することができます。

フェーズ 2: 性能最適化 基本動作が確認できたら、性能最適化に取り組みます。モデルの量子化、バッチサイズの調整、キャッシュの導入などを段階的に実施します。

フェーズ 3: 運用機能の追加 監視、ログ、アラート、自動スケーリングなどの運用に必要な機能を追加します。

インフラ自動化の活用

Infrastructure as Code (IaC) の採用 Terraform や Ansible などのツールを使用して、インフラの構築・管理を自動化します。これにより、環境の再現性と一貫性を確保できます。

CI/CD パイプラインの構築 コードの変更から本番環境への反映までを自動化し、デプロイ時間を短縮するとともに人的ミスを防ぎます。

監視とアラートの重要性

包括的な監視体制 CPU/GPU 使用率、メモリ使用量、推論時間、エラー率など、システムの健全性を示すメトリクスを包括的に監視します。

プロアクティブなアラート 問題が深刻化する前に検知できるよう、適切な閾値でアラートを設定します。特に、GPU 温度、メモリ使用率、レスポンス時間の監視は重要です。

セキュリティとコンプライアンス

最小権限の原則 各コンポーネントには必要最小限の権限のみを付与し、セキュリティリスクを最小化します。

データ保護 モデルファイルや推論データの暗号化、アクセスログの記録など、適切なデータ保護対策を実施します。

継続的改善

パフォーマンス分析 定期的にシステムのパフォーマンスを分析し、ボトルネックを特定して改善します。

コスト最適化 リソース使用状況を継続的に監視し、過剰なリソースの削減や、より効率的な構成への移行を検討します。

GPT-OSS の成功的なデプロイには、技術的な実装だけでなく、適切な計画、段階的なアプローチ、継続的な改善が不可欠です。本記事で紹介したテンプレートと手法を参考に、プロジェクトの要件に最適な環境を構築し、安定的な運用を実現してください。

関連リンク

公式ドキュメント

最適化・パフォーマンス

監視・運用

セキュリティ・コンプライアンス