FFN 在每个 token 上共享一组特征变换参数,注意力负责跨位置汇聚;归一化控制输入尺度,残差提供直接传递路径。这些机制会组合出现,但参数预算、归一化统计和梯度通路必须分别推导,不能用“采用新架构”解释所有性能差异。Transformer 的子层与逐位置FFN
前置学习:Transformer与自回归生成。完整示例:ffn-norm.py。
学习目标
- 写出 SwiGLU 的两输入分支,核算等参数预算需要的宽度变化。
- 推导 RMSNorm 的统计量与雅可比,并构造与 LayerNorm 不同的平移反例。
- 比较 Pre-Norm、Post-Norm 的链式法则,识别残差直通项的条件与局限。
前置知识
输入 为 [B,T,d], 为 FFN 中间宽度。本文数学使用列向量,线性矩阵按 [out,in] 存储,与示例一致。 是逐元素乘法; 是函数 对输入的雅可比; 是归一化分母中的小正数,不是训练学习率。三个知识点都只做小型确定性计算,没有自动求导或真实网络训练。
基本机制
普通无偏置 FFN 为 ,门控 FFN 把一个投影的激活与另一投影逐元素相乘,再投影回隐藏宽度。LLaMA 论文采用 Pre-Norm、RMSNorm 和 SwiGLU;该版本 Transformers 的实现分别落在 LlamaDecoderLayer、LlamaRMSNorm、LlamaMLP。读取时要核对 hidden_act、中间宽度和 bias 配置,不能仅依据类名推断模型必然使用某个固定激活。LLaMA 架构说明 LlamaMLP 与解码层
推导或示例
知识点一:SwiGLU 的门控计算与等参数宽度
问题与机制。 SwiGLU 不是给原 FFN 的激活换一个名字,它增加了一个输入投影。设 ,则
普通两矩阵 FFN 的无偏置参数量是 ;上述门控版本为 。要与宽度 的普通 FFN 等参数,需 。若 ,则 ,实际模型往往再按实现要求取整。这个预算是矩阵元素数,尚不包括归一化、偏置或对齐填充。GLU变体的公式与等预算比较
def swiglu(x, gate_matrix, up_matrix, down_matrix):
"""单token无偏置SwiGLU;返回两分支、门控激活、输出与参数量。"""
if not x or len(gate_matrix) != len(up_matrix) or len(down_matrix) != len(x):
raise ValueError("分支宽度与输出宽度须匹配")
gate, up = _linear(gate_matrix, x), _linear(up_matrix, x)
hidden = [g * _sigmoid(g) * u for g, u in zip(gate, up)]
output = _linear(down_matrix, hidden)
return {"gate": gate, "up": up, "hidden": hidden, "output": output,
"parameters": 3 * len(x) * len(gate), "hidden_elements": len(hidden)}
完整文件中 _linear 做矩阵乘向量,_sigmoid 用正负分支避免无必要的指数上溢。取 ,三个矩阵都为二维单位矩阵,得到 、 ,输出相同。第二项为正,是负的 SiLU 值乘负的上投影值;这说明门控不是只能把非负激活乘一个零到一概率的简单开关。
参数与激活还需分开: 的普通 FFN 有2097152个矩阵参数;在同宽2048直接加门控则为3145728,增加一半。若 ,一个中间分支有4194304个元素;改变 T 会改变这个激活数,不会改变共享矩阵的参数量。反向保存、融合及重计算会改变真实峰值,不能把两条分支的元素和当成最终显存。
flowchart LR
X["单token隐藏向量"] --> G["门控投影"]
X --> U["上投影"]
G --> S["逐元素SiLU"]
S --> M["两分支逐元素相乘"]
U --> M
M --> D["下投影回隐藏宽度"]
源码定位。 该版本 LlamaMLP.forward 明确执行 down_proj(act_fn(gate_proj(x))*up_proj(x));nanoGPT.MLP 则是两矩阵 GELU 路径,用于区分结构。LlamaMLP 三投影计算 nanoGPT MLP 两投影计算 LLaMA 论文明确提到用 宽度,和上述参数推导一致。
条件与反例。 示例无偏置且门控为 SiLU,输入维度必须匹配。把乘法改成相加、或把激活应用到两条分支,都是不同函数。固定参数量也不意味着相同训练显存和吞吐;要比较质量,仍需固定数据、优化器、训练 token 和其他层结构。
知识点二:RMSNorm 保持尺度而不去均值
问题与机制。 RMSNorm 与 LayerNorm 到底少了什么?对 ,定义 、 。单位增益、零偏置时
平方均值满足 ;除非均值为零,两种分母也不同。对 且暂取 ,RMSNorm 是 [1/sqrt5,3/sqrt5],LayerNorm 是 [-1,1]。平移到 [3,5] 后 LayerNorm 不变,RMSNorm 改变。RMSNorm 定义与不变性
推导雅可比: ,因此
若有逐通道增益 ,左乘 ;示例把增益固定为1,使计算更容易核对。径向作用 ,所以 时缩放方向被消去,但保留正 epsilon 后只近似如此。这也是“缩放不变”必须注明 epsilon 条件的原因。
def norm_statistics(x, eps=1e-6):
"""计算单位增益的RMSNorm、LayerNorm及RMSNorm解析雅可比。"""
if not x or not math.isfinite(eps) or eps < 0 or not all(math.isfinite(a) for a in x):
raise ValueError("输入须有限非空且epsilon非负")
n = len(x)
mean = sum(x) / n
square_mean = sum(a * a for a in x) / n
variance = sum((a - mean) ** 2 for a in x) / n
if square_mean + eps <= 0 or variance + eps <= 0:
raise ValueError("归一化分母不能为零")
scale = math.sqrt(square_mean + eps)
rms = [a / scale for a in x]
layer = [(a - mean) / math.sqrt(variance + eps) for a in x]
jacobian = [[(1.0 if i == j else 0.0) / scale - x[i] * x[j] / (n * scale**3)
for j in range(n)] for i in range(n)]
return {"mean": mean, "square_mean": square_mean, "variance": variance,
"rmsnorm": rms, "layernorm": layer, "jacobian": jacobian}
函数同时返回均值、平方均值、方差、两种输出及解析雅可比,便于将统计量错误与梯度错误分开。对 [1,3] 可手算分母;对全零输入,正 epsilon 保证分母非零且输出零。若 epsilon 设为零而输入常量,LayerNorm 分母为零;因为函数同时比较两种归一化,所以会拒绝该输入。
flowchart LR
X["当前token全部隐藏通道"] --> Q["平方均值加epsilon"]
Q --> S["求平方根得到尺度"]
X --> D["逐通道除以尺度"]
S --> D
D --> G["生产实现乘可学习增益"]
S --> J["结合输入外积构造雅可比"]
X --> J
源码定位。 该版本 LlamaRMSNorm.forward 先升到 float32 算平方均值和逆平方根,恢复输入 dtype 后乘权重;变量名 variance 在这里装的是平方均值,不是减均值后的方差。LlamaRMSNorm.forward 梯度形式对应 RMSNorm 梯度分析。
条件与反例。 正比例缩放且忽略 epsilon 时 ;负比例会翻转符号,不满足同一个等式。每个通道各乘不同系数也不具有统一尺度不变性。统计量是在单个 token 的隐藏维求得,与 batch 统计无关;不能把其训练/推理行为照搬 BatchNorm 的运行均值逻辑。
知识点三:归一化位置改变残差雅可比
问题与机制。 为什么 Pre-Norm 的残差常被称为直接通路?设子层为 ,归一化为 。两种连接为
按链式法则,
Pre-Norm 在这一层的 Jacobian 中有裸的 ;Post-Norm 的整条局部通路都经过归一化。为可核算起见令 ,于是 ,无需自动微分即可比较。这里为了隔离“位置”,两者统一使用 RMSNorm;原 Transformer 使用 LayerNorm 的 Post-Norm,不能把此教学对照称为原模型重现。Transformer Post-Norm 结构 LLaMA Pre-Norm 结构
def residual_paths(x, matrix, eps=1e-6):
"""以线性子层F(x)=Ax比较前归一化、后归一化输出与雅可比。"""
n = len(x)
if not n or len(matrix) != n or any(len(row) != n for row in matrix):
raise ValueError("子层矩阵须为输入宽度的方阵")
norm_x = norm_statistics(x, eps)
pre = [a + b for a, b in zip(x, _linear(matrix, norm_x['rmsnorm']))]
inner = [a + b for a, b in zip(x, _linear(matrix, x))]
norm_inner = norm_statistics(inner, eps)
identity_plus_a = [[float(i == j) + matrix[i][j] for j in range(n)] for i in range(n)]
pre_jac = [[float(i == j) + sum(matrix[i][k] * norm_x['jacobian'][k][j] for k in range(n))
for j in range(n)] for i in range(n)]
post_jac = [[sum(norm_inner['jacobian'][i][k] * identity_plus_a[k][j] for k in range(n))
for j in range(n)] for i in range(n)]
return {"pre": pre, "post": norm_inner['rmsnorm'], "pre_jacobian": pre_jac,
"post_jacobian": post_jac}
把 设为全零,输入 [1,3]。Pre-Norm 输出保留 [1,3] 且雅可比为单位阵;Post-Norm 输出约 [0.447214,1.341641],其雅可比是上一知识点的 。因此即便子层没有提供任何变换,两种残差块仍不同。再用非零对角 A 检查矩阵乘法顺序,通常 ,交换两者会改变反向信号。
flowchart LR
X["同一输入与线性子层"] --> N["前归一化分支"]
N --> F["先归一化再过子层"]
F --> A["加回原始输入"]
X --> B["后归一化分支"]
B --> C["子层输出先与输入相加"]
C --> D["对残差和归一化"]
A --> J["分别核算链式雅可比"]
D --> J
源码定位。 LlamaDecoderLayer.forward 在 attention 前做 input_layernorm,相加后再以该和为下一残差,MLP 前做 post_attention_layernorm。第二个名字中的 post-attention 指位于注意力之后,它仍然是 MLP 的 Pre-Norm,不能按变量名误判成 Post-Norm 架构。LlamaDecoderLayer.forward 的两次残差 nanoGPT 的 Block.forward 也可直接看到同类次序。nanoGPT Block.forward
条件与反例。 局部有单位项不等于完整深层网络梯度永不消失或爆炸,多个雅可比相乘、最终归一化、优化器和初始化仍重要。Post-Norm 也不是必然不能训练。比较训练稳定性时不能同时改变宽度、激活、学习率和归一化位置后只归因其中一项。
适用条件与限制
解析示例不模拟混合精度、融合内核、激活重计算或优化器状态。RMSNorm 原论文的运行时间改善属于其任务与实现条件,本页没有独立测量,因此不报告通用加速比例。标准库中的 double 精度也不能替代 float16/bfloat16 对溢出和舍入的验证。
实践任务
交付普通 FFN 与 SwiGLU 的参数/中间激活预算,分别只改变 B、T、d、m;记录 RMSNorm 与 LayerNorm 的平移及缩放对照;用零矩阵、对角矩阵和非对称矩阵核算两种残差雅可比。常驻 UT 可用有限差分检查解析雅可比,本组未运行该检查。真实 Pre/Post-Norm 训练对照仍为已设计。
掌握标准
能说明门控新增哪一个矩阵、为什么等参数需改宽度;能区分方差与平方均值;能指出 epsilon 对严格不变性的影响;能写对两个雅可比的乘法顺序。能构造零子层反例,且不会把一个局部代数性质直接提升为任意深度的训练结论。
源码与后续阅读
证据包括 Transformer、LLaMA、GLU Variants 和 RMSNorm 原论文,以及固定提交下的 Llama、nanoGPT 实现。本页未独立复现任一大型模型或论文质量结果。下一步可读预训练目标与数据,连接结构计算与训练损失。
2026研究进展
MoSE在专家内部使用嵌套宽度,说明FFN中间维度也可以成为条件计算的控制点。理解本页的前馈计算后,可以进一步比较“选哪些专家”和“每个专家用多少宽度”。多宽度训练是方法的一部分,不能把普通模型直接切片视为已实现论文。 会议来源与读取范围
更多公式、代码示例、结构图及当前开源版本见模型网络研究进展。新内容未执行真实模型实验。