AIFAQ

AI/ML 常见问题知识库

⌘K
标签筛选
排序:

84 条,第 1/5

Decoupled RoPE 将 Cache 拆为 content 和 position 两部分:

Cachet=[ctKV,ktrope]\text{Cache}_t = [c_t^{KV}, k_t^{rope}]

每 token 每层存储元素数 =dc+drope= d_c + d_{rope}

代入 DeepSeek-V2 参数(dc=512,drope=64,dmodel=5120d_c=512, d_{rope}=64, d_{model}=5120):

  • 纯 MLA(无 RoPE):512512 元素
  • Decoupled RoPE MLA:512+64=576512 + 64 = 576 元素
  • 增量:64512=12.5%\frac{64}{512} = 12.5\%

相对 MHA 的压缩比推导:

MHA=2×dmodel=2×5120=10240 元素\text{MHA} = 2 \times d_{model} = 2 \times 5120 = 10240 \text{ 元素}

Decoupled RoPE MLA=576 元素\text{Decoupled RoPE MLA} = 576 \text{ 元素}

压缩比=1024057617.8×\text{压缩比} = \frac{10240}{576} \approx 17.8\times

对比纯 MLA 的 20×20\times10240512\frac{10240}{512}),引入 RoPE 后压缩比从 20×20\times 降到 17.8×17.8\times,代价很小,换来了完整的相对位置编码能力。跨所有层(60 层)的每 token 总存储为 576×60×2 bytes=67.5 KB576 \times 60 \times 2 \text{ bytes} = 67.5 \text{ KB},远小于 MHA 的 1.2 MB。

参考来源

Tcompute(BS)=Tmemory(BS)T_{compute}(BS) = T_{memory}(BS)

tcBS=CkvBWBS+WBWt_c \cdot BS = \frac{C_{kv}}{BW} \cdot BS + \frac{W}{BW}

移项,将 BS 提出:

BS(tcCkvBW)=WBWBS \cdot \left(t_c - \frac{C_{kv}}{BW}\right) = \frac{W}{BW}

解出交叉点:

BS=W/BWtcCkv/BWBS^* = \frac{W / BW}{t_c - C_{kv} / BW}

前提条件:tc>CkvBWt_c > \frac{C_{kv}}{BW}(计算斜率 > 搬运斜率),否则两线发散,无交叉点。

代入 MQA + A6000 参数(Ckv=64MB,BW=768GB/s,W=13.5GB,tc=0.09msC_{kv}=64\text{MB}, BW=768\text{GB/s}, W=13.5\text{GB}, t_c=0.09\text{ms}):

a=64×103768=0.083 msa = \frac{64 \times 10^{-3}}{768} = 0.083 \text{ ms}

tca=0.090.083=0.007 mst_c - a = 0.09 - 0.083 = 0.007 \text{ ms}

b=WBW=13.5768×1000=17.58 msb = \frac{W}{BW} = \frac{13.5}{768} \times 1000 = 17.58 \text{ ms}

BS=17.580.0072511BS^* = \frac{17.58}{0.007} \approx 2511

BS2511BS \approx 2511 时两线交叉。但 seq=4096 时 MQA 单请求 KV Cache 为 64MB,2511×64MB157GB2511 \times 64\text{MB} \approx 157\text{GB},远超 A6000 的 48GB 显存,所以这个交叉点在当前硬件上不可达。这也说明了为什么 MQA/GQA 路线在实际场景中很难真正翻转到 Compute Bound。

Up-Projection 需要将 LL 个 latent vector 还原为 K 和 V,各做一次矩阵乘法([L,dc]×[dc,dmodel][L, d_c] \times [d_c, d_{model}]),每次 FLOPs=2×L×dc×dmodel\text{FLOPs} = 2 \times L \times d_c \times d_{model}。K 和 V 共两次,总 FLOPs:

FLOPsUP=2×(2×L×dc×dmodel)=4×L×dc×dmodel\text{FLOPs}_{UP} = 2 \times (2 \times L \times d_c \times d_{model}) = 4 \times L \times d_c \times d_{model}

代入参数(L=4096,dc=512,dmodel=4096L=4096, d_c=512, d_{model}=4096):

4×4096×512×409634.4 GFLOPs4 \times 4096 \times 512 \times 4096 \approx 34.4 \text{ GFLOPs}

在 A6000(155 TFLOPS)上的计算时间:

34.4×109155×10120.222 ms\frac{34.4 \times 10^9}{155 \times 10^{12}} \approx 0.222 \text{ ms}

