大模型推理基础:Transformer架构、自回归生成、推理阶段划分
要理解大模型推理服务的吞吐优化,首先必须回到模型本身的工作原理。当前主流的大语言模型(如GPT系列、Llama、Qwen等)几乎都基于 Transformer 解码器架构,其推理过程与传统的深度学习模型(如CNN分类、BERT编码)有本质区别。吞吐优化的每一项技术——KV Cache、连续批处理、投机采样、张量并行——都源于Transformer推理的两个核心特征:自回归生成与两阶段计算。本节将拆解这三个基础概念,为后续优化策略建立认知框架。
2.1 Transformer解码器架构:从输入到输出的数据流
现代大语言模型的主体是堆叠的 Transformer 解码器层。每一层包含两个核心子模块:自注意力(Self-Attention) 和 前馈网络(FFN)。自注意力负责捕捉序列中token之间的依赖关系,FFN则对每个token的位置独立进行非线性变换。此外,层归一化(LayerNorm)和残差连接贯穿其中,保证深层网络训练的稳定性。
以一次完整的前向传播为例,输入是一段已分词并映射为嵌入向量的token序列,数据流如下:
- 输入嵌入(
Input Embedding)加上位置编码(Positional Encoding),得到初始隐状态。 - 依次通过
L个解码器层。每层内部:先做自注意力(对当前序列所有token两两计算注意力权重),再做FFN(对每个token独立做两次线性变换加激活函数)。 - 最后一层输出经过归一化后,通过一个 语言模型头(LM Head)(通常是一个线性层,权重与输入嵌入共享),将隐状态映射为词表大小的 logits 向量。
- 对 logits 做 softmax 得到概率分布,再通过采样策略(如贪心、top-k、top-p)选出下一个token。
下图展示了单次前向传播中,一个解码器层内部的计算流程以及多层的堆叠关系:
从上图可以看到,自注意力的计算复杂度是 O(N²·d)(N为序列长度),而FFN的复杂度是 O(N·d²)。当序列变长时,注意力部分会逐渐成为瓶颈。更重要的是,注意力计算中 Q·Kᵀ 的结果需要与 V 相乘,而 K 和 V 是序列中所有历史token的键值向量——这为后续的 KV Cache 优化埋下了伏笔。
2.2 自回归生成:逐token的迭代过程
大语言模型的文本生成采用 自回归(Autoregressive) 方式:模型在每一步只预测 一个 下一个token,然后将该token拼接到输入序列末尾,作为下一步的输入,如此循环直到生成结束符(EOS)或达到最大长度。这意味着生成一个长度为 T 的句子,需要执行 T 次完整的前向传播。
以用户输入“请介绍一下Transformer”为例,生成过程如下:
第1步: 输入 = [请, 介绍, 一下, Transformer] → 预测下一个token: 的
第2步: 输入 = [请, 介绍, 一下, Transformer, 的] → 预测下一个token: 核心
第3步: 输入 = [请, 介绍, 一下, Transformer, 的, 核心] → 预测下一个token: 思想
...
第T步: 输入 = [..., 思想] → 预测下一个token: [EOS](结束)
这种串行依赖关系决定了推理延迟的下限:生成第 t 个token必须等待前 t-1 个token全部生成完毕。从吞吐优化的角度看,自回归生成带来两个关键挑战:
- 内存带宽瓶颈:每一步都需要读取模型全部参数(动辄数十GB),但只计算一个token,计算与访存比极低。
- 无法并行处理序列内部:不同于训练阶段可以并行处理整个序列,推理时序列内部存在严格的时间依赖。
然而,自回归生成也带来了一个重要的优化机会:每一步的输入只比上一步多一个token。对于已经计算过的前 t-1 个token,它们的 K 和 V 向量在每一步都被重复计算——这显然是巨大的浪费。KV Cache 正是针对这一点的缓存优化,我们将在后续章节详细展开。
2.3 推理阶段划分:Prefill 与 Decode
一次完整的推理请求可以清晰地划分为两个计算特征截然不同的阶段:
| 对比维度 | Prefill(预填充) | Decode(解码) |
|---|---|---|
| 处理内容 | 处理完整的输入提示(Prompt) | 逐token生成输出 |
| 计算模式 | 并行处理所有输入token | 串行处理,每次仅1个token |
| 计算特点 | 计算密集(Compute-bound) | 访存密集(Memory-bound) |
| GPU利用率 | 高(矩阵乘大,并行度高) | 低(矩阵乘小,带宽受限) |
| 耗时占比 | 短(通常<10%总时间) | 长(通常>90%总时间) |
| KV Cache | 生成并存储所有输入token的K/V | 读取已有K/V,追加新token的K/V |
用一个具体案例来说明:假设用户输入提示词长度为 P=100,期望生成 O=200 个token。
- Prefill 阶段:一次前向传播,并行处理100个token,计算量约为
2·P·d·L。此阶段GPU的矩阵乘单元被充分利用,计算吞吐接近峰值。 - Decode 阶段:需要循环200次,每次只处理1个token。每次前向传播的计算量仅为
2·1·d·L,但需要从显存中读取全部模型权重(例如70B模型需要读取140GB)。此时GPU的计算单元大量空闲,瓶颈在于显存带宽。
下图直观展示了两个阶段在时间轴上的计算负载差异:
理解这两个阶段的差异是吞吐优化的分水岭。例如:
- Prefill 阶段的优化重点是提高矩阵乘法的计算效率(如使用更高效的FlashAttention、减少padding浪费)。
- Decode 阶段的优化重点是减少显存读取次数(如KV Cache、算子融合)和提高批处理大小(如连续批处理)。
2.4 常见误区与复盘
误区一:认为推理瓶颈是“计算量太大”
很多初学者以为大模型推理慢是因为FLOPs太高。实际上,在Decode阶段,单次前向传播的FLOPs很低(只处理1个token),但需要从HBM中读取全部权重。以A100 80GB为例,其HBM带宽约2TB/s,读取70B模型(140GB)就需要约70ms,而实际计算只需几ms。因此Decode阶段是访存受限,而非计算受限。
误区二:忽略Prefill与Decode的切换开销
在实际推理服务中,Prefill和Decode往往交错进行(多个请求并发)。频繁在两种模式间切换会带来额外的调度开销和GPU流水线气泡。这也是为什么现代推理框架(如vLLM、TensorRT-LLM)会采用分块Prefill或动态批处理来平滑两种阶段的切换。
复盘:从架构看优化空间
回顾Transformer的每一层结构,我们可以梳理出推理优化的几个抓手:
- 自注意力中的K/V重复计算 → KV Cache(减少90%以上的重复计算)
- Decode阶段访存密集 → 增大Batch Size(分摊权重读取成本)
- Prefill阶段计算密集 → FlashAttention(减少HBM访问)
- 自回归的串行依赖 → 投机采样(用小模型并行猜测多个token)