Transformer模型计算过程
自注意力的核心数学公式只有一行:
● Query (Q):代表“当前这个新词”想找什么。
● Key (K) 和 Value (V):代表“历史所有词”提供了什么线索。
➤ Q (Query):代表当前这个词“我想找什么”。
➤ K (Key):代表当前这个词“我能提供什么特征以供对照”。
➤ V (Value):代表当前这个词“我包含的实际核心内容是什么”。
以下是大模型在实际运行中,单次计算(以生成一个新词为例)的完整标准流水线:
一、 大模型单次推理的完整计算顺序
假设当前历史对话为“我想吃”(),模型正在解码(Decoding 阶段)准备输出第四个词“苹果”。
1. 线性投影与身份解耦(算新词 )
- 输入:上一步生成的最新词
“吃”的向量特征 。 - 动作:通过矩阵乘法,乘以三个可学习的权重参数矩阵:
- 结果:只算出了最新词的 ,此时历史词的 随用随扔,不参与计算。
2. 缓存更新与追加(KV Cache 拼接)
- 动作:将刚刚算出的 和 追加到显存中已有的 KV Cache 矩阵末尾。
- 结果:
- 变更为:
[词1的K, 词2的K, 词3的K, 词4的K],形状为 。 - 变更为:
[词1的V, 词2的V, 词3的V, 词4的V],形状为 。
3. 全局关联计算(点积与缩放)
- 动作:拿最新词的一行 乘以整个 的转置,并除以缩放因子 (防止方差过大导致梯度消失)。
- 矩阵变化:。
- 结果:算出了最新词对全句(包括对角线上它自己)的原始相关性得分向量。
4. 权重平滑归一化(Softmax 变换)
- 动作:进行硬件防溢出处理(各元素减去最大值 )后,执行 Row-wise Softmax。
- 结果:得到一行平滑、可导且相加严格等于 1 的注意力权重概率分布(例如
[0.1, 0.1, 0.1, 0.7],表示 70% 的注意力在自己身上)。
5. 特征加权聚合(打包带走)
- 动作:用这一行权重 去乘以完整的 。
- 结果:历史词的所有核心资产被按比例抽取,融合进这个全新的上下文特征向量 中。
6. 词表映射(算 Logits 分数)
- 动作:将 乘以上层全连接线性层权重 ,将其从特征空间映射到整个人类词表空间。
- 结果:词表里的每一个词(如“苹果”、“汽车”)都得到了一个未归一化的原始得分(Logits)。
7. 灵魂调节与概率生成(温度系数与采样)
- 温度干预:用 Logits 除以温度系数 。 小则放大差距、生成严谨; 大则熨平差距、充满创意。
- 最终预测:再次过一次 Softmax 得到各词语的最终被选概率。
- 摇号采样:如果是贪婪搜索则直接取最高分;如果是 Top-p/Top-k 随机采样,则在概率转盘上“摇号”蹦出最终的新词:
“苹果”。
二、 工业级加速与异常处理方案
在长文本或高并发的实际业务场景中,上述原生流水线会遭遇算力与显存的极限挑战。以下是对应的工业级解决方案:
1. 运行阶段的加速方案 (Prefill 与 Decoding 分离)
由于单次推理中,用户刚输入的阶段与蹦字阶段的性能瓶颈完全不同,现代引擎(如 vLLM, TensorRT-LLM)会进行架构拆分:
-
Prefill 阶段(预填充):
-
机制:用户 Prompt 输入后,不使用 KV Cache,而是利用因果掩码(Causal Mask)强行将 注意力矩阵的右上角抹为 0,实现整个输入序列的一次性全局并行预计算。
-
定位:计算密集型。专门交给算力强劲的流水线处理。
-
Decoding 阶段(解码):
-
机制:完美运行上述“一字一轮”的串行计算,全面依赖 KV Cache 将每步计算量从 降维到 的行向量。
-
底层硬件架构优化(GQA 分组查询):在模型设计时让多个 头共享一组 头,从源头上将 KV Cache 的常驻体积裁剪 4~8 倍。
2. 显存超限 (OOM) 异常处理方案
当上下文极长、显存即将被 KV Cache 撑爆时,系统会触发以下多级防御机制:
-
防御一级:虚拟内存页式管理 (PagedAttention)
-
做法:打碎连续显存的限制,将 KV Cache 像操作系统分页一样拆成固定大小的物理页块动态分配,彻底消除显存碎片,提升并发容纳率。
-
防御二级:量化压缩 (KV Cache Quantization)
-
做法:将原本 FP16(2字节)存储的 矩阵动态量化为 INT8(1字节)甚至 INT4(0.5字节),在几乎不损耗模型长文本理解力的情况下,让显存直接缩减到原来的 1/2 至 1/4。
-
防御三级:长期对话的流式驱逐 (StreamingLLM)
-
做法:针对无限轮次的对话,在缓存中死守开头凝聚巨大注意力的“注意力汇(Attention Sinks)”,同时开启滑动窗口。随着新词进来,自动把最老、且不是开头的 KV 缓存从显存中驱逐丢弃,确保显存永远恒定,杜绝长文本崩溃。
-
防御四级:空间换成功的内存兜底 (Offloading)
-
做法:当 GPU 显存彻底见底,推理引擎通过 PCIe 总线将久未使用的 KV Cache 临时置换卸载到主机的 CPU 系统内存 或 NVMe SSD 中。虽然带来了传输延迟,但保证了超长上下文任务的“绝对死不断线”。
在大模型的整个生命周期中,训练(Training)和推理(Inference)有着本质的区别。
推理是“一字一字往外蹦”的串行复仇记;而训练则是“上帝视角”的全局并行大合唱。在训练时,我们手头已经有了完整的标准答案(比如一整篇网文、一本书或一段对话),我们不需要、也绝对不用 KV Cache,而是利用因果掩码(Causal Mask)实现整句话的并行计算和梯度回传。
以下是大模型在训练时,单次迭代(One Forward & Backward Pass)的完整计算全景:
一、 前向传播阶段:完全并行的“并行计算”
假设我们的训练样本是一句话:“我想吃苹果”(一共 5 个 Token,序列长度 )。
1. 词嵌入与位置编码 (Embedding)
- 动作:5 个词同时被送入模型。首先通过词表转换成 5 个一维稠密向量,再加上位置编码(Positional Encoding),组合成一个完整的输入矩阵 。
- 矩阵形状:(5 行,每行代表一个词的初始特征)。
2. 算齐所有的 Q、K、V(矩阵大合唱)
在训练时,GPU 发挥其恐怖的矩阵并行能力,拿整个 (5行)直接去乘以三个权重矩阵 :
- 重点:这里一步到位,算出了所有词在所有位置的 。
3. 计算全员关联方阵(点积与缩放)
- 动作:让整个 矩阵乘以 的转置 ,并除以 。
- 矩阵形状: 的方阵。
- 物理意义:这个 的矩阵,算出了这 5 个词两两之间所有的关联分数(包含过去看现在、现在看未来、现在看现在)。
4. 引入因果掩码(Causal Mask)—— 防止作弊
因为我们在训练模型预测下一个词,绝对不能让前面的词提前看到后面的词(不能让“我”看到后面的“吃”和“苹果”)。
- 动作:引入一个 的上三角掩码矩阵,右上角全为 。将其加到刚刚算出的 矩阵上。
- 矩阵效果:
5. 平滑归一化与特征聚合 (Softmax & V)
- Softmax:对上述矩阵进行按行(Row-wise)Softmax。因为右上角是 ,经过指数化后全变成了 0。这在数学上完美实现了“只有过去的词和自己能拥有注意力,未来的词权重为0”。
- 乘以 V:
- 成果:我们得到了一个 的输出矩阵 。它的第 1 行只融合了
“我”的特征;第 3 行融合了“我、想、吃”三个词的特征。整个句子的上下文特征被一次性全部并行抽完。
6. 计算损失(Loss Computation)
-
动作:将 映射到词表空间得到所有位置的 Logits。接下来,模型要同时做 5 个预测任务,并与标准答案对比:
-
拿着第 1 行(输入是“我”)去预测下一个词,看是不是“想”。
-
拿着第 3 行(输入是“我想吃”)去预测下一个词,看是不是“苹果”。
-
算总账:通过交叉熵损失函数(Cross-Entropy Loss),把这 5 个预测结果和真实标签计算出一个综合总损失(Loss)值。
二、 反向传播阶段:误差倒推与参数洗练
有了总 Loss 之后,训练最核心的魔术——反向传播(Backpropagation) 开始启动。GPU 要沿着前向传播的逆方向,利用微积分链式法则把误差传回源头。
1. 第一步:误差传回注意力层输出 ()
优化器从最终的 Loss 出发,首先算出门户线性层和词表映射层的导数,将误差信号推回到注意力机制的输出矩阵 ,得到梯度矩阵 (形状为 )。
2. 第二步:穿过特征聚合(对 和 求导)
因为前向是 ,逆向时:
- 对注意力权重 的梯度:
- 对语义资产 的梯度:
- 物理意义:模型在排查责任。如果某处的预测大错特错,说明当时分配的注意力权重 或者提取的特征 问题很大,这部分就会收到极高强度的修正信号。
3. 第三步:逆穿 Softmax 与掩码区
将梯度 传回 Softmax 的输入矩阵 。
- 神奇之处:因为前向传播时,右上角被掩码强行抹成了 0(不参与计算),所以在反向传播时,右上角那一半矩阵的梯度也全部是 0!这意味着未来的信息不仅在前向时被屏蔽,在反向时也完全无法对过去的参数产生任何污染和影响。
4. 第四步:推导源头参数梯度(对 求导)
通过链式法则继续往前推,穿过点积,最终计算出大模型真正的核心资产——那三个可学习权重矩阵的精确梯度:
5. 第五步:参数更新(梯度下降)
这时候,优化器(如 AdamW)拿着这三个热乎的梯度矩阵,对现有的参数进行微调:
三、 为什么训练不需要 KV Cache?(总结对比)
学完训练的全过程后,你可以非常清晰地看出它们两者的本质区别:
- 推理时(Decoding):我们没有未来,句子是一个字一个字动态变长的。为了不重复计算历史,我们必须搞一个 KV Cache 把过去的资产存起来,每一步只算最新的一行。
- 训练时(Training):我们掌控未来,整句话都在手里。我们利用 Causal Mask 矩阵在数学上直接切出了一个左下三角形,实现了全句 Token 的一次性并行输入、一次性并行计算、一次性并行回传。所以,训练过程不需要、也根本用不上 KV Cache。
- 点赞
- 收藏
- 关注作者
评论(0)