TT Lab
はじめる
学ぶ 学習パス コース

LLMサービング

メモリ予算を手で立てる

TT Labで続きを見る

一言でいうと

GPUメモリのバジェットは、3つの項目です。モデルの重み、KVキャッシュ、そしてアクティベーションとオーバーヘッドです。2番目が最も大きく、最もよく無視されます。

なぜ必要なのか

「A100 80GB 1枚に70Bモデルは入りますか」という質問に答えるには、計算が必要です。重みだけを見ると、fp16基準で140GBなので、入りません。4ビットに量子化すると約35GBなので、入りそうです。ところが、KVキャッシュを忘れています。

計算せずに始めると、デプロイ当日にOOMに出会います。そして、OOMは負荷が集中するときに起きるので、最も悪い時点で起きます。

どう動くのか

モデルの重みは、パラメーター数掛けるdtypeのバイト数です。7Bのfp16なら14GB、70Bのfp16なら140GBです。量子化すると、この値が減ります。INT8は半分、INT4は4分の1程度です。

KVキャッシュの公式は、次のとおりです。

KV 바이트 = 2 x 레이어 수 x 은닉 차원 x 시퀀스 길이 x 배치 x dtype 바이트

このコードブロックの韓国語の式は、KVのバイト数が、2×レイヤー数×隠れ次元×シーケンス長×バッチ×dtypeのバイト数だ、という意味です。

先頭の2は、キーと値の2つという意味です。7B(32層、隠れ次元4096)のfp16を基準に計算してみると、次のようになります。

コンテキスト バッチ1 バッチ8
4K 2 GiB 16 GiB
32K 16 GiB 128 GiB
128K 64 GiB 512 GiB

128Kコンテキストでバッチ8なら、512GiBです。重みが14GBのモデルを動かすのに、KVキャッシュが512GBです。ロングコンテキストがなぜ難しいのかが、この表1つにあります。

減らす方法は、3つあります。GQAは、キー・値ヘッドをグループで共有して、8グループなら8分の1程度に減らします。KVキャッシュの量子化は、dtypeのバイト数を減らして、INT8なら半分、INT4なら4分の1です。PagedAttentionは、サイズそのものは減らしませんが、断片化をなくして、実使用の効率を上げます。

これらを重ねると、大きな節約になります。著者の例では、基本の1,280GBが、GQA-8で320GB、INT8で160GB、PagedAttentionの実使用ベースで約128GB、INT4まで行くと80GBになります。

現場での姿

同時リクエスト数を決める計算が、実務で最もよく必要になります。GPUの総メモリから、重みとオーバーヘッドを引くと、KVキャッシュのバジェットが出て、それをリクエスト1つあたりのKVサイズで割ると、最大の同時リクエスト数が出ます。この値がmax_num_seqsの上限で、キャパシティプランニングの出発点です。

量子化の選択も、この計算から出てきます。GPTQとAWQは、重みだけを量子化し、KVキャッシュの量子化は、別の設定です。2つを混同すると、「4ビットに変えたのに、メモリがあまり減らなかった」ということになります。コンテキストが長いワークロードでは、KVキャッシュが支配的だからです。

バジェットを立てる式

GPUメモリは、3つの取り分に分かれます。順に計算すると、同時に処理できるリクエスト数が出ます。

1. 가중치 = 파라미터 수 × (비트수 ÷ 8)
   7B × 2바이트(FP16)  = 14.0 GB
   7B × 0.5바이트(INT4) =  3.5 GB

2. 여유 = 활성화 + 단편화 ≈ 전체의 5~10%

3. KV 캐시로 쓸 수 있는 몫 = 전체 − 가중치 − 여유

このコードブロックの韓国語は、手順1で重みがパラメーター数×(ビット数÷8)、手順2で余裕がアクティベーションと断片化で全体のおよそ5–10%、手順3でKVキャッシュに使える取り分が全体から重みと余裕を引いた値だ、という意味です。

KVキャッシュがトークン1つあたりに食うサイズは、次のとおりです。

토큰당 = 2(K와 V) × 레이어 수 × KV 헤드 수 × 헤드 차원 × 정밀도 바이트

예: Llama-3 8B (32레이어, KV헤드 8, 헤드차원 128, FP16)
    = 2 × 32 × 8 × 128 × 2 = 131,072 바이트 ≈ 128 KB/토큰

このコードブロックの韓国語は、トークンあたりが2(KとV)×レイヤー数×KVヘッド数×ヘッド次元×精度のバイト数で、例はLlama-3 8B(32レイヤー、KVヘッド8、ヘッド次元128、FP16)だ、という意味です。

GQA(Grouped-Query Attention)がここで大きな違いを生みます。KVヘッドが32個なら512KB/トークンですが、8個なら128KBです。最近のモデルがGQAを使う理由が、これです。

24GB 카드, 8B 모델 FP16:
  가중치 16GB + 여유 2GB → KV 로 6GB
  6GB ÷ 128KB = 약 49,000 토큰
  → 문맥 4K 면 동시 12요청, 문맥 8K 면 6요청

このコードブロックの韓国語は、24GBのカードで8BモデルのFP16の場合、重み16GBと余裕2GBを除いてKVに6GBが残り、6GBを128KBで割ると約49,000トークンで、コンテキスト4Kなら同時12リクエスト、8Kなら6リクエストだ、という意味です。

この計算が教えてくれること

あふれたときに何が起きるのか

vLLMは、KVが足りなくなると、プリエンプション(preemption)します。進行中のリクエストを1つ選んで、キャッシュを捨て、あとで最初から計算し直します。

로그: Sequence group ... is preempted by PreemptionMode.RECOMPUTE

このログがよく見えるなら、同時実行数が容量を超えています。レイテンシが跳ねるのに、GPUの使用率は高く出て、「うまく使えている」と読み違えやすいです。プリエンプションの回数を指標に置くことが、この状態に気づく方法です。

次のラボですること

公式をコードで実装して、複数のシナリオを計算します。7Bの4Kが2GiBであることを検証し、128Kを計算し、GQAとINT8を適用し、最後に、80GBのGPUで可能な最大の同時リクエスト数を求めます。