Skip to content

✍️ 필사 모드: LLM推論最適化完全ガイド2025:vLLM、TensorRT-LLM、KV Cache、Speculative Decoding

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

目次(もくじ)

1. LLM推論(すいろん)のボトルネック理解:Compute-Bound vs Memory-Bound

LLM推論最適化を議論する前に、まずボトルネックがどこで発生するかを正確に理解する必要があります。

1.1 Arithmetic IntensityとRoofline Model

GPU演算の性能は二つのリソースによって決定されます。

リソース単位A100 80GBH100 80GBH200 141GB
演算能力(FP16)TFLOPS312989989
メモリ帯域幅(たいいきはば)TB/s2.03.354.8
Arithmetic Intensity境界FLOP/byte156295206

Arithmetic Intensity = 総演算量(FLOPs) / 総メモリ転送量(Bytes)

  • Compute-Bound:Arithmetic Intensityが境界値より高い場合。行列積が代表的
  • Memory-Bound:Arithmetic Intensityが境界値より低い場合。Attention、Decodingが代表的

1.2 Prefill vs Decode段階(だんかい)

LLM推論は大きく二つの段階に分かれます。

┌──────────────────────────────────────────────────────┐
LLM推論パイプライン                      │
├──────────────────┬───────────────────────────────────┤
Prefill段階Decode段階  (プロンプト処理)        (トークン生成)├──────────────────┼───────────────────────────────────┤
- 入力トークン並列  │ - トークン1つずつ順次生成           │
- Compute-Bound- Memory-Bound- 高いGPU活用率   │ - 低いGPU活用率(通常5-15%)        │
- 一回実行        │ - 出力長分だけ繰り返し              │
- KV Cache生成- KV Cache読み取り+追加└──────────────────┴───────────────────────────────────┘

Prefill段階:プロンプト全体を一度に処理します。行列-行列積(GEMM)が主となりcompute-boundです。

Decode段階:トークンを一つずつ生成します。行列-ベクトル積(GEMV)が主となりmemory-boundです。毎ステップでモデル全体の重みを読み込む必要がありますが、実際の演算量は少ないです。

1.3 なぜDecodeが遅(おそ)いのか

Llama-2 70Bモデル基準:

  • モデル重み:約140GB(FP16)
  • Decode1ステップあたり:140GBをメモリから読み込む必要
  • A100帯域幅2TB/s基準:140GB / 2TB/s = 70ms per token
  • 実際の演算に必要な時間:約1ms

メモリ読み込みが70倍長くかかります。 これがLLM推論最適化の核心的な動機です。


2. KV Cache:LLM推論の核心データ構造

2.1 KV Cacheとは何(なに)か

TransformerのSelf-Attentionはすべての過去トークンのKey(K)とValue(V)を必要とします。KV Cacheは既に計算されたK、Vテンソルを保存して再計算を防止します。

# KV Cacheなしの場合(毎ステップ全再計算)
# トークンn個生成時の総演算: O(n^2 * d)

# KV Cacheありの場合(以前の結果を再利用)
# トークンn個生成時の総演算: O(n * d)
# ただし、KV Cacheメモリ: O(n * d) 追加必要

2.2 KV Cacheメモリ計算

KV Cacheサイズ = 2 * num_layers * num_kv_heads * head_dim * seq_len * batch_size * dtype_size

: Llama-2 70B, seq_len=4096, batch_size=1, FP16
= 2 * 80 * 8 * 128 * 4096 * 1 * 2 bytes
= 1.34 GB (シーケンス1つに!)

batch_size=32の場合: 1.34 * 32 = 42.9 GB
モデルパラメータKV Cache/token (FP16)4Kシーケンスx14Kシーケンスx32
Llama-2 7B7B800 KB3.2 GB102 GB
Llama-2 70B70B320 KB1.34 GB42.9 GB
Mixtral 8x7B46.7B640 KB2.56 GB81.9 GB
Llama-3 405B405B1.6 MB6.4 GB204 GB

2.3 PagedAttention(vLLMのコア技術)

従来方式の問題:シーケンスごとに最大長分の連続メモリを事前確保。実際には60-80%が無駄になります。

┌─────────────────────────────────────────────┐
│        従来のKV Cache割り当て方式│                                             │
Request 1: [████████░░░░░░░░░░░░]  40% 使用│
Request 2: [████████████░░░░░░░░]  60% 使用│
Request 3: [██░░░░░░░░░░░░░░░░░░]  10% 使用│
^^^^^^^^ 無駄なメモリ            │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
PagedAttention KV Cache割り当て│                                             │
│  物理ブロック: [B0][B1][B2][B3][B4][B5]│                                             │
Request 1 → ページテーブル: [B0, B3, B5]Request 2 → ページテーブル: [B1, B4, B6]Request 3 → ページテーブル: [B2]│                                             │
│  内部フラグメンテーションほぼゼロ               │
│  非連続メモリブロック活用                      │
Copy-on-Writeでプロンプト共有└─────────────────────────────────────────────┘

