惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
博客园_首页
博客园 - 聂微东
V
V2EX
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
SegmentFault 最新的问题
J
Java Code Geeks
Last Week in AI
Last Week in AI
The Cloudflare Blog
月光博客
月光博客
雷峰网
雷峰网
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
博客园 - Franky
腾讯CDC
Jina AI
Jina AI
博客园 - 叶小钗
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
量子位
爱范儿
爱范儿
美团技术团队
T
Tailwind CSS Blog
博客园 - 【当耐特】
D
Docker
IT之家
IT之家
V
Visual Studio Blog
P
Proofpoint News Feed
L
LangChain Blog
Engineering at Meta
Engineering at Meta
C
Check Point Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
Recorded Future
Recorded Future

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
以 Qwen 为例,学习大模型的结构
微信公众号 · 2025-02-09 · via 陈少文的网站

1. Qwen 模型介绍

2023 年 4 月,阿里巴巴推出 Qwen 的测试版。

2023 年 12 月,阿里巴巴开源了 Qwen 的第一个版本。

2024 年 9 月,阿里巴巴发布了 Qwen2.5。

2025 年 1 月,阿里巴巴发布了 Qwen 2.5-Max。

Qwen 2.5 是 Qwen 大语言模型的目前最新系列。之所以说是系列,是因为在训练完一个预训练模型之后,为了最大化模型的价值,我们会针对业务场景和资源需求,对模型进行微调、蒸馏、裁剪、量化,得到不同的模型,以达到不同用途下性能和资源消耗的平衡。

除了基座模型,Qwen2.5 还发布有对数学、编程、指令微调的版本;参数规模从 0.5 B 到 72 B 不等;还有 Int4、Int8 的量化版本。

Qwen 系列大模型在各种榜单上都取得了很好的成绩,在我们的生产环境中,也有部分业务使用的就是基于 Qwen 进行微调的模型。

2. 准备环境

  • 下载 Miniforge
1
wget "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
  • 安装 Miniforge
1
bash Miniforge3-$(uname)-$(uname -m).sh
  • 配置变量
1
2
echo "export PATH=$HOME/miniforge3/bin:$PATH" >> ~/.bashrc
source ~/.bashrc
  • 创建环境
1
conda create -n qwen python=3.12
  • 激活环境
  • 下载模型
1
git lfs clone https://huggingface.co/Qwen/Qwen2.5-0.5B
  • 查看文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
tree Qwen2.5-0.5B

.
├── config.json
├── generation_config.json
├── LICENSE
├── merges.txt
├── model.safetensors
├── README.md
├── tokenizer_config.json
├── tokenizer.json
└── vocab.json
  • 安装依赖包
1
conda install transformers pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia

3. 查看模型结构

  • 指定使用的显卡号
1
export CUDA_VISIBLE_DEVICES=0
  • 进入 IPython 环境
  • 查看模型结构
1
2
3
4
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("./Qwen2.5-0.5B")
print(model)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Qwen2ForCausalLM(
# 这是一个 CausalLM 模型
  (model): Qwen2Model(
    (embed_tokens): Embedding(151936, 896)
    # 表示输入的词嵌入层,输入的词表大小为 151936,输出的维度为 896
    (layers): ModuleList(
      # 一共有 24 层 decoder 层
      (0-23): 24 x Qwen2DecoderLayer(
        # 自注意力层
        (self_attn): Qwen2Attention(
          # QKV 矩阵的维度, 输出维度为 896
          (q_proj): Linear(in_features=896, out_features=896, bias=True)
          (k_proj): Linear(in_features=896, out_features=128, bias=True)
          (v_proj): Linear(in_features=896, out_features=128, bias=True)
          (o_proj): Linear(in_features=896, out_features=896, bias=False)
        )
        # 前馈网络层,这里由 MLP 构成,
        (mlp): Qwen2MLP(
          # 门控线性层
          (gate_proj): Linear(in_features=896, out_features=4864, bias=False)
          # 上游投影
          (up_proj): Linear(in_features=896, out_features=4864, bias=False)
          # 下游投影
          (down_proj): Linear(in_features=4864, out_features=896, bias=False)
          # 激活函数shi
          (act_fn): SiLU()
        )
        # 多头注意力,输入特征维度为 896
        (input_layernorm): Qwen2RMSNorm((896,), eps=1e-06)
        # 对多头注意力输出特征进行归一化处理
        (post_attention_layernorm): Qwen2RMSNorm((896,), eps=1e-06)
      )
    )
    # 归一化处理,为下一层的输入做准备
    (norm): Qwen2RMSNorm((896,), eps=1e-06)
    # 位置编码,将位置信息加入到特征向量中
    (rotary_emb): Qwen2RotaryEmbedding()
  )
  # 线性层,将特征向量映射到词表大小
  (lm_head): Linear(in_features=896, out_features=151936, bias=False)
)
  • 查看模型参数量
