每天学一点AI知识|DAY 10 - 隐状态、Logits 与 Softmax
Transformer 内部为每个 Token 位置逐层计算隐状态。最后一层当前位置的隐状态经过输出层映射成与词表等长的 logits,Softmax 再把这些原始分数归一化为总和为 1 的概率分布。
在 DAY 9 中,我们认识了 self-attention、cross-attention 和 causal attention。
Attention 让每个位置根据允许读取的信息更新自己的表示。经过一层又一层 Transformer 以后,模型内部已经形成了融合上下文的向量。
但用户最终看到的不是向量,而是文字。
模型内部的一组浮点数,怎样变成“北京”、“上海”、“。”等整个词表上的候选倾向?为什么模型能发现某个 Token 的概率更高?Logit 与概率又是不是同一个东西?
这条输出链路可以先压缩成四步:
隐状态↓输出层映射↓Logits↓ Softmax词表概率分布
隐状态是当前输入经过模型逐层计算形成的内部表示;logits 是模型为词表中每个 Token 给出的原始分数;Softmax 则把整组分数转换成概率分布。
今天,我们就沿着这条链路回答一个核心问题:模型内部的向量怎样变成整个词表上的概率?

一、先把完整输出链路连起来
假设用户输入:
中国的首都是Tokenizer 先把文本转换成 Token ID,Embedding 再把 ID 转成初始向量。随后,这些向量经过多层 Transformer,不断融合当前上下文中的信息。
到最后一层时,生成位置已经形成一个内部向量。这个向量还不是“北京”,也不是一个词表概率表,而是一组长度固定的连续数值。
模型需要继续完成两次转换:
可以想象模型得到一张很长的候选表:
真实词表可能包含数万甚至更多 Token,所以这张表非常长。模型并不是只给少数候选打分,而是为完整词表中的每个 Token 产生一个 logit。
解码策略再根据概率或相关分数,从候选中选择实际输出的 Token。
今天先关注概率是怎样得到的;具体如何根据分布选择 Token,会在后面的解码策略章节继续讨论。
二、隐状态:每一层、每个 Token 的内部向量
Transformer 不是只在最后得到一个向量。实际上输入序列经过每一层以后,每个 Token 位置都会形成新的内部表示。
这些中间表示叫作隐状态,英文是 hidden states。
如果模型当前处理的序列有 n 个 Token,每个隐状态向量的维度是 d_model,那么第 ℓ 层的全部隐状态可以写成:

其中:
ℓ 是层编号; H⁽ℓ⁾ 表示第 ℓ 层输出的全部隐状态; n 是当前输入序列的 Token 数量; d_model 是每个隐状态向量的维度; ℝ^(n × d_model) 表示这是一个由实数组成的 n 行、d_model 列矩阵。

矩阵中的每一行,对应一个 Token 位置在当前层的内部向量。
例如,输入序列有 5 个 Token,模型的隐状态维度是 768,那么每一层输出矩阵的形状就是:
5 × 768可以把它想象成 5 行,每行 768 个数:
Token 1 → [第 1 个位置的 768 维隐状态]Token 2 → [第 2 个位置的 768 维隐状态]Token 3 → [第 3 个位置的 768 维隐状态]Token 4 → [第 4 个位置的 768 维隐状态]Token 5 → [第 5 个位置的 768 维隐状态]
当这些表示进入下一层时,模型会使用当前层输出继续计算,形成下一层隐状态。层数不断增加,每个位置的表示也不断被上下文和模型计算更新。
因此,隐状态中的“隐”并不是神秘或不可知,而是说它属于模型内部的中间表示,不直接等于人类可读文本或最终概率。
三、同一个 Token,为什么会有不同隐状态
在 DAY 6 中,我们区分了初始 Embedding 与上下文化后的隐状态。
如果同一个 Token ID 出现在不同句子中,它从 Embedding 表查到的初始向量可以相同,但经过 Transformer 以后形成的隐状态通常不同。
比较:
苹果发布了新手机。我吃了一个苹果。
假设两处“苹果”对应同一个 Token ID,它们最初取得相同的 Embedding。但第一句话中,“苹果”会与“发布”“新手机”等位置交互;第二句话中,它会与“吃了”“一个”等位置交互。
经过多层 Attention 和其他计算以后,这两个位置形成不同的内部向量。

