🐱小可 & 🐶博士 · Word2Vec 科普漫画
从离散符号到语义向量空间------一场跨越25幕的知识冒险!
小可(好奇地探头):计算机看到「苹果」这个词,到底在想什么?
博士(推了推眼镜):对人类来说,看到「苹果」会联想到水果、红色、甜美、甚至iPhone......但对计算机而言,它只是一个毫无意义的离散符号!

这就是自然语言处理(NLP)面临的第一个根本性问题:如何让计算机理解人类语言中的词?
人看到"苹果"这个词,脑海中会自然浮现出一幅丰富的画面------红润的果实、清脆的口感、水果店的货架、甚至是某个科技品牌。这种联想能力是人类语言理解的基石。但计算机完全不同。对计算机来说,"苹果"只是一个字符串,一个由两个汉字组成的离散符号。计算机最擅长的是数学运算------加减乘除、矩阵乘法、梯度下降------但这些都要求输入是数字,而词不是数字。
这就引出了NLP最核心的挑战:如何把离散的词变成计算机可以处理的数学表示? 如果不能解决这个基础问题,后续所有的NLP技术------从简单的文本分类到复杂的Transformer大模型------都无从谈起。今天,小可和博士就带领大家踏上一段从整数编号到Word2Vec的进化之旅,看看科学家们是如何一步步破解这个难题的。
深入思考:什么是"离散符号"?
在计算机科学中,离散符号是指那些没有连续性、无法进行数学运算的标识符。比如"苹果"和"香蕉"是两个完全不同的字符串,它们之间没有中间状态,也不能说"苹果"加0.1等于某个词。这与数字完全不同------1和2之间有1.5、1.25、1.125等无穷多个值,而且1+1=2是有意义的数学运算。
神经网络------包括我们现在用ChatGPT时接触到的大语言模型------本质上是做数学运算的机器。它们的每一层都在做矩阵乘法、激活函数计算、梯度下降等数学操作。所以输入必须是数字(张量),而不是文本字符串。这就是为什么我们需要Embedding层作为"翻译器":把离散的文本符号翻译成连续的数学向量。
小可(歪着脑袋):那给每个词编个号不就行了?苹果=1,香蕉=2,汽车=3......
博士(摇头摆手):不行不行!模型会以为火车(4)比苹果(1)大,这是虚假的大小关系!

给词编号看起来是最直观的办法。我们建立一个词表,给每个词分配一个唯一的整数ID:苹果→1,香蕉→2,汽车→3,火车→4。当模型看到数字1,就去查表找到对应的词。这个方案叫整数编码(Integer Encoding),它确实在一些简单的场景中被使用,比如Keras的Tokenizer就提供了这种功能。
但整数编码有一个致命的缺陷:它引入了虚假的数学关系。在数学上,4 > 1,3 - 1 = 2,这些运算对整数来说是有意义的。但把这些运算映射到词上就荒谬了------"火车大于苹果"?"汽车减去苹果等于香蕉"?这显然没有意义。
更严重的是,模型在训练过程中会"学习"到这些虚假的关系。如果使用整数编码的词作为神经网络的输入,模型会隐式地学到:词ID越大,某种"程度"就越高。但词之间根本不存在这种程度关系!苹果和香蕉之间没有谁"大"谁"小",它们只是不同的水果而已。
所以整数编码虽然简单,但它给模型注入了错误的先验知识,导致模型学到错误的模式。我们需要一种更好的方法。
补充知识:什么时候可以用整数编码?
整数编码并非完全没有用处。在某些特定场景下,它是合适的:
- 序列编号任务:比如给句子中的词编号位置(第1个词、第2个词......),这里的数字确实有大小意义
- 类别编号但后续做Embedding:Keras等框架中,先把文本转为整数序列,然后通过Embedding层转为向量。这里的整数编码只是中间步骤,不是最终表示
- 简单的词汇表映射:当你只需要给每个词一个唯一标识,且模型会学习自己的表示时
但关键是:整数编码不能直接作为神经网络的输入表示,必须经过Embedding层或One-Hot编码转换后才有意义。
小可(眼睛一亮):那就用One-Hot编码!每个词一个位置是1,其余全是0!
博士(点头):对,这样消除了假顺序。但问题更大------维度太高、极度稀疏、所有词都正交!

