大模型的权重到底怎么用?拆开一个 token 的生成过程
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
我们已经知道,大模型里有很多参数,训练时会调整它们,平常聊天时通常不会。 但这还没回答一个最直观的问题:
“经过注意力、FFN,最后预测下一个 token”这句话没有错,但跳过了最关键的部分:数据到底怎样使用这些权重? 这篇只沿着一个例子往下走,不展开训练、蒸馏和量化。 假设输入是“我喜欢”,为了讲解,约定分成两个 token:
这里的切分、编号、向量和分数都是教学示意,不是真实模型的测量结果。“我喜欢”也完全可能接出其他内容。 本文讨论常见的、从左到右生成文本的 decoder-only Transformer;层内顺序采用常见的 Pre-Norm 形式,不代表所有模型都完全相同。 一、先分清:词表、代码和权重不是一回事运行一个模型,通常需要几类东西配合:
图里最需要区分的是两张“表”:
例如,“喜欢”可能被示意为 ID
|
| 名称 | 来源 | 普通推理时是否固定 |
|---|---|---|
| Q/K/V 等投影权重 | 训练得到的模型参数 | 固定 |
| 注意力权重,也就是上面的参考比例 | 根据本次输入计算 | 随输入和位置变化 |
它们都叫“权重”,但不是同一类东西。
Attention 的结果与原向量相加后,B 的表示已经带上了上下文信息。经过归一化,它进入 FFN,也叫前馈网络,代码里常写作 MLP。
B 的向量 → 第一组权重 → 非线性变换 → 第二组权重 → 更新量
第一组权重把输入的多个数字重新组合,通常会得到一串更长的中间向量。例如,教学模型可以把 4 个数字变成 8 个数字。
中间再加一道非线性变换。最简单的例子是 ReLU:负数变成 0,正数保留。这样,哪些中间值继续发挥作用,就与这次输入有关。
第二组权重再把这些中间值组合回原来的宽度,例如从 8 个数字回到 4 个数字,方便与原向量相加。
这里变多的是一个向量里的数字,不是 token 数从 4 个变成了 8 个。
这也解释了为什么 FFN 不只是“又乘一次矩阵”:如果中间没有非线性,连续两次线性变换可以合成一次,表达能力就不同了。原始 Transformer 的逐位置 FFN 使用两次线性变换和 ReLU;同一层的所有位置复用相同参数,不同层使用各自的参数。FFN 原理
实际模型可能采用带门控的 FFN,例如 Llama 实现会让两条计算分支相乘,再投影回来;不一定是上述 ReLU 版本。这里保留的是共同点:使用学到的参数,对每个位置的向量做非线性变换。
FFN 不会直接去读取 A 的向量,但 B 交给它的输入,已经包含 Attention 汇入的上下文。因此,“逐位置处理”不等于“完全不知道前文”。
因为 Attention 和 FFN 的输出都是向量。
图中还有两个辅助操作:归一化用于调整向量的数值尺度;残差相加是把模块更新量加回它的输入,保留原来的信息通路。
以图中的 Pre-Norm 顺序为例:
先归一化 → Attention → 加回这一段的输入
再归一化 → FFN → 加回这一段的输入
B 的向量更新后,会交给下一层。下一层也做 Attention 和 FFN,但使用的是下一层自己的权重。如此走完 N 层,才进入最终归一化和输出打分。层顺序、FFN 与输出层实现
层数不是生成次数。经过 N 层,是本轮计算的一部分,不是生成了 N 个 token。
处理完输入 A、B 后,我们取最后一个已知位置 B 的最终向量,用它预测后面接什么。
LM Head 不是另外请来的评分模型。它就是当前模型的输出层,有自己的训练参数;有些模型会与 Embedding 共享权重。
它把这串向量与输出权重矩阵相乘,得到与词表大小对应的一串分数:一个候选 token 对应一个分数。这些原始分数叫 logits。
例如,只展示其中三个候选的示意分数:
| 候选 token | 本轮分数 |
|---|---|
| 猫 | 3.2 |
| 茶 | 2.7 |
| 书 | 1.1 |
这个表不是事先存好的答案。事先存好的是计算这些分数的权重;分数由本轮向量算出来。
接下来才轮到生成策略:可以取最高分,也可以把分数转换为概率后采样。采样不保证每次都选最高分,而且这种概率不是“答案客观正确的概率”。
假设这次选中了“猫”的 ID,它才成为新 token C。分词器再把 ID 序列解码成我们看见的文字。
到这里,才算走完了“根据 A、B,生成 C”的过程。
最容易绕晕的地方,是把“正在处理的 token”和“即将生成的 token”都叫成“当前 token”。
我们直接把两轮分开。

第一轮,模型处理已知的 A、B。经过各层计算,使用 B 的最终向量,选出 C“猫”。
第二轮,“猫”已经是已知 token。它的 ID 直接作为新输入,查 Embedding、经过各层 Attention 和 FFN,最后用 C 的最终向量预测 D“。”。
注意,不需要先把“猫”显示成文字,再重新分词。生成循环里已经拿到了它的 ID,可以直接续在 token 序列后面。
使用 KV Cache 时,也不用每轮把 A、B 的全部计算重做一遍。第一轮各层算出的 A、B 的 K、V 会被保存;第二轮处理 C 到哪一层,就复用那一层对应的历史 K、V,同时计算 C 自己的 Q、K、V。
因此,第二轮虽然通常只把 C 作为新增输入送进网络,但它的 Attention 仍能通过缓存参考 A、B,不是只看“猫”这一个词。KV Cache 与逐步生成
还有一个时间点值得记住:刚选出 C 时,缓存里还没有 C 自己的 K、V;下一轮真正处理 C 时,才会计算并写入。
KV Cache 是运行中保存的中间数据,不是新训练的权重。两轮使用的模型参数仍然是同一套。
再回到开头的问题:固定的数字为什么能生成新话?
不是因为权重文件里藏着每一句完整答案,而是因为这套训练得到的计算,能把不同上下文变成不同的候选分数,再一步步选出后面的 token。
阅读原文:点击这里