12

词嵌入——65,536 × 1,536 这张表在做什么

阅读约 6 分钟第 12/60 课

进入注意力机制之前,有一个基础构件需要看清楚:嵌入层。

第 09 章节简要提过,嵌入层是一张 65,536 × 1,536 的查找表——给一个 token ID,返回一行 1,536 个数字。这一章节把它讲透:这张表怎么初始化、怎么被训练、训练之后学到了什么。

查表的过程

嵌入层没有任何复杂的计算。它就是一个二维数组(矩阵),每一行对应一个 token:

行 0:     [0.023, -0.156, 0.891, ..., 0.334]     ← token 0 的向量
行 1:     [0.712, 0.045, -0.223, ..., 0.567]     ← token 1 的向量
行 2:     [...]
...
行 65535: [-0.134, 0.678, 0.012, ..., -0.891]    ← token 65535 的向量

当 tokenizer 把一段文本编码成 token ID 序列 [3847, 2190, 1523, 892, 4401] 之后,嵌入层做的就是:

output = []
for token_id in [3847, 2190, 1523, 892, 4401]:
    output.append(embedding_table[token_id])   # 去第 token_id 行取向量

五次查表,得到五个 1,536 维向量。排起来就是一个 5×1,536 的矩阵。

这个操作等价于一种特殊的矩阵乘法:把 token ID 转成 one-hot 向量(在 ID 对应的位置放 1,其余全是 0),然后乘以嵌入矩阵。但实际实现中没有人真的去做这个乘法——直接查表比乘法快得多。

训练前:随机噪声

训练开始之前,这张表的每一个数字都是随机初始化的——通常是从均值为 0、标准差很小的正态分布中采样的随机数。

这意味着训练开始时:

  • 「猫」和「狗」的向量没有任何相似性——它们只是两组随机数字。
  • 「的」和「了」的向量也没有任何关系。
  • 所有 token 在 1,536 维空间中的分布像一团均匀的噪声,没有结构。

模型在这个阶段对语言一无所知。

训练中:梯度推动向量移动

训练过程中发生了什么?

回顾第 01 章节的学习循环:模型预测下一个词 → 跟正确答案比较 → 计算 loss → 根据 loss 调整参数。嵌入表的每一个数字都是参数,都会在这个过程中被调整。

具体来说,当模型在某个位置预测错了,梯度会从 loss 一路反向传播到嵌入层(反向传播是第 25 章节的主题),告诉嵌入层:「这个 token 的向量需要往某个方向移动一点」。

经过 200 亿个 token 的训练,每个 token 的向量都被推了无数次。最终结果是:

  • 经常出现在相似上下文中的词,向量被推到了相近的位置。「猫」「狗」「兔子」经常出现在「养了一只__」「__跑过来」这样的语境中,它们的向量逐渐靠近。
  • 功能相似的词也会靠近。「但是」「然而」「不过」都是转折连词,向量相近。
  • 含义无关的词被推到远离彼此的位置。「猫」和「经济」几乎不会出现在相似的上下文中,向量越推越远。

没有人给模型标注了「猫和狗是动物」——这个知识完全是从上下文的统计规律中涌现出来的。

训练后:有结构的空间

训练结束后,65,536 个 token 在 1,536 维空间中不再是一团无序的噪声,而是形成了有意义的结构。

虽然我们无法直接观察 1,536 维空间,但可以用降维可视化工具(比如 t-SNE 或 UMAP)把高维向量投影到二维平面上来观察。在典型的词向量可视化中,你会看到:

  • 动物词聚成一簇
  • 数字词聚成一簇
  • 国家名聚成一簇
  • 动词、名词、形容词各自有偏向的区域
  • 中文词和对应的英文词在空间中的相对位置相似

这就是嵌入层学到的东西:一张把离散的 token ID 映射到连续高维空间的地图,地图上的距离和方向编码了语义关系。

嵌入层的参数量

65,536 × 1,536 = 100,663,296,约 1 亿个参数。

这 1 亿个参数占了 Sophia 总参数量(约 10.1 亿)的大约 10%。它们没有做任何「计算」——只是存储了每个 token 的向量表示。但这张表是模型理解语言的第一步:如果嵌入向量学得不好,后面的 28 层 Transformer 拿到的输入就是混乱的,再多的计算也难以补救。

还有一个细节:Sophia 的输出层(把 1,536 维向量映射回 65,536 维、生成对每个词的预测概率的那一层)和嵌入层共享同一张表——这种做法叫权重绑定(weight tying)。共享权重既节省了参数(不用存两份 1 亿参数的表),也让输入和输出的语义空间保持一致。

下一章节进入本单元的核心:自注意力。一个 token 的向量怎么「看到」前面其他 token 的向量,怎么根据上下文修正自己的表示。