笔记
Qwen3系列1-理论基础&真实结构
Qwen3 系列的第一篇文章,三天时间重新复习了 Transformer 的结构和 Qwen3 的结构。现在主流大模型和老祖论文提出的结构有了很大变化。看模型的结构,弄清楚输入输出还有有趣的,毕竟每天都在用的大模型,知道它是怎么个工作原理,也觉得他没那么神秘了。
Qwen3 的结构图:https://zhanghao0806.github.io/blog/Qwen3-TrueInference/?from=note
从一句话到 Attention:看懂并亲手算出来
D1-1 建立大模型整体地图
-
什么是语言模型、什么是 Causal Language Model。
因果语言模型;自回归生成,只能看到前面的信息;
-
为什么 Qwen3-8B 是 Decoder-only Transformer,而不是原版 Encoder–Decoder Transformer。
要回答这个问题,先清楚 encoder-decoder 中 这两个是干嘛的?(以机器翻译为例:理解+生成)
各自的注意力区别?前者 decoder 有两种注意力;后者只有一种;
下面正式回答这个问题:
1 首先 decoder-only 能做到原来 encoder 做的事情,理解上下文:生成答案的位置可以看到前文所有 token;
2 结构统一:自然语言生成(对话,数学推理、写代码)就是自回归过程:根据已有的token,输出下一个 token;
-
模型一次前向计算给出的是 Token 的预测分数,不是一次性写好完整回答。
“推理时,模型一次前向计算得到的是词表中所有 token 的预测分数”
-
模型参数、激活值/中间张量、输入 Token、输出 Token 分别是什么。
激活值:前向计算内部产生的浮点张量;
-
推理与训练/微调的区别:推理固定权重,训练通过梯度更新权重。
必须回答的问题:
-
Q2:模型为什么能反复生成直到结束?它每一轮额外拿到了什么信息?
-
Q4:参数和中间激活值有什么区别?为什么推理时也会占用显存?
显存被参数占用、激活值、 KVcache
-
Q5:
forward()与generate()概念上有什么不同?后者包括很多次前者;
动手产物 :在一页纸上画 input text → token ids → embedding → blocks → logits → next token → loop。
D1-2 最低限度的张量、线性层与 Softmax
-
[B,T,D]中B=Batch、T=序列长度、D=隐藏维度 = 词嵌入向量的维度。 - 矩阵乘法与逐元素乘法、广播;转置后维度如何变化。
-
Linear在数学上是仿射变换:Y = XW + b;Qwen3 的多数投影不带 bias。 - Softmax 的意义:将一组分数转换成总和为 1 的正数概率。
核心公式:
必须回答:
-
Q5:为什么通常用
softmax(z - max(z))进行数值稳定计算?防止溢出;
D1-3 Tokenizer、Token ID 与 Embedding
-
Tokenizer : 包括两部分:1先把文本切分成 Token;2把Token 映射为 ID 序列;
映射用的是词表。词表也是被训练出来的;在模型训练之前词表就固定了;词表可以用别人训练好的;
大模型里面的 tokenizer.json tokenizer.model 就是这个大模型的词表;
-
Embedding 是用 ID 查一个可学习矩阵的行;
Embedding 是模型的 block0,训练时参数也会更新;
-
同一个 Token 的初始 Embedding 通常相同,但不同上下文下,经 Transformer 后表示不同。
意思是不同的两句话里面相同的 token,他们初始查 embedding 得到的向量是一样的;但是经过Transformer 层之后不一样了;
-
Qwen3 聊天输入先经过 Chat Template,包含角色、边界、生成提示等特殊 Token(在Qwen 系列 2里面可以看到);“你看到的原始一句话”不等于真实送入网络的全部 Token。
必须回答:
-
Q4:Embedding 是怎么训练出来的?本轮需知道哪些、不需要知道哪些?
Embedding 也算模型参数,跟 Transformer 的权重参数一块更新;
-
Q5:特殊结束 Token(如 EOS)在生成停止中扮演什么角色?
数据驱动学出来的停止偏好,不是硬编码规则;
D1-4 单头 Scaled Dot-Product Attention
-
Q=XW_Q, K=XW_K, V=XW_V三组向量如何产生;这里的Q/K/V都来自同一序列时叫 Self-Attention。与之相对是 cross-attention;K 用来判断信息的相关性,V 才是信息的实际内容;
-
每一行 Softmax,得到针对各 Key 位置的权重。
-
权重乘以
V,得到各 Query 位置的加权信息汇总。
必须回答:
-
Q1:
Q、K、V是模型参数吗?真正的可训练参数是什么?是激活值;三个投影矩阵才是可训练参数;Wo 输出投影矩阵;
-
Q2:为什么用
QKᵀ,而不是QK?它的形状为什么与序列长度相关? -
Q3:Attention 分数矩阵的第
i行、第j列表示什么?输入 X 的第 i 个 token 和 输入 X 的第 j 个 token 的注意力分数。(手动做个乘法,就是两个 token 对应的 Q 和 K token 相乘)
注意力分数矩阵,第 i 行是第 i 个 token 对其他所有 token 的注意力分数;
softMax 是对每一行做的;
-
Q4:为什么要缩放
sqrt(d_k)?“缩放是为了得到概率”这个说法准确吗?为了防止某一个注意力的概率非常大,其他注意力很小,导致梯度消失;
-
Q5:Softmax 沿哪个维度做?每一行的和应该是多少?
沿着行 Attention 矩阵的行做;把原始权重变成分数;
-
Q6:如果某一行权重为
[0.1, 0.2, 0.7],对应 Value 向量如何合成输出?V 矩阵的每一行是一个 token 的 V 向量;
注意力矩阵乘以 V,用 AB=C 的行向量视角更容易理解;
AB 的行向量是 B 的行向量线性组合得到,第 i 个行向量的线性组合系数是 A 的第 i 行;
这样理解的好处:A(注意力矩阵) 第 i 行是第 i 个 token 对所有 token 的注意力权重,权重作为线性组合的系数,决定每个 token 的 V 要关注多少;
按行向量计算 AV,更容易理解;能把权重系数的意义体现出来;
-
Q8:如果对
Q乘一个很大的系数,Softmax 分布通常会发生什么变化?softmax 的公式是什么?它对大权重很敏感,这样会放大某一个注意力的影响,变成独热编码;后续梯度消失或爆炸;
纸笔任务:
-
3 个 Token,单头维度 2,显式给出
Q、K、V的所有数字; -
计算全部点积,形成
3×3分数矩阵; -
除以
sqrt(2),加入掩码(可和 D1-5 合并),逐行做 Softmax;
D1-5 Causal Mask、多头注意力、输出投影、残差
-
自回归 LM 的 Causal Mask:位置
i只能看到j≤i的位置;不能偷看未来 Token。为什么加入因果掩码?在训练的时候并行。一次性输入整个序列,让所有位置同时预测下一个 token;
上三角还是下三角?结合注意力矩阵元素 Aij 的含义;为了不让第 i 个 token 看到它后面的 token 的权重;
“不能偷看未来 token”在数学上的实现是:softmax 之后对这个 token 的注意力分数为 0;
-
掩码可理解为在不允许的位置加
−∞,使 Softmax 后对应权重为 0。 -
Multi-Head Attention(MHA):多个 Query/Key/Value 子空间并行计算,合并后再经过输出投影
W_O。 -
残差连接:
y = x + f(x),使主干输入与模块结果相加。记住一句话:不让每一层网络都学习完整的结果,只在上一层的基础上,学习需要修改的部分。
-
为什么模块输入输出必须适配隐藏维度,才能做残差相加。
残差是逐元素相加;
必须回答:
-
Q1:Causal Mask 矩阵加在哪里?
-
Q3:为什么训练/Prefill 可以把整段输入并行送入模型,仍然满足“不看未来”?
-
Q4:多头合并步骤?
每个头单独计算注意力、单独 softmax ,然后乘以 V;最后直接拼接,乘以融合头矩阵;
-
Q5:
Concat(head_1,head_2)后为什么还有一个W_O?不同的头关注不同维度的信息,需要按不同权重融合一下;
**纸笔任务:**对 D1-4 的 3×3 分数应用因果掩码;另画一个“两头→拼接→输出投影”的形状示意图,并算一次 x+Attention(x)。
Qwen3 特有结构
D2-1 RMSNorm、Pre-Norm 和残差路径
-
RMS(root mean square,均方根)与
RMSNorm的计算。均方根和 LayerNorm 都是在同一个样本内部做。
没有中心化,所以计算更省。只涉及放缩;
会计算 RMS;然后仿射变换每个归一化都有,有两个参数;
γ也是可训练的;
-
Qwen3 的注意力和 MLP 前使用 RMSNorm,属于 Pre-Norm 风格。
Pre-Norm是从梯度考虑的,更稳定;
Pre-Norm 是进入子层之前(在计算 QKV 之前);
Post-Norm 是计算残差之后;
必须回答:
-
Q3:Attention 前的 RMSNorm 与 QK-Norm 是同一处操作吗?
-
Q4:
x + Attention(RMSNorm(x))与RMSNorm(x + Attention(x))在计算顺序上有何不同?就是 Pre-Norm 和 Post-Norm 区别;前者梯度更稳定;
D2-2 QK-Norm 与 RoPE
-
Qwen3 注意力中,Q/K 线性投影后按注意力头归一化,随后对 Q/K 应用 RoPE。
-
QK-Norm对 Query、Key 使用各自的 RMSNorm;Value 不做同样的 QK-Norm,也不使用 RoPE。 -
RoPE编码:让一个 Token 的 Q K 向量根据相对位置不同,旋转不同的角度;
原始 transformer 的正余弦位置编码加在哪里?
RoPE 加在哪里;
效果:不会改变向量模长;旋转矩阵的转置等于负方向旋转对应角度;不会引入与位置无关的噪声项(正余弦编码会)
容易迷糊的地方:一个token 对应一个 RoPE 矩阵;每一个 token 对应的向量左乘 RoPE 矩阵,乘以的都是它对应的 RoPE 矩阵;RoPE 矩阵(隐藏层维度 4)
-
2 维 RoPE 可以看成一个旋转矩阵:一个二维向量乘以旋转矩阵等于该向量逆时针旋转θ角度;
必须回答:
-
Q1:QK-Norm 与模型 Block 开头的 RMSNorm 有何位置与作用差别?
QKNorm 考虑的是,虽然经过一次 Norm 之后,但是乘以投影之后可能依然变得很大,导致注意力高度集中在某个位置(softmax 的特性),同时为了训练时数值稳定;
每个头内部自己做 Norm;
-
Q2:QK-Norm 对
Q和K使用不同的可训练缩放参数吗?Norm 最后一步的仿射变换中 Q 的所有头共享放缩参数;K 的所有头共享放缩参数;
-
Q3:为什么 RoPE 作用在 Q/K,而不是直接把位置编号加到 Softmax 概率上?
答案应该是会导致梯度爆炸
**纸笔任务:**算一个二维 Query 的 RMSNorm,再取指定角度计算 RoPE(可使用 sin/cos 的近似值),最后与一个 Key 计算点积。
D2-3 从 MHA 理解 GQA【重点】
要学明白:
-
MHA:多头注意力,Query/K/V 的头数通常相同。推理时 KVcache占用大量显存; -
MQA:多查询注意力,多个 Query 头共享一组 K/V 头。损失模型表达能力; -
GQA:Group Quary Attention 分组查询注意力。把多个 Query 头分组,每组共享一组 K/V 头。减少一些 KV,换取显存开销下降。
-
Qwen3-8B 使用 32 个 Q 头、8 个 K/V 头,因此 每 4 个 Q 头共享 1 个 K/V 头。
投影的时候只有 Q 保持了向量的维度,KV 都变小了;每个头的内部维度都是一样大的;
-
为什么 GQA 有助于减少 KV Cache 容量和内存访问,而不是“减少了 Query 头所以一定降低表达能力”。
-
为什么推理时候需要 KV cache?
本质是什么?空间换时间;
缓存之后有用的例子:要生成第 i 个 token,把第 i 个 token 的 Q 乘以它前面所有向量的 K,V 得到输出,预测出下一个token;但是在生成第 i-1 个 token 时,前 i-2个 token 的 KV 已经算过了,可以直接用,这就是要存的 KV;
-
为什么不需要缓存 Q;
因为生成新的token,需要拿新 token 的 Q 去和所有能看见的 token 的 KV 做计算;之前 token 的 Q 没用了;
-
KV cache 大致计算公式(和哪些参数有关?)
每一个 transformer 层都需要 KVcache;
每一个 KV 头都要缓存自己的 KV;
KV 的每一行都是128 (Qwen3 分头之后的维度)维度的向量;
Token 越长,KVcache 越大;KV 的行数增加了;
2 X BatchSize X Tokens X Head_num X L(Transformer 层数) X d(每个 head 维度) X 字节数
-
硬件知识,为什么 KV cache 要放在显存不放在内存:
内存特点,容量大(可达到 1T)但是带宽低(读取速度几十到 100GB);显存容量小,但是带宽高(A100 1.5T~2T/s);KV Cache 要靠近计算单元;
-
关于 KV Cache 多说一点:在现代大模型真实推理过程中的例子
-
大模型推理分为两个阶段:Prefill 和 Decode; 前者负责生成 Prompt 的所有 KV Cache 以及第一个预测出的 Token;后续所有 Token 都由 Decode 预测;Decode 阶段每次输入的 Token 只有一个(最新预测出来的);
-
真实的例子:拿到用户的 Prompt,映射成一个 Token 序列;进入第一次也是唯一一次 Prefill 阶段;在第一层,经过归一化和 QKV 线性投影计算得到 QKV,此时将 KV 写入 Cache(Qwen3 是在计算 Attention 之前);这一层的每一个 KV 头都要建立自己的 Cache;每一层都要建立自己的 KV Cache;
-
单轮对话,是一次 prefill 和多次 decode;多轮对话,有新的提示词,就有新的 prefill;
-
prefill 要并行计算 KV Cache,计算密集型,瓶颈在计算速度上;decode 涉及很少的计算,只用一个 Token 和KV Cache 做计算,计算量小。但是要从显存读取大量数据到计算单元上,所以带宽是瓶颈;
-
-
必须回答:
-
Q1:32 个 Q 头 / 8 个 KV 头,分组倍数是几?
Q 头要分为 4 组;
-
Q2:为什么 Q 与 K 的总投影宽度可以不相同,但点积仍能做?
总的不同,但是每个头内部的维度相同;
-
Q5:序列长度增加时,缓存 K/V 主要增长在哪些维度?
序列长度这一维度:已缓存的 token 数量;
**纸笔任务:**画出 2 个 Q 头、1 个 KV 头、每头 2 维 的微型 GQA。两组 Q 用同一组 K/V,分别算两行注意力权重并拼接输出。
这一步是走完了Attention 计算公式,下面进入前馈神经网络。
FFN 的表达式:
D2-4 SwiGLU:激活函数、门控 MLP【A:重点】
要学明白:
-
为什么只有线性变换的层叠还不够,需要非线性激活函数。
Attention 负责融合各个 Token 之间的信息,MLP 负责对融合后的 Token 进行加工;
-
sigmoid(x)、SiLU(x) = x·sigmoid(x)、ReLU的公式-
SiLU激活函数:处处可导;与门控机制结合
-
ReLU:
-
-
SwiGLU 有 两条向上投影路径:
gate_proj与up_proj;它们是逐元素相乘,不是相加或拼接。 -
down_proj再把中间维度映射回隐藏维度,方便残差连接。
必须回答:
-
Q2:为什么不能把 SwiGLU 简单理解成“先线性变换一次,再激活一次”?
一般的前馈神经网络是线性变换+激活函数+线性变换;SwiGLU 有两条路径,左边相当于是门控,右边很像原来的普通神经网络的激活;
-
Q3:
gate_proj、up_proj、down_proj的输入输出尺寸分别是什么?前两者 4096 12288;后者 12288 4096;
-
Q4:SwiGLU 中的
*是点积、矩阵乘法还是逐元素乘法?逐元素乘法,相当于给原来每个元素乘以一个权重,调节;
-
Q5:为什么 MLP 最终需要映射回
hidden_size?做残差;
**纸笔任务:**对一个长度为 4 的输入,用两组尺寸简化、数字稀疏的权重算出 gate、up、SiLU、逐元素乘法与 down 的完整数值。
D2-5 拼出真实 Qwen3 Decoder Block
简洁公式:
必须回答:
-
Q1:一个 Block 有几个残差加法?加法的两个张量各是哪一个?
-
Q2:Attention 之前、MLP 之前各有一个什么归一化?
-
Q4:Attention 输出之后,MLP 能否跳过?为什么这是两个不同子模块?
负责不同的功能:Attention 负责融合 token 之间信息;MLP 负责非线性加工。
-
Q5:真实 Qwen3 中,QK-Norm、RoPE 的顺序能否颠倒后仍声称按源码实现?
**纸笔任务:**画出完整 Block,给所有箭头写维度(先用微型模型 D=4,再用真实模型 D=4096)。
映射到真实 Qwen3-8B:结构、算子、源码、实际推理
以后有时间再看。