而 MHA 搬运完整 KV Cache(单层 64MB)的时间:

64×106768×1090.083 ms\frac{64 \times 10^6}{768 \times 10^9} \approx 0.083 \text{ ms}

0.222ms>0.083ms0.222\text{ms} > 0.083\text{ms},直接解压反而比 MHA 搬完整 KV 还慢。这就是为什么必须用矩阵吸收跳过 Up-Projection,否则"以算换存"是亏的。

各方案单层每 token 的 KV Cache 元素数推导:

  • MHA:K 和 V 各 nh×dh=dmodeln_h \times d_h = d_{model} 维,共 2×dmodel2 \times d_{model}
  • GQA-g:K 和 V 各 nkv×dhn_{kv} \times d_h 维,共 2×nkv×dh2 \times n_{kv} \times d_h
  • MQA:K 和 V 各 1×dh1 \times d_h 维,共 2×dh2 \times d_h
  • MLA:只存一个 latent vector,共 dcd_c

代入 LlaMA-2-7B(nh=32,dh=128,dmodel=4096,dc=512n_h=32, d_h=128, d_{model}=4096, d_c=512):

  • MHA:2×4096=81922 \times 4096 = 8192(基准 1×)
  • GQA-8:2×8×128=20482 \times 8 \times 128 = 2048,压缩比 =8192/2048=4×= 8192/2048 = 4\times
  • MQA:2×128=2562 \times 128 = 256,压缩比 =8192/256=32×= 8192/256 = 32\times
  • MLA:512512,压缩比 =8192/512=16×= 8192/512 = 16\times

MLA 的 16×16\times 介于 GQA-8(4×4\times)和 MQA(32×32\times)之间,但不砍 head 数,保留全部表达能力。

加上 RoPE 后,Score 展开为 xmTWQRmTRnWUKTcnKVx_m^T \cdot W_Q \cdot R_m^T \cdot R_n \cdot W_{UK}^T \cdot c_n^{KV}。位置相关的 RnmR_{n-m}=RmTRn= R_m^T \cdot R_n)卡在 WQW_QWUKTW_{UK}^T 中间,由于矩阵乘法不满足交换律,无法将 RnmR_{n-m} 挪开,也就无法合并 WQW_QWUKTW_{UK}^T 为固定的 WQW_Q'

Decoupled RoPE 的解决思路:将 Q 和 K 各拆为两部分——Content 部分走 MLA 压缩 + 矩阵吸收(不含位置信息),RoPE 部分单独存储(drope=64d_{rope}=64,不压缩)。最终 Score=QcontentKcontentT+QropeKropeT\text{Score} = Q_{content} \cdot K_{content}^T + Q_{rope} \cdot K_{rope}^T,向量拼接后内积天然等于分段内积之和,交叉项在数学上直接消失。每 token 每层存储 dc+droped_c + d_{rope} 个元素,额外开销仅 12.5%(64512\frac{64}{512})。

参考来源

矩阵吸收后,MLA 的计算量 FLOPs4×nh×L×dc\text{FLOPs} \approx 4 \times n_h \times L \times d_c,搬运量 BytesL×dc×2\text{Bytes} \approx L \times d_c \times 2。令计算时间 > 搬运时间:

4×nh×L×dcPeak Compute>dc×L×2Bandwidth\frac{4 \times n_h \times L \times d_c}{\text{Peak Compute}} > \frac{d_c \times L \times 2}{\text{Bandwidth}}

约掉 LLdcd_c,得到:

nh>Peak Compute×24×Bandwidthn_h > \frac{\text{Peak Compute} \times 2}{4 \times \text{Bandwidth}}

代入 A6000 参数:

nh>155×1012×24×768×109=310T3072G101n_h > \frac{155 \times 10^{12} \times 2}{4 \times 768 \times 10^9} = \frac{310T}{3072G} \approx 101

LlaMA-2-7B 的 nh=32n_h=32 远不够。DeepSeek-V2 的 nh=128n_h=128 超过阈值,其 MLA Attention 层计算时间(6.9μs)首次超过搬运时间(5.2μs),实现了 Compute Bound 翻转。head 数量直接决定了 MLA 能否翻转瓶颈。

