外观
Transformer:逐步追踪一次前向与反向
一个 decoder-only Transformer 可以看作反复交替进行两件事:注意力让当前位置读取允许的历史,前馈网络加工每个位置的特征。残差保留原信息,归一化控制数值尺度,位置编码打破序列的排列对称性。这里逐项对照 labs/llm/model.py,避免把模型理解成一串只需照抄的层名。
形状是第一份规格书
设 [2,5,8] 张量。先 reshape 成 [2,5,2,4],再交换时间和头维,才得到 [2,2,5,4]。直接 reshape 成 [2,2,5,4] 会把原有元素分错组;形状相同并不代表语义相同。
[B,H,T,T],最后一维是被读取的 key 位置;softmax 应沿它归一化。[B,T,d],再乘输出投影
因果 mask 是模型定义的一部分
训练时同时计算全部位置,但位置
python
scores = q @ k.swapaxes(-1, -2) / np.sqrt(q.shape[-1])
mask = np.tril(np.ones((t, t), dtype=bool))
scores = np.where(mask, scores, -np.inf)
probabilities = softmax(scores)本地测试把输入后三个位置改变,检查更早位置的 logits 完全不变。这比观察注意力图更直接。注意 padding mask 与 causal mask 是两个条件;若一整行都被屏蔽,-inf - (-inf) 会变成 NaN,应在数据组织或内核中明确处理。我们的固定长度无 padding 实验,每行至少允许对角线。
RMSNorm、RoPE 与 SwiGLU
RMSNorm 沿特征维度计算
它没有 LayerNorm 的减均值步骤。增益
RoPE 对 query/key 的每两个分量进行旋转:
位置 rope(..., inverse=True) 可用于梯度。这一实现要求每头维度为偶数,配置校验会拒绝不满足条件的模型。
SwiGLU 用两次升维投影形成门控:
flowchart TB X[输入 X] --> N[RMSNorm] N --> Q[Q K V 投影与 RoPE] Q --> A[因果多头注意力] A --> R[输出投影 加 X] X --> R R --> N2[RMSNorm] N2 --> F[SwiGLU] F --> Y[加 R 得 Y] R --> Y
查看流程图文本
flowchart TB X[输入 X] --> N[RMSNorm] N --> Q[Q K V 投影与 RoPE] Q --> A[因果多头注意力] A --> R[输出投影 加 X] X --> R R --> N2[RMSNorm] N2 --> F[SwiGLU] F --> Y[加 R 得 Y] R --> Y
注意力反向传播不神秘
若输出梯度是
再得 [T,T,T] 雅可比;这正是框架自动微分实际利用的结构。被 mask 的位置 attention_backward 实现了这些式子,完整模型测试覆盖两层及全部参数种类。
参数与运行成本
无偏置、输入输出权重不共享时,参数主要是
自测
阅读本地实现时,可以从 loss 进入 forward,在每个 block 记录 z,q,k,v,joined,n,hidden 的形状,再沿 backward 反向寻找它们的使用位置。缓存不是额外的模型参数,而是本次前向为求导保留的中间结果;batch 改变后就应重新计算。参数量统计只计 params,训练峰值内存还要算这些缓存、梯度和优化器状态。多层网络每层有独立权重;在代码中误把同一数组引用放到多个 block,会无意形成跨层权重共享,有限差分虽可能通过,架构语义却已变化。
没有位置编码,因果 mask 是否已经给出完整位置信息?
mask 确实区分了可读取的集合大小,但不能替代明确、可控制的相对或绝对位置表示。模型仍需从内容与层间结构间接推断顺序;RoPE 直接让 query-key 匹配随相对距离变化。不要由“有三角形 mask”推导出“对所有顺序关系都足够”。
为什么损失下降不能替代因果性测试?
未来信息泄漏往往让训练 loss 降得更快,甚至趋于零。只有构造“改变未来、不改变过去输出”的不变量,才能针对性检测这个错误;还需另测输入目标错位。
来源:官方 A1 固定讲义、Transformer 原论文、RoFormer、RMSNorm。下一章:训练。