Qwen1、2、3模型全解析

674 阅读8分钟

Qwen:

1.分词器采用BPE

核心思想:先按照字符切分,逐渐合并出现频率高的子词

  • 问题:

    • BPE理论上还是会出现OOV的,当词汇表受限,语料中又没有出现过某个子词,这个子词就无法进入词典中。而BBPE理论上不会出现这种问题。

参考:

  1. LLM大语言模型之Tokenization分词方法

2.使用Untied Embedding

输入嵌入(input embedding)和输出投影(output projection)使用独立的权重矩阵,而不是共享的权重。会增加内存消耗,但是可以获得更好的性能

3.采用FP32精度的旋转位置编码(RoPE)

并选择使用FP32精度的逆频率矩阵

4.在QKV层中添加bias,其他层移除bias

移除大多数层的bias有助于提高模型稳定性和性能,这种做法减少参数量,从而降低模型复杂度和过拟合风险。在QKV注意力层中添加bias,可以更好捕捉输入数据的特征,从而提升模型在处理未知或者未见数据时候的表现,这点能增强模型的外推能力。

5.采用Pre-Norm

  • Pre-Norm:LN在MHA和FFN之前(->LN->MHA->残差->LN->FFN->残差->)
  • Post-Norm: LN再MHA和FFN之后(->MHA->残差->LN->FFN->残差->LN->)
  • Pre-Norm收敛速度更快、有助于训练早期阶段梯度稳定。Post-Norm效果更好。

6.替换LN,采用RMSNorm

  • LN:Layer Normalization是模型每一层对输入进行归一化的技术。

    •     LayerNorm(x)=xμσλ+βLayerNorm(x) = \frac{x-\mu}{\sigma}·\lambda + \beta,其中μ\mu σ\sigma 是输入x的均值和标准差,后面两个是可学习的参数。

    • 优点:

      • 稳定性:通过对每一层的输入进行归一化,可以缓解梯度消失和梯度爆炸的问题。
      • 无batch依赖:LN是在句子内部做归一化,BN是在batch维度做归一化。因此LN在小batch或者单样本依然有以下。
    • 缺点:

      • 计算复杂度高:LN需要计算均值和标准差,计算相对复杂。
      • 对特征缩放不敏感:有时候会对特征缩放不敏感,需要额外调整超参数。
  • RMS Norm:

  RMS Norm是一种通过均方根值( Root Mean Square 对输入进行归一化的方法:

    RMSNorm(x)=xRMS(x)λRMSNorm(x) = \frac{x}{RMS(x)}·\lambda

  • 优点:

    • 计算效率高:RMS Norm比LN计算复杂度低,因为不需要计算均值和标准差,只需要计算均方根值
    • 稳定性好:RMS Norm也可以缓解梯度消失和梯度爆炸的问题,提升模型的训练稳定性。
  • 缺点:

    • 信息损失:由于RMS Norm只考虑了均方根值,会丢失一些与输入分布相关的信息。

7.激活函数采用SwiGLU

  结合了Swish和Gated Linear Units(GLU)的优点,提供更强的表达能力和更好的性能。

  • Swish激活函数是对ReLU激活函数的改进,在0附近提供更平滑的转换。在零点可微的。

  • GLU激活函数具有门控机制, 可以帮助网络更好的捕获序列数据中的长距离依赖。在大语言模型中,对于处理长序列、长距离依赖的文本更适合。

8.注意力模块采用Flash Attenion,提高训练速度

9.外推能力扩展

Transformer在注意力机制的上下文方面有限制,直接增加训练阶段上下文,会导致训练成本急剧增长。

Qwen在推理阶段实现上下文长度的扩展。

经过下面的优化,Qwen模型在inferenc可以处理8192(训练使用的是2048,提升了4倍)个token的长序列。

9.1 RoPE的问题:直接外推会出现比较大的Attention score

  Qwen使用位置编码是RoPE,虽然RoPE相对绝对位置编码有可外推的优点,但是直接使用,会有一些问题,QWen针对这些问题做了改进:

  • cos和sin函数的周期性

    • 由于cos和sin的周期性,训练数据中,位置通常在一个相对较小的周期内(例如:0到512或者0-到2048),这些位置的编码值会保持在周期的某一部分。
    • 当位置超出这个范围(如位置到3000或者5000),编码值会进入cos和sin的另一个周期。由于函数的周期性,这些位置的编码值可能与训练数据中的位置编码值非常不同,导致模型在计算attention score的时候出现剧烈变化。
  • 高频成分的影响

    • RoPE编码中,较高维度的编码会对位置变化更加敏感。这一位置,随着位置数据的增加,这些高频成分会迅速变化。

    • 对于较大位置的编码值,cos和sin的值会经历迅速变化,这会导致计算Attenion score出现剧烈变化

  9.2 解决办法:“动态NTK感知差值”来实现Inference阶段的上下文长度扩展- 位置插值法:    直观理解:右上角是预训练阶段位置向量范围[0,2048],右上角微长度外推部分(2048,4096],如果直接使用位置(2048,4096]进行推理,因为模型没有见过这部分位置,效果就会出现灾难性下降。    因此把[0,4096]这个区间压缩到[0,2048],这就是位置内插法。- NTK-aware差值法    位置插值法的问题:如果差值是正对绝对位置m,那么对每个维度j都同等生效,公平对待。但是在高频维度,差值之后会变得很密集,这样高频的维度就变得很拥挤。    NTK-aware差值的核心思想:高频外推,低频内插。
  9.2 采用LogN-Scaling    在attention计算时使用 LogN-Scaling,根据上下文长度调整点乘,注意力的熵在上下文长度增加的时候也保持稳定,提高外推能力。    Attention(Q,K,V)=softmax(klogndQKT)VAttention(Q,K,V) = softmax(\frac{k·logn}{\sqrt{d}}QK^T)V    n是输入长度,k是超参。
  9.3 SWA(sliding window attention)1. 只在一段窗口内做注意力计算。
  1. 发现较低的层对上下文长度更敏感,因此在底层采用更短的窗口。

Qwen2

1. 采用BBPE(Byte-leve BPE):

  与BPE的区别:BPE是字符级别,BBPE是字节级别

  在UTF-8编码下,每个中文字符由3个字节表示,如“我爱北京天安门”,“我”对应的UTF-8字节是

  合并算法与BPE一样。

  • BBPE优势:

    • 理论上不会存在OOV的问题。
    • 解决生僻字:如emoji等。

参考:

  1. zhuanlan.zhihu.com/p/200047771…

2. 采用了GQA(Grouped Query Attention)

代替了传统的MHA(multi head attention)。GQA通过KV-cache,在推理阶段显著提高了吞吐量。

3.采用双块注意力:

  为了扩展大模型的上下文窗口,Qwen2实现了双快注意力机制,将长序列分割成可管理的长度快。

  如果整个序列分成4个块,C1,C2,C3,C4,具体的做法:

  1. 计算块内的局部注意力:就是在块内执行Self-attention,得到attention score。
  2. 对每个块,计算一个块表示:计算平均值或者最大值。
  3. 计算全局注意力:在上面的快表示之间计算全局注意力。

4.YARN

采用YARN(Yet Another Rescaling Method),用于重新调整注意力权重,以更好的处理不同长度的序列。

具体实现过程:

  1. 计算原始注意力权重:如常规的dot-product attention。
  2. 计算缩放因子:这个因子通常是一个与序列长度相关的函数,用来调整注意力权重的分布。比如:α=1L\alpha=\frac{1}{\sqrt{L}}
  3. 应用缩放因子:将前面的缩放因子应用在原始注意力权重上。
  4. 归一化:对调整后的注意力权重进行归一化处理,确保权重总和为1。

5.MoE架构

6.RLHF采用DPO算法

7.源码解读

github.com/huggingface…

参考:

  1. www.zhihu.com/tardis/zm/a…

Qwen3:

1.q,k做了RMSNorm归一

Attention(Q,K,V)=Softmax(RMSNorm(Q)RMSNorm(K)Tdk)VAttention(Q,K,V)=Softmax(\frac{RMSNorm(Q)·RMSNorm(K)^T}{\sqrt{d_k}})·V

2.混合推理

  • 具体应用

AIP中提供了一个“enable_thinking”的字段

  apply_chat_template()这个函数是transformers中构建对话模版的方法

text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
    enable_thinking=False  # True is the default value for enable_thinking.
)
  • 实现原理