One-Hot编码是机器学习中最经典的表示方法之一。它的思路很巧妙:假设有V个不同的词,我们就创建一个V维的向量。每个词对应向量中的一个维度,在那个维度上是1,其余维度全是0。
比如我们的词表是{苹果, 香蕉, 汽车, 火车},那么:
- 苹果 = 1, 0, 0, 0
- 香蕉 = 0, 1, 0, 0
- 汽车 = 0, 0, 1, 0
- 火车 = 0, 0, 0, 1
One-Hot编码确实解决了整数编码的问题:不再有虚假的大小关系了。1和0之间没有"谁大谁小"的含义,每个词都在自己的维度上"发光",其他维度保持沉默。
但One-Hot编码带来了三个更严重的问题:
第一,维度灾难。 现实中的词表不是4个词,而是几十万甚至上百万个词!英文维基百科的词表大约有200万,中文的更大。这意味着每个词的向量都有百万维度------这太浪费存储空间和计算资源了。
第二,极度稀疏。 百万维的向量中,只有一个位置是1,其余999,999个位置都是0。信息密度低得可怜,绝大部分存储空间都在浪费。
第三,所有词都正交。 这是最致命的问题。任意两个不同的One-Hot向量做点积(内积),结果永远是0。这意味着在One-Hot表示下,"苹果"和"香蕉"的距离,与"苹果"和"汽车"的距离完全一样!但从语义上来说,苹果和香蕉显然更接近------它们都是水果,都可以吃,都有甜味。One-Hot编码完全无法表达这种语义上的远近关系。
小可(困惑地挠头):正交是什么意思?所有词的余弦相似度都是0?
博士(拿出粉笔在黑板上画起来):对!夹角90度,cos(θ)=0,完全没关系。但苹果和香蕉明明更接近啊!

让我们来认真理解一下"正交"这个概念。在向量空间中,两个向量的关系可以用它们的夹角来衡量。夹角的余弦值(cosine)就是我们常说的余弦相似度:
cosine_similarity(A,B)=A⋅B∣∣A∣∣×∣∣B∣∣=cos(θ)\text{cosine\_similarity}(A, B) = \frac{A \cdot B}{||A|| \times ||B||} = \cos(\theta)cosine_similarity(A,B)=∣∣A∣∣×∣∣B∣∣A⋅B=cos(θ)
当两个向量完全相同时,夹角为0°,cos(0°) = 1,相似度为1。当两个向量完全相反时,夹角为180°,cos(180°) = -1,相似度为-1。当两个向量正交时,夹角为90°,cos(90°) = 0,相似度为0。
在One-Hot编码中,任意两个不同的词向量,它们非零的维度不同,所以点积永远是0,余弦相似度永远是0。这意味着在One-Hot的世界里,所有的词都是毫无关系的------苹果和香蕉的关系,与苹果和汽车的关系,完全一样。
但从人类的直觉来看,这显然是不对的。苹果和香蕉都是水果,都能吃,都有甜味,颜色鲜艳------它们在语义上非常接近。而苹果和汽车之间,除了都是名词之外,几乎没有任何共同点。一个好的词表示方法应该能反映出这种差异。
小可(兴奋地跳起来):那怎么才能让计算机理解词之间的关系呢?
博士 (微笑):看上下文!相似的词,上下文也很相似。这就是分布式假设(Distributional Hypothesis)。

英国语言学家J.R. Firth在1957年说过一句名言:
"You shall know a word by the company it keeps."
(你可以通过一个词的"朋友圈"来认识它。)
这就是分布式假设 的核心思想:一个词的含义,由它经常出现的上下文决定。 如果两个词经常出现在相似的上下文环境中,那么它们的含义也应该相似。
让我们用简单的例子来说明:
- "我吃了一个苹果"
- "我吃了一个香蕉"
这两句话的结构几乎一模一样,"苹果"和"香蕉"出现在完全相同的句法位置------都是"吃"的宾语,都在"一个"之后。这说明它们在语法功能上是等价的。
再看:
- "苹果很甜"
- "香蕉很甜"
同样,"苹果"和"香蕉"都能和"很甜"搭配,说明它们在语义属性上也很接近------都是甜的、都是可以食用的。
而"汽车"这个词,它常出现的上下文完全不同:
- "这辆汽车很漂亮"
- "汽车的轮毂非常亮"
"汽车"和"漂亮""轮毂""行驶"等词经常一起出现,这些是"苹果"和"香蕉"几乎不会搭配的。
通过观察大量文本中词的共现情况,我们就能发现:苹果和香蕉的上下文分布非常相似,而它们与汽车的上下文分布差异很大。这种上下文分布的相似性,就是语义相似性的可靠指标。
小可(认真地做笔记):怎么统计上下文关系呢?
博士 :用共现矩阵(Co-occurrence Matrix)!统计每对词在同一窗口中出现的次数。