PagedAttentionの核心アイデア

  1. KV Cacheを固定サイズの**ブロック(ページ)**に分割
  2. OSの仮想メモリのようにページテーブルで非連続ブロックを論理的に接続
  3. 必要な時だけブロックを割り当て、内部フラグメンテーションを除去
  4. Copy-on-Write:同じプロンプトを共有するリクエストがKV Cacheを共有

2.4 Prefix Caching

繰り返されるシステムプロンプトや共通プレフィックスのKV Cacheを再利用します。

# vLLMでPrefix Cachingを有効化
from vllm import LLM

llm = LLM(
    model="meta-llama/Llama-3.1-70B-Instruct",
    enable_prefix_caching=True,
    max_model_len=8192,
)

# 同じシステムプロンプトを使用するリクエストは
# システムプロンプト部分のKV Cacheを共有します

3. Attention最適化:FlashAttentionとMQA/GQA

3.1 FlashAttention:IO-Aware Attention

標準Attentionの問題点:

  1. Q、K、V行列をHBM(High Bandwidth Memory)から読み込む
  2. S = Q @ K^Tを計算してHBMに書き込む
  3. P = softmax(S)を計算してHBMに書き込む
  4. O = P @ Vを計算してHBMに書き込む

合計4回のHBM読み書き — これがボトルネックです。

┌──────────────────────────────────────────────┐
FlashAttention核心アイデア│                                              │
GPUメモリ階層:│  ┌─────────┐  19 TB/s   ┌─────────────────┐ │
│  │  SRAM   │◄──────────►│  Compute Units   │ │
 (20 MB) │            └─────────────────┘ │
│  └────┬────┘                                 │
│       │ 2-4.8 TB/s                           │
│  ┌────▼────────────────┐                     │
│  │    HBM (80-141 GB)  │                     │
│  └─────────────────────┘                     │
│                                              │
│  戦略: Q,K,Vをタイル(ブロック)に分割して        │
SRAMですべての計算を実行し                     │
│  最終結果のみHBMに記録                         │
└──────────────────────────────────────────────┘

3.2 FlashAttentionバージョン比較

特性FlashAttention-1FlashAttention-2FlashAttention-3
リリース202220232024
速度向上2-4倍追加2倍追加1.5-2倍
GPU対応A100A100, H100H100(Hopper最適化)
主要最適化タイリング、再計算並列化改善、warp分割FP8、非同期コピー、パイプライニング
MHA比FLOPS50-70%70-80%最大740 TFLOPS(75%)

3.3 Multi-Query Attention (MQA) vs Grouped-Query Attention (GQA)

KV Cacheサイズを削減するアーキテクチャレベルの最適化です。

┌─────────────────────────────────────────────────────┐
Multi-Head Attention (MHA)Q heads: [H1][H2][H3][H4][H5][H6][H7][H8]K heads: [H1][H2][H3][H4][H5][H6][H7][H8]V heads: [H1][H2][H3][H4][H5][H6][H7][H8]KV Cache: 8x                                     │
├─────────────────────────────────────────────────────┤
Multi-Query Attention (MQA)Q heads: [H1][H2][H3][H4][H5][H6][H7][H8]K heads: [        H_shared         ]V heads: [        H_shared         ]KV Cache: 1x (8倍削減)├─────────────────────────────────────────────────────┤
Grouped-Query Attention (GQA, 2グループ)Q heads: [H1][H2][H3][H4] | [H5][H6][H7][H8]K heads: [   K_group1   ] | [   K_group2   ]V heads: [   V_group1   ] | [   V_group2   ]KV Cache: 2x (4倍削減)└─────────────────────────────────────────────────────┘
モデルAttentionタイプKV HeadsQ HeadsKV Cache削減
GPT-J 6BMHA16161x
Falcon-40BMQA16464x
Llama-2 70BGQA8648x
Llama-3 70BGQA8648x
Mistral 7BGQA8324x

4. Batching戦略:Static vs Continuous

4.1 Static Batchingの限界(げんかい)

Static Batching(従来方式):
時間 ──────────────────────────────────►

