微调LLM前你需要了解的一些概念-- 基于 Qwen3 配置文件的实践
本文基于如下 Qwen3 配置文件进行讲解:
{
"architectures": [
"Qwen3ForSequenceClassification"
],
"attention_bias": false,
"attention_dropout": 0.0,
"bos_token_id": 151643,
"dtype": "bfloat16",
"eos_token_id": 151645,
"head_dim": 128,
"hidden_act": "silu",
"hidden_size": 1024,
"id2label": {
"2": 68,
"3": 99,
"5": 158,
"8": 239,
xxx
},
"initializer_range": 0.02,
"intermediate_size": 3072,
"label2id": {
"0": "10197",
"1": "102",
"10": "1168",
xxx
},
"layer_types": [
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention",
"full_attention"
],
"max_position_embeddings": 40960,
"max_window_layers": 28,
"model_type": "qwen3",
"num_attention_heads": 16,
"num_hidden_layers": 28,
"num_key_value_heads": 8,
"pad_token_id": 151643,
"rms_norm_eps": 1e-06,
"rope_parameters": {
"rope_theta": 1000000,
"rope_type": "default"
},
"sliding_window": null,
"tie_word_embeddings": true,
"transformers_version": "5.3.0",
"use_cache": true,
"use_sliding_window": false,
"vocab_size": 151669
}
目标是把前面学习过的 Transformer、QKV、多头注意力、MLP、输出层、分类头等概念,和一个真实模型配置对应起来,做到“知道概念,也看得懂工程配置”。
1. 这个配置文件描述的是什么模型
配置里最关键的一项是:
"architectures": [
"Qwen3ForSequenceClassification"
]
这说明它不是普通的文本生成模型,而是一个序列分类模型:
Qwen3 Transformer 主干
+ Sequence Classification 分类头
结合目录名:
oncall_tenant_predict
可以推断它的任务大概率是:
输入一段 oncall / 告警 / 问题描述文本,预测它应该归属到哪个 tenant、团队或业务标签。
所以它和普通生成式 LLM 的区别在最后一层。
普通生成模型:
输入文本
→ Transformer
→ 词表输出层 W_out
→ vocab logits
→ softmax
→ 下一个 token
这个序列分类模型:
输入文本
→ Transformer
→ 分类头
→ class logits
→ softmax
→ tenant 类别
也就是说:
Transformer 主干认知是一样的,但最后任务头不同。
2. 配置文件里的关键参数
从配置中抽出和模型结构最相关的字段:
{
"model_type": "qwen3",
"hidden_size": 1024,
"num_hidden_layers": 28,
"num_attention_heads": 16,
"num_key_value_heads": 8,
"head_dim": 128,
"intermediate_size": 3072,
"hidden_act": "silu",
"vocab_size": 151669,
"max_position_embeddings": 40960,
"rms_norm_eps": 1e-6,
"attention_dropout": 0.0,
"dtype": "bfloat16",
"tie_word_embeddings": true,
"use_cache": true
}
对应成人话:
| 配置字段 | 含义 |
|---|---|
model_type = qwen3 |
使用 Qwen3 架构 |
hidden_size = 1024 |
每个 token 的主干 hidden state 是 1024 维 |
num_hidden_layers = 28 |
有 28 层 Transformer Block |
num_attention_heads = 16 |
每层有 16 个 Query attention heads |
num_key_value_heads = 8 |
每层有 8 个 Key/Value heads,说明使用 GQA |
head_dim = 128 |
每个 attention head 的维度是 128 |
intermediate_size = 3072 |
MLP 中间层升维到 3072 |
hidden_act = silu |
MLP 使用 SiLU 激活函数 |
vocab_size = 151669 |
tokenizer 词表大小 |
max_position_embeddings = 40960 |
最大上下文长度约 40960 token |
rms_norm_eps = 1e-6 |
RMSNorm 的数值稳定参数 |
dtype = bfloat16 |
使用 bf16 数值格式 |
use_cache = true |
推理时可使用 KV Cache |
整体结构可以概括为:
Token IDs
→ Embedding
→ 28 层 Qwen3 Transformer Blocks
→ 序列级 hidden state
→ 分类头
→ tenant logits
→ softmax
→ tenant 预测结果
图示如下:
3. 28 层 Transformer Block 对应什么
配置:
"num_hidden_layers": 28
表示模型有 28 个 Transformer Block 串行堆叠。
也就是:
X0 = Embedding(tokens)
X1 = Block1(X0)
X2 = Block2(X1)
...
X28 = Block28(X27)
每一层的输出都会作为下一层输入。
一个典型 Decoder-only Transformer Block 大致包含:
RMSNorm
→ Multi-Head / Grouped Query Attention
→ 残差相加
→ RMSNorm
→ MLP / FFN
→ 残差相加
图示:
对应到 oncall tenant 预测任务:
低层:识别 token、服务名、错误码、局部短语
中层:理解报警、调用关系、错误上下文、业务实体
高层:形成更适合 tenant 分类的语义表示
这不是人工规定,而是帮助理解的直觉。
4. hidden_size = 1024:每个 token 的向量维度
配置:
"hidden_size": 1024
表示在 Transformer 主干里,每个 token 通常用一个 1024 维向量表示。
例如输入:
service A 在集群 X 出现大量 timeout
被 tokenizer 切成 token 后,每个 token 都会映射成类似这样的向量:
token_i → [0.12, -0.08, 0.31, ..., 0.05] # 1024 维
随着 28 层 Transformer 不断加工,这个向量会从“基础 token 表示”逐渐变成“融合上下文后的语义表示”。
5. Multi-Head Attention 在这个配置里如何落地
配置:
"num_attention_heads": 16,
"head_dim": 128
表示每一层有 16 个 Query attention heads,每个 head 是 128 维。
因此 Query 侧的 attention 展开维度是:
16 × 128 = 2048
注意这里有一个实践细节:
hidden_size = 1024
num_attention_heads × head_dim = 2048
二者不相等。
这说明在该 Qwen3 配置中,attention 内部的 Q 投影维度可以和主干 hidden size 不完全一致。
可以粗略理解为:
主干 token 表示:1024 维
Q 投影后:16 个 head × 128 = 2048 维
Attention 计算后:再通过输出投影 Wo 回到 1024 维
也就是:
X: [batch, seq_len, 1024]
Q = X Wq
Q: [batch, seq_len, 2048]
reshape Q:
[batch, 16, seq_len, 128]
每个 Query head 会从一个角度理解上下文,比如:
Head 1:关注服务名和 PSM
Head 2:关注错误码
Head 3:关注调用链关系
Head 4:关注报警标题
Head 5:关注业务关键词
...
这只是直觉类比,实际 head 的功能是训练中自然形成的。
6. num_key_value_heads = 8:这里使用的是 GQA
配置:
"num_attention_heads": 16,
"num_key_value_heads": 8
这说明它不是最朴素的 Multi-Head Attention,而是使用了 GQA:
GQA = Grouped Query Attention
在普通 Multi-Head Attention 中:
Q heads = K heads = V heads
而这里是:
Query heads = 16
Key heads = 8
Value heads = 8
也就是说,每 2 个 Query heads 共享一组 K/V:
16 / 8 = 2
可以理解为:
Q:我想查什么,有 16 个视角
K/V:可被查询的信息,有 8 组,被 Query heads 分组共享
形状大致是:
X: [batch, seq_len, 1024]
Q = X Wq → [batch, seq_len, 2048]
reshape Q → [batch, 16, seq_len, 128]
K = X Wk → [batch, seq_len, 1024]
reshape K → [batch, 8, seq_len, 128]
V = X Wv → [batch, seq_len, 1024]
reshape V → [batch, 8, seq_len, 128]
图示:
GQA 的好处:
保留较多 Query 视角
减少 K/V 参数量
减少 KV Cache 显存占用
提升推理效率
这在长上下文和线上推理场景里很重要。
7. KV Cache 和 use_cache
配置:
"use_cache": true
表示模型支持在推理时缓存历史 token 的 K/V。
对于生成模型,KV Cache 的作用非常直观:
每生成一个新 token,只计算新 token 的 Q/K/V
历史 token 的 K/V 直接复用
对于这个序列分类任务,如果一次性输入完整文本做分类,KV Cache 不一定是核心瓶颈;但因为它继承的是 Qwen3 Transformer 架构,配置上仍然支持缓存。
结合 GQA:
num_key_value_heads = 8
比 16 个完整 K/V heads 更省缓存。
可以粗略理解为:
KV Cache 体积和 K/V heads 数量相关
K/V heads 越少,推理缓存越省
8. MLP / FFN 在这里怎么对应
配置:
"hidden_size": 1024,
"intermediate_size": 3072,
"hidden_act": "silu"
表示每层 MLP 大致是:
1024 → 3072 → 1024
Qwen 类模型通常使用带门控的 MLP,例如类似 SwiGLU / gated MLP:
gate_proj: 1024 → 3072
up_proj: 1024 → 3072
激活函数: SiLU
down_proj: 3072 → 1024
对应我们之前学的:
Attention:负责 token 之间交换信息
MLP:负责对每个 token 自己的向量做非线性加工
在 oncall 场景里:
Attention:
把报警标题、服务名、错误码、日志片段、调用链等线索联系起来。
MLP:
把这些线索加工成更适合判断 tenant 的高层特征。
例如模型可能在中间表示里形成类似特征:
服务实体 = service A
错误类型 = timeout / 5xx
业务关键词 = 某业务页面不可用
调用链线索 = A 调 B 失败
可能归属 = 某 tenant
当然,这些不是显式字段,而是分布在高维向量里的模式。
9. RMSNorm 和残差连接
配置:
"rms_norm_eps": 1e-06
说明模型使用 RMSNorm 相关结构来稳定数值。
一个 Block 中通常会有:
x' = x + Attention(RMSNorm(x))
y = x' + MLP(RMSNorm(x'))
RMSNorm 的作用:
稳定 hidden state 的数值范围
让深层网络更容易训练
减少梯度传播中的不稳定
残差连接的作用:
保留原始信息
让每层学习增量修改
避免每层都完全重写表示
帮助梯度传回前面层
也就是说,每层不是把旧理解扔掉,而是:
新表示 = 旧理解 + 本层补充
10. RoPE 和长上下文
配置:
"max_position_embeddings": 40960,
"rope_parameters": {
"rope_theta": 1000000,
"rope_type": "default"
}
这说明模型使用 RoPE 位置编码,并支持约 40960 token 的上下文长度。
RoPE 的作用是:
给 token 注入位置信息
让 attention 不仅知道 token 内容,也知道 token 的相对/顺序位置
在 oncall tenant predict 中,长上下文很有用,因为输入可能包含:
报警标题
报警详情
日志片段
服务名
调用链
用户描述
历史处理记录
长上下文能力让模型可以读更多现场证据,再判断归属 tenant。
11. 输出层:从词表预测变成分类预测
这是这份配置最值得和“普通 LLM”区分的地方。
普通 Causal LM 的最后输出是:
hidden state → W_out → vocab logits → 下一个 token
这里的 vocab_size 是:
"vocab_size": 151669
如果是生成模型,最后会输出 151669 个 token 的分数。
但这个模型是:
"Qwen3ForSequenceClassification"
所以最后不是输出词表概率,而是输出类别概率。
配置里 id2label 有 268 个类别映射,因此分类头大概率输出:
268 个 class logits
例如:
tenant_10197: 8.2
tenant_102: 3.1
tenant_30287: 1.5
...
softmax 后:
tenant_10197: 0.91
tenant_102: 0.03
tenant_30287: 0.01
...
最终选择概率最高的 tenant。
图示:
12. id2label 和 label2id:业务标签映射
配置中有大量类似:
"id2label": {
"10197": 0,
"102": 1,
"10359": 2
}
以及:
"label2id": {
"0": "10197",
"1": "102",
"2": "10359"
}
这类映射用于在模型内部类别索引和业务标签之间转换。
可以理解为:
模型内部输出类别 index: 0
业务系统里的 tenant id: 10197
所以预测流程可能是:
分类头输出 268 个 logits
→ 取 argmax 得到类别 index
→ 通过 label2id / id2label 映射回业务 tenant id
实践中要特别注意:
训练数据的 label 编码
config.json 里的 id2label / label2id
线上服务解释预测结果的逻辑
这三者必须保持一致,否则模型可能预测对了 index,但业务解释错了 tenant。
13. attention_dropout = 0.0 和 dtype = bfloat16
配置:
"attention_dropout": 0.0,
"dtype": "bfloat16"
attention_dropout = 0.0 表示 attention 权重上不做 dropout。在线上推理配置或某些训练设置中,这很常见。
bfloat16 表示使用 bf16 数值格式:
相比 float32:更省显存,计算更快
相比 float16:指数范围更大,数值稳定性通常更好
这也是大模型训练和推理中常见的工程选择。
14. 从一条 oncall 文本看完整推理流程
假设输入文本是:
报警:service A 在集群 X 出现大量 timeout。
日志:调用 B 接口返回 5xx。
描述:用户反馈某业务页面不可用。
模型处理过程可以串成:
1. tokenizer 把文本切成 token ids
2. embedding 把 token ids 变成 1024 维向量
3. 进入第 1 层 Transformer Block
4. 每层用 16 个 Query heads 从不同角度看上下文
5. 8 个 KV heads 提供可共享的 K/V 信息
6. Attention 聚合报警、服务名、错误码、调用链、业务描述等线索
7. MLP 对这些线索进行非线性加工
8. 28 层之后得到整段文本的高层语义表示
9. 分类头把语义表示映射成 268 个 tenant logits
10. softmax 得到每个 tenant 的概率
11. 选择概率最高的 tenant 作为预测结果
完整流程图:
15. 和前面学习内容的统一
这份配置把前面抽象概念都落到了字段上:
Transformer Block 层数
→ num_hidden_layers = 28
token 向量维度
→ hidden_size = 1024
多头注意力
→ num_attention_heads = 16
每个 head 的维度
→ head_dim = 128
GQA / KV heads
→ num_key_value_heads = 8
MLP 升维
→ intermediate_size = 3072
激活函数
→ hidden_act = silu
归一化
→ rms_norm_eps = 1e-6
长上下文
→ max_position_embeddings = 40960
词表大小
→ vocab_size = 151669
任务类型
→ Qwen3ForSequenceClassification
业务类别
→ id2label / label2id
因此,这个模型可以用一句话概括:
这是一个基于 Qwen3 Transformer 主干的 oncall tenant 序列分类模型。它有 28 层 Transformer Block,主干 hidden size 为 1024,每层使用 16 个 Query heads 和 8 个 KV heads 的 GQA 注意力机制,MLP 中间层为 3072 维,支持长上下文,最后通过分类头把整段 oncall 文本映射到 268 个 tenant 类别之一。
16. 分享时可以用的总结话术
如果要向别人解释这份配置,可以这么说:
这份
config.json描述的是一个 Qwen3 序列分类模型,而不是普通的下一个 token 生成模型。它的主体仍然是 Transformer:28 层 Block,每层有注意力、MLP、RMSNorm 和残差连接。注意力部分使用 16 个 Query heads、8 个 Key/Value heads 的 GQA 结构,可以在保留多视角查询能力的同时减少 K/V 缓存和计算开销。模型把 oncall 文本编码成高层语义表示后,不再映射到 151669 个词表 token,而是通过分类头输出 268 个 tenant 类别概率,用于预测问题归属。
最短版:
Qwen3ForSequenceClassification
= Qwen3 Transformer 主干
+ tenant 分类头
Transformer 负责理解 oncall 上下文;
分类头负责把理解结果映射到具体 tenant。
浙公网安备 33010602011771号