共现矩阵是一个经典的统计学方法。它的做法是:给定一个窗口大小(比如前后各2个词),遍历整个语料库,统计每对词在同一个窗口中共同出现的次数。
构建一个共现矩阵,行和列都是词表中的所有词,矩阵中的每个元素Mij表示词i和词j在窗口中共同出现的次数。
以苹果为例,统计它和各个词的共现次数:
- 苹果 ↔ 吃:12次
- 苹果 ↔ 甜:8次
- 苹果 ↔ 香蕉:5次
- 苹果 ↔ 汽车:0次
- 苹果 ↔ 发动机:0次
而火车和各个词的共现:
- 火车 ↔ 铁轨:15次
- 火车 ↔ 发动机:10次
- 火车 ↔ 道路:12次
- 火车 ↔ 苹果:0次
- 火车 ↔ 甜:0次
从这个共现矩阵中,我们可以提取出每个词的"共现向量"------它和所有其他词的共现次数组成的向量。苹果和香蕉的共现向量非常相似(都和"吃""甜"共现频繁),而苹果和火车的共现向量差异巨大。
这样,词不再是孤立的符号,而是由它和整个语言环境中其他词的关系来定义的。每个词的含义,就是它和所有其他词的关系的总和。
但共现矩阵也有严重的问题。首先是规模问题 ------矩阵大小是V×V,V是词表大小。如果词表有100万,矩阵就有1万亿个元素!其次是泛化能力差 ------"apple"和"苹果"如果都出现在语料中,它们会被当成完全不同的词,各自有独立的行,无法被合并。最后是数据稀疏------绝大多数词对的共现次数是0或很小的数字,统计噪声很大。
小可(翻着自己的笔记):这几种方法各有什么优缺点?
博士:让我们做一个完整的对比。整数编号→One-Hot→共现矩阵→Embedding,这是一个一步步进化的过程!

让我们用表格来系统地对比这四种方法:
| 方法 | 表示形式 | 维度 | 语义关系 | 主要问题 |
|---|---|---|---|---|
| 整数编号 | 1, 2, 3, 4 | 1 | ✗ 虚假大小关系 | 引入虚假顺序 |
| One-Hot | 1,0,0,0 | V | ✗ 全部正交 | 维度灾难+无语义 |
| 共现矩阵 | 12,10,3... | V | ✓ 有统计语义 | O(V²)+稀疏+无法泛化 |
| Embedding | 0.31,-0.82... | d (d≪V) | ✓ 密集语义 | 需要训练 |
这个进化路径非常清晰:
- 整数编号解决了"把词变成数字"的问题,但引入了虚假的数学关系
- One-Hot编码消除了虚假关系,但维度太高且完全没有语义
- 共现矩阵引入了语义关系(通过统计上下文),但规模太大且无法泛化
- Embedding最终解决了所有问题:低维、密集、可学习、保留语义
每一步都在前一步的基础上解决了一个核心问题,同时又引入了新的挑战。这就是科学进步的经典模式。
小可(满脸期待):Embedding到底是什么?就是把词变成向量?
博士 (竖起大拇指):对!Embedding就是把离散词嵌入(embed)到连续的向量空间中,让词变成可以计算的坐标!

Embedding这个词的英文原意就是"嵌入"------把一些原本离散、孤立的东西,放进一个连续的空间中,让它们有坐标、有距离、有方向。
在NLP中,Embedding层的作用是把每个词映射为一个固定维度的实数向量。假设我们选择100维,那么每个词都被表示为一个包含100个实数的向量,比如:
- 苹果 → 0.31, -0.82, 0.15, 0.47, ...(100个数字)
- 香蕉 → 0.28, -0.79, 0.22, 0.43, ...
- 汽车 → -0.65, 0.41, -0.33, 0.18, ...
- 火车 → -0.62, 0.38, -0.28, 0.15, ...
这些数字不是人工指定的,而是通过训练自动学习到的。训练过程中,模型不断调整这些数字,使得语义相近的词在向量空间中靠得更近,语义不同的词离得更远。
Embedding的关键性质:
- 低维:通常100~300维,远小于词表大小(百万级)
- 密集:每个维度都是非零的实数,信息密度高
- 可学习:通过梯度下降自动优化,不需要人工设计
- 语义保留:相似的词在空间中距离近,可以用余弦相似度衡量
从本质上说,Embedding层是离散符号空间和连续向量空间之间的桥梁。它把人类语言中离散的、不可计算的词,变成了数学上连续的、可计算的向量。这就是为什么Embedding被称为"现代AI的通用接口"------任何离散对象(文字、图片、用户、商品......)都可以通过Embedding变成连续的表示,然后交给神经网络处理。
小可(惊叹地睁大眼睛):向量空间里,语义关系变成了几何关系?
博士(满意地点头):完全正确!相似的词在空间中靠得近,可以用余弦相似度来衡量距离!

这是Embedding最迷人的特性之一:语义相似性被编码为几何距离。
想象一个二维平面(实际上Embedding空间是100~300维的,但二维方便理解)。在这个平面上:
- 苹果、香蕉、梨、橘子聚在一起,形成"水果簇"
- 汽车、火车、飞机聚在一起,形成"车辆簇"
- 两个簇之间有明显的距离
两个词之间的距离越近,说明它们的语义越相似。我们可以用余弦相似度来精确量化这种相似性:
- cosine(苹果, 香蕉) ≈ 0.85 --- 非常相似
- cosine(苹果, 汽车) ≈ 0.12 --- 几乎不相似
- cosine(汽车, 火车) ≈ 0.78 --- 比较相似
这种几何化的语义表示有很多强大的应用。比如我们可以做词类比推理:找出与C的关系类似于A与B的关系的词D。最著名的例子就是"国王-男人+女人=女王"------这在Word2Vec的论文中被广泛引用,展示了词向量不仅能编码语义,还能编码语法关系。
小可(兴奋地拍手):Word2Vec为什么这么厉害?
博士(激动地站起来):因为它不再构建完整语言模型,目标就是学词向量!训练快、效果好,震惊了整个NLP领域!

