推理架构基础:Transformer Decoder架构、自回归生成机制、KV Cache原理

聊大模型推理,绕不开这三个东西:Decoder架构、自回归生成、KV Cache。我刚开始接触推理优化时,觉得这些概念太理论了,直到亲手调过几个模型,才发现——不懂这些,你连性能瓶颈在哪都找不到。

1. Transformer Decoder架构:推理的“心脏”

大模型推理用的基本都是Decoder-only架构。说白了,就是只有解码器,没有编码器。GPT系列就是典型代表。

一个Decoder层长什么样?我画了张图,你一看就明白:

Transformer Decoder 单层结构 输入 Embedding Masked Multi-Head Self-Attention (带因果掩码) Add & LayerNorm Feed-Forward Network (FFN) 通常 4x 隐藏层维度 Add & LayerNorm 输出到下一层 关键点: • 只能看当前位置 及之前的位置 • 不能看到未来 token • 这就是自回归的基础

每个Decoder层就干三件事:

  • Masked Multi-Head Self-Attention:带因果掩码的自注意力。只能看当前位置及之前的位置,不能偷看未来的token。这是自回归生成的关键约束。
  • Add & LayerNorm:残差连接加层归一化。残差连接解决梯度消失,LayerNorm稳定训练。
  • Feed-Forward Network:两层全连接,中间通常放大4倍。比如GPT-3的隐藏层12288,FFN中间层就是49152。
  • 我的经验:实际推理时,FFN占了大部分计算量。我记得有一次调优,发现FFN的矩阵乘法占了70%的耗时。优化FFN往往比优化Attention更有效。

    2. 自回归生成机制:一个词一个词往外蹦

    自回归生成,说白了就是“用已经生成的词,预测下一个词”。每次只生成一个token,然后把新token拼到输入里,继续预测下一个。

    举个例子,生成“我爱北京天安门”:

    1. 输入“[BOS]”,预测“我”
    2. 输入“[BOS] 我”,预测“爱”
    3. 输入“[BOS] 我爱”,预测“北”
    4. 输入“[BOS] 我爱北”,预测“京”
    5. ……直到预测出“[EOS]”

    这个过程有什么问题?你想想看——每次都要重新计算前面所有token的注意力。假设生成了100个token,第100步就要计算100次注意力。复杂度是O(n²),n是序列长度。

    注意:我曾经踩过一个坑——以为自回归生成可以并行加速。实际上,自回归的每一步都依赖上一步的输出,这是天然的串行过程。你没法同时预测第5个和第6个词,因为第6个词依赖第5个词的结果。

    那怎么办?KV Cache就是来解决这个问题的。

    3. KV Cache原理:用空间换时间

    KV Cache的核心思想很简单:把之前计算过的Key和Value缓存起来,避免重复计算

    我画个图对比一下,你就懂了:

    有/无 KV Cache 的推理对比 无 KV Cache Step 1: 计算 Q1,K1,V1 Step 2: 重新计算 Q1,K1,V1 + Q2,K2,V2 Step 3: 重新计算 Q1,K1,V1 + Q2,K2,V2 + Q3,K3,V3 ... 每次都要重算前面的 K,V 复杂度 O(n²) 有 KV Cache Step 1: 计算 K1,V1,缓存 Step 2: 从缓存读 K1,V1,只算 K2,V2 Step 3: 从缓存读 K1,V1,K2,V2,只算 K3,V3 每次只算当前 token 的 K,V 复杂度 O(n) KV Cache 本质:用显存换算力

    具体怎么做的?我拆解一下:

    • Prefill阶段(也叫预填充阶段):处理输入的prompt,一次性计算所有token的K和V,存入缓存。这个阶段是并行的,速度快。
    • Decode阶段(也叫生成阶段):每次只生成一个token。从缓存中读取之前所有token的K和V,只计算当前token的Q,然后做注意力计算。生成完新token后,把它的K和V也加入缓存。

    KV Cache的大小怎么算?公式很简单:

    KV Cache大小 = 2 × 层数 × 隐藏层维度 × 序列长度 × 精度字节数
    
    举例:GPT-3 175B
    - 层数:96
    - 隐藏层维度:12288
    - 序列长度:2048
    - 精度:FP16(2字节)
    
    KV Cache = 2 × 96 × 12288 × 2048 × 2 = 9.66 GB

    关键数据:一个175B模型,单条请求的KV Cache就要近10GB显存。如果并发100条请求,光KV Cache就要1TB显存。这就是为什么大模型推理这么吃显存。

    4. 实际推理中的性能瓶颈

    了解了这些基础,我们来看看实际推理中哪里最慢:

    阶段 计算特点 瓶颈 占比(典型值)
    Prefill 并行计算,计算密集型 矩阵乘法(GEMM) 20-30%
    Decode 串行计算,访存密集型 KV Cache读写 + Attention 70-80%

    Prefill阶段虽然计算量大,但因为可以并行,GPU利用率高。Decode阶段才是真正的瓶颈——每次只算一个token,GPU利用率可能不到10%。

    我的建议:优化推理时,优先关注Decode阶段的访存优化。我曾经把一个模型的Decode速度提升了3倍,方法就是优化KV Cache的存储布局,减少显存碎片和带宽浪费。

    5. 避坑指南

    最后分享几个我踩过的坑:

    • KV Cache内存管理:我曾经没做内存预分配,每次生成新token都动态申请显存,结果频繁的cudaMalloc把推理速度拖慢了5倍。一定要预分配最大序列长度的缓存空间。
    • Batch推理时的KV Cache:不同请求的序列长度不一样,KV Cache大小也不同。我见过有人用padding对齐,结果浪费了大量显存。更好的做法是用动态batch,按实际长度分配。
    • 精度选择:FP16的KV Cache比FP32省一半显存,但精度损失可以忽略。我建议默认用FP16,显存紧张时可以用INT8量化。

    嗯,以上就是Transformer Decoder架构、自回归生成和KV Cache的核心内容。这些是推理优化的地基,后面讲的各种加速技术——比如FlashAttention、PageAttention、量化推理——都是在这个基础上做的优化。


    公众号:蓝海资料掘金营,微信deep3321