Skip to content

词嵌入

神经网络只认数字,不认文字。词嵌入(Word Embedding) 的任务,就是把人类语言里的「词 / 子词 / 字符」翻译成一串串可以被计算的向量,并且让意思相近的词,向量也相近

为什么需要嵌入

模型的输入必须是张量(数字矩阵)。最朴素的做法是 One-Hot:

词表 = [猫, 狗, 鱼, 书]
猫 → [1,0,0,0]
狗 → [0,1,0,0]
鱼 → [0,0,1,0]
书 → [0,0,0,1]

One-Hot 有两个致命问题:

  1. 维度爆炸:词表有 5 万个词,每个向量就得 5 万维,且绝大多数是 0(稀疏)。
  2. 语义缺失:任意两个 One-Hot 向量的点积都是 0,「猫」和「狗」的距离,与「猫」和「书」的距离完全一样——模型看不出谁和谁更像。

稠密向量:让距离有意义

词嵌入用低维稠密向量(如 512、768 维)表示一个词,每个维度都可以理解为某种「隐含特征」的强度:

        维度含义(示意,实际由模型自己学出来)
        动物性  可爱度  水生  ...
猫  → [ 0.9 ,  0.8 ,  0.1 ]
狗  → [ 0.9 ,  0.7 ,  0.0 ]
鱼  → [ 0.6 ,  0.2 ,  0.9 ]
书  → [ 0.0 ,  0.1 ,  0.0 ]

向量距离: 猫≈狗  >  猫~鱼  >  猫≠书

经典的「向量算术」直观展示了这种语义结构:

  king - man + woman  ≈  queen
  北京 - 中国 + 法国  ≈  巴黎

嵌入是「查表」,而且是学出来的

实现上,词嵌入就是一张巨大的查找表(Embedding Matrix)

  嵌入矩阵 E 的形状 = [词表大小 V, 嵌入维度 d_model]

  第 0 行 → 词表第 0 个词的向量
  第 1 行 → 词表第 1 个词的向量
  ...

  输入 token id = 5  →  取 E[5] 这一行向量,就是它的嵌入

关键在于:这张表的每一行都是训练时学出来的,不是人工设定。模型为了把下游任务做好,会自动把语义相近的词在向量空间里拉近。

随机初始化 E  ──训练(反向传播)──►  有意义的语义空间 E

在 PyTorch 里就一层

python
import torch
import torch.nn as nn

V = 10000      # 词表大小
d_model = 512  # 嵌入维度(Transformer 的"宽度")

# 一张可学习的查找表
embedding = nn.Embedding(V, d_model)

ids = torch.tensor([[5, 128, 7, 0]])   # 一句话: 4 个 token
x = embedding(ids)                      # 形状 [1, 4, 512]
print(x.shape)   # torch.Size([1, 4, 512])
  • 输入:一串 token id(整数)。
  • 输出:[batch, 序列长度, d_model] 的浮点张量——这就是后续所有注意力运算的起点。

一个必须搞清的量:d_model

d_model(原始论文取 512)是 Transformer 的「主干道宽度」,贯穿全流程:

 token id ──嵌入──► 向量(维度 d_model)

     位置编码(同样 d_model)└──► 相加,仍是 d_model

                   注意力/FFN 全程都在 d_model 空间里流动

记住:嵌入层输出必须是 d_model 维,才能和位置编码相加、才能进入注意力。这是各模块能「串起来」的前提。

词、子词还是字符?

「一个词对应一个向量」在现代大模型里其实是简化的说法。真实情况有三种切分粒度:

粒度例子优缺点
字符级h,e,l,o词表极小,但序列很长、语义稀疏。适合 NanoGPT 练手
词级hello,world直观,但遇到没见过的词(OOV)就抓瞎,词表巨大
子词级(主流)un,##believ,##able兼顾词表大小与覆盖率,是 BERT/GPT 的实际做法

子词的切分由分词器(Tokenizer) 完成,嵌入层则负责把切好的 token id 变成向量。二者是上下游关系:

文本 ──Tokenizer──► token 序列 ──Embedding查表──► 向量序列
      (见 Transformers库/分词器)      (本页)

详见 分词器

权重共享的小技巧

在 GPT 这类模型里,输入嵌入矩阵和最后输出投影矩阵常常共享同一份权重(tied embeddings):既省参数,又让「一个词作为输入的含义」和「作为输出被预测的含义」保持一致。这一点我们会在 搭建NanoGPT 里实际用到。

小结

  • 嵌入把离散符号变成低维稠密向量,让「语义相似 = 向量相似」。
  • 本质是一张可学习的查找表nn.Embedding 一行搞定。
  • 输出维度必须为 d_model,这是所有后续模块的接口。
  • 现代模型多用子词切分,分词与嵌入是两步。

下一步

有了向量,但还不知道「谁在第几位」。下一页给向量打上顺序戳 → 位置编码