在Word2Vec出现之前(2013年),获取高质量词向量主要有两条路:
第一条路:共现矩阵 + SVD降维。 先构建庞大的共现矩阵,然后用奇异值分解(SVD)等矩阵分解方法降维。这种方法的问题在于:构建共现矩阵需要遍历整个语料库,SVD的计算复杂度很高,而且降维过程会有信息损失。
第二条路:神经语言模型。 Bengio等人在2003年提出了神经概率语言模型,在预测下一个词的过程中顺便学到了词向量。但这种方法的问题是:它的核心目标是语言建模(预测下一个词),词向量只是训练的"副产品"。为了得到词向量,你需要训练一个完整的语言模型------这太昂贵了!
Word2Vec的革命性在于:它把目标直接定为学习词向量本身。 不再需要完整的语言模型,不再需要庞大的共现矩阵。它用一个极简的神经网络架构------只有一层隐藏层------就能高效地学习到高质量的词向量。
Word2Vec提供了两种经典的训练方式:
- CBOW(Continuous Bag of Words):用上下文预测中心词
- Skip-gram:用中心词预测上下文
这两种方式都极其简单高效,在大规模语料上训练只需几小时,就能得到质量极高的词向量。Word2Vec的论文《Efficient Estimation of Word Representations in Vector Space》由Tomas Mikolov等人发表于2013年,至今已被引用数万次,是NLP领域最有影响力的论文之一。
小可(震惊地张大嘴巴):vec(king) - vec(man) + vec(woman) ≈ vec(queen)?向量居然能做加减运算?
博士(自豪地微笑):对!词与词之间的关系变成了向量空间中的方向!语义和语法都被编码在向量中了!

这是Word2Vec最令人震惊的发现之一。训练好的词向量不仅能表达语义相似度,还能表达语义关系------而且这种关系可以用简单的向量加减法来操作!
最经典的例子:
king⃗−man⃗+woman⃗≈queen⃗\vec{\text{king}} - \vec{\text{man}} + \vec{\text{woman}} \approx \vec{\text{queen}}king −man +woman ≈queen
这个等式的含义是:从"国王"的向量中减去"男人"的向量(去掉"男性君主"中的"男性"属性),再加上"女人"的向量(添加"女性"属性),得到的结果非常接近"女王"的向量。
这意味着什么呢?意味着向量空间中的方向和距离编码了语义关系。"男人→女人"这个语义变化,对应着向量空间中的一个特定方向。把这个方向应用到"国王"上,就得到了"女王"。
这种类比推理在词向量空间中大量存在:
| 类比 | 语义关系 |
|---|---|
| 北京 - 中国 + 法国 ≈ 巴黎 | 首都关系 |
| 走 - 现在 + 过去 ≈ 走了 | 时态关系 |
| 大 - 好 + 坏 ≈ 小 | 反义关系 |
| 猫 - 公 + 母 ≈ 母猫 | 性别关系 |
这些例子展示了词向量不仅编码了词的"含义",还编码了词与词之间的"关系"。这是传统方法(One-Hot、共现矩阵)完全无法做到的。
小可(好奇地凑近黑板):CBOW是怎么工作的?用上下文猜中心词?
博士(耐心讲解):对!取上下文词向量求平均,用简单神经网络预测中心词。

CBOW(Continuous Bag of Words)的工作原理如下:
给定一个句子:"我今天想吃苹果",设定窗口大小为2。当中心词是"想"时,它的上下文是左右各2个词:"今天", "我", "吃", "苹果"。
CBOW的训练步骤:
- 取上下文词向量:从Embedding矩阵中查找"今天""我""吃""苹果"对应的词向量
- 求平均:将这4个词向量相加后除以4,得到一个综合的上下文表示
- 前向传播:将这个平均向量输入到一个简单的神经网络(输入层→隐藏层→输出层)
- 预测:输出层使用softmax,预测中心词是什么
- 计算损失:用交叉熵损失比较预测结果和真实的中心词("想")
- 反向传播:计算梯度,更新所有词向量
整个过程非常简洁。神经网络的结构只有三层:输入层(词向量查表)、隐藏层(线性投影)、输出层(softmax分类)。没有复杂的激活函数,没有深层网络,就是最简单的MLP。
正是因为结构简单,CBOW的训练速度极快。而且因为它是用多个上下文词来预测一个中心词,所以对高频词的建模效果特别好------上下文词的平均操作起到了平滑作用。
小可(恍然大悟):Skip-gram和CBOW正好相反?用中心词猜周围词?
博士(竖起食指):对!一个中心词拆成多个训练样本,对低频词更友好!