1
2
num_params = sum(p.numel() for p in model.parameters())
print(f"模型参数总量: {num_params / 1e9:.5f} B")
  • 查看模型参数
1
2
3
4
from transformers import AutoConfig

config = AutoConfig.from_pretrained("./Qwen2.5-0.5B")
print(config)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Qwen2Config {
  "_name_or_path": "./Qwen2.5-0.5B",
  "architectures": [
    "Qwen2ForCausalLM"
  ],
  "attention_dropout": 0.0,
  "bos_token_id": 151643,
  "eos_token_id": 151643,
  "hidden_act": "silu",
  "hidden_size": 896,
  "initializer_range": 0.02,
  "intermediate_size": 4864,
  "max_position_embeddings": 32768,
  "max_window_layers": 24,
  "model_type": "qwen2",
  "num_attention_heads": 14,
  "num_hidden_layers": 24,
  "num_key_value_heads": 2,
  "rms_norm_eps": 1e-06,
  "rope_scaling": null,
  "rope_theta": 1000000.0,
  "sliding_window": null,
  "tie_word_embeddings": true,
  "torch_dtype": "bfloat16",
  "transformers_version": "4.48.1",
  "use_cache": true,
  "use_mrope": false,
  "use_sliding_window": false,
  "vocab_size": 151936
}

其中,

max_position_embeddings 表示模型支持的最大序列长度为 32768。

num_attention_heads 表示多头注意力的头数,num_key_value_heads 表示表示用于 key 和 value 的独立部分数量, num_attention_heads / num_key_value_heads 就是每个 key-value 组中包含多少个注意力头。

torch_dtype 表示模型的数据类型,bfloat16 表示半精度浮点数

vocab_size 表示词表大小为 151936。

4. 哪些因素决定模型的参数量

这里有一个估算模型参数量的公式:

参数量 ≈ (隐藏层大小的平方 × 4 + 隐藏层大小 × 中间层大小) × 隐藏层层数 + 词汇表大小 × 隐藏层大小

下面是一些典型的模型结构参数:

模型名称参数量隐藏层维度层数注意力头数
Qwen-0.5B~0.5B8962414
Llama-7B7B40963232
Llama-13B13B51204040
Yi-34B34B71686056
Llama-65B65B81928064
DeepSeek-67B67B81928064

5. 为什么需要 Embedding 层

有两个问题:

1,为什么要进行这样的变换

计算机能够有效处理的是数值型连续数据,而离散的词汇(如单词、字符、标记等)无法直接输入到神经网络中进行计算。

Embedding 层将离散的词汇(如单词、字符、标记等)转换为连续的、低维的向量表示的一层。

2,为什么是这样的变换

传统的独热编码(One-Hot Encoding)等方式,会导致向量维度极高且稀疏,存在计算量大、过拟合、表达能力差等问题。

在训练时,Embedding 层的向量表示可以捕捉到单词之间的语义相似性。

举个例子,[“狗”, “猫”, “鱼”],对应的索引分别是 [0, 1, 2],词表大小为 3。假设,隐藏层大小为 3,Embedding 层的输出是一个 3x3 的矩阵,每一行对应一个词的嵌入向量。

