Home 論文解説: DeepSeek-V2 — MoEモデルのKVキャッシュを93.3%削減するMulti-head Latent Attention
投稿
キャンセル

📄 論文解説: DeepSeek-V2 — MoEモデルのKVキャッシュを93.3%削減するMulti-head Latent Attention

本記事は DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model の解説記事です。

論文概要(Abstract)

DeepSeek-V2は、合計236Bパラメータのうちトークンあたり21Bのみを活性化するMoE(Mixture-of-Experts)言語モデルである。著者らは2つの技術的革新を提案している。第一に、MLA(Multi-head Latent Attention)はKVキャッシュを低ランク結合圧縮により93.3%削減しながら、標準的なMHA(Multi-Head Attention)を上回る性能を達成する。第二に、DeepSeekMoEは細粒度エキスパート分割と共有エキスパート分離により、経済的なコストで高性能モデルの学習を可能にする。

この記事は Zenn記事: Qwen3.5×RTX 3090でバイブコーディング環境を構築する実践ガイド の深掘りです。Zenn記事で扱うQwen3.5-MoEモデルのアーキテクチャ理解に直結する基盤技術として、MLAとDeepSeekMoEの仕組みを詳細に解説します。

情報源

  • arXiv ID: 2401.06066
  • URL: https://arxiv.org/abs/2401.06066
  • 著者: DeepSeek-AI(Aixin Liu, Bingxuan Wang, Damai Dai, Daya Guo, Dejian Yang 他多数)
  • 発表年: 2024
  • 分野: cs.CL, cs.LG

背景と動機(Background & Motivation)

LLMの推論時にボトルネックとなるのがKVキャッシュのメモリ消費である。標準的なMHAではトークンあたり $2 n_h d_h$ 要素($n_h$: ヘッド数、$d_h$: ヘッド次元)のKVキャッシュが必要になる。DeepSeek-V2の設定($n_h = 128$, $d_h = 128$)では1トークンあたり32,768要素に達する。

この問題に対し、MQA(Multi-Query Attention)やGQA(Grouped-Query Attention)がKVヘッド数を減らすアプローチとして知られているが、これらはモデル性能の低下を伴う場合がある。著者らは「KVキャッシュをMQA並みに削減しつつ、MHAを上回る性能を実現する」という目標を掲げてMLAを設計した。

主要な貢献(Key Contributions)

  • MLA(Multi-head Latent Attention): 低ランクKV結合圧縮により、MHAの約1/57のKVキャッシュでMHA以上の性能を達成
  • DeepSeekMoE: 160個の細粒度ルーティングエキスパート + 2個の共有エキスパートにより、経済的な学習を実現
  • 効率性: DeepSeek 67B比で学習FLOPs 42.5%削減、KVキャッシュ93.3%削減、最大生成スループット5.76倍

技術的詳細(Technical Details)

MLA: 低ランクKV結合圧縮

MLAの核心は、KeyとValueを別々に保持する代わりに、1つの低次元潜在ベクトル $\mathbf{c}_t^{KV}$ に圧縮する点にある。

位置 $t$ のトークンの隠れ状態 $\mathbf{h}_t \in \mathbb{R}^d$ に対し、まずダウンプロジェクションで圧縮する:

\[\mathbf{c}_t^{KV} = W^{DKV} \mathbf{h}_t\]

ここで、

  • $W^{DKV} \in \mathbb{R}^{d_c \times d}$: ダウンプロジェクション行列
  • $d_c$: KV圧縮次元(DeepSeek-V2では512)
  • $d$: 隠れ次元(5120)

この圧縮ベクトルからKey・Valueを復元する:

\[\mathbf{k}_t^C = W^{UK} \mathbf{c}_t^{KV}, \quad \mathbf{v}_t^C = W^{UV} \mathbf{c}_t^{KV}\]

ここで $W^{UK}, W^{UV} \in \mathbb{R}^{n_h d_h \times d_c}$ はアッププロジェクション行列である。

推論時にキャッシュするのは $\mathbf{c}_t^{KV}$(512次元)のみで、標準MHAの $2 n_h d_h = 32{,}768$ 要素と比較して大幅に削減される。

Decoupled RoPE: 位置埋め込みとの互換性確保

