当前位置:AIGC资讯 > AIGC > 正文

llama 2 改进之 RMSNorm

RMSNorm

论文:https://openreview.net/pdf?id=SygkZ3MTJE
Github:https://github.com/bzhangGo/rmsnorm?tab=readme-ov-file

论文假设LayerNorm中的重新居中不变性是可有可无的,并提出了均方根层归一化(RMSNorm)。RMSNorm根据均方根(RMS)将一层神经元的总和输入正则化,得到模型重新缩放不变性特性和隐式学习率适应能力

LayerNorm 公式

深度学习当中,没有线性激活函数的预测公式

a i = ∑ j = 1 m w i j x j , y i = f ( a i + b i ) , \begin{aligned}a_i=\sum_{j=1}^mw_{ij}x_j,\quad y_i=f\left(a_i+b_i\right),\end{aligned} ai​=j=1∑m​wij​xj​,yi​=f(ai​+bi​),​

通过激活函数后,其中,随着前一层的更新,层的输入分布会发生变化。这可能会对参数梯度的稳定性产生负面影响,延迟模型收敛。为了减少这种转变,LayerNorm 对求和的输入进行归一化,以固定它们的均值和方差,如下所示:

a ˉ i = a i − μ σ g i , y i = f ( a ˉ i + b i ) , \begin{aligned}\bar{a}_i=\frac{a_i-\mu}{\sigma}g_i,\quad y_i=f\left(\bar{a}_i+b_i\right),\end{aligned} aˉi​=σai​−μ​gi​,yi​=f(aˉi​+bi​),​

其中 a ˉ i \bar{a}_i aˉi​是向量 a ˉ ∈ R n \bar{a}\in\mathbb{R}^n aˉ∈Rn的第 i i i个值,作为 α i \alpha_i αi​的归一化替代值用于层激活。 g ∈ R n \mathbf{g}\in\mathbb{R}^n g∈Rn是增益参数,用于重新调整标准化求和输入的大小,一开始设置为 1。 μ \mu μ 和 σ 2 \sigma^2 σ2 分别是根据原始求和输入估计的均值和方差统计量。

μ = 1 n ∑ i = 1 n a i , σ = 1 n ∑ i = 1 n ( a i − μ ) 2 . \begin{aligned}\mu=\frac{1}{n}\sum_{i=1}^na_i,\quad\sigma=\sqrt{\frac{1}{n}\sum_{i=1}^n(a_i-\mu)^2}.\end{aligned} μ=n1​i=1∑n​ai​,σ=n1​i=1∑n​(ai​−μ)2 ​.​

在本文中,假设重新缩放不变性是LayerNorm成功的原因,而不是重新定中心不变性。我们提出了RMSNorm,它只关注重新缩放不变性,并简单地根据均方根(RMS)统计对求和输入进行正则化:
a ˉ i = a i RMS ( a ) g i , where RMS ( a ) = 1 n ∑ i = 1 n a i 2 . \begin{aligned}\bar{a}_i=\frac{a_i}{\text{RMS}(\mathbf{a})}g_i,\quad\text{where RMS}(\mathbf{a})=\sqrt{\frac{1}{n}\sum_{i=1}^na_i^2}.\end{aligned} aˉi​=RMS(a)ai​​gi​,where RMS(a)=n1​i=1∑n​ai2​ ​.​

python实现

# root mean square layer normalization
def rln(x, s):
    _eps = 1e-5
    output = x / tensor.sqrt((x * x).mean(1)[:,None] + _eps)
    output = s[None, :] * output
    return output

# layer normalization
def ln(x, b, s):
    _eps = 1e-5
    output = (x - x.mean(1)[:,None]) / tensor.sqrt((x.var(1)[:,None] + _eps))
    output = s[None, :] * output + b[None,:]
    return output

使用pytorch来写RMSNorm的函数

import torch
import torch.nn as nn


