最后位置的 hidden state 仍是一个 d_model 维向量。输出层用一个学出来的大矩阵,把它一次性变成“词表里每个 token 的候选分数”。
| Topic | hidden state → logits → 词表概率 |
| Objectives | 理解输出矩阵 W_U 的形状、每列的语义、logit 与概率的区别 |
| Prerequisites | 矩阵=变换 ✅、softmax ✅、最后位置预测下一词 ✅ |
| Outcome | 能具体解释“向量怎么翻译回 token” |
| Warning | 输出层先给“分数”,还没有选择 token;选择属于下一课采样 |
输入 The cat sat on the 经最后一层后,完整输出仍是 H_last [5×d_model]:五个位置各有一个 hidden state。输出层只读取最后一行,即位置5 the 的 hidden state:
不是 Transformer 只算出一个向量;而是它算出整个列表,生成时取 H_last[最后一行] 预测位置6。矩阵逐层更新与因果掩码的具体例子见 Lesson 13 FAQ。
这个向量已经编码了“整句在说什么、接下来可能是什么”,但它仍是 512 个浮点数。要输出 token,模型必须回答:
词表中 10 万个候选 token,分别和当前语境有多匹配?
输出层就是一个“大规模候选打分器”。
设词表大小 vocab_size = 100,000、d_model = 512。输出矩阵:
把最后位置 hidden state 乘它:
结果是 10 万个数:每个词表 token 一个原始分数,叫 logit。
矩阵乘法展开后,每个 token 的 logit 本质是:
也就是说,W_U 的第 j 列可以粗略理解成:
“什么样的 hidden state,适合把 token_j 当作下一个词?”
mat 那一列方向很匹配 → mat logit 高。dog 那列不匹配 → logit 低。Embedding 是 token id → d_model 向量;unembedding 是反方向:d_model 向量 → 词表分数。所以名字像“反向翻译”。
| Embedding | [vocab_size × d_model]:从词表取一行,得到初始词向量 |
| Unembedding W_U | [d_model × vocab_size]:拿 hidden state 对所有候选列打分 |
很多模型会让 W_U = Eᵀ,直接复用 embedding 表的转置,叫 weight tying(权重绑定):同一套“token 方向”既负责读入,也负责输出,可省参数并让两个空间对齐。
logit 是任意实数(可正可负、不和为1)。把整串 logits 过一次你已学过的 softmax,才得到词表概率:
例如:
但概率出来后,模型还没决定究竟选哪个——选词属于下一课“采样”。可能选最高概率,也可能按概率随机选。
不是。它就是 Token / Embedding 课中 tokenizer 使用的同一套 token vocabulary(token ↔ id 映射),现在只是第一次从输出端重新看到它:
词表里不只完整单词,也可能有子词、标点、空格和特殊 token。
方向基本对,但更准确是:hidden state 本来就不是某个 token embedding 的复制品。它表达的是“结合当前全部上下文,什么样的 token 适合出现在下一位置”。因此不是去 embedding 表里找一个完全相等的向量,而是对所有候选 token分别计算匹配分数。
有两种设计:
| 独立输出矩阵 | 单独训练一个 W_U [d_model×vocab_size],它是额外的模型参数。 |
| 权重绑定(常见) | 直接用 embedding 表的转置:W_U = Eᵀ。不额外存一份,让同一套 token 方向既负责读入,也负责输出。 |
两种都成立;今天只需记住“W_U 可以独立,也常复用 Eᵀ”。
logit 可以是任何实数(正、负、零都行)。softmax 不会把它变成整数,而是变成 0~1 之间的正小数,并让所有概率加起来等于 1。
最终得到的 token id 才是整数:采样算法从这组概率中选中某个位置,例如选中第 3 项 → 对应那个 token id。
| logit | 任意实数的原始分数,可为负 |
| probability | softmax 后的正小数,范围 0~1,总和为1 |
| token id | 采样最终选中的离散整数索引 |
答完这 3 题,下一课下钻“采样”:有概率之后,为什么不总选第一名?temperature / top-k / top-p 各自改变什么。