Req 1: [████████████████████████████████]  (長い応答)
Req 2: [████████░░░░░░░░░░░░░░░░░░░░░░]  (短い応答)
Req 3: [██████████████░░░░░░░░░░░░░░░░]  (中程度の応答)
Req 4: [WAIT WAIT WAIT WAIT WAIT WAIT ]  (待機中)

= GPUアイドル(パディング), WAIT = バッチ完了まで待機
バッチ全体が終わるまで次のバッチ開始不可 → スループット非常に低い

4.2 Continuous Batching (In-Flight Batching)

Continuous Batching:
時間 ──────────────────────────────────►

Req 1: [████████████████████████████████]
Req 2: [████████]
Req 3:          [██████████████]
Req 4:                  [████████████████]
Req 5:                          [████████]

完了したリクエストを即座に除去 → 新しいリクエストを即座に投入
GPUアイドル時間を最小化 → スループット10-20倍向上

Continuous Batchingの核心原理

  1. 毎イテレーションで完了したリクエストをバッチから除去
  2. 待機中のリクエストを即座にバッチに追加
  3. GPUが常に最大負荷で動作
  4. 個々のリクエストのレイテンシも改善(待機時間削減)

4.3 Chunked Prefill

長いプロンプトのPrefill段階がDecodeリクエストをブロッキングする問題を解決します。

# vLLM chunked prefill設定
from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Llama-3.1-8B-Instruct",
    enable_chunked_prefill=True,
    max_num_batched_tokens=2048,  # 一度に処理する最大トークン数
)

# 長いプロンプト(例:32Kトークン)を2048トークンチャンクに分割処理
# チャンク間にDecodeリクエストも処理可能
# TTFTは若干増加するが、全体のスループットとITLが改善

5. Speculative Decoding:推論速度のゲームチェンジャー

5.1 核心アイデア

小さな**ドラフトモデル(Draft Model)が複数トークンを高速に予測し、大きなターゲットモデル(Target Model)**が1回のforward passですべて検証します。

┌────────────────────────────────────────────────────┐
Speculative Decodingフロー│                                                    │
Step 1: Draft Model(小さく高速なモデル)"The capital of France is"[Paris][,][a][city]4トークンを非常に高速に予測(4ms)                   │
│                                                    │
Step 2: Target Model(大きく正確なモデル)1回のforward passで4トークンを同時検証              │
[Paris OK] [, OK] [a NG"known"] [city NG]│                                                    │
│  結果: "Paris, known" (2個受理 + 1個修正)│  従来: 3回のforward pass必要 → 今は1回              │
│  速度向上:2-3倍                                  │
└────────────────────────────────────────────────────┘

5.2 数学的保証:出力品質の維持

Speculative Decodingの核心的な利点は、ターゲットモデルの出力分布を正確に維持することです。

受理/棄却確率:

  • ドラフトトークンxに対し、受理確率 = min(1, p_target(x) / p_draft(x))
  • 棄却時:(p_target(x) - p_draft(x))分布から再サンプリング

この過程を通じて、最終出力はターゲットモデルのみを使用した場合と数学的に同一の分布を持ちます。

5.3 Speculative Decodingのバリエーション

# 1. 別途Draft Modelを使用
from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Llama-3.1-70B-Instruct",
    speculative_model="meta-llama/Llama-3.1-8B-Instruct",
    num_speculative_tokens=5,
    use_v2_block_manager=True,
)

# 2. Medusa Heads(追加MLPヘッドで複数位置を同時予測)
# Draftモデル不要 - ターゲットモデル自体に軽量ヘッドを追加
# 学習が必要だがメモリオーバーヘッド最小

# 3. EAGLE (Extrapolation Algorithm for Greater Language-model Efficiency)
# ドラフトモデルがターゲットモデルのhidden stateを再利用
# 別途ドラフトモデルより高い受理率

5.4 Tree Attention

複数の候補シーケンスをツリー構造で同時に検証します。

トークン位置:     1        2        3
              ┌── Paris ─┬── is ── ...
The ──────────┤          └── was ── ...
              ├── Lyon ── is ── ...
              └── capital ── of ── ...

ツリーのすべてのパスを1回のforward passで検証
→ 受理確率最大化、スループット向上

6. 量子化(りょうしか)で推論を加速

6.1 データ型(かた)別比較

データ型ビット数範囲メモリ削減品質影響
FP3232非常に広い基準基準
FP1616広い2倍無視可能
BF1616FP32と同等2倍無視可能
FP8 (E4M3)8中程度4倍非常に小さい
INT88-128から1274倍小さい
INT44-8から78倍中程度
NF44正規分布最適化8倍INT4より小さい

6.2 量子化技法の比較