RoPE(Rotary Position Embedding)は位置依存の変換をKey・Queryに適用するため、低ランク圧縮と直接組み合わせられない。著者らはこの問題を「分離RoPE」で解決している。

コンテンツ情報と位置情報を分離し、位置成分には別途生成した共有Key $\mathbf{k}_t^R \in \mathbb{R}^{d_h^R}$ を用いる:

\[\mathbf{q}_{t,i} = \left[\underbrace{W^{UQ}_i \mathbf{c}_t^Q}_{\text{コンテンツクエリ}}; \underbrace{\text{RoPE}(\mathbf{q}_{t,i}^R)}_{\text{位置クエリ}}\right]\] \[\mathbf{k}_{t,i} = \left[\underbrace{W^{UK}_i \mathbf{c}_t^{KV}}_{\text{コンテンツキー}}; \underbrace{\text{RoPE}(\mathbf{k}_t^R)}_{\text{位置キー}}\right]\]

推論時のキャッシュ対象は $\mathbf{c}_t^{KV}$(512次元)と $\mathbf{k}_t^R$(64次元、全ヘッド共有)の合計 576要素/トークン/レイヤー となる。

行列吸収トリック: 推論時の追加計算をゼロに

MLAの推論効率化の鍵は、アッププロジェクション行列を隣接する重み行列に「吸収」できる点にある。コンテンツキーの計算において:

\[\mathbf{q}_{t,i}^{C\top} \mathbf{k}_{j,i}^C = (\mathbf{q}_{t,i}^C)^\top (W^{UK}_i \mathbf{c}_j^{KV}) = \underbrace{(W^{UK\top}_i \mathbf{q}_{t,i}^C)}_{\text{事前計算可能}}{}^\top \mathbf{c}_j^{KV}\]

$\tilde{W}^{UQ}_i = W^{UK\top}_i W^{UQ}_i$ を事前に計算しておけば、推論時に明示的なKey計算が不要になる。同様に $W^{UV}_i$ を出力射影 $W^O_i$ に吸収することで、Value計算も省略できる。

KVキャッシュ削減量の比較

論文Table 6(1Tトークン学習でのアブレーション)より、各Attention手法のKVキャッシュ量と性能の比較を以下に示す:

手法トークンあたりキャッシュ要素数MHA比KVキャッシュ性能差
MHA$2 n_h d_h = 32{,}768$100%ベースライン
GQA$2 n_g d_h$ (可変)12.5%-0.5%
MQA$2 d_h = 256$6.25%-1.3%
MLA$d_c + d_h^R = 576$6.25%+0.3%

著者らの実験によれば、MLAはMQAと同等のKVキャッシュ量でありながら、MHAを上回る性能を達成している。

DeepSeekMoE: 細粒度エキスパート分割

DeepSeekMoEは以下の式で計算される:

