# 从向量到词：logits、softmax 与权重共享的输出投影

最后一个隐藏向量怎样变成词表上的概率、怎么选出下一个词，以及输出矩阵与词向量表共用一份参数是怎么回事

> Transformer 架构 · 序列建模基础 · 自注意力机制 · 约 6 分钟 · 10 月 26 日

## 本篇要点

1. 模型最后一层输出的是 d 维隐藏向量，它先乘输出矩阵 $W_{\text{out}}$（$V \times d$）得到 V 个 logits，再由 softmax 归一成词表上的概率，这一步才让“预测下一个词”落地。
2. logits 是未归一化的原始分数，可正可负；softmax 只保序和归一，每个词都拿到非零份额，所以概率分布天然带尾巴，这也是采样生成的基础。
3. 四词小例：$h=[1,0,1]$ 时点积得 2、1、1、0，softmax 后为 0.534、0.197、0.197、0.072，正确词若落在末位，训练就是要把它的分数顶上去。
4. 从概率到具体的词只有两种选择：取最大（贪心，输出固定）或按概率抽样（同一输入也能产生不同句子），前面的计算完全相同。
5. 权重共享（weight tying）就是令 $W_{\text{out}}=E$，此时 $z_k=e_k\cdot h$，每个词的分数变成它与隐藏向量的点积；概念上输入是“词→向量”、输出是“向量→词”，是同一空间里的正反两问。
6. 共享的收益是参数：GPT-2 的 50257×768 词表约 3860 万参数，占 12 层模型约 1.2 亿的近三分之一；共享还让每一行在每个样本上都被更新，稀有词也因此受益。
7. 共享不是普适最优：要求两端同词表同维度，翻译模型不适用，也有模型为训练并行故意分开；并且点积未除以长度，隐藏向量变长会让分布变尖，这正是调温度的着力点。

---

上一篇收尾时留了一句话没兑现：最后一层的向量怎么变成词表上的概率。这一篇把它补上，因为“预测下一个词”这句话真正落地的地方就在这里。可实际动手去看，网络最后一层吐出来的东西跟“词”没有半点关系——它是一个数向量，比如 768 个实数。

**一个 768 维的向量，凭什么指认出五万个词里的某一个？** 而做这件事的那张矩阵，为什么常被说成“就是输入那张词向量表”？

## 要跨过去的是一段什么距离

前面几篇里，一句话进了模型，先变成一串词向量，经过几层注意力和前馈网络，出来的时候每个位置还是 $d$ 维向量（GPT-2 small 里 $d=768$）。这个向量不是词，它是“这个位置上的上下文含义”：混合了前面所有词的信息，但没有任何一个坐标对应“猫”或“跑”。

而我们要的是一张有 50257 个格子的概率表，每格对应词表里的一个词，加起来等于 1。从 768 个数到五万个概率，中间必须有一台翻译机。

## 最笨但正确的想法：拿这个向量去表里挨个比像不像

先想输入那一端做了什么：词向量表 $E$ 是一张 $V \times d$ 的表（$V$ 是词表大小），第 $k$ 行就是第 $k$ 个词的向量；“把词变成向量”就是按编号取一行，也就是查表。

输出这一端做的是反过来的事：**手里有一个向量，去表里找最像它的那一行**。“像不像”可以直接用点积算：把隐藏向量 $h$ 和某个词向量 $e_k$ 逐维相乘再相加，方向越接近、长度越相当，点积越大。

于是整件事变成：拿 $h$ 和词表里每一行比一次，得到 50257 个分数，谁高就说明“下一个词更像谁”。输入是“词→向量”，输出是“向量→词”，两次都是同一张表在起作用——这个观察后面会变成一个真实的设计。

## 换成准确的说法：logits 与 softmax

把“挨个比”写成矩阵乘法：词向量表转置成 $d \times V$，一次乘完。

$$z = W_{\text{out}}\, h,\qquad W_{\text{out}} \in \mathbb{R}^{V \times d},\quad z \in \mathbb{R}^{V}$$

这个 $z$ 叫 **logits**，也就是“原始分数”。它不是概率，可以是负数，也不要求加起来等于某个数。想让分数变成概率，套 softmax：

$$p_k=\frac{e^{z_k}}{\sum_{j=1}^{V} e^{z_j}}$$

这和上一篇掩码里用的是同一个函数：指数把分数变成正数，再按总和分配一个固定预算。它只保序、只归一，不改变谁大谁小。

## 四个词的小例子，手算一遍

设词表只有四个词，$d=3$，某个位置的隐藏向量是 $h=[1,0,1]$。$W_{\text{out}}$ 的四行恰好是：

| 词 | 向量 | 与 $h$ 的点积 |
| --- | --- | --- |
| 猫 | $[1,0,1]$ | 2 |
| 狗 | $[1,0,0]$ | 1 |
| 鱼 | $[0,1,1]$ | 1 |
| 跑 | $[0,1,0]$ | 0 |

取指数：$e^{2}=7.389$，$e^{1}=2.718$（狗、鱼各一个），$e^{0}=1$，总和 $13.825$。于是

$$p=[0.534,\ 0.197,\ 0.197,\ 0.072]$$

四项相加正好是 1。模型的意思是：下一个词有 53% 的可能是“猫”，7% 的可能是“跑”。**注意最后一项不是零**：softmax 给每个词都留了份额，只是份额小。如果这里的正确答案是“跑”，0.072 就太低了，训练要做的事就是把这个分数顶上去——那是下一篇的话题。

## 从概率到一个具体的词：取最高分，还是抽签

有了这串概率，生成下一个词有两条路。