因此,可以把两者的关系概括为:
初始 Embedding:Token 身份提供的起点表示隐状态:Token 在当前层、当前上下文中的临时表示
同一个 Token 不仅会因为上下文不同而产生不同隐状态,也会在模型不同层拥有不同隐状态。如果把每一层的输出称为该层的隐状态,那么第 2 层隐状态是在第 1 层输出的基础上,由第 2 层继续计算得到的;第 20 层隐状态则是在第 19 层输出的基础上,由第 20 层继续计算得到的。
所以,谈论隐状态时要同时说明两个位置:
它属于序列中的哪个 Token 位置; 它来自模型的哪一层。
四、隐状态不是参数、概率或长期记忆
“模型内部的数字”很容易被统称为参数,但隐状态与参数不是一回事。
参数:模型训练后保留下来的计算规则
权重矩阵和偏置等参数在训练过程中学习得到。普通推理时,同一套参数会被反复用于处理不同输入,通常不会因为一轮聊天而自动改变。
隐状态:本次输入产生的临时计算结果
隐状态由当前输入与当前参数共同计算得到。输入改变,隐状态通常也会改变;当前前向传播结束后,这些中间表示也不等于已经写入模型的长期知识。
可以对照理解:
隐状态也不是概率。它的各个维度可以是正数、负数或其他实数,并不要求位于 0 到 1 之间,也不要求所有维度相加等于 1。
它同样不等于模型的长期记忆。模型在当前上下文中形成某些隐状态,只说明这些信息参与了本轮计算,不表示它们已经永久修改参数。
五、为什么生成下一个 Token 时关注最后一个可见位置
在 decoder-only 模型中,提示词和已生成内容位于同一条因果序列中。
假设当前序列是:
中国 的 首都 是按照这个简化后的 Token 划分,模型经过多层 Transformer 后,会为“中国”“的”“首都”“是”等每个位置产生最后一层隐状态。
由于因果 self-attention 的限制,最后一个可见位置可以汇总当前序列中允许读取的全部前文信息。因此,当模型要预测紧接在当前序列之后的下一个 Token 时,会使用最后一个可见位置的最终隐状态进行输出映射。
在这个简化例子中,最后一个 Token 是“是”,所以“最后一个可见位置的隐状态”就是“是”这个位置经过最后一层 Transformer 后得到的隐状态。它不只包含“是”本身的信息,还包含这个位置通过因果 self-attention 从“中国”、“的”、“首都”等前文位置获得的信息。
需要区分隐状态所属的位置与它用于预测的对象:
隐状态所属的位置 → 当前序列末尾的“是”它用于预测的对象 → “是”后面的下一个 Token
模型不会额外创建一个“空白位置”的隐状态,而是将“是”这个位置的最终隐状态映射到词表 logits,用来预测后续可能出现的“北”、“北京”等 Token。实际 tokenizer 不一定按照示例中的汉字和词语切分,这里只用简化后的 Token 划分说明计算过程。
可以抽象为:
当前序列所有位置的最终隐状态↓取最后一个可见位置的隐状态↓映射到下一个 Token 的词表分数
训练时,模型可能一次为多个位置计算下一 Token 预测;推理时,我们通常关心当前序列末尾位置对应的下一步分布。
这也解释了为什么模型不是把整张隐状态矩阵直接当成一个概率表。隐状态仍然位于 d_model 维的内部表示空间,而词表概率需要覆盖 |V| 个候选 Token。两者维度和含义都不同,还需要一个输出层连接起来。
六、Logits:从内部表示映射到词表维度
假设 Transformer 一共有 L 层,第 i 个位置在最后一层的隐状态记作 hᵢ⁽ᴸ⁾。
模型通过输出权重矩阵和偏置,把这个 d_model 维向量映射成词表维度:

其中:
L 是 Transformer 的最后一层编号; i 是当前处理的 Token 位置; hᵢ⁽ᴸ⁾ 是第 i 个位置在最后一层的隐状态,长度为 d_model; W_out ∈ ℝ^(d_model × |V|) 是可训练的输出权重矩阵; b_out ∈ ℝ^|V| 是输出层偏置向量; V 是 Tokenizer 的完整词表; |V| 是词表包含的 Token 总数; z 是长度为 |V| 的 logits 向量。