┌───────────────────────────────────────────────────────┐
│              量子化技法の分類                            │
├─────────────────────┬─────────────────────────────────┤
Post-TrainingTraining-AwareQuantization(PTQ)Quantization├─────────────────────┼─────────────────────────────────┤
- GPTQ (INT4)- QLoRA + Merge- AWQ (INT4)- QAT (Quantization-Aware- GGUF (各種)Training)- bitsandbytes     │                                 │
- SmoothQuant      │                                 │
- FP8 Dynamic      │                                 │
└─────────────────────┴─────────────────────────────────┘

6.3 主要量子化フォーマットの詳細

# GPTQ: レイヤー別最適量子化(OBQベース)
# 利点: INT4でも良好な品質、GPU推論最適化
# 欠点: キャリブレーションデータ必要、量子化時間が長い

from transformers import AutoModelForCausalLM, GPTQConfig

gptq_config = GPTQConfig(
    bits=4,
    group_size=128,
    dataset="c4",
    desc_act=True,
)
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B-Instruct",
    quantization_config=gptq_config,
    device_map="auto",
)
# AWQ: Activation-aware Weight Quantization
# 核心: 重要な重みチャネルを発見し保護(活性化の大きさ基準)
# GPTQより高速な量子化、同等の品質

from awq import AutoAWQForCausalLM

model = AutoAWQForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-70B-Instruct"
)
quant_config = {
    "zero_point": True,
    "q_group_size": 128,
    "w_bit": 4,
    "version": "GEMM"
}
model.quantize(tokenizer, quant_config=quant_config)
# bitsandbytes: 簡単なINT8/NF4量子化
from transformers import BitsAndBytesConfig

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype="bfloat16",
    bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.1-8B-Instruct",
    quantization_config=bnb_config,
)

6.4 GGUF:CPU/Metal推論用フォーマット

llama.cppで使用される量子化フォーマットです。多様な量子化レベルをサポートします。

GGUF量子化ビット方法品質速度
Q2_K2-3K-quant混合低い非常に高速
Q4_K_M4-5K-quant中間良好高速
Q5_K_M5-6K-quant中間非常に良好中程度
Q6_K6K-quantほぼ原本遅い
Q8_08均一量子化原本と同等遅い
F1616量子化なし原本最も遅い

7. サービングフレームワーク比較:vLLM vs TensorRT-LLM vs TGI

7.1 総合比較表

機能vLLMTensorRT-LLMTGIOllamallama.cpp
開発元UC BerkeleyNVIDIAHugging FaceOllamaggerganov
言語Python/C++C++/PythonRust/PythonGoC/C++
PagedAttentionOOOXX
Continuous BatchingOOOXX
Tensor ParallelismOOOXX
FP8サポートOO(最適)OXX
Speculative DecodingOO限定的XO
LoRAサービングO(複数)OOOO
VisionモデルOOOOO(一部)
CPU推論限定的XXOO(最適)
Metal (Apple)XXXOO
インストール難易度簡単困難簡単非常に簡単中程度
本番適合度高い高い高い低い中程度

7.2 スループットベンチマーク (Llama-3.1 8B, A100 80GB)

フレームワークスループット (tok/s)TTFT (ms)ITL (ms)メモリ使用量
vLLM (FP16)4,200451218 GB
vLLM (AWQ-4bit)6,8003287 GB
TensorRT-LLM (FP16)4,800381017 GB
TensorRT-LLM (FP8)7,50028710 GB
TGI (FP16)3,600521418 GB
llama.cpp (Q4_K_M)120200355 GB

8. vLLM深堀り:アーキテクチャからLoRAサービングまで

8.1 vLLMアーキテクチャ

┌──────────────────────────────────────────┐
│              vLLMアーキテクチャ             │
│                                          │
│  ┌─────────┐     ┌──────────────────┐   │
│  │ FastAPI  │────►│   LLM Engine     │   │
│  │ Server   │     │                  │   │
│  └─────────┘     │  ┌────────────┐  │   │
│                  │  │ Scheduler   │  │   │
│  ┌─────────┐    │   (バッチング)  │  │   │
│  │ OpenAI  │────►│  └─────┬──────┘  │   │
│  │ compat  │     │        │         │   │
│  └─────────┘     │  ┌─────▼──────┐  │   │
│                  │  │ Block Mgr   │  │   │
│                  │   (PagedAttn) │  │   │
│                  │  └─────┬──────┘  │   │
│                  │        │         │   │
│                  │  ┌─────▼──────┐  │   │
│                  │  │  Worker(s)  │  │   │
│                  │    (GPU実行)  │  │   │
│                  │  └────────────┘  │   │
│                  └──────────────────┘   │
└──────────────────────────────────────────┘

