
图中先把向量缩到安全尺度,再计算归一化,重点是中间结果而不只是最终公式。
读到 RMSNorm 的公式,很容易把实现写成“逐个平方、求平均、开根、再相除”。对普通数字,这条路径没有问题。但把输入换成两个极大的有限数,平方可能先变成无穷,最后得到的归一化结果反而接近零。数学答案并没有变成零,坏掉的是中间计算。
最终能表示,不代表中间也能表示
用一组自设输入说明:两个分量都是 10 的二百次方。在常见双精度浮点范围内,原数是有限值,均方根仍然是这个数量级,理想归一化结果约为 [1,1]。直接平方却会超过可表示范围,把分母推成无穷。
这不是模型学坏了,也不能先靠调学习率解决。判断数值问题时,应该沿计算链检查输入、乘积、累加和分母,定位第一个非有限值。最终结果看起来很小,并不证明过程稳定,更不能因此宣称输入已经被正常压缩。
与之对应,极小数平方还可能下溢,得到零或损失有效位。仅仅检查输入不是 NaN、不是无穷,也无法证明后面的乘法安全。输入检查与运算稳定是两层要求。
把共同尺度提前拿出来
设 m 是各分量绝对值的最大值。对非零且有限的向量,先计算 z_i=x_i/m,此时每个 z 的绝对值都不超过一。再计算 q=mean(z_i²),就避免了因为原数幅度过大而直接平方溢出。
如果只需要没有稳定项的归一化,可以直接用 z_i/sqrt(q),不必先重建 m×sqrt(q) 再拿原输入相除。后者在某些表达式中又可能制造不必要的大中间值。稳定实现常常不是改变目标,而是选择不同的求值顺序。
还要区分求平方和、求范数与求均方根:它们的缩放关系不同。分量变大,平方和按平方尺度增长;范数按一次尺度增长;求平均还要除以分量个数。把三个名字混用,会让本来正确的缩放推导多出一个维度因子。

epsilon 不能随手挪位置
加入 epsilon 后,原分母是 sqrt(m²×q+epsilon)。在实数代数上,归一化可改写为 z_i/sqrt(q+epsilon/m²)。但“代数上等价”不等于“直接写 epsilon/m² 就一定稳定”,因为 m² 本身仍可能溢出,极小 m 又会带来相反的问题。
因此,上述缩放示例适合解释为什么要管理中间尺度,不是一份覆盖所有浮点极值的生产实现。工程中可以使用经过验证的求范数或缩放平方和算法,并核对它与目标稳定项定义是否一致。若接口改变了稳定项位置,还需要重新验证小输入附近的行为。
尤其不能把 sqrt(q+epsilon) 与 sqrt(q)+epsilon 当成同一公式。二者量纲与数值表现都不同,给 epsilon 取同一个数也不能互换。修复溢出时顺手改公式,可能把一个数值问题变成模型语义变化。
全零、非有限输入要走明确分支
全零向量让 m 等于零,直接除以 m 会产生无效结果。对于带正稳定项的常见归一化,有限的全零输入对应零输出;实现可以明确处理这个分支,但仍须考虑可学习参数与具体算子的定义。
如果输入已经包含 NaN 或无穷,缩放步骤本身也可能出现无穷除以无穷。不能把所有异常统一换成零,就宣称算法稳健,因为这会隐藏上游错误。应按系统政策拒绝、记录或传播错误,并避免未经说明地修补训练数据。
验证要选能区分两种实现的输入
只测试 [3,4],直接实现与缩放实现都给出合理结果,看不出问题。测试集还应包含相同大数、相反符号的大数、极小数、全零,以及非有限输入。再与独立高精度计算或可靠数值库比较,才能知道误差是否来自预期的舍入。
这个检查只证明当前实现的有限输入行为,不等于测过 GPU 内核性能,也不证明训练一定更稳定。真实模型还要核对累加精度、融合算子、梯度和设备差异。
如果一段归一化代码的输入输出都是有限值,你还会检查哪些中间量,才能排除“中间溢出后碰巧得到有限答案”的情况?