Skip-gram几乎是CBOW的反方向:
CBOW是:上下文词1, 上下文词2, 上下文词3, 上下文词4 → 预测中心词
Skip-gram是:中心词 → 预测上下文词1, 预测上下文词2, 预测上下文词3, 预测上下文词4
同样以"我今天想吃苹果"为例,窗口大小为2,中心词是"想":
- CBOW产生1个训练样本:("今天","我","吃","苹果", "想")
- Skip-gram产生4个训练样本:("想","今天"), ("想","我"), ("想","吃"), ("想","苹果")
这意味着Skip-gram的训练样本数量是CBOW的窗口大小倍。窗口为2时是4倍,窗口为5时是10倍!
这对低频词非常友好。即使一个词在语料中只出现了一次,Skip-gram也能通过它产生多个训练样本(每个上下文词一个),从而让这个低频词的向量得到充分的训练。而CBOW中,低频词作为中心词出现时只有一个样本,作为上下文词时又被平均掉了,训练效果不如Skip-gram。
Skip-gram的训练过程:
- 取中心词的向量
- 分别预测每个上下文词(每个上下文词是一个独立的softmax分类任务)
- 计算每个预测的交叉熵损失
- 反向传播更新词向量
小可(歪着脑袋思考):两种方法该怎么选?
博士(推了推眼镜):高频词多用CBOW,低频词多用Skip-gram,根据数据特征决定。

CBOW和Skip-gram各有优劣,选择时需要考虑以下因素:
选择CBOW的场景:
- 数据集很大,词频分布相对均匀
- 更关注训练速度
- 语料中低频词不多
- 需要快速得到一个可用的词向量模型
选择Skip-gram的场景:
- 数据集较小
- 语料中有大量低频词、专有名词
- 更关注词向量质量(特别是低频词的表示)
- 不介意多花一些训练时间
在实际应用中,gensim的Word2Vec实现提供了一个sg参数:
sg=0:使用CBOWsg=1:使用Skip-gram
大多数情况下,如果你不确定选哪个,用Skip-gram(sg=1)通常能得到更好的结果,特别是在中文这种低频词较多的语言中。
小可(搓搓手):训练Word2Vec需要什么步骤?
博士(拿出清单):读取文本→分词→配置参数→训练→验证结果,五步搞定!

使用gensim训练Word2Vec模型非常简单,主要分为五个步骤:
第一步:读取文本
python
text = open('西游记.txt', encoding='utf-8').read()
第二步:分词
python
import jieba
sentences = [list(jieba.cut(s)) for s in text.split('。')]
第三步:配置参数并训练
python
from gensim.models import Word2Vec
model = Word2Vec(
sentences, # 分词后的句子列表
vector_size=100, # 词向量维度
window=5, # 上下文窗口大小
min_count=3, # 最低词频
sg=1, # 1=Skip-gram, 0=CBOW
epochs=10, # 训练轮数
negative=5, # 负采样数量
)
第四步:验证结果
python
# 查看最相似的词
model.wv.most_similar('孙悟空', topn=10)
# 计算两个词的相似度
model.wv.similarity('孙悟空', '唐僧')
第五步:保存模型
python
model.save('word2vec.model')
# 后续可以直接加载使用
model = Word2Vec.load('word2vec.model')
关键参数说明:
vector_size:词向量维度,通常100~300window:上下文窗口大小,通常3~10min_count:过滤低频词的阈值sg:选择CBOW(0)还是Skip-gram(1)negative:负采样数量,通常5~20epochs:训练轮数
小可(皱眉思考):分词质量会影响训练效果?
博士(严肃地点头):对!把「孙悟空」拆成「孙」「悟空」就没意义了,要保护专有名词!

分词是中文NLP中最关键的预处理步骤之一,对词向量训练的质量影响极大。
好的分词示例:
孙悟空 / 唐僧 / 齐天大圣 / 三藏 / 沙悟净
坏的分词示例:
孙 / 悟空 / 唐 / 僧 / 齐 / 天 / 大 / 圣
如果"孙悟空"被拆成"孙"和"悟空",那么模型学到的"孙"这个词会和"孙膑""孙中山""孙悟空"等等完全无关的词产生联系,而"悟空"又会和"领悟""空空如也"等词混淆。"孙悟空"作为一个完整的专有名词,它的语义意义完全丢失了。
jieba分词默认就能识别大部分常见的专有名词,但对于特殊的领域词汇,可以通过添加自定义词典来改进:
python
jieba.add_word('齐天大圣')
jieba.add_word('金箍棒')
jieba.add_word('花果山')
顺便提一下,"Token"是更标准的说法。 我们常说的"词"其实不太准确。Token可以是一个字、一个词、甚至一个词的一部分(比如"review"可能被拆成"re"和"view")。现代大模型使用的BPE(Byte Pair Encoding)和WordPiece等Subword Tokenization方法,就是自动学习最优的Token切分方式。
小可(迫不及待地):训练完怎么检查模型有没有学到语义?
博士(打开终端):计算余弦相似度!孙悟空和唐僧0.17,和唐太宗只有0.05,很合理!