8.2 vLLM本番デプロイ

# vLLMサーバー起動(OpenAI API互換)
# vllm serve meta-llama/Llama-3.1-70B-Instruct \
#     --tensor-parallel-size 4 \
#     --max-model-len 32768 \
#     --gpu-memory-utilization 0.90 \
#     --enable-prefix-caching \
#     --enable-chunked-prefill \
#     --max-num-batched-tokens 4096 \
#     --port 8000

# PythonでAPI呼び出し
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="token-abc123",
)

response = client.chat.completions.create(
    model="meta-llama/Llama-3.1-70B-Instruct",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Explain quantum computing"},
    ],
    max_tokens=512,
    temperature=0.7,
)

8.3 vLLMマルチLoRAサービング

一つのベースモデルで複数のLoRAアダプターを同時にサービングできます。

# vllm serve meta-llama/Llama-3.1-8B-Instruct \
#     --enable-lora \
#     --lora-modules \
#         sql-lora=./adapters/sql-lora \
#         code-lora=./adapters/code-lora \
#         chat-lora=./adapters/chat-lora \
#     --max-loras 3 \
#     --max-lora-rank 64

# API呼び出し時にモデル名でLoRAアダプターを選択
response = client.chat.completions.create(
    model="sql-lora",  # LoRAアダプター名
    messages=[{"role": "user", "content": "SELECT ..."}],
)

8.4 vLLM Visionモデルサービング

# マルチモーダルモデルサービング
# vllm serve Qwen/Qwen2-VL-7B-Instruct \
#     --max-model-len 8192 \
#     --limit-mm-per-prompt image=4

from openai import OpenAI
import base64

client = OpenAI(base_url="http://localhost:8000/v1", api_key="key")

response = client.chat.completions.create(
    model="Qwen/Qwen2-VL-7B-Instruct",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What is in this image?"},
            {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}
        ]
    }],
)

9. TensorRT-LLM深堀り:最高性能のための選択

9.1 TensorRT-LLMビルドパイプライン

┌────────┐     ┌───────────┐     ┌──────────┐     ┌──────────┐
HFモデル │────►│チェックポイント│────►│ TRT-LLM  │────►│ Triton(元モデル)│     │  変換      │     │ Engine   │     │サービング │
└────────┘     └───────────┘     └──────────┘     └──────────┘
                 量子化適用       コンパイル最適化    APIサーバー
# Step 1: チェックポイント変換 + FP8量子化
python convert_checkpoint.py \
    --model_dir meta-llama/Llama-3.1-70B-Instruct \
    --output_dir ./checkpoint_fp8 \
    --dtype bfloat16 \
    --tp_size 4 \
    --pp_size 1 \
    --use_fp8

# Step 2: TensorRTエンジンビルド
trtllm-build \
    --checkpoint_dir ./checkpoint_fp8 \
    --output_dir ./engine_fp8 \
    --gemm_plugin auto \
    --max_batch_size 64 \
    --max_input_len 4096 \
    --max_seq_len 8192 \
    --paged_kv_cache enable \
    --use_paged_context_fmha enable \
    --workers 4

9.2 TensorRT-LLM FP8最適化

H100 GPUのFP8 Tensor Coreを最大限活用します。

設定スループット (Llama-3.1 70B, 4xH100)レイテンシ
FP16, TP=42,400 tok/s16ms ITL
FP8, TP=44,200 tok/s9ms ITL
FP8 + Speculative5,800 tok/s6ms ITL
INT4 AWQ, TP=23,800 tok/s11ms ITL

9.3 Inflight Batching (TensorRT-LLM)

TensorRT-LLMのContinuous Batching実装です。

# Triton Inference Server + TensorRT-LLMバックエンド
# model_config.pbtxt設定
"""
backend: "tensorrtllm"
max_batch_size: 64

model_transaction_policy {
  decoupled: True    # ストリーミングレスポンスサポート
}

parameters: {
  key: "batching_type"
  value: {string_value: "inflight"}  # Inflight Batching有効化
}

parameters: {
  key: "max_tokens_in_paged_kv_cache"
  value: {string_value: "131072"}   # KV Cacheトークン数制限
}
"""

10. モデル並列化:マルチGPU戦略

10.1 Tensor Parallelism (TP)

一つのレイヤーを複数のGPUに分割します。

Tensor Parallelism (TP=4):

         レイヤーNの重み行列W
    ┌──────┬──────┬──────┬──────┐
