词向量小史:从 one-hot 到 embedding
AI 系列第 6 篇。上一篇讲了 Transformer 是怎么把整句话并行处理的。 这一篇回头补一课:那些被丢进 Transformer 的"词",本身是怎么变成向量的? 你会发现,词向量 这个概念,是过去 15 年 NLP 最被低估、也最重要的发明。
0. 一个被忽略的根本问题
我们已经讲了好几篇神经网络。但有件事我们一直含糊带过——
神经网络只能处理数字。一段文字怎么进去?
input: "今天天气真好"
▼
神经网络: ??? 这是什么乱码?
机器看不懂中文。也看不懂英文。它只懂浮点数向量。所以在所有 NLP 工作之前,必须先把字符串变成数字。这就是 embedding(词嵌入)的任务。
听起来好像无关紧要的预处理?错。embedding 决定了模型能"理解"的语义粒度。embedding 做得不好,后面再厉害的 Transformer 也救不了。
这一篇我们就讲:人类是怎么花了 60 年,才搞清楚"机器眼里的词"应该长什么样的。
1. 第一代:one-hot 编码——"暴力但天真"
最朴素的想法:给每个词一个编号。
词典:
"今天" → 0
"天气" → 1
"真好" → 2
"下雨" → 3
"可惜" → 4
... (总共 5 万个词)
但直接用编号不行——神经网络会把"3"当成"比 2 大、比 4 小"的有序数字,而实际上"下雨"和"真好"之间没有任何"大小关系"。
解决方案:one-hot 向量。
"今天" → [1, 0, 0, 0, 0, ...] ← 第 0 位是 1
"天气" → [0, 1, 0, 0, 0, ...] ← 第 1 位是 1
"真好" → [0, 0, 1, 0, 0, ...] ← 第 2 位是 1
每个词被表示成一个 5 万维的向量,只有自己那一位是 1,其他全是 0。
one-hot 的两个致命缺陷
缺陷 1:维度灾难
一个英文词典有 50 万词。一个 5 万词的 one-hot 向量乘以一个全连接层,参数量就要爆炸:
输入 50000 维 × 隐藏层 1024 维 = 5120 万个参数
光是第一层就 5000 万参数。整个网络?吓人。
缺陷 2:所有词都"等距离"
"猫" → [1, 0, 0, ...]
"狗" → [0, 1, 0, ...]
"汽车" → [0, 0, 1, ...]
在 one-hot 空间里,"猫"和"狗"的距离 = "猫"和"汽车"的距离 = √2。
模型根本无法知道"猫"和"狗"语义相近、"猫"和"汽车"不相关。 每个词都是孤岛。
这就是 one-hot 的根本问题——它编码了身份,但没编码意义。
2. 中间过渡:词频统计与 LSA(1957 → 2000s)
人们很早就想:能不能让"语义相近的词"在向量空间里"距离相近"?
1957 年,语言学家 J.R. Firth 说过一句被引爆的话:
"You shall know a word by the company it keeps." (一个词的意思,由它经常和谁一起出现来定义。)
这就是 分布假说(distributional hypothesis)。它的逻辑是:
- "猫"经常和"狗"、"宠物"、"喵"、"喂食"一起出现。
- "汽车"经常和"司机"、"轮胎"、"加油"、"高速"一起出现。
- 所以"猫"和"狗"的"邻居词集"高度重合 → 它们语义相近。
LSA:第一个把这个假说落地的方法
1988 年 出现的 LSA(Latent Semantic Analysis) 就是这个思路:
- 建一个超大的"词-文档"矩阵:行是词,列是文档,单元格是词频。
- 用矩阵分解(SVD)压缩到几百维。
- 每个词变成一个 300 维的稠密向量。
这是历史上第一次把词变成"低维稠密向量"。但 LSA 的问题是它只用了统计,没有学习。给定一个新句子,它没法处理。
90 年代到 2000 年代,词表示一直停留在"统计 + 降维"的阶段。神经网络派偶尔在尝试,但因为算力不够,效果不显著。
3. 2013:word2vec——那个让"国王 − 男人 + 女人 ≈ 女王"成立的算法
2013 年 1 月,Google 的 Tomas Mikolov 团队发了两篇论文,提出了 word2vec。这是词向量史上最重要的一个里程碑。
word2vec 的核心思想还是 Firth 那句话——用上下文定义词义。但它用神经网络来学。
训练目标:从上下文预测词(或反过来)
word2vec 有两种训练方式:
方式 1:CBOW(Continuous Bag of Words)—— 用周围猜中间
输入: ["今天", "天气", ___, "出去", "玩"]
任务: 猜 ___ 是什么词
答案: "不错"
方式 2:Skip-gram —— 用中间猜周围
输入: "不错"
任务: 猜它周围最可能出现的词
答案: ["今天", "天气", "出去", "玩"]
训练时,给模型 1000 亿条这样的句子。模型为了猜对,必须学会一件事:让经常出现在相似上下文里的词,向量靠近。
训完之后,每个词得到一个 300 维的稠密向量。
让全世界震惊的发现
word2vec 训完后,研究者发现这些向量有数学结构:
vec("国王") − vec("男人") + vec("女人") ≈ vec("女王")
vec("Paris") − vec("France") + vec("Italy") ≈ vec("Rome")
vec("walked") − vec("walk") + vec("swim") ≈ vec("swam")
这就是著名的 word analogy(词类比)。它说明 word2vec 不只是把相似的词放近,它还把"语义关系"编码成了向量空间里的方向。
- "国王 → 男人"和"女王 → 女人"是平行的方向 = 性别关系。
- "Paris → France"和"Rome → Italy"是平行的方向 = 首都-国家关系。
- "walked → walk"和"swam → swim"是平行的方向 = 过去时关系。
模型没人教过它"性别"或"时态"这些概念。它自己从数据里涌现出来了。
一句你可以拿去吹的话: word2vec 第一次让人类相信:神经网络不只是在做分类、回归。它能从纯文本里,自动提取出语言学家几百年来一直在研究的"语义结构"。
word2vec 的影响
2013 之后,几乎所有 NLP 任务都先跑一遍 word2vec 拿到词向量,再喂进下游模型。
[原始文本] → [word2vec] → [词向量] → [LSTM/CNN] → [任务输出]
这成了 2013–2018 的标配流水线。word2vec 那篇论文今天引用 4 万次。
4. 2014 年:GloVe——把统计派和神经派合一
word2vec 几乎完美,但有个理论上的不满——它只用了局部窗口(左右几个词),没用全局统计。
2014 年,斯坦福的 Pennington、Socher、Manning 三人提出 GloVe(Global Vectors)。它的目标:让词向量同时反映全局共现统计 + 局部上下文。
GloVe 的训练目标可以简化为:
学习词向量 w_i 和 w_j,使得:
w_i · w_j ≈ log(共现次数(i, j))
直觉是:两个词在语料里一起出现得越多,它们向量的点积越大。
GloVe 在 word analogy 任务上比 word2vec 略好。但俩兄弟的差异已经不大了。2014 之后的几年,word2vec / GloVe 几乎成了同义词。
5. 2018:ELMo / BERT——"一个词在不同句子里,应该有不同向量"
word2vec 有个隐性假设:一个词只有一个向量。
"我去银行存钱。"
"河边有一棵银行树。" ← (假设有这个东西)
"银行" → [0.2, -0.3, 0.5, ...] ← 永远是这个向量
但显然,"银行"在两个句子里意思完全不同。word2vec 把它们混在了同一个向量里,丢了上下文信息。
ELMo:用 LSTM 算"上下文相关"的向量
2018 年 2 月,Allen AI 的研究员提出 ELMo(Embeddings from Language Models)。它的核心改变:
同一个词,在不同句子里,给不同向量。
"我去银行存钱" → "银行" 向量 ≈ "金融机构"方向
"河边有银行树" → "银行" 向量 ≈ "植物"方向
ELMo 用一个双向 LSTM 在大语料上预训练,给每个句子里的每个词单独算一个向量。这种向量叫 contextualized embedding(上下文化嵌入)。
BERT:用 Transformer 把这件事做到极致
2018 年 10 月,Google 的 BERT 把 ELMo 的思路推到顶——但用的不是 LSTM,是 双向 Transformer encoder。
BERT 的训练任务很有意思——它玩完形填空:
原句: "今天天气真好,我想出去散步。"
训练: "今天天气[MASK]好,我想出去[MASK]步。"
任务: 预测 [MASK] 处该填什么
为了猜对 mask,模型必须深度理解上下文。训完之后,BERT 内部每一层对每个词的向量表示,都包含了深度上下文信息。
BERT 一出现,几乎所有 NLP benchmark 都被它刷爆——情感分类、问答、命名实体识别、相似度…… 2018 年是 NLP 圈的"BERT 之年"。
一句你可以拿去吹的话: 从 word2vec 到 BERT,词向量经历了从"一个词一个固定向量"到"一个词在每个句子里都有专属向量"的范式转换。这是 NLP 史上第一次,机器能"读懂语境"。
6. 今天的 LLM:embedding 已经"看不见"了
ChatGPT、Claude、Llama 这些大模型里还有 embedding 吗?有,但它已经被深度藏起来了。
现代 LLM 处理一段文本的完整流程:
"今天天气真好"
│
▼
[Tokenizer] 把文本切成 token → ["今", "天天气", "真好"]
│
▼
[Embedding Layer] 把每个 token 转成向量
→ [v_1, v_2, v_3]
每个 v_i 大约 4096 维
│
▼
[Transformer 96 层]
│
▼
最终输出
Embedding Layer 就是一个查找表:input 是 token id(一个整数),output 是一个固定的向量。这个表的大小是 vocab_size × hidden_dim。
GPT-3 的 vocab 是 50,257 个 token,hidden_dim 是 12,288。embedding 表就是:
50,257 × 12,288 = 6.17 亿个参数
光这个表就比 BERT 整个模型还大。
但这是 word2vec 那种"独立学习"的 embedding 吗?
不是。现代 LLM 的 embedding 是端到端学的——和整个网络一起训练,不再单独搞一个 word2vec 步骤。
1990s: one-hot ── 静态、稀疏
2013: word2vec / GloVe ── 静态、稠密、独立预训练
2018: ELMo / BERT ── 上下文化、独立预训练
2020+: 现代 LLM 内嵌 embedding ── 上下文化、端到端学
Embedding 在今天还有什么用?
虽然 LLM 把 embedding 内化了,但作为单独工具的 embedding 模型反而越来越火。原因是 RAG 和向量搜索:
1. 把所有知识库文档切成小段。
2. 用 embedding 模型把每段编成一个向量。
3. 用户问问题时,把问题也变成向量。
4. 在向量库里找"距离最近"的几段。
5. 把这几段 + 问题一起喂给 LLM。
这就是 RAG(Retrieval-Augmented Generation)的核心。今天主流的 embedding 模型:
- OpenAI
text-embedding-3-large - Cohere
embed-v3 - BGE / GTE(开源)
- Voyage AI
voyage-3
这些模型本质上都是 BERT 的变种,专门优化了"语义相似度"。今天创业公司搞 RAG 时,第一步就是挑一个 embedding 模型——这又把 word2vec 时代的"独立 embedding 训练"思路带了回来。
7. 关于 tokenizer:embedding 之前还有一步
讲到这要补一刀:embedding 不是直接作用在"词"上的,是作用在 token 上的。
token 是什么?是 tokenizer 切分出来的"子词"。例如 GPT 的 BPE tokenizer:
"GPT-4 是 OpenAI 发布的模型"
│
▼ tokenize
["GPT", "-", "4", " 是", " Open", "AI", " 发布", "的", "模型"]
│
▼ token ids
[3877, 12, 19, 1234, 9012, ...]
│
▼ embedding layer
[v_1, v_2, v_3, ...]
注意几件事:
- "GPT-4" 被切成了
GPT,-,4三个 token。 - " 是" 包含前导空格(GPT BPE 这么干)。
- "OpenAI" 被切成
Open+AI,不在一个 token 里。
中文也是同理。一个汉字可能是一个 token,也可能两三个汉字组成一个 token,看 tokenizer 怎么训的。
这是为什么 LLM 偶尔会犯一些"低级错误"——比如数不清 "strawberry" 里有几个 r。因为它看到的是 token,不是字符。
第 10 篇会专门讲 tokenizer 和 context window 的故事。
8. 总结这条线
1957 分布假说:"一个词由它的邻居定义"
1988 LSA:用矩阵分解把这个假说落地
2013 word2vec:用神经网络把它落地,规模爆炸
2014 GloVe:统计派 + 神经派合一
2018 ELMo / BERT:上下文化 embedding,"一词多向量"
2020+ 现代 LLM:embedding 端到端集成
一句你可以拿去吹的话: 从"词是一个独热编号"到"词是一个 12288 维的上下文相关向量",机器对语言的理解走了 60 年。但真正的飞跃,只在最后 10 年。
9. 给你的小作业
- 用
gensim这个 Python 库加载预训练 word2vec,试试vec('国王') - vec('男人') + vec('女人')最近的几个词是什么。 提示:可能不只是"女王",还会有"王后"、"公主"等。 - 解释为什么 word2vec 给"银行"只有一个向量,而 BERT 给不同句子里的"银行"不同向量。
- 写一段伪代码描述 RAG 的工作流程,明确指出 embedding 在哪里发挥作用。
下一篇钩子:到这里,我们已经把"模型怎么读懂顺序"和"词怎么变成向量"都搞清楚了。 下一篇起,我们正式进入大模型时代—— GPT-1 (2018)、GPT-2 (2019)、GPT-3 (2020)、GPT-3.5 (2022)、GPT-4 (2023)、GPT-4o / o1 (2024–2025),每一代到底变了什么? 答案可能让你意外:架构基本没变。变的是规模、数据、训练技巧——以及一些你以为是"smarter"的小动作。