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

LLaMa、Qwen、ChatGLM、ChatGLM2的区别

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(归一化的维度,通常是最后一维)、weightbias(可学习的缩放和平移参数)以及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留言联系方式。课程五折。

更新时间 2023-12-27