训练完成后,我们需要验证模型是否真的学到了有意义的语义关系。有几种方法:
方法一:most_similar --- 检查近义词质量
python
model.wv.most_similar('孙悟空', topn=5)
# 可能输出: [('齐天大圣', 0.89), ('沙悟净', 0.76), ('猪悟能', 0.72), ...]
如果结果符合直觉(和孙悟空最相似的确实是西游记中的人物),说明语义编码是合理的。
方法二:计算特定词的相似度
python
model.wv.similarity('孙悟空', '唐僧') # 0.17 --- 同团队,有一定关联
model.wv.similarity('孙悟空', '唐太宗') # 0.05 --- 几乎无关
这些结果看起来很合理:孙悟空和唐僧是同团队的,有一定的上下文关联;而唐太宗虽然也是"唐"字开头,但在西游记中和孙悟空几乎没有交集,相似度很低。
方法三:词类比测试
python
model.wv.most_similar(positive=['北京', '法国'], negative=['中国'], topn=1)
# 如果输出是'巴黎',说明模型学到了首都关系
需要注意的是,如果训练语料较小(比如只用了一本西游记)、训练轮数较少(比如只有10轮),结果可能不够精确。实际应用中,通常需要更大的语料(维基百科、新闻语料等)和更多的训练轮数(50~100轮)。
小可(看着屏幕上密密麻麻的数字):100个数字,每个是什么意思?
博士(摇头):单个数字没有独立含义,只有100个合起来才有意义,类似PCA!

这是理解词向量时最常见的困惑。当我们看到孙悟空的100维向量:
[0.31, -0.82, 0.15, 0.47, -0.63, 0.91, -0.22, 0.08, ...]
人们很自然地会想问:"第3维的0.15是什么意思?代表'战斗力'吗?第6维的0.91代表'知名度'吗?"
答案是:单个维度没有可解释的含义。
这和我们熟悉的One-Hot编码完全不同。在One-Hot中,第3维是1就代表"这个词是词表中的第3个词",意义很明确。但在Embedding中,没有任何一个维度对应某个具体的特征。
这其实和PCA(主成分分析)很像。PCA降维后的每个主成分都是原始特征的线性组合,单个主成分的含义很难解释,但所有主成分合起来就能很好地表示数据。
词向量也是如此:
- 每个维度本身没有独立可解释的含义
- 单个数字(比如0.31)不代表某个具体特征
- 只有整个100维向量合起来才有意义
- 语义关系隐藏在整体向量模式中
词向量是通过训练自动学习到的分布式表示。训练过程中,100个数字被同时优化,使得相似词的向量在空间中靠近。每个维度的值是多少不重要,重要的是它们组合起来形成的"方向"和"位置"。
小可(双手一摊):100维超出人的理解范围了,怎么展示?
博士(拿出一张图):用PCA降到2维画在图上!相似的词会聚在一起!

人类最多只能理解三维空间,100维的词向量远远超出了我们的直觉范围。但我们可以通过降维技术把高维向量投影到二维平面上,从而直观地看到词之间的远近关系。
最常用的方法是PCA(主成分分析):
python
from sklearn.decomposition import PCA
import numpy as np
# 获取所有词的向量
words = list(model.wv.key_to_index.keys())
vectors = np.array([model.wv[w] for w in words])
# PCA降到2维
pca = PCA(n_components=2)
reduced = pca.fit_transform(vectors)
# 画图
import matplotlib.pyplot as plt
for i, word in enumerate(words):
plt.scatter(reduced[i, 0], reduced[i, 1])
plt.annotate(word, (reduced[i, 0], reduced[i, 1]))
plt.show()
在2D图上,我们可以看到:
- 神仙类的词(如来、玉帝、观音、菩萨)聚在一起
- 取经团的词(唐僧、行者、三藏、沙僧)聚在一起
- 妖怪类的词(妖精、魔王、小妖)聚在一起
- 地名类的词(花果山、火焰山、龙宫)聚在一起
不同类别的簇之间有明显的距离,同一类簇内的词彼此靠近。即使PCA从100维降到2维有大量信息损失,这种聚类结构仍然清晰可见。
更先进的降维方法如t-SNE 和UMAP能更好地保持高维空间中的局部结构,可视化效果通常比PCA更好。
小可(看着散点图惊叹):在语义空间里,词之间有什么关系?
博士(指着图):水果类聚在一起,车辆类聚在一起,不同类之间有明显的距离!