输入:[0, 1, 2],输出:

1
2
3
4
5
[
  [0.1, 0.3, 0.5],  # 对应 "狗" 的嵌入向量
  [0.2, 0.4, 0.6],  # 对应 "猫" 的嵌入向量
  [0.3, 0.5, 0.7]   # 对应 "鱼" 的嵌入向量
]

这里也可以看到 Embedding 层大小 = 词表大小 × 隐藏层大小

在训练的过程中,Embedding 层的参数会随着模型的训练而不断调整,使得模型能够更好地捕捉到词汇之间的语义相似性。

6. 什么是 CausalLM 模型

CausalLM (Causal Language Model,因果语言模型)是一种自回归语言模型,生成文本时,只依赖于已经生成的文本,不依赖于未来的文本。

CaualLM 模型通常采用的是 Decoder-only 的 Transformer 架构,即只有解码器部分,没有编码器部分。

  • Encoder, 编码器

编码器提取输入序列的特征,得到一个固定长度的向量表示。编码器通常采用双向注意力机制,能够关注到整个序列的信息。

  • Decoder, 解码器

解码器会根据已经生成的输出元素以及上下文向量来预测下一个输出元素,直到达到预设的终止标记。解码器通常采用单向注意力机制,只能关注到已经生成的部分序列。

6.1 Encoder-Olny

Encoder-Only 模型只包含编码器,没有解码器,只能看到输入序列,不能利用已经生成的序列。

通常用于特征提取、文本分类等任务。

6.2 Encoder-Decoder

Encoder-Decoder 模型是既包含编码器,也包含解码器,能够看到输入序列和输出序列。

通常用于序列到序列的任务,如机器翻译、文本摘要等。

6.3 Decoder-Only

Decoder-Only 模型只包含解码器,没有编码器,只能看到已经生成的序列。

通常用于 GPT 等任务,如文本生成、对话生成等。掩码机制,保障了解码器只能看到已经生成的序列,而不能看到未来的序列。

下图是一个典型的 Decoder-Only 模型的结构:

7. 前馈网络层的作用

Qwen2MLP 作为 Transformer 架构里编码器或解码器模块中的前馈网络层,它的作用是在多头自注意力机制处理完序列信息之后,进一步对特征进行非线性变换和信息整合。

前馈网络层通常是由以下两个主要步骤组成:

  1. 线性变换,对输入进行加权处理

可以用公式 y=Wx+b 表示,其中 W 是权重矩阵,b 是偏置向量,x 是输入向量,y 是输出向量。

  1. 非线性激活函数,增加模型的表达能力

可以用公式 y=f(Wx+b) 表示,其中 f 是激活函数,用来控制神经元的激活程度。

常用激活函数有 ReLU、GELU、SiLU 等。

在训练过程中,前馈网络层需要不断地调整权重矩阵 W 和偏置向量 b,使得模型能够更好地拟合训练数据。

8. RMSNorm 归一化的作用

有两个问题:

  1. 为什么要进行归一化

通过归一化来去除输入的尺度差异,减少输入的变化范围,这有助于模型在训练过程中更容易收敛

  1. 为什么使用 RMSNorm

RMSNorm 是一种新型的归一化方法,它是一种基于均方根的归一化方法,与 BatchNorm、LayerNorm 等传统归一化方法相比,主要的优点是不用计算样本的均值,速度提升了 40%。

9. RoPE 旋转位置编码

纯粹的 Attention 模块是无法捕捉输入顺序的,即无法理解不同位置的 token 代表的意义不同。

RoPE 的核心思想是将位置编码与词向量通过旋转矩阵相乘,使得词向量不仅包含词汇的语义信息,还融入了位置信息,其具有以下优点:

  1. 相对位置感知:RoPE 能够自然地捕捉词汇之间的相对位置关系。
  2. 无需额外的计算:位置编码与词向量的结合在计算上是高效的。
  3. 适应不同长度的序列:RoPE 可以灵活处理不同长度的输入序列。