一条是取最大（`argmax`，贪心）：上例会选出“猫”，每次都一样。

一条是按概率抽签：随机数落在哪个区间就取哪个词，上例里约 53% 的机会出“猫”，偶尔蹦出“鱼”。

区别全在最后这一步，前面的计算一模一样。同一个模型、同一个输入，两种做法能给出不同的句子。怎么调抽签的“放肆程度”（温度）、怎么同时保留几条候选路径（beam search），下一篇再说。

## 那张表为什么真的能用两次

如果把 $W_{\text{out}}$ 直接设成词向量表 $E$（形状正好是 $V \times d$，尺寸对得上），那么

$$z_k = e_k \cdot h$$

也就是说，每个词的分数就是“它的词向量与当前隐藏向量的点积”。这不是近似，是恒等式。让两块权重共用一份参数，叫 **weight tying（权重共享）**。

为什么说得通？因为输出端问的问题是“当前语境下，下一个词应该落在向量空间的哪个方向”，而输入端的词向量表已经把这个空间建好了：语义相近的词方向相近。同一张表既回答“这个词什么意思”，又回答“下一步该往哪个意思走”，本来就是一体两面。

第二笔账是参数。GPT-2 的词表被扩到 50257，$d=768$，一张表就是

$$50257 \times 768 \approx 3{,}860\text{ 万}$$

个参数。12 层的 GPT-2 small 总共约 1.2 亿参数，这一张表占了将近三分之一。共享就省下同样大的第二张表；不共享，参数量要涨到 1.6 亿左右。

还有一层更细的差别：只当输入表用时，第 $k$ 行只有在第 $k$ 个词真的出现时才被更新，稀有词轮不到几次；共享之后每个位置都要给所有词算分数，每一行受到的更新都变多了。Press 和 Wolf 在 2016 年正是从这条更新规则出发提出共享的：他们报告困惑度下降，机器翻译模型参数量减半而效果不降 [1]。

## 这个比喻在哪里会失真

**“找最像的一行”不是真的只挑一行。** 输出是给所有 $V$ 个词打分并归一化，每条尾巴都非零。语言模型能写出意料之外的句子，一部分原因就在这些尾巴上。

**点积不是“纯相似度”。** 它没有除以长度，$h$ 的模长一变长，所有分数一起变大，softmax 就更尖锐。所谓调温度，做的正是缩放这个尺度。

**共享不是必须的。** 它要求输入端和输出端是同一套词表、同一维度，翻译模型的源语言和目标语言词表不同，就不能简单共享。也有大模型为了让训练时的矩阵切分更方便，故意把两块矩阵分开 [2]；即便如此，GPT-2 本身是共享的 [3]。Press 和 Wolf 的结论是实验性的收益，不是一条定理。

## 走完这一步

链路到这里通了：一句话进来，经过注意力和前馈网络，每个位置得到一个隐藏向量；最后一个位置的向量乘输出矩阵得到 $V$ 个 logits，softmax 压成概率表，取最高或抽签得到下一个词，接回输入，再来一遍。

“预测下一个词”这句话里藏着的，就是这个乘法和这次归一化。而训练要做的，是让正确那格的概率变大、其余变小——这件事怎么写成可求导的损失，一个 batch 里几十个位置怎么同时算分，是下一篇的内容。

## 思维导图

```mermaid
flowchart LR
  H["隐藏向量 h（d 维）"] --> M["输出投影 W_out（V×d）"]
  M --> L["logits：V 个原始分数"]
  L --> S["softmax 归一化"]
  S --> P["词表上的概率（和为 1）"]
  P --> G["取最大 argmax：贪心"]
  P --> R["按概率抽样：多样"]
  E["输入词向量表 E"] -. "共享参数 W_out = E" .-> M
  T["weight tying 的收益"] --> T1["省掉第二张表：约 3860 万参数"]
  T --> T2["每行每个样本都被更新，稀有词受益"]
  T --> T3["前提：同词表同维度"]
```

## 术语表

- 隐藏向量：注意力堆到最后，每个位置留下的 d 维实数向量，表示这段上下文的含义，不对应任何具体的词。
- logits：输出矩阵乘出来的 V 个原始分数，可正可负、不需要加起来等于 1，是 softmax 的输入。
- softmax：把任意一组分数变成正数并按总和分配成概率，与掩码里用的是同一个函数。
- 输出投影：形状为 $V \times d$ 的矩阵，把隐藏向量一次翻译成每个词的分数；换成代码通常叫 `lm_head`。
- 权重共享（weight tying）：让输出投影与输入词向量表共用同一份参数，使每个词的分数等于它的词向量与隐藏向量的点积。

## 来源

1. [Using the Output Embedding to Improve Language Models (Press & Wolf, 2016) — 提出共享输入与输出词向量表，分析更新规则，并报告困惑度下降与模型体积减半](https://arxiv.org/abs/1608.05859)
2. [Intriguing Properties of Quantization at Scale — 说明该模型故意不共享输入与输出 embedding 权重，以支持更高的模型并行度](https://arxiv.org/pdf/2305.19268)
3. [Language Models are Unsupervised Multitask Learners（GPT-2）— 2.3 节给出词表 50257、d_model=768 与 12 层约 1.2 亿参数的配置](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf)

---

原文：https://pangzhengboyin.com/articles/logits-softmax-output-projection-weight-tying-d89a09b6

> **庞征博引** · 想学的，慢慢都会
>
> 庞征博引是把想学的东西写成连载的 AI 学习工具：每篇 5–10 分钟，边读边问，接下来学什么跟着你走。这篇就是这样写出来的。
>
> 开始你自己的连载 → https://pangzhengboyin.com