降维可视化最直观地展示了语义空间的本质特征:
1. 同类词聚类
语义相近的词会自动聚集成簇。在我们的西游记语料中:
- 菩萨、如来佛祖、玉帝、观音聚在一起(神仙类)
- 孙悟空、东海、花果山、火焰山、龙宫、金箍棒聚在一起(相关事物)
- 妖怪、妖精、魔王、大王、小妖聚在一起(反派类)
- 沙僧、八戒、师傅、唐僧、行者、三藏聚在一起(取经团队)
2. 不同类之间有距离
不同语义类别的簇之间有明显的距离。神仙类和妖怪类相距甚远,取经团队类和相关事物类距离较近(因为在故事中经常一起出现)。
3. 语义关系被编码为向量关系
更重要的是,不仅是"相似"被编码,"关系"也被编码了。"孙悟空"到"齐天大圣"的向量方向,可能和"猪八戒"到"猪悟能"的向量方向相似------因为都是"本名→法号"的关系。
这种结构化的语义空间,是之前所有方法(整数编号、One-Hot、共现矩阵)都无法实现的。它不是手工设计的规则,而是从数据中自动学习到的。
小可(好奇地歪着头):训练这么快,有什么技巧?
博士 (竖起大拇指):负采样(Negative Sampling)!只计算正样本+少量负样本,从O(V)降到O(k),提速数百倍!

Word2Vec训练速度极快的一个关键原因是使用了**负采样(Negative Sampling)**技术。
在没有负采样的情况下,每次训练都需要对整个词表计算softmax概率:
P(wt∣wcontext)=exp(vwt⋅vcontext)∑w∈Vexp(vw⋅vcontext)P(w_t | w_{context}) = \frac{\exp(v_{w_t} \cdot v_{context})}{\sum_{w \in V} \exp(v_w \cdot v_{context})}P(wt∣wcontext)=∑w∈Vexp(vw⋅vcontext)exp(vwt⋅vcontext)
分母需要对词表中所有V个词计算,当V = 10万时,每次训练要做10万次指数运算------这太慢了!
负采样的思路极其巧妙:把多分类问题转化为二分类问题。
对于每个训练样本(中心词, 真实上下文词),我们:
- 构造正样本:(中心词, 真实上下文词) → 标签为1
- 构造负样本:随机选取k个词作为"假"的上下文词 → 标签为0
比如,真实的上下文词是"苹果",我们随机采样5个词作为负样本(如"轨道""发动机""轨道""法律""哲学"),那么训练目标就变成了:
- 让模型判断"苹果"确实是上下文(输出接近1)
- 让模型判断"轨道""发动机"等不是上下文(输出接近0)
每次只需要计算1个正样本 + k个负样本 = k+1次sigmoid运算,而不是V次softmax运算。当k=5,V=10万时,计算量从10万降到6,提速超过16000倍!
负采样的另一个关键是采样策略:不是均匀随机采样,而是按词频的3/4次方来采样。这样高频词不会被过度采样,低频词有足够的机会被选为负样本。
小可(若有所思):有些词出现特别多,有些特别少,怎么办?
博士(认真地说):高频词会主导训练,需要降采样;低频词需要更多关注。

在自然语言中,词频分布遵循Zipf定律:少数词出现极其频繁,大多数词很少出现。
在语料中,"的""了""是""在"这样的虚词可能各出现数十万次,而专有名词如"红孩儿""白骨精"可能只出现几十次。这种极端的词频不平衡给训练带来了两个问题:
问题一:高频词主导训练
"的""了"这些词信息量很低(几乎每个句子都有),但它们的训练样本数量极多,会主导梯度更新,导致模型花大量时间在无意义的词上。
解决方案:降采样(Subsampling)
Word2Vec使用以下概率公式随机丢弃高频词:
P(discardw)=1−tf(w)P(\text{discard}_w) = 1 - \sqrt{\frac{t}{f(w)}}P(discardw)=1−f(w)t
其中t是阈值(通常设为1e-5),f(w)是词w的频率。对于频率极高的词,被丢弃的概率就大。这样既保留了足够的训练样本,又减少了高频词的负面影响。
问题二:低频词训练不充分
专有名词、生僻词出现次数少,向量的学习不够充分。
解决方案:Skip-gram + 降低min_count
Skip-gram每个中心词产生多个训练样本,对低频词更友好。同时可以降低min_count参数(比如从5降到2),让更多低频词进入词表。
小可(翻着评测报告):怎么评价训练出来的词向量好不好?
博士:看三个维度:most_similar结果、类比准确率、降维可视化!