原始计算路径(单 head):QKT=(xWQ)(cKVWUK)TQ \cdot K^T = (x \cdot W_Q) \cdot (c^{KV} \cdot W_{UK})^T。展开转置得 (xWQ)WUKT(cKV)T(x \cdot W_Q) \cdot W_{UK}^T \cdot (c^{KV})^T,利用矩阵结合律重新分组:x(WQWUKT)(cKV)Tx \cdot (W_Q \cdot W_{UK}^T) \cdot (c^{KV})^T。由于 WQW_QWUKW_{UK} 都是固定权重,可以在模型加载时预计算 WQ=WQWUKTRdmodel×dcW_Q' = W_Q \cdot W_{UK}^T \in \mathbb{R}^{d_{model} \times d_c},推理时直接用 Q=xWQQ' = x \cdot W_Q'cKVc^{KV} 做点积。V 侧同理,将 WUVW_{UV} 吸收进输出投影 WOW_O。这样 Attention 直接在 dcd_c 维的 latent space 计算,完全跳过了 Up-Projection。代价是每个 head 的 Attention 维度从 dhd_h(128)变为 dcd_c(512),计算量增大约 4 倍,但搬运量减少 16 倍,净效果是大幅加速。

既然 GPU 算力严重闲置(Memory Bound),就主动增加计算量来换取更小的传输量。具体做法:存储时,用 Down-Projection 矩阵 WDKVW_{DKV} 将 KV 压缩成低维的 latent vector cKVRdcc^{KV} \in \mathbb{R}^{d_c}dcdmodeld_c \ll d_{model}),压缩公式为 ctKV=xtWDKVc_t^{KV} = x_t \cdot W_{DKV},维度从 [1,dmodel][1, d_{model}] 变为 [1,dc][1, d_c];推理时,用闲置算力通过 Up-Projection 将 latent vector 解压回完整的 K/V。只要解压计算时间 < 节省的搬运时间,就是净赚。与 MQA/GQA 的"有损砍头"不同,MLA 是低秩压缩,保留了全部 head 的表达能力。

参考来源

关键在于斜率比较。计算时间的斜率 tc0.09mst_c \approx 0.09\text{ms},而搬运时间的斜率取决于单请求 KV Cache 大小:MHA 为 2.604ms2.604\text{ms},GQA-8 为 0.667ms0.667\text{ms},MQA 为 0.083ms0.083\text{ms}。只有当搬运斜率 < 计算斜率时,两条线才会相交(翻转到 Compute Bound)。MHA 和 GQA 的搬运斜率远大于计算斜率,随 BS 增大两条线是发散的;只有 MQA 的斜率(0.083ms0.083\text{ms})低于计算斜率(0.09ms0.09\text{ms}),理论交叉点约在 BS2500BS \approx 2500,但受限于显存容量和上下文长度,实际很难达到。

搬运时间 Tmemory(BS)=CkvBWBS+WBWT_{memory}(BS) = \frac{C_{kv}}{BW} \cdot BS + \frac{W}{BW}。截距 b=WBWb = \frac{W}{BW}(如 13.5GB768GB/s17.6ms\frac{13.5\text{GB}}{768\text{GB/s}} \approx 17.6\text{ms})代表模型权重的搬运时间,这部分不随 BS 变化——不管 BS 是 1 还是 100,模型权重只搬一次。而计算时间 Tcompute(BS)=tcBST_{compute}(BS) = t_c \cdot BS 是过原点的正比例函数。BS 越大,权重搬运的固定开销被均摊到每个请求上的份额越小,这就是提升 BS 能缩小计算和搬运差距的原因。

因为模型权重(约 13.5GB)是搬运量的大头。KV Cache 从 2GB 压到 0.5GB,只减少了 1.5GB,但总搬运量从 15.5GB 降到 14GB,被 13.5GB 的权重"稀释"了。这说明在 BS=1 时,单纯压缩 KV Cache 对端到端延迟的改善有限,真正的收益在于:压缩后省下的显存和带宽可以用来增大 Batch Size,从而提高整体吞吐量。

(1) 变量定义:引入 num_kv_heads 参数,MHA 时等于 num_heads,GQA 时小于 num_heads,MQA 时为 1。(2) 线性层维度:K/V 投影的输出维度从 num_heads × head_dim 缩小为 num_kv_heads × head_dim,投影矩阵变小。(3) 前向传播:因为 Q 和 KV 头数不匹配,需要通过 expand + reshape 将 KV 复制/广播到与 Q 相同的头数,才能进行批量矩阵乘法。通过 config.json 中 num_attention_heads 和 num_key_value_heads 的对比即可判断使用的是哪种 Attention。

