LLaMa、Qwen、ChatGLM、ChatGLM2的区别
以下比较的前提是首先和BERT(transfomer)的对比
感谢帮忙给我github repository的star,更多最新模型长期更新:https://github.com/zysNLP/quickllm
LLaMa:
去掉bias
LayNorm方式:RMSnorm:https://zhuanlan.zhihu.com/p/650231190
# torch自带LayerNorm
if self.norm_mode == 'torch_buildin':
return F.layer_norm(hidden_states, self.normalized_shape, self.weight, self.bias, self.eps)
# RMSnorm: t5、大模型系列均使用
elif self.norm_mode == 'rmsnorm':
variance = hidden_states.float().pow(2).mean(-1, keepdim=True)
o = (hidden_states.float() * torch.rsqrt(variance + self.eps)).type_as(hidden_states)
torch自带LayerNorm (F.layer_norm
):
这是PyTorch库中内置的Layer Normalization实现。
输入参数包括:hidden_states
(需要归一化的张量)、normalized_shape
(归一化的维度,通常是最后一维)、weight
和bias
(可学习的缩放和平移参数)以及eps
(为了数值稳定性添加的小常数)。
它首先计算输入在指定维度上的均值和方差,然后使用这些统计量对输入进行归一化,并通过应用可学习的缩放和平移参数来恢复模型的表达能力。
RMSNorm (Root Mean Square Normalization):
只计算输入的方差(即每个元素的平方的平均值),然后通过元素级操作计算归一化后的输出。
具体步骤如下:
计算输入的平方的平均值(variance)。
使用逆平方根(torch.rsqrt()
)来计算方差的倒数(相当于标准差的倒数)。
将输入与计算出的标准差倒数相乘,得到归一化的结果。
torch自带的LayerNorm是最完整的实现,包括了可学习的参数;而RMSNorm和自定义LayerNorm则省略了这些参数,可能会牺牲一些模型的表达能力,但在某些情况下可能更简单或更高效。RMSNorm特别适用于那些不需要额外参数的大规模模型。
feedForward不同, 三层全连接
# 普通bert的FFN:
self.outDense(self.inter_act_fn(self.interDense(x)))
# llama、qwen的FFN:
self.outDense(self.inter_act_fn(self.interDense(x)) * self.interDense2(x))
新增rotary相对位置编码(RoPE)
InternLM:
模型结构: 基本和llama基本一致, 只是各个linear层多了bias; 和Qwen基本一致, 除了o有bias
FeedForward和Llama一致, 三个dense层
除了qkvo有bias, 其余均没有bias
Qwen:
FeedForward和Llama一致, 三个dense层
除了qkv有bias, 其余均没有bias
和InternLM基本一致, 唯一的差别是InternLM的multiHeadAttention.o有bias
ChatGLM
rotary(RoPE)使用的updown+position_encoding_2d
这是ROPE的二维表达方式,普通的ROPE是一维
qkv合并成一个权重convert时不是concat在一起的
attention_mask的最后一个token仅能访问之前的, 之前的tokens可以互相访问
跳跃连接有权重设计;embedding之后没有layernorm
# 原始bert,LayerNorm + multiHeadAttention + dropout + FFN + dropout + x+ FFN:其中x来自第一次FFN之后
x = self.attnLayerNorm(hidden_states, conditional_emb) if self.pre_layernorm else hidden_states # pre/post layernorm
self_attn_output = self.multiHeadAttention(x, attention_mask, past_key_value=past_key_value, position_ids=position_ids)
residual = x if self.apply_residual_post_layernorm else hidden_states
hidden_states = self.dropout_add(self_attn_output[0], residual)
hidden_states = self.attnLayerNorm(hidden_states, conditional_emb) if not self.pre_layernorm else hidden_states
x = self.ffnLayerNorm(hidden_states, conditional_emb) if self.pre_layernorm else hidden_states # pre/post layernorm
feedforward_output = self.feedForward(x)
residual = x if self.apply_residual_post_layernorm else hidden_states
hidden_states = self.dropout_add(feedforward_output, residual) # x在这
hidden_states = self.ffnLayerNorm(hidden_states, conditional_emb) if not self.pre_layernorm else hidden_states
# GhatGLM:LayerNorm + multiHeadAttention + alpha*x + FFN + alpha*x:多了一个alpha,其中x来自一开始的LayerNorm之后
x = self.attnLayerNorm(hidden_states)
alpha = (2 * self.num_hidden_layers) ** 0.5
self_attn_output = self.multiHeadAttention(x, attention_mask, past_key_value=past_key_value, **model_kwargs)
hidden_states = x * alpha + self_attn_output[0]
x = self.ffnLayerNorm(hidden_states)
hidden_states = x *alpha + self.feedForward(x)
ChatGLM2
不使用Unilm式的mask
flash_attention
这段代码定义了一个名为flash_attention_forward
的函数,用于实现Flash Attention机制。以下是该函数的详细解释:
函数接受以下参数:
query_layer
:查询(query)层的输出。
key_layer
:键(key)层的输出。
value_layer
:值(value)层的输出。
attention_mask
:注意力掩码,用于指示哪些位置应该被忽略。
query_length
:查询序列的长度。
softmax_scale
:可选的softmax缩放因子。
_get_unpad_data
函数用于处理未填充的数据。它计算每个批次中的序列长度、累积和最大序列长度,并返回未填充数据的索引、累积序列长度和最大序列长度。
_upad_input
函数负责对输入进行解压和平铺操作。它根据attention_mask
计算出需要保留的序列部分,并将查询、键和值层的输出调整为未填充的形状。
dropout
变量用于控制dropout概率,如果模型处于训练状态,则使用self.attention_probs_dropout_prob
作为概率。
将查询、键和值层的输出进行转置,以便于后续的矩阵运算。
根据是否为因果自注意力(即是否为序列到序列任务)和注意力掩码的形状,选择不同的计算方法:
如果不是因果自注意力且注意力掩码为二维(表示仅包含键填充掩码),则使用Flash Attention进行计算。首先调用_upad_input
函数对输入进行解压和平铺,然后调用flash_attn_varlen_func
函数执行Flash Attention操作,并在计算完成后将结果恢复为原始形状。
如果不是因果自注意力但注意力掩码不符合要求,则发出警告并使用PyTorch内置的注意力计算方法。
如果是因果自注意力,则直接调用flash_attn_func
函数执行Flash Attention操作。
最后,将注意力输出转置回原来的形状并返回。
总的来说,这段代码实现了Flash Attention机制,通过矩阵分解和局部注意力等技术优化了Transformer模型的计算效率和内存使用效率。在处理非因果自注意力任务时,它支持仅包含键填充掩码的情况,并在其他情况下退回到使用PyTorch内置的注意力计算方法。
multi_query_attention
"multi_query_attention"是一种创新的注意力机制设计,它扩展了传统Transformer中的单查询注意力机制。 在Multi-Query Attention中,每个位置的输入可能会生成多个查询向量,这些查询向量可以独立地参与注意力计算,并与键(key)和值(value)矩阵进行交互。 多个查询向量可以捕捉到输入的不同方面或信息源,增强模型的理解和表达能力。例如,一个查询可能关注词汇级别的信息,另一个查询可能关注句法或语义级别的信息。 具体实现可能包括对输入向量进行分解、复制或学习多个查询权重等技术。生成的多个查询向量将分别用于计算注意力分数,并与相应的值向量进行加权求和,得到最终的注意力输出。NLP基础付费课程(自己讲的):《AIGC大模型理论与工业落地实战》 折扣方式:
公众号”NLP小讲堂“回复自己的联系方式,或github中issue留言联系方式。课程五折。