评估词向量质量有三个层次:
层次一:定性检查(most_similar)
python
model.wv.most_similar('美丽', topn=10)
# 期望输出: 漂亮, 好看, 俊美, 优美, 秀丽...
如果输出符合直觉,说明语义编码基本到位。这是最简单也最直观的检查方法。
层次二:定量评测(类比准确率)
使用标准的词类比评测集,如Google Analogy Dataset(包含19550条语义和语法类比题):
python
# 语义类比: 巴黎是法国的首都,东京是__的首都?
model.wv.most_similar(positive=['东京', '法国'], negative=['巴黎'], topn=1)
计算模型在语义类比(如"首都关系")和语法类比(如"时态关系")上的准确率,准确率越高,词向量质量越好。
层次三:降维可视化
用PCA/t-SNE将词向量降到2维,在图上直观检查同类词是否聚在一起,不同类是否有明显距离。这是定性检查的可视化工具。
层次四:下游任务测试
最终的检验标准是:用这些词向量作为特征,在下游NLP任务(文本分类、命名实体识别、情感分析等)上的表现如何。好词向量应该能提升下游任务的性能。
此外还有标准的词相似度评测集,如WordSim-353(353对词的相似度标注)和SimLex-999(999对词的语义相似度标注),可以计算模型预测的相似度与人工标注的相关系数。
小可(激动地转圈):Word2Vec训练出来的词向量有什么用?
博士(掰着手指头数):推荐系统、搜索引擎、文本分类、情感分析、机器翻译......用途太多了!

Word2Vec词向量的应用极其广泛,几乎涵盖了所有需要"理解"文本的场景:
推荐系统:
- 将用户和商品都embedding到同一向量空间
- 计算用户向量和商品向量的相似度来推荐
- Item-to-Item推荐:买了A商品的用户也买了B,本质就是item embedding的相似度
搜索引擎:
- 查询词和文档都用词向量表示
- 通过向量相似度匹配查询和文档
- 解决词汇不匹配问题:搜"手机"也能找到包含"智能手机"的文档
文本分类:
- 将文档中所有词的向量取平均(或加权平均),得到文档向量
- 用文档向量训练分类器(SVM、神经网络等)
- 比传统的TF-IDF + 分类器效果更好
情感分析:
- "好"和"坏"的词向量方向相反
- 通过词向量的组合可以推断文本的情感倾向
- 对未知词汇的情感极性也能做出合理推测
机器翻译:
- 跨语言词向量对齐:将英文和中文的词向量映射到同一空间
- "apple"和"苹果"的向量在跨语言空间中应该很近
- 为神经机器翻译提供初始词向量
RAG(检索增强生成):
- 向量相似度召回是RAG系统的核心之一
- 先将文档分词、embedding
- 查询时也embedding,然后计算相似度召回最相关的文档
- 这就是为什么分词质量对RAG很重要
更广泛的应用:
- 图像:图片也可以embedding到向量空间(Image Embedding)
- 生物信息学:氨基酸序列embedding
- 音乐:音符序列embedding
- 任何离散对象都可以embedding到连续空间!
小可(双手合十,满眼崇拜):今天学到了很多!从离散符号到语义向量空间!
博士(欣慰地笑):完美!从Word2Vec到Transformer,Embedding思想贯穿了整个NLP的发展史!

让我们回顾一下今天学到的核心内容:
📚 词表示方法的进化之路
- 整数编号 --- 把词变成数字,但引入了虚假的大小关系
- One-Hot编码 --- 消除了虚假关系,但维度太高、全部正交、无语义
- 共现矩阵 --- 引入了基于统计的语义,但规模太大、稀疏、无法泛化
- Word2Vec (Embedding) --- 低维、密集、可学习、保留语义的终极方案
🔑 Word2Vec的核心要点
- 思想:通过预测上下文的轻量任务来学习词向量
- CBOW:用上下文预测中心词,对高频词友好,训练快
- Skip-gram:用中心词预测上下文,对低频词友好,质量好
- 负采样:从O(V)降到O(k),训练加速数百倍
- 结果:语义和语法关系都被编码在向量空间中
🌟 Embedding的深远影响
Word2Vec只是一个开始。它开创的Embedding思想贯穿了整个AI发展史:
- GloVe:结合全局统计信息和局部上下文
- FastText:处理词内结构和未登录词
- BERT:上下文相关的动态词向量
- GPT系列:从词级别到Token级别的全面Embedding
- 多模态Embedding:文字、图片、音频统一向量空间
从Word2Vec到Transformer,从静态词向量到动态上下文表示,Embedding的核心思想从未改变:
离散对象 → 连续向量空间 → 可计算、可学习、可比较
这是所有现代AI模型的基石。无论是ChatGPT、Claude、还是Gemini,它们的第一层都是Embedding------把输入的文字变成向量。没有Embedding,就没有深度学习,就没有大语言模型,就没有今天的AI革命。
小可(合上笔记本):博士,下次我们学什么?
博士(神秘一笑):RNN?LSTM?还是直接上Transformer?敬请期待!
🐱 小可 & 🐶博士的科普漫画,用轻松的方式讲硬核的知识。如果觉得有用,欢迎分享给更多人!
学习建议:
- 动手用gensim训练一个Word2Vec模型,试试西游记、红楼梦等语料
- 用t-SNE可视化你的词向量,观察聚类效果
- 尝试词类比推理,看看模型学到了哪些有趣的语义关系
- 对比CBOW和Skip-gram的结果差异
- 探索负采样数量对训练速度和词向量质量的影响