RMSNorm与LayerNorm的区别
RMSNorm与LayerNorm最容易混淆的地方,是“归一化后均值一定为0”。LayerNorm先减均值;RMSNorm直接用均方根调整尺度,因此通常保留非零均值。两者不能只因为输出尺寸相同,就在已有权重中随意替换。
两条公式,差在减均值
对一个token的d维隐藏向量x,RMSNorm使用r=√(Σxᵢ²/d+ε),输出yᵢ=gᵢxᵢ/r。g是可学习的逐维增益。LayerNorm先计算μ=Σxᵢ/d和v=Σ(xᵢ-μ)²/d,再使用(xᵢ-μ)/√(v+ε),并可附带逐维增益和偏置。
本例省略增益、偏置,用总体方差的分母d。归一化作用在隐藏维度,不把不同请求或不同token混在一起。ε用于避免分母为零,也会影响精确的尺度不变性。
常量向量揭示区别
x=[3,3]时,省略仿射参数的LayerNorm输出[0,0];RMSNorm输出接近[1,1]。不是精确的1,因为本例ε为正。
x=[1,2,3]时,RMSNorm约为[0.462910,0.925820,1.388730],平均值并非0。LayerNorm约为[-1.224744,0,1.224744]。不同输出不说明谁更准确;判断需要训练与任务结果。
平移与缩放怎样影响输出
不考虑ε且没有仿射参数时,LayerNorm对统一平移不变。RMSNorm通常不具备这一性质。RMSNorm对正数倍缩放不变;负倍数会翻转符号。
实际ε为正时,正数倍缩放仅近似不变,并非严格相等。小幅输入可能让ε的影响变得明显,因此测试不能只检查较大的随机向量。
import math
def rmsnorm(x, eps=1e-6):
denom = math.sqrt(sum(v*v for v in x)/len(x)+eps)
return [v/denom for v in x]
def layernorm(x, eps=1e-6):
mean = sum(x)/len(x)
var = sum((v-mean)**2 for v in x)/len(x)
return [(v-mean)/math.sqrt(var+eps) for v in x]
x = [1.0, 2.0, 3.0]
r, l = rmsnorm(x), layernorm(x)
assert abs(sum(l)) < 1e-12
assert sum(r)/len(r) > 0.9
assert rmsnorm([0.0,0.0]) == [0.0,0.0]
assert layernorm([3.0,3.0]) == [0.0,0.0]
assert rmsnorm([3.0,3.0])[0] > 0.99
for a,b in zip(rmsnorm(x,0),rmsnorm([2*v for v in x],0)):
assert math.isclose(a,b)
assert not math.isclose(rmsnorm(x)[0],rmsnorm([v+1 for v in x])[0])
print([round(v,6) for v in r])
print([round(v,6) for v in l])
不要把少一个步骤变成速度承诺
代码已执行,覆盖常量、全零、普通向量以及ε=0时的正比例缩放,未训练模型或测试GPU。计算更简洁不自动意味着端到端吞吐按某个比例提升。
RMSNorm论文在2019年公开。本文核对的是原论文定义;没有把论文特定实验中的速度结果外推到现代LLM。部署时还要检查归一化位置、精度、ε与权重形状。理解数值表示的影响,可参阅LLM量化。
资料来源
Root Mean Square Layer Normalization
本文于2026年10月12日整理;文章日期保留原计划时段。
支持
如果这篇文章对你有帮助,欢迎支持本站。
二维码可点击放大。更多支持方式见支持页面。


