1. Tokenizer(分词器)
功能:将输入的文本转化为模型可以理解的 input_ids
(token ID)。通过查找词汇表,将文本中的每个词汇转换成一个唯一的整数 ID。
代码位置:在 Qwen2Tokenizer
类中定义(此类继承自 PreTrainedTokenizer
),负责处理 token 的转化。
from transformers import Qwen2Tokenizer
# 加载Qwen2的tokenizer
tokenizer = Qwen2Tokenizer.from_pretrained("Qwen/Qwen-tokenizer")
# 将文本转化为input_ids
input_ids = tokenizer("Hello world")["input_ids"]
2. Embedding(嵌入层)
功能:将 input_ids
转换为嵌入向量。这些嵌入向量会被作为模型输入,用于表示每个 token 的特征。嵌入层通过查找预定义的嵌入矩阵,找到每个 token 对应的向量。
代码位置:在 Qwen2Model
的初始化方法中,定义了 nn.Embedding
,它将词汇表中的 token ID 转换为向量。
# nn.Embedding 实现了从input_ids到嵌入向量的转换
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
# 在 forward 方法中调用
inputs_embeds = self.embed_tokens(input_ids)
作用:从输入的 token ID 转换为 (batch_size, sequence_length, embedding_dim)
形状的嵌入向量。
3. Hidden States & Layers(隐藏状态和解码层)
功能:Hidden_states
是嵌入向量通过多个解码层的传递过程中逐步更新的特征表示。在每个解码层中,数据会通过自注意力机制和多层感知机(MLP)层来提取和融合信息。
代码位置:Qwen2DecoderLayer
类实现了每个解码层,包括自注意力模块、RMSNorm 和 MLP 模块。
# Qwen2DecoderLayer 中的核心结构
class Qwen2DecoderLayer(nn.Module):
def forward(self, hidden_states, attention_mask=None, position_ids=None, past_key_value=None, use_cache=False):
residual = hidden_states
hidden_states = self.input_layernorm(hidden_states)
# 自注意力机制
hidden_states, _ = self.self_attn(hidden_states, attention_mask=attention_mask)
hidden_states = residual + hidden_states
# MLP 层
residual = hidden_states
hidden_states = self.post_attention_layernorm(hidden_states)
hidden_states = self.mlp(hidden_states)
hidden_states = residual + hidden_states
return hidden_states
作用:Hidden_states
是嵌入向量的初始状态,通过解码层不断提取特征,并逐步更新,直至模型最终输出。
4. RMSNorm(RMS归一化层)
功能:RMSNorm
是一种正则化层,用于对每一层的隐藏状态进行标准化。它确保隐藏状态的方差一致,避免模型在深层网络中发生数值不稳定。
代码位置:Qwen2RMSNorm
类实现了这个功能。
# RMSNorm 实现
class Qwen2RMSNorm(nn.Module):
def forward(self, hidden_states):
variance = hidden_states.pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
return self.weight * hidden_states
作用:RMSNorm
规范化每层的输出,确保数值的稳定性,并改善梯度传播。
5. Attention(自注意力机制)
功能:自注意力机制通过计算每个 token 对其他 token 的注意力权重,来捕捉序列中不同 token 之间的依赖关系。它可以让模型关注到句子中不同部分的信息。
代码位置:Qwen2Attention
类定义了自注意力机制,包含旋转位置编码 (RoPE),键值对重复和注意力计算的逻辑。
# 自注意力机制的实现
class Qwen2Attention(nn.Module):
def forward(self, hidden_states, attention_mask=None, position_ids=None):
query = self.q_proj(hidden_states)
key = self.k_proj(hidden_states)
value = self.v_proj(hidden_states)
# 旋转位置编码 (RoPE)
query, key = apply_rotary_pos_emb(query, key, cos, sin)
# 注意力权重计算
attn_weights = torch.matmul(query, key.transpose(2, 3)) / math.sqrt(self.head_dim)
attn_weights = nn.functional.softmax(attn_weights, dim=-1)
# 最终输出
attn_output = torch.matmul(attn_weights, value)
return attn_output, attn_weights
作用:通过计算 query
和 key
的相似度,生成注意力权重,进而加权组合 value
来生成每个 token 的新的表示。
6. MLP(多层感知机)
功能:MLP 是每个解码层中的非线性变换层。它通过对输入的隐藏状态进行线性变换和激活函数处理,进一步丰富每个 token 的表示。
代码位置:Qwen2MLP
类实现了多层感知机,通常在自注意力机制之后应用。
# MLP的实现
class Qwen2MLP(nn.Module):
def forward(self, hidden_state):
hidden_state = self.down_proj(self.act_fn(self.gate_proj(hidden_state)) * self.up_proj(hidden_state))
return hidden_state
作用:MLP 通过非线性变换增强模型的表达能力,提取和组合更多复杂的特征。
7. 输出层(Linear & Loss)
功能:输出层使用线性层将模型的最后一层隐藏状态转换为目标任务所需的输出,例如生成任务的词汇表分布或者分类任务的分类结果。
代码位置:Qwen2ForCausalLM
中的 lm_head
实现了线性输出层,并根据具体任务计算损失。
# 输出层和损失计算
class Qwen2ForCausalLM(Qwen2PreTrainedModel):
def forward(self, input_ids, labels=None):
outputs = self.model(input_ids)
logits = self.lm_head(outputs)
# 计算损失
if labels is not None:
loss_fct = CrossEntropyLoss()
loss = loss_fct(logits.view(-1, self.config.vocab_size), labels.view(-1))
return loss
return logits
作用:将隐藏状态通过线性层映射到词汇表大小的 logits,并计算生成任务中的交叉熵损失。