W_1W_2W_3W_4GPU 0GPU 1GPU 2GPU 3    └──┬───┴──┬───┴──┬───┴──┬───┘
       │      │      │      │
       ▼      ▼      ▼      ▼
    [部分1] [部分2] [部分3] [部分4]
       │      │      │      │
       └──────┴──────┴──────┘
              All-Reduce
              (結果集約)

利点: レイテンシ削減(全GPU同時計算)
欠点: GPU間通信が必要(NVLink推奨)
適用: 同一ノード内GPU(低レイテンシ必要)

10.2 Pipeline Parallelism (PP)

レイヤーを順次複数のGPUに分配します。

Pipeline Parallelism (PP=4, 80 layers):

GPU 0: [Layer 0-19]GPU 1: [Layer 20-39]
GPU 2: [Layer 40-59]
GPU 3: [Layer 60-79]

利点: GPU間通信最小(一方向)
欠点: パイプラインバブル(GPUアイドル時間)
適用: ノード間分散(高レイテンシ許容)

10.3 Expert Parallelism (EP) - MoEモデル用

Mixture of Expertsモデルでエキスパートを分散します。

Expert Parallelism (Mixtral 8x7B, EP=4):

GPU 0: Expert 0, 1 + Shared Layers
GPU 1: Expert 2, 3 + Shared Layers
GPU 2: Expert 4, 5 + Shared Layers
GPU 3: Expert 6, 7 + Shared Layers

トークンルーティング: 各トークンはTop-2 Expertに送信
GPU間All-to-All通信が必要

10.4 実践的な並列化の組み合わせ

# Llama-3.1 405Bサービング (8x H100 80GB)
# モデルサイズ: 約810 GB (FP16) → FP8で約405 GB

# オプション1: TP=8(全GPUに全レイヤーを分割)
vllm serve meta-llama/Llama-3.1-405B-Instruct-FP8 \
    --tensor-parallel-size 8 \
    --max-model-len 16384

# オプション2: TP=4, PP=2(4 GPUずつ2パイプラインステージ)
vllm serve meta-llama/Llama-3.1-405B-Instruct-FP8 \
    --tensor-parallel-size 4 \
    --pipeline-parallel-size 2 \
    --max-model-len 16384

11. GPUメモリ最適化の深堀り

11.1 KV Cache量子化

# vLLMでKV Cache FP8量子化
# vllm serve meta-llama/Llama-3.1-70B-Instruct \
#     --tensor-parallel-size 4 \
#     --kv-cache-dtype fp8 \
#     --quantization fp8

# KV Cacheメモリ削減効果
# FP16 KV Cache: 1.34 GB / シーケンス (Llama-2 70B, 4K)
# FP8 KV Cache:  0.67 GB / シーケンス (50%削減)
# 同じGPUで2倍多くの同時リクエストを処理可能

11.2 メモリ割り当て戦略

GPUメモリ配分 (A100 80GB, Llama-3.1 70B FP16):

┌─────────────────────────────────┐
│  モデル重み:35 GB (TP=2)43.75%
├─────────────────────────────────┤
KV Cache:35 GB43.75%
  (gpu_memory_utilization=0.90)├─────────────────────────────────┤
│  活性化メモリ:2 GB2.5%
├─────────────────────────────────┤
│  システム予約:8 GB10%
└─────────────────────────────────┘

KV Cacheが処理可能な最大同時リクエスト数を決定します。

11.3 メモリ不足(ぶそく)時の対応戦略

戦略実装効果副作用
量子化FP16→INT4重み4倍削減微小な品質低下
KV Cache量子化FP16→FP8KV Cache 2倍削減無視できるレベル
max_model_len縮小32K→8K該当比率分KV Cache削減長いコンテキスト不可
TP増加TP=2→TP=4GPU当たりメモリ半減GPU追加コスト
Prefix Cachingシステムプロンプト共有繰り返しリクエスト時大きな削減ユニークなリクエストには効果なし

12. コスト分析:プラットフォーム別tokens/dollar

12.1 セルフホスティングコスト比較

GPUクラウド時間当たりコストLlama-3.1 70Bスループットtokens/dollar
A100 80GB x1約3.0 USD800 tok/s (FP16)960K
A100 80GB x4 (TP=4)約12.0 USD2,800 tok/s840K
H100 80GB x1約4.5 USD1,500 tok/s (FP8)1,200K
H100 80GB x4 (TP=4)約18.0 USD5,000 tok/s (FP8)1,000K
L40S x1約1.5 USD600 tok/s (INT4)1,440K
4090 x1(自前サーバー)約0.3 USD(電気代)400 tok/s (INT4)4,800K