在千问3.0模型中,通过Jinja2模版来定义文本模板,包括:

  1. <|im_start|><|im_end|>:标记消息的开始和结束
  2. role:标识消息发送者(system、user、assistant、tool)
  3. <think></think>:围绕助手的思考过程
  4. <tool_call></tool_call>:包含工具调用信息
  5. <tool_response></tool_response>:包含工具响应信息

其中有一段内容:

{%- if add_generation_prompt %}
    {{- '<|im_start|>assistant\n' }}
    {%- if enable_thinking is defined and enable_thinking is false %}
        {{- '<think>\n\n</think>\n\n' }}
    {%- endif %}
{%- endif %}

会根据config中enable_thinking的值来生成不同格式的输入:

"""
<|im_start|>system
你是一名乐于助人的助手。<|im_end|>
<|im_start|>user
给我讲讲大语言模型。<|im_end|>
<|im_start|>assistant
"""
"""
<|im_start|>system
你是一名乐于助人的助手。<|im_end|>
<|im_start|>user
给我讲讲大语言模型。<|im_end|>
<|im_start|>assistant
<think>

</think>
"""

相当于在enable_thinking=False的情况下,在构建context的时候,把内容已经放进去了,那么大模型就不会再生成部分了。

  • 高级用法-软控制

可以直接在用户输入中添加 "/think"和“/no_think”来实现,比如:

参考:

  1. zhuanlan.zhihu.com/p/189836516…
  2. blog.csdn.net/Python_coco…
  3. zhuanlan.zhihu.com/p/190722283…
  4. qwenlm.github.io/zh/blog/qwe…

3.qwen3.0 post-train的四个阶段

  1. 长思维链冷启动:使用math、code、long-cot、STEM等问题做全参SFT,让LLM具备基础的推理能力。
  2. 长思维链强化学习:利用基于规则的奖励增强模型的探索和钻研能力。
  3. 思考模式融合:同时使用长思维链数据和常用的指令微调数据对模型进行微调,将非思考模式整合到思考模式中,实现混合思考的能力。
  4. 通用强化学习:在指令遵循、格式遵循和Agent能力等20多个通用领域的任务上做强化学习,以进一步增强模型的通用能力并纠正不良行为。