MQA 让所有 Query Head 共享同一组 KV Head(nkv=1n_{kv}=1),KV Cache 直接减少 nhn_h 倍(如 32 倍);GQA 将 Query Head 分组,每组共享一组 KV Head(如 nkv=8n_{kv}=8),KV Cache 减少 nh/nkvn_h/n_{kv} 倍(如 4 倍)。代价是模型质量的有损下降——MQA 压缩最激进但质量损失最大,GQA 在压缩比和质量之间取得平衡,是目前主流方案。本质上都是"有损压缩",通过砍 KV Head 来减少缓存和搬运量。

Prefill 阶段输入是完整序列矩阵 XRL×dX \in \mathbb{R}^{L \times d},投影后得到 Q/K/V 都是矩阵,Score=Q×KT\text{Score} = Q \times K^T 是矩阵乘矩阵(GEMM),可以充分利用 GPU 并行计算。Decoding 阶段每次只输入一个新 token 的向量 xtR1×dx_t \in \mathbb{R}^{1 \times d},投影后得到的 qtq_t 是行向量,Score=qt×KcacheT\text{Score} = q_t \times K_{cache}^T 是向量乘矩阵(GEMV),计算量大幅减少,但也意味着 GPU 算力严重闲置,瓶颈转移到数据搬运上。

用排除法分析公式 Size=2×nlayers×nheads×dhead×Pprecision\text{Size} = 2 \times n_{layers} \times n_{heads} \times d_{head} \times P_{precision}:2 是 K/V 两个矩阵的物理定义,不可改;nlayersn_{layers} 决定模型深度和推理能力,砍了会降智;dheadd_{head} 决定每个头的特征容量,通常为 128,砍了严重影响质量;PprecisionP_{precision} 是量化方向,可以叠加但属于另一条优化路线。只有 nheadsn_{heads}(KV 头数)可以在不根本改变模型架构的前提下大幅减少,这就是 MQA/GQA 的出发点。

内存墙是指 Decoding 阶段搬运数据(模型权重 + KV Cache)的时间远大于实际计算时间,GPU 计算单元大部分时间在等数据。以 LlaMA-2-7B 在 A100 上为例,搬运 15GB 数据需要约 7.5ms,而计算只需约 0.04ms,差距约 187 倍。延迟近似公式为 LatencyModel Weights+KV Cache SizeMemory Bandwidth\text{Latency} \approx \frac{\text{Model Weights} + \text{KV Cache Size}}{\text{Memory Bandwidth}},瓶颈完全在带宽而非算力。

生成第 tt 个 token 时,需要重新计算前 t1t-1 个 token 的 K 和 V。总计算量为 1+2+3++(N1)=N(N1)21+2+3+\dots+(N-1) = \frac{N(N-1)}{2},即 O(N2)O(N^2)。例如生成第 4096 个 token 时,要为这 1 个新 token 重新计算前 4095 个 token 的 K 和 V,而这些值在之前的步骤中已经算过了。KV Cache 通过缓存历史 K/V 将每步的增量计算降为 O(1)O(1),总复杂度降为 O(N)O(N)

Decoding 阶段的输入是单个 token 的 embedding 向量,经过线性投影后得到的是向量 q(而非矩阵 Q),这个 q 只用于当前步的注意力计算,不参与后续任何步骤的计算。而 K 和 V 需要被所有后续 token 的 q 访问,因此必须缓存。简言之,Q 是"一次性消费品",K/V 是"持续被引用的资产"。

Prefill 阶段处理完整输入序列,执行矩阵-矩阵乘法(GEMM),是 Compute Bound;Decoding 阶段每次只处理一个新 token,执行矩阵-向量乘法(GEMV),是 Memory Bound。Prefill 并行计算所有 token 的 Q/K/V 并生成完整的 [b, h, L, L] 注意力分数矩阵,而 Decoding 只需计算当前 token 的 q 向量与历史 K/V 的交互,计算量大幅减少,但瓶颈转移到了数据搬运上。

计算效率和任务特化。BERT 的 Encoder 架构可以并行处理整个文本,瞬间完成分析,速度和资源消耗远低于需要逐词生成的 GPT。对于信息抽取、情感分析、文本分类等纯"理解"任务,微调多个专精 BERT 模型是高效方案。实际工程中常见做法:用微调 BERT 做垂类初步分类筛选(取 logits 置信度),只有低置信度的才交给大模型处理,兼顾效率和效果。

84 条,第 1/5