首页 > 基础资料 博客日记

微调LLM前你需要了解的一些概念-- 基于 Qwen3 配置文件的实践

2026-06-10 17:30:04基础资料围观4

文章微调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 预测结果

图示如下:

flowchart LR A["oncall 文本"] --> B["Tokenizer"] B --> C["Token IDs"] C --> D["Embedding: vocab_size x hidden_size"] D --> E["28 层 Transformer Blocks"] E --> F["序列级 hidden state"] F --> G["Classification Head"] G --> H["268 个类别 logits"] H --> I["softmax"] I --> J["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
→ 残差相加

图示:

flowchart TD X["输入 x"] --> N1["RMSNorm"] N1 --> A["Attention / GQA"] A --> ADD1["残差相加 x + Attention(...)"] X --> ADD1 ADD1 --> N2["RMSNorm"] N2 --> M["MLP / FFN"] M --> ADD2["残差相加 x' + MLP(...)"] ADD1 --> ADD2 ADD2 --> Y["输出 y,传给下一层"]

对应到 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]

图示:

flowchart TD X["X: [B, S, 1024]"] --> Q["Q = XWq: [B, S, 2048]"] X --> K["K = XWk: [B, S, 1024]"] X --> V["V = XWv: [B, S, 1024]"] Q --> QR["reshape Q: [B, 16, S, 128]"] K --> KR["reshape K: [B, 8, S, 128]"] V --> VR["reshape V: [B, 8, S, 128]"] KR --> REP["K/V 按组供 16 个 Q heads 使用"] VR --> REP QR --> ATT["Grouped Query Attention"] REP --> ATT ATT --> O["输出投影回 [B, S, 1024]"]

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。

图示:

flowchart LR H["Transformer 最终 hidden state"] --> C["分类头 classifier"] C --> L["268 个 class logits"] L --> S["softmax"] S --> P["tenant 概率分布"] P --> T["预测 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 作为预测结果

完整流程图:

flowchart TD A["oncall 文本<br/>报警、日志、描述、服务名"] --> B["Tokenizer"] B --> C["Token IDs"] C --> D["Embedding<br/>[B, S, 1024]"] D --> E1["Transformer Block 1"] E1 --> E2["..."] E2 --> E28["Transformer Block 28"] E28 --> H["序列级语义表示"] H --> CL["分类头"] CL --> LOGITS["268 个 tenant logits"] LOGITS --> SM["softmax"] SM --> OUT["预测 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。

文章来源:https://www.cnblogs.com/accordion/p/20426858
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云