class RMSNorm(nn.Module):
    def __init__(self, d, p=-1., eps=1e-8, bias=False):
        """
            Root Mean Square Layer Normalization
        :param d: model size
        :param p: partial RMSNorm, valid value [0, 1], default -1.0 (disabled)
        :param eps:  epsilon value, default 1e-8
        :param bias: whether use bias term for RMSNorm, disabled by
            default because RMSNorm doesn't enforce re-centering invariance.
        """
        super(RMSNorm, self).__init__()

        self.eps = eps
        self.d = d
        self.p = p
        self.bias = bias

        self.scale = nn.Parameter(torch.ones(d))
        self.register_parameter("scale", self.scale)

        if self.bias:
            self.offset = nn.Parameter(torch.zeros(d))
            self.register_parameter("offset", self.offset)

    def forward(self, x):
        if self.p < 0. or self.p > 1.:
            norm_x = x.norm(2, dim=-1, keepdim=True)
            d_x = self.d
        else:
            partial_size = int(self.d * self.p)
            partial_x, _ = torch.split(x, [partial_size, self.d - partial_size], dim=-1)

            norm_x = partial_x.norm(2, dim=-1, keepdim=True)
            d_x = partial_size

        rms_x = norm_x * d_x ** (-1. / 2)
        x_normed = x / (rms_x + self.eps)

        if self.bias:
            return self.scale * x_normed + self.offset

        return self.scale * x_normed

总结

### 文章总结:RMSNorm
**引言**
RMSNorm(均方根层归一化)是一种神经网络层归一化技术,旨在通过关注输入的重新缩放不变性,而非重新定中心不变性,来优化模型性能和训练稳定性。RMSNorm由论文([链接](https://openreview.net/pdf?id=SygkZ3MTJE))提出,它通过均方根(RMS)统计量对神经元的总输入进行归一化。
**背景与动机**
- **问题**:传统LayerNorm(层归一化)同时关注重新缩放和重新定中心不变性。在RMSNorm中,研究者假设重新缩放不变性是关键,而重新定中心不变性可能是不必要的。
- **目标**:通过仅通过重新缩放输入来改善训练速度和模型收敛性,同时保持模型性能。
**RMSNorm与LayerNorm的比较**
1. **LayerNorm**:
- 公式:对求和输入进行归一化,以固定均值和方差。
- 特性:同时实现了重新缩放和重新定中心。
2. **RMSNorm**:
- 公式:仅通过输入的RMS(均方根)统计量进行归一化。
- 公式简化:$\bar{a}_i = \frac{a_i}{\text{RMS}(\mathbf{a})}g_i$,其中RMS为输入的均方根。
- 特性:关注重新缩放不变性,不强制实现重新定中心。
**实现**
在代码中,RMSNorm的实现展示了对输入应用RMS归一化,并且在需要时可选地添加偏差项。以下是使用PyTorch的基本实现示例:
```python
import torch
import torch.nn as nn
class RMSNorm(nn.Module):
def __init__(self, d, p=-1., eps=1e-8, bias=False):
# 参数初始化,包括模型的尺寸d、部分RMSNorm比例p、epsilon值eps以及是否使用偏差项bias
...

def forward(self, x):
# 根据p的值判断是否采用部分RMSNorm
# 计算RMS统计量
# 对输入进行归一化

# 如果启用偏差项,则添加偏差
if self.bias:
return self.scale * x_normed + self.offset
return self.scale * x_normed
```
**实验与效果**
- RMSNorm增强了模型的重新缩放能力,同时避免了重新定中心可能带来的不必要的复杂度和计算成本。
- 文中假设的重新缩放不变性的重要性得到了初步的实验验证,显示出RMSNorm在某些情况下能够提高模型的性能和训练效率。
**总结**
- RMSNorm通过仅关注归一化的重新缩放不变性而非重新定中心不变性,为深度学习模型提供了一种新的归一化方法。
- 实验结果表明,RMSNorm能在保持甚至提高模型性能的同时,简化训练过程,提升训练效率。
有关RMSNorm的更多实现细节和实验分析,请参考论文完整内容及其在GitHub([链接](https://github.com/bzhangGo/rmsnorm?tab=readme-ov-file))上的实现代码。

更新时间 2024-07-29