transformer你不学?03|Embedding:让文字变成向量
作 者:吴佳浩(Alben)
公某众某号:全栈架构师笔记
导读
Token ID 只是个编号,“5” 和 “9” 之间没有任何语义关系。Embedding 做的事是把每个编号映射成一个高维向量,让"语义相近的词在向量空间里也相近"。
这个"查表 + 可训练"的机制,是大模型语义理解的地基。
本篇你会学到什么
- 🔸 为什么 ID 不能直接当输入,必须过 Embedding;
- 🔸 Embedding 本质是可训练的查表操作;
- 🔸 用余弦相似度度量向量"语义距离"。
一、为什么要学这个
上篇 第 2 篇 的产出是input_ids,比如[46358, 80090, 117]。直接把 ID 喂给网络有两个致命问题:
- 🔸数值假设错误:ID 的大小顺序没有语义。ID=100 并不比 ID=10 “大十倍”,但网络会把它们当连续数值处理;
- 🔸单点无结构:一个标量表达不了语义。猫、狗、老虎的相似性需要多个维度才能编码(会捕食、体型、是否宠物……)。
Embedding 的解法:给每个 ID 分配一个d_model 维的可训练向量,语义在训练中自己学出来。经典发现:训练好的词向量里king - man + woman ≈ queen——语义关系变成了向量运算。
二、核心理论:查表即训练
nn.Embedding(vocab_size, d_model)本质是一个(vocab_size, d_model)的矩阵:
输入 ID=5 → 取出矩阵第 5 行 → 输出 d_model 维向量前向是查表,但这一行向量参与梯度更新——训练时它被不断挪动,直到语义相近的词靠在一起。
三、真实项目里怎么用
- 🔸 语义搜索:把 query 和文档都转成向量,算余弦相似度排序(RAG 的核心);
- 🔸 推荐系统:user embedding 和 item embedding 内积即兴趣分;
- 🔸 聚类分析:把客服问题聚类,发现高频诉求。
四、流程图
五、真实代码
# Embedding:ID 变向量 + 余弦相似度importtorchimporttorch.nnasnnimporttorch.nn.functionalasF torch.manual_seed(42)vocab_size,d_model=100,8# 词表 100 个词,每个词 8 维向量emb=nn.Embedding(vocab_size,d_model)# 模拟一个 batch:1 句话 4 个 tokenids=torch.tensor([[1,5,9,3]])out=emb(ids)print(f"输出 shape:{out.shape}")# (1, 4, 8):每 token 一个 8 维向量print(f"第1个token向量:{out[0,0]}")# Embedding 是可训练参数print(f"参数 shape:{emb.weight.shape}")# (100, 8) 查表矩阵本身print(f"requires_grad:{emb.weight.requires_grad}")# 余弦相似度:衡量两个词向量的方向接近程度v1=emb(torch.tensor(1))v2=emb(torch.tensor(9))cos=F.cosine_similarity(v1,v2,dim=0)print(f"token1 与 token9 的余弦相似度:{cos.item():.3f}")输出结果怎么看(真实运行输出):
输出 shape: torch.Size([1, 4, 8]) 第1个token向量: tensor([-0.7521, 1.6487, -0.3925, -1.4036, -0.7279, -0.5594, -0.7688, 0.7624], grad_fn=<SelectBackward0>) 参数 shape: torch.Size([100, 8]) requires_grad: True token1 与 token9 的余弦相似度: 0.204- 🔸
out.shape == (1, 4, 8):批量维度不变,每个 ID 膨胀成 8 维向量——数据从"编号"变成了"几何点"; - 🔸
grad_fn=<SelectBackward0>:查出来的向量挂着计算图,训练时梯度会回传到查表矩阵; - 🔸 随机初始化时相似度 0.204 没有意义——训练之后这个数字才开始编码语义,这是理解 embedding 最关键的一步。
六、运行结果应该怎么看
训练良好的 embedding 空间里:
- 🔸 同类词(猫/狗)余弦相似度 > 0.7;
- 🔸 无关词(猫/微积分)接近 0;
- 🔸 反义词不一定远(好坏都在"评价"维度上),注意别把"反义"和"无关"混为一谈。
七、常见错误与排查
- 🔸IndexError: index out of range:ID ≥ vocab_size。第 14 篇 的工具箱初版就踩过这个坑——词表 151643 的 tokenizer 配了 100 行的表。Embedding 行数必须 ≥ tokenizer 词表;
- 🔸把 embedding 当固定特征:
nn.Embedding默认可训练,想冻结要手动requires_grad_(False); - 🔸维度越大越好?:d_model 翻倍参数量平方级增长,小任务 64~128 维足够。
八、练习题
- 构造
(vocab=50, dim=16)的 Embedding,喂shape=(2,7)的 ID 张量,验证输出 shape 是(2,7,16); - 对 embedding 矩阵随机抽 10 对词向量算余弦相似度,画出分布直方图(训练前),猜测训练后直方图会怎么变;
- 用
nn.Embedding实现king - man + woman实验:随机初始化下结果无意义,思考需要什么样的训练数据才能让它成立。
一句话总结:Embedding 把无语义的 Token ID 映射成可训练的高维向量,让"语义相近"变成"几何相近"——大模型的一切语义理解都从这个查表开始。
下一篇:transformer你不学?04|位置编码:让模型知道词的顺序。