12.2 API vs セルフホスティング損益分岐点

月間トークン使用量別コスト比較(Llama-3.1 70B級):

┌─────────────────────────────────────────────────┐
│ コスト                                           │
 ($)5000/API│     │                                  /3000│                    ────────── Self-Hosted│     │              /  (H100x4 月額固定費)1000/ API│     │   /0├──┬────┬────┬────┬────┬────┬────►          │
0  2B   5B  10B  20B  50B 100B  token/月    │
│                                                 │
│  損益分岐点: 約10Bトークン/月                      │
└─────────────────────────────────────────────────┘

13. ベンチマーキング:正しい測定方法

13.1 コアメトリクス

メトリクス定義重要な理由
TTFT (Time To First Token)最初のトークン生成までの時間ユーザー体感の応答開始時間
ITL (Inter-Token Latency)トークン間の生成時間ストリーミング時の体感速度
E2E Latencyリクエスト全体の完了時間総待機時間
Throughput秒当たり生成トークン数システム全体の処理能力
TPS/Userユーザー当たり秒当たりトークン個人の体感速度

13.2 ベンチマーキングツールと方法

# vLLM内蔵ベンチマーク(推奨)
# python -m vllm.entrypoints.openai.api_server 実行後:

# python benchmarks/benchmark_serving.py \
#     --backend vllm \
#     --model meta-llama/Llama-3.1-8B-Instruct \
#     --dataset-name sharegpt \
#     --dataset-path ShareGPT_V3_unfiltered.json \
#     --num-prompts 1000 \
#     --request-rate 10 \
#     --endpoint /v1/completions

# 結果例:
# Successful requests:                     1000
# Benchmark duration (s):                  105.23
# Total input tokens:                      215000
# Total generated tokens:                  180000
# Request throughput (req/s):              9.50
# Output token throughput (tok/s):         1710.5
# Mean TTFT (ms):                          48.2
# Median TTFT (ms):                        42.1
# P99 TTFT (ms):                           125.3
# Mean ITL (ms):                           11.8
# Median ITL (ms):                         10.2
# P99 ITL (ms):                            35.7

13.3 負荷(ふか)別の性能特性

スループットとレイテンシの関係(concurrency増加時):

スループット                      レイテンシ
(tok/s)                        (ms)
  │        ┌──────────           │              /
//
//
//
//
//
//
//
  ├──────────────► concurrency   ├──────────────► concurrency

  最適運用ポイント: スループットが飽和する直前(Knee point)
  通常GPU活用率70-80%の地点

14. 本番デプロイアーキテクチャ

14.1 プロダクションサービングアーキテクチャ

┌──────────────────────────────────────────────────┐
│               本番アーキテクチャ                    │
│                                                  │
ClientLoad BalancerAPI Gateway│                              │                   │
│                    ┌─────────┼─────────┐         │
│                    ▼         ▼         ▼         │
│              ┌─────────┐┌────────┐┌────────┐    │
│              │ vLLM    ││ vLLM   ││ vLLM   │    │
│              │ Pod 1   ││ Pod 2  ││ Pod 3  │    │
 (4xH100)││(4xH100)││(4xH100)│    │
│              └────┬────┘└───┬────┘└───┬────┘    │
│                   │         │         │          │
│              ┌────▼─────────▼─────────▼────┐    │
│              │     Prometheus + Grafana     │    │
    (メトリクス収集/可視化)     │    │
│              └─────────────────────────────┘    │
│                                                  │
│  オートスケーリング: キュー長/GPU活用率基準         │
│  ヘルスチェック: /healthエンドポイント              │
Graceful Shutdown: 進行中リクエスト完了後に終了    │
└──────────────────────────────────────────────────┘

14.2 Kubernetesデプロイ例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-llama3-70b
spec:
  replicas: 3
  selector:
    matchLabels:
      app: vllm-llama3
  template:
    metadata:
      labels:
        app: vllm-llama3
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:latest
        command: ["python", "-m", "vllm.entrypoints.openai.api_server"]
        args:
          - "--model=meta-llama/Llama-3.1-70B-Instruct"
          - "--tensor-parallel-size=4"
          - "--max-model-len=16384"
          - "--gpu-memory-utilization=0.90"
          - "--enable-prefix-caching"
          - "--enable-chunked-prefill"
        resources:
          limits:
            nvidia.com/gpu: "4"
            memory: "64Gi"
          requests:
            nvidia.com/gpu: "4"
            memory: "32Gi"
        ports:
        - containerPort: 8000
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 120
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 180
          periodSeconds: 30
      nodeSelector:
        gpu-type: h100
      tolerations:
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule

