Module 2 · LLM Lesson 14 下钻 · 输出层

输出层 / Unembedding

最后位置的 hidden state 仍是一个 d_model 维向量。输出层用一个学出来的大矩阵,把它一次性变成“词表里每个 token 的候选分数”。

Topichidden state → logits → 词表概率
Objectives理解输出矩阵 W_U 的形状、每列的语义、logit 与概率的区别
Prerequisites矩阵=变换 ✅、softmax ✅、最后位置预测下一词 ✅
Outcome能具体解释“向量怎么翻译回 token”
Warning输出层先给“分数”,还没有选择 token;选择属于下一课采样

① Why — hidden state 还不是 token

输入 The cat sat on the 经最后一层后,完整输出仍是 H_last [5×d_model]:五个位置各有一个 hidden state。输出层只读取最后一行,即位置5 the 的 hidden state:

h_last 形状 = [1 × d_model] 例如 [1 × 512]

不是 Transformer 只算出一个向量;而是它算出整个列表,生成时取 H_last[最后一行] 预测位置6。矩阵逐层更新与因果掩码的具体例子见 Lesson 13 FAQ

这个向量已经编码了“整句在说什么、接下来可能是什么”,但它仍是 512 个浮点数。要输出 token,模型必须回答:

词表中 10 万个候选 token,分别和当前语境有多匹配?

输出层就是一个“大规模候选打分器”。

② How — 用 W_U 一次给整个词表打分

设词表大小 vocab_size = 100,000d_model = 512。输出矩阵:

W_U 形状 = [d_model × vocab_size] = [512 × 100,000]

把最后位置 hidden state 乘它:

logits = h_last · W_U → [1 × 100,000]

结果是 10 万个数:每个词表 token 一个原始分数,叫 logit

hidden state × 输出矩阵 = 整个词表的候选分数 h_last 1 × 512 × W_U:512 × 100,000 列: cat 列: mat 列: dog 每一列对应一个候选 token 的“匹配方向” = logits [1 × 100,000] cat: 1.2 mat: 8.7 ← 高 dog: 0.4 … softmax → 概率分布 下一步才采样选 token
W_U 的每一列属于一个候选 token。h_last 与每列做匹配,得到该 token 的 logit;一次矩阵乘法给整个词表打完分。

③ 机制直觉:每列是一个“候选答案方向”

矩阵乘法展开后,每个 token 的 logit 本质是:

logit(token_j) = h_last · W_U[:, j]

也就是说,W_U 的第 j 列可以粗略理解成:

“什么样的 hidden state,适合把 token_j 当作下一个词?”

机制版:Transformer 把语境“压”进 h_last;W_U 把这个语境向量同时拿去和词表中每个候选答案的方向比较,从而恢复成词表分数。

④ 为什么叫 unembedding?和 embedding 表有什么关系?

Embeddingtoken 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 方向”既负责读入,也负责输出,可省参数并让两个空间对齐。

🅿️ 诚实边界:不是所有模型都必须绑定;也可以让 W_U 独立学习。今天只记住“常见做法是复用 Eᵀ”。

⑤ logit 还不是概率,更不是最终 token

logit 是任意实数(可正可负、不和为1)。把整串 logits 过一次你已学过的 softmax,才得到词表概率:

P(token_j) = e^(logit_j) / Σ_k e^(logit_k)

例如:

logits: mat=8.7 cat=1.2 dog=0.4 …
softmax: mat=0.82 cat=0.04 dog=0.02 …

但概率出来后,模型还没决定究竟选哪个——选词属于下一课“采样”。可能选最高概率,也可能按概率随机选。

💬 深入问答(来自讨论)

Q:这里的“词表”是新出现的对象吗?

不是。它就是 Token / Embedding 课中 tokenizer 使用的同一套 token vocabulary(token ↔ id 映射),现在只是第一次从输出端重新看到它:

输入:文字 → 同一词表 token→id → 查 embedding 表
输出:词表中每个 id 的概率 → 采样某个 id → 同一词表 id→token → 文字

词表里不只完整单词,也可能有子词、标点、空格和特殊 token。

Q:最后 hidden state 是不是一个无法精确匹配 embedding 表的“新词向量”,所以才需要 W_U?

方向基本对,但更准确是:hidden state 本来就不是某个 token embedding 的复制品。它表达的是“结合当前全部上下文,什么样的 token 适合出现在下一位置”。因此不是去 embedding 表里找一个完全相等的向量,而是对所有候选 token分别计算匹配分数。

链路:token id → 初始 embedding → Transformer 加工成上下文 hidden state → W_U 对全词表候选打分。hidden state 是“当前语境需求”,W_U 的列是“候选答案方向”。

Q:W_U 是一个新的矩阵吗?

有两种设计:

独立输出矩阵单独训练一个 W_U [d_model×vocab_size],它是额外的模型参数。
权重绑定(常见)直接用 embedding 表的转置:W_U = Eᵀ。不额外存一份,让同一套 token 方向既负责读入,也负责输出。

两种都成立;今天只需记住“W_U 可以独立,也常复用 Eᵀ”。

一句话全链:最后位置 hidden state → 乘 W_U → 每个 token 一个 logit → softmax → 词表概率 →(下一课采样)→ 选出下一个 token。

Q:logit 可以是负数吗?softmax 会把它变成整数吗?

logit 可以是任何实数(正、负、零都行)。softmax 不会把它变成整数,而是变成 0~1 之间的正小数,并让所有概率加起来等于 1。

logits = [-1, 0, 2]
e^logit = [0.368, 1.000, 7.389]
除以总和 8.757
probabilities ≈ [0.042, 0.114, 0.844]

最终得到的 token id 才是整数:采样算法从这组概率中选中某个位置,例如选中第 3 项 → 对应那个 token id。

logit任意实数的原始分数,可为负
probabilitysoftmax 后的正小数,范围 0~1,总和为1
token id采样最终选中的离散整数索引
不是总选最高概率。直接选最高分叫 greedy decoding;按概率随机抽取叫 sampling。为什么以及 temperature/top-k/top-p 如何控制随机性,是下一课。

✅ 快速检查(用自己的话答)

  1. 若 d_model=512、词表=100,000,h_last 和 W_U 各是什么形状?相乘后得到什么形状、每个数代表什么?
  2. 用“候选答案方向”解释:为什么 h_last 与 W_U 某一列更匹配,该 token 的 logit 就更高?
  3. logit、概率、最终选出的 token 三者分别处在哪一步?它们是同一个东西吗?

答完这 3 题,下一课下钻“采样”:有概率之后,为什么不总选第一名?temperature / top-k / top-p 各自改变什么。