这次映射完成了一个关键转换:
d_model 维内部表示↓|V| 维词表原始分数
如果模型的隐状态维度是 4096,词表大小是 50,000,那么输入输出层的是一个 4096 维向量,得到的则是一个包含 50,000 个分数的 logits 向量。
词表中的每个 Token 恰好对应一个 logit。
为了避免与位置编号 i 混淆,可以用 zⱼ 表示词表中第 j 个 Token 的 logit。这里的 j 是词表条目编号,不是输入序列的位置编号。
七、为什么输出层维度必须等于词表大小
模型下一步可能输出的候选,来自 Tokenizer 定义的词表。
如果词表有 50,000 个 Token,输出层就必须为这 50,000 个候选分别提供一个分数。少一个维度,就会有一个 Token 没有对应分数;多一个维度,则会产生无法对应到词表条目的输出。
因此,输出层、Token ID 与 Tokenizer 词表之间存在严格对应:
输出向量第 0 项 ↔ 词表 ID 0输出向量第 1 项 ↔ 词表 ID 1输出向量第 2 项 ↔ 词表 ID 2……
这与 DAY 6 介绍的输入链路形成首尾呼应:
输入:Token ID → Embedding 向量输出:隐状态 → 每个 Token ID 对应的 logit
模型输入和输出都必须与同一套词表协议匹配。随意更换 Tokenizer,不仅会让输入 ID 与 Embedding 错位,也会让输出 logits 无法按照原来的词表正确解码。
八、Logit 是原始分数,不是概率
Logit 表示模型对某个词表 Token 的原始倾向分数。
它可以是任意实数,例如:
Token A → 2.4Token B → 0.7Token C → -1.2
负 logit 并不表示出现了负概率,正 logit 也不表示它已经是合法概率。
Logits 不需要满足概率的两个基本条件:
例如 logits 为:
(2, 1, 0)三个数相加等于 3,而且第一个值大于 1,显然不能直接当作概率。
Logits 的主要意义在于相对大小。其他条件不变时,logit 越高,经过 Softmax 后对应概率通常也越高。
但模型最终需要一组可以比较、总和为 1 的概率分布,因此还要继续执行 Softmax。
九、Softmax 怎样把 Logits 变成概率
对于词表中第 j 个 Token,Softmax 概率写成:

其中:
j 是当前正在计算概率的词表 Token 编号; k 是求和时使用的索引,从 1 遍历到 |V|; zⱼ 是第 j 个 Token 的 logit; e 是自然常数,约等于 2.718; e^(zⱼ) 把当前 Token 的原始分数转换成正数; 分母把词表中所有 Token 的指数分数相加; pⱼ 是第 j 个 Token 的归一化概率。

Softmax 可以分成两步理解。
第一步:对每个 logit 取指数
指数结果一定为正数,所以负 logit 也会得到一个正值。
第二步:除以所有指数结果之和
每个候选都除以同一个总和,因此所有输出概率相加恰好等于 1。
对于 logits:
(2, 1, 0)Softmax 后的概率约为:
(0.665, 0.245, 0.090)这表示第一个候选在当前三项中获得最高概率,但另外两个候选仍然保留一定概率。
Softmax 不会改变 logits 的相对排序:原始分数最高的候选,归一化以后仍然拥有最高概率。它完成的是把整组相对分数转换到一个统一概率尺度上。
十、Softmax 为什么要同时查看整组 Logits
一个 Token 的概率不是只由它自己的 logit 决定,还取决于词表中其他 Token 的 logits。
假设某个候选的 logit 保持为 2。如果其他候选的 logits 都很低,它可能获得较大概率;如果许多其他候选也有接近或更高的 logits,它分到的概率就会下降。
原因就在 Softmax 的分母:
所有候选的指数分数总和每个 Token 都在与整个词表共同参与归一化。
所以,下面两组情况中,Token A 虽然 logit 都是 2,最终概率却可能不同:
情况一:(2, 0, -2)情况二:(2, 1.9, 1.8)
第一种情况下,Token A 明显领先其他候选;第二种情况下,多个候选分数接近,概率会更分散。
这也解释了为什么只查看某一个 logit 的绝对数值,无法单独判断它最终会获得多大概率。概率来自整组 logits 的相对关系。
十一、从概率分布到实际生成,还需要解码策略
Softmax 得到概率分布以后,模型仍然没有自动决定最终输出哪个 Token。
接下来需要由解码策略选择一个候选。
最简单的做法可以是选择概率最高的 Token;其他策略也可以在多个候选之间进行采样,或者先调整分布再选择。
因此,完整链路是:
最后一层当前位置隐状态↓输出层映射↓整个词表的 logits↓Softmax 概率分布↓解码策略选择实际 Token
生成出的 Token 会被追加到序列中,模型再基于更新后的上下文进行下一次前向计算。
这正好关联了 DAY 4 的自回归生成:每一步都重新形成当前位置隐状态、词表 logits 和下一 Token 分布,然后选择一个 Token 继续向前。
十二、高概率为什么不等于事实正确
Softmax 做的是数学归一化,不是事实核验。
它只根据模型已经算出的 logits,决定如何把相对倾向转换成总和为 1 的分布。至于 logits 为什么会是当前这些数值,取决于模型参数、训练数据和当前上下文。
如果模型学到了错误模式,输入信息不足,或者问题涉及模型不了解的最新事实,错误 Token 仍然可能获得很高 logit,并在 Softmax 后得到很高概率。