15. クイズ

Q1. vLLMのPagedAttentionが解決する核心的な問題は何ですか?

正解:KV Cacheのメモリフラグメンテーション問題を解決します。

従来方式はシーケンスごとに最大長分の連続メモリを事前確保し、60-80%が無駄になっていました。PagedAttentionはOSの仮想メモリのようにKV Cacheを固定サイズブロック(ページ)に分割し、ページテーブルで非連続ブロックを論理的に接続します:

  • 内部フラグメンテーションほぼゼロ
  • 非連続メモリブロック活用可能
  • Copy-on-Writeで共通プレフィックスのKV Cache共有

結果として同じGPUメモリで2-4倍多くの同時リクエストを処理できます。

Q2. Continuous BatchingがStatic Batchingよりスループットが高い理由は?

正解:Static Batchingはバッチ内のすべてのリクエストが完了するまで待機してから次のバッチを開始します。短い応答が先に終わってもGPUはアイドル状態で待機します。

Continuous Batchingは:

  1. 毎イテレーションで完了したリクエストを即座に除去
  2. 待機キューの新しいリクエストを即座に投入
  3. GPUが常に最大負荷で動作

これによりStatic Batching比10-20倍高いスループットを達成します。個々のリクエストのレイテンシも待機時間削減により改善されます。

Q3. Speculative Decodingが出力品質を低下させない理由は?

正解:数学的にターゲットモデルの出力分布を正確に保存するからです。

ドラフトモデルが予測したトークンxに対して:

  • 受理確率 = min(1, p_target(x) / p_draft(x))
  • 棄却時:(p_target - p_draft)分布から再サンプリング

この過程を通じて最終出力はターゲットモデルのみを使用した場合と数学的に同一の分布を持ちます。速度のみ向上し品質損失はゼロです。

Q4. LLM Decode段階がMemory-Boundである理由は?

正解:Decode段階では一度に1トークンのみ生成します。この時モデル全体の重みをメモリから読み込む必要がありますが(行列-ベクトル積)、実際の演算量は非常に少ないです。

Llama-2 70Bの例:

  • モデル重み140GBを毎ステップ読み込む必要
  • A100帯域幅2TB/s基準:70ms(メモリ読み込み)
  • 実際の演算時間:約1ms

メモリ帯域幅がボトルネックであるためMemory-Boundです。これが量子化(重みサイズ縮小)とバッチング(重み読み込み1回で複数リクエスト処理)が効果的な理由です。

Q5. FP8量子化がINT8よりLLM推論に適している理由は?

正解:FP8は浮動小数点形式であり、広いダイナミックレンジを持ちます。LLMの重みと活性化は非常に多様な大きさを持つため、固定小数点のINT8よりFP8が適しています。

具体的には:

  • FP8 E4M3:指数部4ビット、仮数部3ビット → 広い範囲、適度な精度
  • INT8:-128から127の固定範囲 → 外れ値に脆弱
  • H100 GPUはFP8専用Tensor Coreを搭載し、FP16比2倍の演算性能
  • FP8は別途キャリブレーションなしで動的量子化可能

結果としてFP8はINT4に近い性能向上を提供しつつ、FP16に近い品質を維持します。


16. 参考資料(さんこうしりょう)

  1. vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention - Kwon et al., 2023
  2. FlashAttention: Fast and Memory-Efficient Exact Attention - Dao et al., 2022
  3. FlashAttention-2: Faster Attention with Better Parallelism - Dao, 2023
  4. Efficient Memory Management for Large Language Model Serving with PagedAttention - Kwon et al., 2023
  5. Fast Inference from Transformers via Speculative Decoding - Leviathan et al., 2023
  6. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers - Frantar et al., 2023
  7. AWQ: Activation-aware Weight Quantization - Lin et al., 2024
  8. TensorRT-LLM - NVIDIA公式ドキュメント
  9. Orca: A Distributed Serving System for Transformer-Based Generative Models - Yu et al., 2022
  10. GQA: Training Generalized Multi-Query Transformer Models - Ainslie et al., 2023
  11. Medusa: Simple LLM Inference Acceleration Framework - Cai et al., 2024
  12. EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty - Li et al., 2024
  13. SmoothQuant: Accurate and Efficient Post-Training Quantization - Xiao et al., 2023

현재 단락 (1/633)

LLM推論最適化を議論する前に、まず**ボトルネックがどこで発生するか**を正確に理解する必要があります。

작성 글자: 0원문 글자: 22,927작성 단락: 0/633