一维的输入,归一化后的输出

对输入特征做尺度调整,有助于改善优化条件。

图中展示参数空间的优化轨迹;输入缩放的效果仅作示意。
“更容易优化”,就一定“更不容易过拟合”吗?
前一页讨论优化是否容易;还要区分泛化是否可靠。
例如,损失惩罚是正则化的一种形式:
归一化也可能影响泛化,但不能据此将它等同于正则化。
Normalization:“调整数据分布”

输入
输入 X [B, S, H]
统计量 [B, S, 1] ← 沿 hidden 维,keepdim=True
广播并缩放 [B, S, H] ← 每个 token 使用自己的统计量
固定一个 token,记它的 hidden 向量为

输入与输出:
x.square().mean(-1, keepdim=True):平方均值,形状 rsqrt(mean_square + eps):缩放系数,广播乘到 这里
x = torch.tensor([[[1., 2., 1., 2.], [2., 4., 2., 4.]]])
norm = nn.RMSNorm(4, eps=1e-6)
x32 = x.float()
mean_square = x32.square().mean(-1, keepdim=True)
y = (x32 * torch.rsqrt(mean_square + norm.eps)).to(x.dtype)
y = y * norm.weight
torch.testing.assert_close(y, norm(x))
keepdim=True 保留 [b, s, 1],广播到各自的 4 个特征。
验证时统一
两者都用于控制每个 token 的激活尺度,但处理方式不同:
| 方法 | 中心化 | 尺度调整 |
|---|---|---|
| LayerNorm | 减去均值 | 除以标准差,再学习缩放与偏移 |
| RMSNorm | 不减均值 | 除以均方根,再学习缩放 |
Attention 让当前位置从其他 token 获取上下文。
FFN 接着对这个位置的表示做非线性特征加工。
例如“我不喜欢这部电影”:汇聚“不”的信息后,
当前位置还需要把这些特征组合成有用的更新。
单个 token 的表示:
[2,1] → 四维响应 [3,1,2,1](和、差、原值)。若只做线性升维再降维:
仍等价于一个线性层。
展开特征之后,怎样根据当前输入进一步加工它们?
Llama 的 SwiGLU 有两条升维分支:
up_proj 产生候选特征,gate_proj 根据当前
候选特征 u [ 2, -1, 3 ]
门控系数 g [ 0, 0.5, 2 ] ← 示意值
逐元素相乘 z [ 0, -0.5, 6 ]
系数接近 0 时抑制该特征,大于 1 时放大。
SiLU 的输出也可为负;它不是 0/1 开关或概率。
升维展开特征,激活与门控对这些特征进行非线性加工。
降维是可学习的组合;输出回到 hidden 维,才能与主干相加。
图中上方 Linear 输出
(mlp): LlamaMLP(
(gate_proj): Linear(in_features=2048, out_features=8192, bias=False)
(up_proj): Linear(in_features=2048, out_features=8192, bias=False)
(down_proj): Linear(in_features=8192, out_features=2048, bias=False)
(act_fn): SiLU()
)


隐藏维度为
三次线性映射约有
比较参数开销时,需要同时说明中间维度。

上图是 SiLU 激活曲线;下面是完整 SwiGLU FFN 的前向计算。
down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
RoPE的2D实现(相邻维度配对)

RoPE的n维实现

目标:实现RoPE(对应的
构建RoPE矩阵:

Llama 使用前后半维配对:
def rotate_half(x):
x1, x2 = x.chunk(2, dim=-1)
return torch.cat((-x2, x1), dim=-1)
def apply_rotary_pos_emb(q, k, cos, sin):
# q/k: [b, s, h, d]; cos/sin: [s, d]
cos = cos[None, :, None, :]
sin = sin[None, :, None, :]
q_embed = (q * cos) + (rotate_half(q) * sin)
k_embed = (k * cos) + (rotate_half(k) * sin)
return q_embed, k_embed
https://marp.app/

此页讲输入特征缩放对参数优化的直觉,不是直接对参数做 norm,也不是 RMSNorm 让损失曲面变圆的证明。原图“较大参数梯度主导”应口头解释为不同方向优化条件不均衡,不能以参数大小推断梯度大小。结尾问题引出下一页的优化与泛化目标区别。
两者的效果可能交叉,此处区分主要作用机制,不应把“优化”与“泛化”讲成互斥。正则化不只限于修改损失函数,例如 dropout 采用随机化。下一页开始讨论模型内部 hidden activations 的归一化。
对比:沿 batch 维归约会将不同样本混在一起;沿完整 sequence 维归约会让当前位置依赖其他位置,可能包含未来 token。当前 LLM LayerNorm(H)/RMSNorm(H) 均只沿 H 统计。参考 PyTorch LayerNorm 与 RMSNorm 官方文档。
PyTorch 实现:torch.nn.RMSNorm(H),https://pytorch.org/docs/stable/generated/torch.nn.RMSNorm.html
延续原 CV 图的着色方式:横轴 B(文本样本)、斜轴 S(token 位置)、竖轴 H(hidden 特征)。着色竖条是 X[b,s,:],一次统计只涉及这条向量。LN 与 RMSNorm 范围相同,统计量不同。公式中的分母实际包含 epsilon,gamma/beta 分别表示逐维缩放/偏移。
依据:Root Mean Square Layer Normalization,https://arxiv.org/abs/1910.07467。论文结果不应泛化为所有模型、任务或现代内核的固定加速比例。Llama pre-norm 分支采用 RMSNorm。
语义例子仅用于直觉:不表示某个神经元必然对应“否定”或“喜欢”。Attention 自身也包含特征投影与 softmax 非线性;这里强调分工,不能讲成 attention 只搬运数据。参考 Attention Is All You Need §3.3:https://arxiv.org/html/1706.03762v7#S3.SS3
升维不增加输入的信息量;更长的向量也不保证效果更好。示例中的 a+b、a-b 是手工组合,真实权重通过训练学习。这里的线性合并结论只针对连续线性投影,不包括两个输入相关分支的逐元素乘法。
这是输入相关的逐维调节;不同 token 使用同一组投影参数,但计算出的门值不同。参考 GLU Variants Improve Transformer:https://arxiv.org/html/2002.05202v1
Llama pre-norm decoder block:t 是第一次残差后的表示,h 是 Norm2(t),z 是门控后的中间特征;Delta_FFN 的命名强调更新量,不意味着 h 与 y 直接相减。全程 batch、sequence 不变。公式使用列向量;PyTorch Linear 对应 z @ W_d.T。
* SiLU:$x\cdot\sigma(x)$,兼具平滑和门控性质,常作为SwiGLU中的激活