RoPE
这个不多谈了,见:旋转位置编码
RMSNorm
标准Transformer的LayerNorm如下:
y
=
x
−
Mean
(
x
)
Var
(
x
)
+
ε
∗
W
+
B
y=\frac{x-\operatorname{Mean}(x)}{\sqrt{\operatorname{Var}(x)+\varepsilon}} * W+B
y=Var(x)+εx−Mean(x)∗W+B
llama2采用了RMSNorm:
y
=
x
R
M
S
(
x
)
+
ε
,
R
M
S
(
x
)
=
1
n
∑
1
n
x
i
2
y=\frac{x}{R M S(x)+\varepsilon}, RMS(x) = \sqrt{\frac{1}{n} \sum_{1}^n {x_i}^2}
y=RMS(x)+εx,RMS(x)=n11∑nxi2
实现源码:
def _norm(self, x):
"""
Apply the RMSNorm normalization to the input tensor.
Args:
x (torch.Tensor): The input tensor.
Returns:
torch.Tensor: The normalized tensor.
"""
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
RMSNorm能保证激活效果变化,且计算效率能提升7%∼64%
SwiGLU
这个不多谈了,见:SwiGLU激活函数
MLP
up、gate、down都是三个linear层:down(up * silu(gate))
def forward(self, x):
return self.w2(F.silu(self.w1(x)) * self.w3(x))
GQA
这个不多谈了,见:Multi Query Attention & Group Query Attention
padding_side
llama系列训练和推理都是right padding:
- 训练:其实只要设置padding mask,那么left/right pad是没有区别的。然而实际上huggingface中某些tokenizer在training的时候必须设成right padding,因为有些tokenizer使用的是absolute position id,导致非padding token的position id不是从0开始的。
- 推理:由于llama是decoder-only结构,每个token的生成依赖于上一个token。而上一个token如果是无实际意义的padding token,那么就打断了句子语义的连续性,导致生成文本质量较差。因此left padding比较make sense,但在llama推理的源码中,batch的时候采用right padding。生成token的时候,从batch中长度最短的序列开始生成,其它较长序列的相同位置保持不变,直到该序列开始生成。猜测llama这样做的原因是保持跟训练一致,但不如left padding优雅。