LLaMa、Qwen、ChatGLM、ChatGLM2的区别
原始bert,LayerNorm + multiHeadAttention + dropout + FFN + dropout + x+ FFN:其中x来自第一次FFN之后hidden_states = self.dropout_add(feedforward_output, residual) # x在这。
LLaMa、Qwen、ChatGLM、ChatGLM2的区别
以下比较的前提是首先和BERT(transfomer)的对比
PS: 大模型基础和进阶付费课程(自己讲的):《AIGC大模型理论与工业落地实战》-CSDN学院 或者《AIGC大模型理论与工业落地实战》-网易云课堂
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特别适用于那些不需要额外参数的大规模模型。
- torch自带LayerNorm (
-
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
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进行计算。首先调用
-
最后,将注意力输出转置回原来的形状并返回。
总的来说,这段代码实现了Flash Attention机制,通过矩阵分解和局部注意力等技术优化了Transformer模型的计算效率和内存使用效率。在处理非因果自注意力任务时,它支持仅包含键填充掩码的情况,并在其他情况下退回到使用PyTorch内置的注意力计算方法。
-
-
multi_query_attention
-
- "multi_query_attention"是一种创新的注意力机制设计,它扩展了传统Transformer中的单查询注意力机制。
- 在Multi-Query Attention中,每个位置的输入可能会生成多个查询向量,这些查询向量可以独立地参与注意力计算,并与键(key)和值(value)矩阵进行交互。
- 多个查询向量可以捕捉到输入的不同方面或信息源,增强模型的理解和表达能力。例如,一个查询可能关注词汇级别的信息,另一个查询可能关注句法或语义级别的信息。
- 具体实现可能包括对输入向量进行分解、复制或学习多个查询权重等技术。生成的多个查询向量将分别用于计算注意力分数,并与相应的值向量进行加权求和,得到最终的注意力输出。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)