Skip to content

Qwen3 ​

Qwen3

Qwen3 在 Qwen2 基础上引入了 QK-Norm,这是架构层面唯一的变化,其余结构(SwiGLU MLP、RoPE、GQA、Pre-Norm 残差连接、Weight Tying)与 Qwen2 完全一致。

transformers 中 Qwen3MLP 与 Qwen2MLP 结构完全一致(SwiGLU),仅增加了 intermediate_size 参数

QK-Norm ​

在 Q、K 投影之后、施加 RoPE 之前,分别对 Q 和 K 按 head 维度做 RMSNorm 归一化:

Q,K,V=WQx,WKx,WVxQ=RoPE(RMSNorm(Q)),K=RoPE(RMSNorm(K))Attn(Q,K,V)=Softmax(QKTdk)V

为什么加 QK-Norm:

  • Q、K 向量的范数随训练增长,导致 attention logits QKT 的绝对值越来越大
  • 极端的 logits 经过 Softmax 后接近 one-hot 分布,注意力退化为只关注单个 token
  • 对 Q、K 做 RMSNorm 将范数约束在稳定范围内,防止 attention score 爆炸,提升长序列和大规模训练的稳定性

与 Qwen2 Attention 的对比:

Qwen2:  qkv_proj → split Q,K,V → RoPE(Q,K)           → Attention → o_proj
Qwen3:  qkv_proj → split Q,K,V → RMSNorm(Q,K) → RoPE → Attention → o_proj
                                  ^^^^^^^^^^^^
📄 transformers/.../modeling_qwen3.py#L222-L291
python
class Qwen3Attention(nn.Module):
    def __init__(self, config: Qwen3Config, layer_idx: int):
        ...
        self.q_proj = nn.Linear(config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias)
        self.k_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias)
        self.v_proj = nn.Linear(config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias)
        self.o_proj = nn.Linear(config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias)
        self.q_norm = Qwen3RMSNorm(self.head_dim, eps=config.rms_norm_eps)
        self.k_norm = Qwen3RMSNorm(self.head_dim, eps=config.rms_norm_eps)

    def forward(self, hidden_states, position_embeddings, attention_mask, past_key_values, ...):
        input_shape = hidden_states.shape[:-1]
        hidden_shape = (*input_shape, -1, self.head_dim)

        # QK-Norm:投影后、RoPE 前做 RMSNorm
        query_states = self.q_norm(self.q_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
        key_states = self.k_norm(self.k_proj(hidden_states).view(hidden_shape)).transpose(1, 2)
        value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)

        cos, sin = position_embeddings
        query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)

        if past_key_values is not None:
            key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)

        attn_output, attn_weights = eager_attention_forward(
            self, query_states, key_states, value_states, attention_mask, ...
        )
        attn_output = attn_output.reshape(*input_shape, -1).contiguous()
        attn_output = self.o_proj(attn_output)
        return attn_output, attn_weights

参考 ​

  1. https://github.com/huggingface/transformers/blob/v5.12.0/src/transformers/models/qwen3/modeling_qwen3.py