因此,需要区分:
模型在当前条件下更倾向生成什么现实世界中什么是真的
Softmax 回答的是前一个问题,不负责回答后一个问题。
一个回答语气自信、概率集中,只说明模型内部对某条生成路径更确定,不等于这条路径已经通过外部证据验证。
这与 DAY 4 的结论一致:高概率不是真实性的担保。
十三、Softmax 不只用于最终输出层
Softmax 是一种通用的归一化操作,并非语言模型输出层专属。
在最终输出层中,Softmax 处理的是:
整个词表上每个 Token 的 logits输出是一组词表概率。
在 Attention 中,Softmax 处理的则是:
一个 Query 与各个可读取 Key 的匹配分数输出是一组注意力权重,用于决定从各个 Value 位置汇总多少信息。
两处使用的归一化公式相同,但归一化对象不同:
因此,看到 Softmax 时需要了解它的本质是为了方便做归一化处理,而不是“它把结果变成下一个词的概率”,需要根据实际使用场景来说明Softmax的目标
十四、隐状态、Logits 与概率到底怎样区分
这三个对象都由数字组成,但维度、含义和用途不同。
可以用一句话分别记忆:
隐状态:模型现在怎样表示这个位置Logits:模型给每个词表候选打了多少原始分概率:这些分数归一化后各自占多少
隐状态到 logits 需要输出层映射;logits 到概率需要 Softmax。
十五、几个常见误解
误解一:隐状态就是模型参数
隐状态是当前输入经过模型计算得到的临时结果;参数是训练中学习并保存的权重和偏置。同一套参数处理不同输入,会产生不同隐状态。
误解二:隐状态中的每一维都有清楚的人工含义
隐状态通常是分布式表示。模型利用许多维度共同编码信息,不能简单规定某一维永远表示“是否是动物”,另一维永远表示“情绪是否积极”。
误解三:Logit 大于 1,所以它是超过 100% 的概率
Logit 不是概率,可以是任意实数。只有经过 Softmax 后,结果才位于 0 到 1 之间并且总和为 1。
误解四:Softmax 会检查哪个答案是真的
Softmax 只做归一化。错误答案也可能因为 logit 很高而获得高概率。
误解五:Softmax 只出现在模型最终输出
Attention 中也会使用 Softmax,把匹配分数归一化成注意力权重。公式相同,处理对象不同。
十六、今天真正需要记住什么
今天最重要的,是把 Transformer 内部表示与最终词表概率之间的通路连起来:
每层、每个 Token 的隐状态↓最后一层当前位置隐状态↓ 输出层整个词表的 logits↓ Softmax整个词表的概率分布↓ 解码策略实际生成的下一个 Token
核心结论可以压缩成八句话:
第一,隐状态是模型为每个 Token 位置在每一层计算出的内部向量。
第二,隐状态属于当前前向传播的中间结果,不是模型参数、概率或长期记忆。
第三,同一个 Token 的初始 Embedding 可以相同,但经过不同上下文处理后会形成不同隐状态。
第四,输出层把最后一层当前位置的 d_model 维隐状态映射到 |V| 维词表空间。
第五,词表中的每个 Token 都对应一个 logit;logit 是原始分数,不是概率。
第六,Softmax 对整组 logits 做指数化和归一化,使所有 Token 概率为正且总和为 1。
第七,一个 Token 的概率取决于它与整个词表其他 logits 的相对关系,不只取决于自己的分数。
第八,Softmax 只整理模型的相对倾向,不验证事实真假;同一个公式也可以用于 Attention 分数归一化。
下一篇,我们会回到 Attention 内部,进一步理解 Query、Key、Value 分别怎样产生,以及因果掩码怎样在分数矩阵中真正遮住未来位置。
自检
隐状态与模型参数在来源、作用和生命周期上有什么区别? 为什么同一个 Token 在不同句子中会形成不同隐状态? 为什么输出层的维度必须等于 Tokenizer 的词表大小? Logit 为什么不能直接当作概率?Softmax 做了哪两步转换? 为什么某个 Token 获得很高 Softmax 概率,仍然不能证明它表达的事实正确?
夜雨聆风