ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

238、【AI】【模型部署】基座模型研究:前向传播

238、【AI】【模型部署】基座模型研究:前向传播 【声明】本博客所有内容均为个人业余时间创作所述技术案例均来自公开开源项目如GithubApache基金会不涉及任何企业机密或未公开技术如有侵权请联系删除标题238、【AI】【模型部署】基座模型研究前向传播背景上篇 blog【AI】【模型部署】基座模型研究反向传播把损失如何摊回参数讲透了反向传播的数学内核是链式法则chain rule在**计算图computational graph**上从损失往回走逐节点用上游梯度 × 本节点局部导数求出每个参数的梯度它是一个参数的敏感度∂ L / ∂ w \partial L/\partial w∂L/∂wloss.backward()负责把梯度填进每个参数的.grad再由opt.step()按随机梯度下降Stochastic Gradient DescentSGD或 AdamW 更新softmax 与交叉熵组合后对 logits 的梯度恰好是p − y p-yp−y深层网络还要靠梯度裁剪与 warmup 保持稳定。但整条链路里有一个被默认对了的前提反向之所以能开始是因为前向已经算出了预测和一个标量损失L LL。上篇反复出现前向算数值、反向算梯度却始终没有把前向单独讲清。本篇补上这一环。模型部署把训练收敛成一句话是前向得到预测、交叉熵算出错了多少、反向分摊误差、优化器更新权重循环往复。其中最先发生、也最少被单独拿出来讲的就是前向传播forward propagation。这篇回答三件事前向在算什么、它已知什么、以及它到底出现在训练还是推理。前向传播是什么给定输入和当前参数模型从第一层一路算到最后一层得到预测与损失——这个过程就是前向传播。一句话概括前向就是把模型跑一遍全程只有加减乘除这类数值运算不涉及求导。它出现的场景比直觉中多推理生成回答、打标签时只做前向训练时前向是每个迭代的第一步后面才接反向与更新。换句话说前向是训练与推理共用的那一段。前向流水线从 token id 一路算到损失以第 231 篇的微型模型为例前向的主干是一串首尾相接的节点图 1 把这条流水线画全了token id → 嵌入 → N×Block → 归一化 → 输出头 → logits → softmax → 交叉熵 → loss。其中阶段输入输出作用嵌入token id( B , S ) (B,S)(B,S)向量( B , S , d ) (B,S,d)(B,S,d)把离散 id 查表成向量Block ×N向量( B , S , d ) (B,S,d)(B,S,d)向量( B , S , d ) (B,S,d)(B,S,d)反复混合、变换信息输出头向量( B , S , d ) (B,S,d)(B,S,d)logits( B , S , V ) (B,S,V)(B,S,V)映射到词表维softmaxlogits概率( B , S , V ) (B,S,V)(B,S,V)归一化成概率交叉熵概率 标签标量 loss汇总错了多少logits 到底是什么前向最后一层吐出的是logits——一组未归一化的分数。它有两个关键特征不是概率取值可以是负数也不会求和为 1形状是( B , S , V ) (B,S,V)(B,S,V)批大小 × 序列长度 × 词表大小即每个位置、每个候选 token 各一个分数。为什么不直接输出概率因为模型内部做的是一堆线性映射矩阵乘加输出任意实数最自然而非负且和为 1这种约束交给下一步的 softmax 统一处理更干净。可以粗略理解为logits 是原始打分softmax 才是把打分变成概率。softmax把 logits 变成概率softmax 把每个位置的V VV个 logits 变成一组概率Q i e z i ∑ j e z j Q_i \frac{e^{z_i}}{\sum_j e^{z_j}}Qi​∑j​ezj​ezi​​它保证概率非负、和为 1并且保持大小顺序分数高的 token 概率也高。这里有一个常被忽略的性质softmax 只关心 logits 之间的差——所有z zz同加一个常数输出不变。这个性质正好解释了两件事一是数值实现里要减去最大值再做指数避免溢出二是第 236 篇讲的温度——把 logits 除以T TT相当于放大或缩小它们的差距T 1 T1T1更尖、T 1 T1T1更平本质就是在调这组差。loss 怎么算前向的终点前向的最后一个节点是损失。以语言模型的 next-token 预测为例真实标签是 one-hot交叉熵退化为给正确 token 的概率取负对数loss − log ⁡ Q ( 正确 token ) \text{loss} -\log Q(\text{正确 token})loss−logQ(正确token)这一步在第 235 篇已经完整展开信息量、ln ⁡ V \ln VlnV基线、困惑度、F.cross_entropy的内部实现。这里只需记住一点loss 是一个标量是整个模型在这一步错了多少的唯一汇总数——它也正是反向传播的起点。loss 和 KL 散度是不是一回事这是一个高频疑问。简答相关但不是同一个量。交叉熵可以拆成两部分H ( P , Q ) H ( P ) K L ( P ∥ Q ) H(P,Q) H(P) \mathrm{KL}(P\|Q)H(P,Q)H(P)KL(P∥Q)第一项H ( P ) H(P)H(P)是真实分布自身的熵与模型无关第二项K L ( P ∥ Q ) \mathrm{KL}(P\|Q)KL(P∥Q)才是预测偏离真实的部分。当真实分布P PP固定时H ( P ) H(P)H(P)是常数于是最小化交叉熵就等价于最小化 KL 散度——但它们并不相等交叉熵比 KL 多了一个H ( P ) H(P)H(P)。这一点后面会有专文展开并与数学系列的《信息论》互相印证。三阶段对照前向 / 反向 / 更新把一次训练迭代拆成三阶段各自已知什么、算什么就一目了然阶段已知算产出前向输入x xx、参数W , b W,bW,b、目标t ttlogits、概率p pp、损失L LL标量L LL 中间激活缓存反向前向缓存的中间值 损失L LL每个参数的梯度∂ L / ∂ W \partial L/\partial W∂L/∂W各参数的.grad更新梯度 学习率新参数更新后的W , b W,bW,b图 2 强调了这个分界前向只算数值不涉及求导求导全部发生在反向。前向的产物既有结果loss也有副产品中间激活缓存——后者此刻看似无用却是下一阶段唯一的输入。逐层走一遍模型内部的前向回到代码主干其实只有四行model.py:110-116xself.tok_emb(idx)# 嵌入(B,S) → (B,S,d)cos,sinself.rope(S,idx.device,x.dtype)# 位置编码forblkinself.blocks:# N 个 Block形状不变xblk(x,cos,sin)returnself.lm_head(self.norm(x))# 输出头(B,S,d) → (B,S,V)真正的内容都在Block里Block.forward它是一个残差 归一化 子层的堆叠RMSNorm均方根归一化先对输入做归一化稳定数值第 226 篇注意力Attention把每个位置的向量线性投影成查询q qq、键k kk、值v vv用旋转位置编码Rotary Position EmbeddingRoPE注入位置信息第 227 篇再算缩放点积q k ⊤ / d qk^\top/\sqrt{d}qk⊤/d​、加因果掩码、softmax 得到权重对v vv加权求和分组查询注意力Grouped-Query AttentionGQA则是让多个查询头共享键值头以省显存第 228 篇前馈网络Feed-Forward NetworkFFN用门控线性单元SwiGLU对每个位置独立做一次升维再降维第 229 篇。这些子层的输出都通过残差连接加回原向量所以张量的形状在 Block 内部始终是( B , S , d ) (B,S,d)(B,S,d)一层层叠加上去。前向中张量的形状把整条链路按形状串起来看会更清楚每一步在做什么图 3 说明( B , S , d ) (B,S,d)(B,S,d)这个形状会在所有 Block 里被反复加工而保持不变只有在最后的输出头处词表维V VV才第一次出现——从( B , S , d ) (B,S,d)(B,S,d)变成( B , S , V ) (B,S,V)(B,S,V)随后 softmax、交叉熵都在这个维度上计算。计算图前向算数值顺手把中间值缓存下来把每一步运算都看成一个节点前向就是从输入走到损失的一次正向遍历图 4 里有一件容易被忽略的事前向边走边把中间结果存下来图中标注的缓存。为什么因为反向要用它们——上篇链式法则的例子里求∂ L / ∂ w 2 ( y − t ) ⋅ x \partial L/\partial w 2(y-t)\cdot x∂L/∂w2(y−t)⋅x需要用到前向算出的y yy和x xx。这就是为什么训练比推理更吃显存推理不需要保存激活值训练必须为反向留着。两阶段都做前向推理 vs 训练最后厘清前向的适用场景图 5 对比了两种场景推理输入 → 前向 → 输出预测。参数不更新不做反向第 232 篇讲的 KV cache就是推理前向的加速技巧缓存已算过的k / v k/vk/v避免逐个 token 重复计算留待后续展开训练输入 → 前向 → 损失 → 反向 → 更新循环往复。即前向训练推理都要做反向只有训练才做。前向的算力账一次前向本质上是大量矩阵乘法参数量越大、序列越长乘的次数越多。更关键的是自回归生成每输出一个 token 就要做一次前向——这也是生成长文本慢的根本原因。理解了这条流水线后面再谈 KV cache、显存与吞吐都是在优化这一次前向的开销。一句话记忆前向传播是把模型跑一遍输入经嵌入、N 个 Block、归一化、输出头得到 logits再经 softmax 变成概率、由交叉熵汇总出一个标量损失它全程只算数值、不涉及求导已知的是输入与参数产出的是损失与中间激活缓存前向训练推理都要做反向只在训练做而缓存正是为反向准备。OK本篇先到这里如有疑问欢迎评论区留言讨论祝各位功力大涨技术更上一层楼更多内容见下篇 blog【AI】【模型部署】基座模型研究反向传播的已知、所求与场景
返回列表