大規模言語モデル推論基盤の構築と最適化:vLLM と TGI を用いた実戦ガイド

1. はじめに:トレーニングからインフラへ

大規模言語モデル(LLM)の開発ライフサイクルにおいて、最も難易度が高く重要なフェーズの一つが「推論環境の構築」です。ハブ上のオープンソースモデルを取得し、あるいは独自に学習済みのモデルを準備したとしても、そのまま高負荷なリクエストに対応可能な Web サービスとして公開することは容易ではありません。PyTorch の標準的なロード手順だけでは、メモリ管理やバッチ処理の観点から本格的な運用には不十分なケースが多く見られます。

この課題を解決するために、業界標準となった推論フレームワークを組み合わせたパッケージングのアプローチが存在します。これは特定のライブラリ自体を新規開発するのではなく、既存の高性能エンジンを選択的に組み合わせ、コンテナ化や監視ツールを統合することで、プロダクション環境に必要な基盤を最短距離で提供することを目的としています。

2. 技術アーキテクチャと選定基準

2.1 専用フレームワークが必要な理由

単純な HTTP サーバーにモデルを紐付ける従来のアプローチには、いくつかのボトルネックが存在します。

  • メモリ効率: キー・バリューキャッシュ(KV Cache)の断片化により、利用可能なシークエンス長やバッチサイズが制約されます。
  • 処理速度: トークン生成は逐次的であるため、GPU の計算資源を効率的に占有できず、スループットが低下します。
  • スケーラビリティ: 多くの同時接続を捌くための動的なオートスケーリング機能がありません。

これに対し、現代の推論エンジンは以下の技術を採用しています。

  • vLLM: 「PagedAttention」アルゴリズムを採用し、仮想メモリのように KV Cache を分割管理することで、メモリの断片化を防ぎつつ、より大きなバッチ処理を可能にします。
  • TGI (Text Generation Inference): FlashAttention や連続的バッチ処理機能をコアに持ち込み、CUDA コアへの負荷分散を極限まで押し上げています。

2.2 システムコンポーネント

本格的な推論プラットフォームは、単一のプロセスではなく複数のレイヤーで構成されます。

  1. バックエンド推論エンジン: 実際のモデル処理を行う部分。設定ファイルで vLLM または TGI 等の指定を行います。
  2. API 統制層: OpenAI 互換の RESTful エンドポイントを定義し、外部クライアントとのインターフェースを整備します。
  3. オーケストレーション: Docker や Kubernetes を経由してリソース割り当てを行い、自動スケールを実現します。
  4. 可観測性: メトリクス(遅延率、スループット、VRAM 使用量)の収集と可視化ダッシュボードの設置。

3. 環境構築と導入手順

3.1 前提条件の整備

Ubuntu 22.04 LTS をベースとしたシステムを用意し、必要なビルドツールキットを導入します。

sudo apt update
sudo apt install -y build-essential cmake git python3.10-venv
git clone https://github.com/open-source-models/llm-serving-starter.git
cd llm-serving-starter
python3.10 -m venv .venv
source .venv/bin/activate

3.2 モデル設定とパラメータ調整

以下は、設定ファイルをカスタマイズする際の例です。元のプロジェクト名やパスを抽象化し、一般的な変数名に変更しています。

# inference_config.yaml
engine_type: vllm
model_source: mistralai/Mistral-7B-Instruct-v0.3
# ローカルパスを使用する場合:/mnt/data/models/mistral
local_path_override: false

quantization_level: fp16
# グランularity の削減:int8, int4
precision_tuning: none

compute_params:
  context_length_limit: 8192
  tensor_parallel_degree: 1
  gpu_reserved_percentage: 0.95

server_settings:
  bind_address: 0.0.0.0
  port_number: 8080
  api_route_prefix: /api/v1

パラメータ解説:

  • quantization_level: モデル精度を調整します。Int4 などに下げると VRAM 使用量が減りますが、精度の微劣化が発生します。
  • context_length_limit: 入力文脈の最大文字数です。これ以上長くするとエラーとなります。
  • gpu_reserved_percentage: GPU メモリの最大使用割合です。1.0 に設定するとクラッシュリスクが高まるため、余裕を持たせて 0.9〜0.95 が推奨されます。

3.3 サービス起動とテスト

設定完了後、デプロイスクリプトを実行します。

./start_serving.sh --config ./inference_config.yaml

サービスが稼働したら、curl コマンドなどで検証可能です。

curl http://localhost:8080/api/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mistral-7b",
    "prompt": "量子力学の基礎について簡潔に説明してください。",
    "max_tokens": 200
  }'

JSON 形式で応答が返ってきた場合、通信ルートは正常に動作していることになります。

4. プロダクション展開戦略

4.1 コンテナ化による隔離

ミドルウェア依存関係を Docker イメージに閉じ込めることで、環境間の差分を排除します。

FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04

ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
ENTRYPOINT ["python", "main.py"]

NVIDIA GPU 付きのホスト上で実行する際は、`--gpus all` フラグが必要です。

docker run --rm -it --gpus all -p 8080:8080 my-llm-service:v1

4.2 クラスター環境での管理

Kubernetes 環境では、ConfigMap を使って設定を分離し、Deployment リソースで Pod を管理します。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ml-model-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: inference-app
  template:
    metadata:
      labels:
        app: inference-app
    spec:
      containers:
      - name: inference-container
        image: registry.example.com/ml-service:v1
        resources:
          limits:
            nvidia.com/gpu: 1
            memory: "16Gi"
            cpu: "4"
        ports:
        - containerPort: 8080

トラフィックの変動に対応するため、HPA (Horizontal Pod Autoscaler) で CPU 利用率やキュー長に基づいてレプリカ数を自動調整することを検討すべきです。

4.3 性能モニタリング指標

運用中は以下の数値を常時監視し、ボトルネックを特定します。

  • Latency (TTFT): 最初のトークンを生成するまでの時間。UX に直結します。
  • TPOT / TPS: 生成されるトークンあたりの時間、または毎秒生成トークン数。スループット評価の基準になります。
  • GPU Utilization: メモリ帯域幅の有効活用状況を示します。
  • Error Rate: 5xx ステータスの発生頻度。システムの健全性を示唆します。

5. よくある障害と対策

5.1 メモリ不足(OOM)によるクラッシュ

モデルサイズが GPU VRAM を超過した場合、カーネルレベルでプロセスが停止します。nvidia-smi で VRAM 使用率が上限に達していないか確認し、必要に応じて quantization_level を Int4 へ変更するか、gpu_reserved_percentage を下げてください。

5.2 推論反応の遅延

スループットが低い場合、CPU トークナイザーの前処理工程がボトルネックになっている可能性があります。バッチサイズの上限 max_batch_size を下げるか、マルチコア CPU へのアップグレードを検討します。また、非同期処理の設定を確認し、並列リクエストの処理能力を見直してください。

5.3 デプロイメントの不安定性

Kubernetes 上で Pod が再起動を繰り返す場合、ログ出力 kubectl logs <pod-name> で詳細なスタックトレースを確認します。ヒートマップなどの可視化ツールを導入し、リソース消費の異常傾向を検知するためのアラートを事前に設定しておくことが重要です。

5.4 ハードウェアとの相性問題

最新のアーキテクチャを持つモデルや、一部の消費向け GPU ではドライバーバージョンや CUDA ライブラリの互換性が衝突することがあります。フレームワーク公式のマニュアルにある互換性表をチェックし、最新のリリースブランチまたは安定版タグを利用するようにしてください。

タグ: vLLM Text Generation Inference Kubernetes Docker Large Language Models

6月13日 22:31 投稿