\[\mathbf{h}_t' = \sum_{i=1}^{K_s} \text{FFN}_i^{(s)}(\mathbf{h}_t) + \sum_{i=1}^{N_r} g_{i,t} \cdot \text{FFN}_i^{(r)}(\mathbf{h}_t)\]

ここで、

  • $K_s = 2$: 共有エキスパート数(常時活性化、共通知識を担当)
  • $N_r = 160$: ルーティングエキスパート数(うち $K_r = 6$ 個を選択)
  • $g_{i,t}$: トークン $t$ に対するエキスパート $i$ のゲーティング値

ゲーティング値はSoftmaxベースのトークン-エキスパート親和度から決定される:

\[s_{i,t} = \text{Softmax}_i(\mathbf{h}_t^\top \mathbf{e}_i)\]

標準MoEと比較した特徴として、エキスパートの中間サイズを1536に縮小し、その分エキスパート数を160に増やすことで、より柔軟な組み合わせを実現している。

アルゴリズム

MLAの推論時の処理フローをPythonコードで示す:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import torch
import torch.nn as nn
import math

class MultiHeadLatentAttention(nn.Module):
    """Multi-head Latent Attention (MLA)

    低ランクKV結合圧縮によりKVキャッシュを大幅に削減する。

    Args:
        d_model: 隠れ次元 (5120)
        n_heads: Attentionヘッド数 (128)
        d_c: KV圧縮次元 (512)
        d_c_q: Query圧縮次元 (1536)
        d_rope: RoPE用次元 (64)
    """
    def __init__(
        self,
        d_model: int = 5120,
        n_heads: int = 128,
        d_c: int = 512,
        d_c_q: int = 1536,
        d_rope: int = 64,
    ):
        super().__init__()
        self.d_h = d_model // n_heads  # 40
        self.n_heads = n_heads
        self.d_c = d_c
        self.d_rope = d_rope

        # KVダウンプロジェクション
        self.W_dkv = nn.Linear(d_model, d_c, bias=False)
        # KVアッププロジェクション(推論時は行列吸収で不要にできる)
        self.W_uk = nn.Linear(d_c, n_heads * self.d_h, bias=False)
        self.W_uv = nn.Linear(d_c, n_heads * self.d_h, bias=False)
        # Queryダウン/アッププロジェクション
        self.W_dq = nn.Linear(d_model, d_c_q, bias=False)
        self.W_uq = nn.Linear(d_c_q, n_heads * self.d_h, bias=False)
        # RoPE用の別線形変換
        self.W_qr = nn.Linear(d_c_q, n_heads * d_rope, bias=False)
        self.W_kr = nn.Linear(d_model, d_rope, bias=False)
        # 出力射影
        self.W_o = nn.Linear(n_heads * self.d_h, d_model, bias=False)

    def forward(
        self,
        h: torch.Tensor,
        kv_cache: dict | None = None,
    ) -> torch.Tensor:
        """MLA forward pass

        Args:
            h: 入力テンソル (batch_size, seq_len, d_model)
            kv_cache: 推論時のKVキャッシュ
                {"c_kv": Tensor, "k_rope": Tensor}
        Returns:
            出力テンソル (batch_size, seq_len, d_model)
        """
        B, T, _ = h.shape

        # KV圧縮: d_model -> d_c (5120 -> 512)
        c_kv = self.W_dkv(h)  # (B, T, d_c)

        # Query圧縮
        c_q = self.W_dq(h)  # (B, T, d_c_q)
        q_content = self.W_uq(c_q)  # (B, T, n_heads * d_h)
        q_rope = self.W_qr(c_q)  # (B, T, n_heads * d_rope)

        # RoPE用Key(全ヘッド共有、d_rope次元のみ)
        k_rope = self.W_kr(h)  # (B, T, d_rope)

        # 推論時はc_kvとk_ropeのみキャッシュ
        # 標準MHAの32,768要素に対し576要素のみ
        if kv_cache is not None:
            c_kv = torch.cat([kv_cache["c_kv"], c_kv], dim=1)
            k_rope = torch.cat([kv_cache["k_rope"], k_rope], dim=1)

        # Key/Valueを圧縮ベクトルから復元
        k_content = self.W_uk(c_kv)  # (B, T_full, n_heads * d_h)
        v = self.W_uv(c_kv)  # (B, T_full, n_heads * d_h)

        # Attention計算(簡略化、実際にはRoPE適用が必要)
        scale = math.sqrt(self.d_h + self.d_rope)
        # ... 標準的なscaled dot-product attention ...

        return h  # 簡略化

実装のポイント(Implementation)

RTX 3090(24GB VRAM)でMoEモデルを動かす際に、MLAの知見が直接活きるポイントを整理する。

KVキャッシュの削減効果: Zenn記事で扱うQwen3.5-35B-A3Bのコンテキスト長別VRAM消費が管理可能な範囲に収まるのは、MLA系の圧縮技術によるところが大きい。DeepSeek-V2の設計(512+64=576要素/トークン/レイヤー)は、Qwen3.5シリーズにも影響を与えていると考えられる。

行列吸収の制約: 論文の行列吸収トリックはFlash Attentionとの組み合わせに技術的な課題がある。吸収後のAttentionパターンはカスタムCUDAカーネルの実装が必要になる場合がある。

量子化との組み合わせ: MLAの圧縮ベクトル $\mathbf{c}_t^{KV}$ はさらにKVキャッシュ量子化(Q8_0等)と組み合わせ可能で、llama.cppの --cache-type-k q8_0 オプションと概念的に近い。

実験結果(Results)

ベースモデルベンチマーク

論文Table 3より、DeepSeek-V2(21Bアクティブ)と他モデルの比較を示す:

ベンチマークDeepSeek 67B (Dense)LLaMA-3 70B (Dense)Mixtral 8x22B (39B active)DeepSeek-V2 (21B active)
MMLU71.379.577.878.5
BBH68.781.078.978.9
MBPP (3-shot)57.168.671.275.1
HumanEval45.148.253.148.8
MATH18.730.042.543.6

著者らの報告によれば、わずか21Bアクティブパラメータで、67B〜72Bの Dense モデルに匹敵する性能を達成している。

効率性の定量比較

論文のTable 4およびセクション5.3より:

指標DeepSeek 67BDeepSeek-V2改善率
学習FLOPsベースライン-42.5%1.74倍効率
KVキャッシュベースライン-93.3%約15倍削減
最大生成スループット1x5.76x5.76倍高速

スループット改善の要因は、KVキャッシュ削減によるバッチサイズ拡大余地と、アクティブパラメータ削減による計算量の減少の組み合わせである。

実運用への応用(Practical Applications)

Zenn記事で扱うRTX 3090でのローカルLLM推論環境において、MLAとDeepSeekMoEの設計思想は以下の形で活用できる。

KVキャッシュ管理: RTX 3090の24GB VRAMのうち、モデル重み(Q4量子化で約19GB)を載せた残り約5GBでKVキャッシュを管理する必要がある。MLA的な圧縮がなければ、32Kコンテキストでさえ困難になりうる。Qwen3.5-35B-A3BがGQA(Grouped-Query Attention)を採用しているとすれば、MLAほどではないがKVキャッシュの削減が行われている。

MoEエキスパートのメモリ管理: DeepSeekMoEの「共有エキスパート + ルーティングエキスパート」パターンは、Qwen3.5-35B-A3B(3Bアクティブ)にも共通する設計哲学である。35Bの全重みはVRAMに載せつつ、トークンごとに3Bのみ計算することで高速推論を実現している。

スループットとバッチサイズのトレードオフ: DeepSeek-V2がKVキャッシュ削減で5.76倍のスループットを達成した知見は、ローカル推論でのバッチサイズ1でも「コンテキスト長を伸ばす余裕」として還元される。

関連研究(Related Work)

  • MQA / GQA (Shazeer 2019, Ainslie et al. 2023): KVヘッド数削減によるキャッシュ削減の先行手法。MLAはこれらと異なり低ランク圧縮アプローチを採用し、性能低下なくMQA並みのキャッシュ量を実現。
  • Mixtral (Jiang et al. 2024): 8x22B MoEモデル。DeepSeekMoEとは異なり粗粒度エキスパート(8個中2個選択)を採用しており、エキスパートの専門化度合いが異なる。
  • FlashAttention (Dao et al. 2022): メモリ効率の良いAttention計算。MLAの行列吸収トリックとFlash Attentionの組み合わせは技術的課題が残る。
  • YaRN (Peng et al. 2023): RoPEの位置埋め込み拡張。DeepSeek-V2は4K→128Kのコンテキスト拡張にYaRNを使用。

まとめと今後の展望

DeepSeek-V2は、MLAによるKVキャッシュの93.3%削減とDeepSeekMoEによる経済的な学習を両立した。著者らの報告によれば、21Bアクティブパラメータで67B Dense モデルを上回る性能を達成しており、「パラメータ効率の高いMoEモデルは、コンシューマGPUでの推論に適している」という方向性を示している。

この設計思想は後続のDeepSeek-V3やQwen3/3.5系列のMoEモデルに引き継がれており、RTX 3090のような24GB VRAMのGPUでMoEモデルを実用的に動かすための技術的基盤となっている。

参考文献


:::message 本記事はarXiv論文 2401.06066 の解説記事です。論文の主張・実験結果を正確に伝えることを目的としており、筆者自身が実験を行ったものではありません。内容の正確性については原論文をご確認ください。 :::

この投稿は CC BY 4.0 でライセンスされています。

NVIDIA解説: NVFP4 KV Cacheで長コンテキストLLM推論を最適化 — メモリ50%削減・TTFT 3倍高速化

論文解説: PowerInfer — コンシューマGPUでLLM推論を最大11.69倍高速化するCPU-GPUハイブリッドエンジン