自然语言处理(二)—— 词向量与语言模型
Chen Kai BOSS

计算机如何理解"国王"和"女王"之间的关系?如何知道"学习"和"研究"比"苹果"更相似?答案藏在词向量中。

词向量是自然语言处理领域最重要的突破之一,它让机器第一次真正"理解"词汇之间的语义关系。从最早的独热编码到如今的上下文化表示,词向量的演进推动了整个 NLP 领域的发展。本文将深入探讨词向量的核心技术: Word2Vec 如何通过简单的神经网络学习语义, GloVe 如何利用全局统计信息, FastText 如何处理未登录词,以及语言模型如何为这一切提供理论基础。

我们不仅会分析算法原理和数学推导,还会通过代码实战、可视化分析和实际案例,让你真正掌握词向量技术。无论你是想理解"king - man + woman = queen"背后的数学原理,还是想动手训练自己的词向量模型,这篇文章都会给你答案。

从独热编码到词向量

独热编码的困境

最直观的词表示方法是独热编码( one-hot encoding)。假设词汇表大小为 ,每个词用一个 维向量表示,对应位置为 1,其余为 0:

这种表示有三个致命缺陷:

维度灾难:英语常用词汇约 5 万个,专业领域可达数十万。每个词需要一个超高维稀疏向量,计算和存储成本极高。假设词汇表有 50,000 个词,每个文档平均 500 个词,那么文档的向量表示就是 个数字,其中只有 500 个非零。

语义鸿沟:任意两个不同词的独热向量内积为 0,无法表达语义相似性。"猫"和"狗"应该比"猫"和"汽车"更相似,但在独热编码中,它们与任何词的距离都相等:

无法泛化:模型在训练集上学到的关于"猫"的知识,无法迁移到"狗"上,即使它们都是动物。这导致模型需要大量数据才能学习相似概念的相似行为。

分布式假设

词向量的理论基础是分布式假设( Distributional Hypothesis),由语言学家 Harris 在 1954 年提出:

"出现在相似上下文中的词,具有相似的语义。"

换句话说,一个词的意义由它的邻居决定。"猫"经常出现在"宠物"、"喵喵叫"、"抓老鼠"等上下文中,"狗"出现在"宠物"、"汪汪叫"、"看家"等上下文中。虽然具体行为不同,但它们共享"宠物"这个核心上下文,因此语义相近。

这个假设让可以从大规模无标注语料中学习词的表示:通过统计词的共现模式,将语义信息压缩到低维稠密向量中。

词向量的优势

词向量( word embeddings)将每个词映射到一个低维稠密的实数向量空间,通常

这种表示具有三大优势:

低维稠密:从 50,000 维的独热向量降到 100-300 维的稠密向量,减少了 99%以上的存储空间,同时每个维度都携带信息。

语义相似:相似的词在向量空间中彼此接近。可以用余弦相似度度量:

典型结果:,而

向量代数:词向量支持语义运算,最著名的例子是:

这意味着词向量不仅捕捉了词的意义,还捕捉了词之间的关系(如性别、时态、单复数等)。

Word2Vec:革命性的突破

Word2Vec 由 Google 的 Mikolov 等人在 2013 年提出,它用浅层神经网络从大规模语料中学习词向量。核心思想极其简单:通过预测上下文来学习词的表示

两种架构

Word2Vec 有两种训练架构:

Skip-gram(跳字模型):给定中心词,预测周围的上下文词。

CBOW(连续词袋模型):给定上下文词,预测中心词。

直观对比:

  • Skip-gram:已知"学习",预测可能出现"深度"、"机器"、"算法"等词
  • CBOW:已知"深度...算法",预测中间可能是"学习"

Skip-gram 详解

模型定义

给定长度为 的词序列, Skip-gram 的目标是最大化平均对数概率:

其中 是上下文窗口大小。对于中心词,我们要预测其前后各 个词。

条件概率使用 softmax 定义:

这里每个词有两个向量:

-:作为中心词时的向量(输入向量) -:作为上下文词时的向量(输出向量)

为什么需要两套向量?

这是一个常被忽视但很重要的设计。考虑一个极端情况:如果只用一套向量,当词 同时作为中心词和上下文词时,目标函数会鼓励 尽可能大,但这会让所有词的向量趋向相同方向,丧失区分度。

两套向量的分工:

  • 输入向量:学习词的核心语义(最终我们用的就是这个)
  • 输出向量:作为预测上下文的参数矩阵

训练结束后,通常只保留输入向量,输出向量 被丢弃。也有研究尝试将两者平均,但实践中单独使用输入向量效果已经很好。

训练过程

假设词汇表为 ,句子是 "I love deep learning",窗口大小

对于中心词 "love"(位置):

  • 上下文词:
  • 目标:最大化 前向传播计算

反向传播更新向量

softmax 的计算瓶颈

问题在于分母:对于词汇表中的每个词都要计算。当 时,每次预测都要做 50,000 次内积和指数运算,计算量巨大。

训练一个模型通常需要处理数十亿个词,如果每个词的每次预测都要遍历整个词汇表,训练时间将长到无法接受。

负采样:高效的近似

负采样( Negative Sampling)是 Word2Vec 最重要的优化技巧,它将多分类问题转化为二分类问题。

核心思想:从考试类比理解

直觉类比

想象你在准备考试,有两种复习策略:

  • 完整训练( Full Softmax):对题库中所有 10000 道题都逐一练习 → 时间成本太高
  • 负采样策略:只练习几道确定会考的题(正样本) + 几道随机抽取的题(负样本) → 高效且覆盖面广

在 Word2Vec 中的应用

原始问题:给定中心词"king",需要从 50000 个候选词中预测哪个词是真实的上下文词。这需要计算 50000 个 softmax 概率,计算量巨大。

负采样的转化:将问题变为"判断某个词是否是真实上下文"的二分类:

  1. 正样本:"king"旁边确实出现"queen" → 标签为 1
  2. 负样本:随机选 5 个词(如"apple", "car", "run", "happy", "blue") → 标签为 0

数学形式化

对于一个正样本对(中心词和真实上下文词),我们随机采样 个负样本,目标函数变为:

其中 是 sigmoid 函数。

公式深度解读

  • 第一项:最大化正样本的概率
    • 越大时, 越接近 1, 越接近 0(损失越小)
    • 直觉含义:"queen"确实应该出现在"king"附近,让它们的向量内积尽可能大
    • 数值示例:若内积=5,则(损失很小);若内积=-2,则(损失很大)
  • 第二项:最小化负样本的概率
    • 越小(甚至为负)时, 越接近 1,损失越小
    • 直觉含义:"apple"不应该出现在"king"附近,让它们的向量内积尽可能小
    • 数值示例:若内积=-3,则(损失很小);若内积=2,则(损失很大)

为什么这样有效?

核心洞察:只要模型能区分"真实上下文词"和"随机噪声词",就能学到有意义的词向量。不需要精确建模每个词出现的概率,只需要知道"哪些词应该接近,哪些词应该远离"。

数学上,负采样是在近似完整的 softmax 目标。 Mikolov 等人的论文证明,当负样本数量足够多时,负采样的目标函数收敛到 softmax 的目标函数。

负样本如何采样?

简单的均匀采样效果不好,因为高频词(如"the"、"is")会被过度采样。 Word2Vec 使用修正的 unigram 分布:

其中 是词 的频率。指数 让低频词有更多被采样的机会,同时不会完全忽略高频词。

实例:假设"the"出现 10,000 次,"deep"出现 100 次。

  • 均匀采样: - 幂采样: 低频词的采样概率提升了 3 倍。

计算量对比

  • 原始 softmax:每个样本需要 次计算, 是词汇表大小
  • 负采样:每个样本需要 次计算,通常取 5-20

时,负采样的计算量是原始方法的,速度提升了 10,000 倍!

层次 softmax:另一种加速方案

层次 softmax( Hierarchical Softmax)用一棵二叉树代替 flat 的 softmax 层,将计算复杂度从降到

霍夫曼树构造

将词汇表组织成一棵霍夫曼树( Huffman Tree),频率高的词靠近根节点,频率低的词在叶子深处。每个词对应一个叶子节点,从根到该叶子的路径定义了一个唯一的二进制编码。

例如,对于词汇表 ,构造的霍夫曼树可能是:

1
2
3
4
5
6
        root
/ \
[1500] learning(20)
/ \
the is
(1000) (500) cat(50)

路径编码: - "the": 左左 → 00 - "is": 左右 → 01
- "cat": 右左 → 10 - "learning": 右 → 1

概率计算

从根到词 的路径上,每个内部节点做一次二分类:走左子树还是右子树。

假设路径为,路径编码为),那么:

其中 是节点 的向量参数。如果(左),计算;如果(右),计算

复杂度分析

  • 计算:每个词的路径长度平均为,计算量比 flat softmax 的 小得多
  • 频繁词优势:高频词(如"the")路径短,低频词路径长,训练自动聚焦于常见词

负采样 vs 层次 softmax

特性 负采样 层次 softmax
计算复杂度
小语料 表现一般 表现较好
大语料 表现优秀 速度较慢
低频词 可能训练不足 路径长,更新充分
实现复杂度 简单 需要构建树

实践建议:大规模语料用负采样(),小语料或关注低频词时用层次 softmax 。

CBOW 详解

CBOW( Continuous Bag of Words)是 Skip-gram 的逆过程:给定上下文词,预测中心词。

模型定义

目标函数:

上下文表示是上下文词向量的平均:

条件概率:

Skip-gram vs CBOW

数据效率

  • CBOW 将多个上下文词平均,每个样本利用 个词的信息,训练更快
  • Skip-gram 对每个上下文词单独预测,生成更多训练样本

低频词处理

  • CBOW 对上下文词做平均,低频词的信号被高频词淹没,学习效果差
  • Skip-gram 单独处理每个词,低频词有专门的训练样本

语义细节

  • CBOW 倾向于学习语法和词性信息(因为上下文是模糊的平均)
  • Skip-gram 学习更细致的语义关系

实验结果( Mikolov 论文):

  • 小数据集: CBOW 略优(训练样本更充分)
  • 大数据集: Skip-gram 显著更好(尤其是低频词)

推荐:默认使用 Skip-gram + 负采样,除非数据量极小或只关注高频词。

超参数调优

向量维度

  • 太小):表达能力不足,无法捕捉复杂语义
  • 太大):过拟合,训练慢,对下游任务帮助不大
  • 推荐,通用语料用 100-150,专业领域用 200-300

窗口大小

  • 小窗口):捕捉语法和词性,相似词倾向于可替换("好"和"优秀")
  • 大窗口):捕捉主题和领域,相似词倾向于相关("医生"和"医院")
  • 推荐(平衡语法和语义)

负采样数量

  • 小数据集
  • 大数据集(大数据下梯度估计已经足够准确)

采样阈值

高频词(如"the")对语义贡献小,但大量出现会支配梯度。 Word2Vec 用子采样策略以概率 丢弃词:

其中 是词频, 是阈值(通常)。频率越高,越容易被丢弃。

GloVe:全局统计的力量

GloVe( Global Vectors for Word Representation)由 Stanford 的 Pennington 等人在 2014 年提出。它结合了矩阵分解方法(如 LSA)的全局统计优势和局部上下文方法(如 Word2Vec)的预测能力。

核心思想

Word2Vec 从局部窗口中学习,每次只看中心词和邻近上下文,没有充分利用全局统计信息。

GloVe 的洞察:词的共现统计蕴含丰富的语义关系

考虑三个词:"ice"(冰)、"steam"(蒸汽)、"water"(水)。统计它们的共现次数:

上下文词 ice steam
solid
gas
water
fashion

观察比值

-:比值很大("solid"与"ice"强相关) -:比值很小("gas"与"steam"强相关) -:比值接近 1("water"与两者都相关) -:比值接近 1(都不相关)

结论:共现概率的比值比原始概率更能区分语义关系!

目标函数

GloVe 构建词-词共现矩阵,其中 表示词 在词 的上下文窗口中出现的次数。

目标函数:

关键组件

词向量与偏置:每个词有中心向量 和上下文向量,以及两个标量偏置

目标:让内积逼近对数共现次数

权重函数

参数通常取

为什么需要权重函数?

权重函数 是 GloVe 设计中的关键创新,它解决了两个核心问题。

问题 1:零共现的处理

如果(两个词从未在上下文窗口中共现),直接计算 会导致数学上的无定义()。但零共现本身也是有价值的信息——它告诉我们这两个词语义上可能不相关。

GloVe 的解决方案:设置权重,这样零共现项对损失函数的贡献为零:

这意味着我们不惩罚零共现的预测误差,但也不完全忽略它(因为模型仍需要学习这些词对的表示)。

问题 2:高频词对主导优化过程

考虑两个词对: - "the" 和 "a" 共现 100,000 次 - "quantum" 和 "entanglement" 共现 100 次

如果使用相同权重,损失函数会被高频词对主导:

即使 很大,第二项的贡献也会被第一项淹没,导致低频词的语义学习不充分。

GloVe 的权重函数设计

这个设计有三个巧妙之处:

  1. 低频共现(:权重随共现次数增加而增加,符合直觉——共现次数越多,统计越可靠,应该给更大权重。

  2. 高频共现(:权重固定为 1,避免极高频词对过度主导。这是一种"截断"策略。

  3. 指数:让权重增长速度比线性慢。为什么不用线性()?看一个数值例子:

数值示例:假设 | 共现次数| 线性权重| 指数权重| |------------|-----------------|------------------------| | 1 | 0.01 | 0.056 | | 10 | 0.10 | 0.178 | | 50 | 0.50 | 0.595 | | 100 | 1.00 | 1.000 |

可以看到,指数 让低频词(如)的权重从 0.01 提升到 0.056(提升 5.6 倍),而对高频词(如)影响不大。这种"压缩"效果让优化过程更平衡。

实际效果

对于"quantum"和"entanglement"(),权重为 对于"the"和"a"(),权重被截断为 1

现在两者对损失函数的贡献相当,低频词的语义也能得到充分学习。

训练细节

共现矩阵构建

遍历语料库,对每个词,统计其上下文窗口内每个词 的出现次数。使用衰减权重:离中心词越远,权重越小。

对于窗口大小,如果词 距离中心词 的距离为,权重为

优化算法

使用 AdaGrad 自适应学习率,初始学习率。训练 50-100 轮( epoch),对于大规模语料可能需要几小时到几天。

最终向量

训练完成后,每个词有两个向量:(作为中心词)和(作为上下文词)。最终词向量取两者之和:

实验表明,求和比单独使用或求平均效果更好。

GloVe vs Word2Vec

维度 Word2Vec GloVe
训练方式 在线学习,逐个窗口 批量优化,全局统计
信息利用 局部上下文 全局共现
训练速度 快(单次遍历) 慢(需多次迭代矩阵)
内存占用 小(只存模型参数) 大(需存共现矩阵)
低频词 Skip-gram 较好 通过权重函数改善
可解释性 较弱 较强(直接建模共现)

理论联系: Levy 等人证明, Word2Vec 的 Skip-gram + 负采样实际上是在隐式分解一个移位的点互信息矩阵( PMI):

其中

这表明 Word2Vec 和 GloVe 本质上都在从共现统计中提取信息,只是方式不同:

  • Word2Vec:隐式、增量式、随机化
  • GloVe:显式、批量式、确定性

实践选择

  • 大规模语料: Word2Vec 更快,性能相近
  • 中小规模语料: GloVe 可能更稳定(充分利用全局信息)
  • 增量更新: Word2Vec 支持, GloVe 需重建矩阵
  • 预训练向量:两者都提供,可以都试试

FastText:子词的威力

FastText 由 Facebook AI Research 在 2016 年提出,核心创新是将词表示为字符 n-gram 的组合,而不是单一向量。

问题背景

Word2Vec 和 GloVe 的共同缺陷:

OOV 问题:训练时未出现的词( Out-Of-Vocabulary),无法得到向量表示。医学文献中的"methylprednisolone"如果训练集没见过,就完全没有表示。

形态信息丢失:忽略词的内部结构。"teach"、"teacher"、"teaching"是独立的三个词,无法共享"teach"这个词根的语义。

复合词处理差:德语"Lebensversicherungsgesellschaftsangestellter"(人寿保险公司员工),即使未见过,人类也能从子词推断含义。

子词表示

FastText 将每个词拆分成字符 n-gram 的集合。对于词 时的 n-gram 为:

  • 字符 3-gram:<wh, whe, her, ere, re>
  • 加上完整词本身:<where>

特殊符号 <> 标记词的边界,区分"her"(独立词)和"her"("where"的子串)。

每个 n-gram 有独立的向量,词 的向量是其所有 n-gram 向量的和:

其中 是词 的 n-gram 集合。

训练目标

FastText 使用 Skip-gram 框架,但把词向量 替换为子词向量之和:

其中评分函数:

训练时更新的是 n-gram 向量,而不是词向量。一个词的梯度会分配到其所有子词上。

OOV 词处理

FastText 最强大的能力之一是处理OOV( Out-Of-Vocabulary)词,即训练时未见过的词。这是 Word2Vec 和 GloVe 无法做到的。

OOV 处理流程

当测试时遇到未登录词(训练集中没有), FastText 通过以下步骤生成其向量:

步骤 1:提取字符 n-gram

将未登录词拆分成字符 n-gram 集合:

特殊符号<>标记词的边界,确保子词的唯一性。

步骤 2:查找 n-gram 向量

在训练好的 n-gram 向量表中查找这些 n-gram 的向量。这些向量是训练时从其他词中学到的。

步骤 3:求和生成词向量

完整实例:处理"teaching"

背景:训练集包含"teacher"和"preaching",但没有"teaching"。测试时遇到"teaching",如何生成向量?

步骤 1:提取 3-gram

"teaching"的 3-gram():

1
<te, tea, eac, ach, chi, hin, ing, ng>

步骤 2:识别共享的 n-gram

与训练集词汇的 n-gram 对比:

  • "teacher"的 3-gram:<te, tea, eac, ach, che, her, er>
  • "preaching"的 3-gram:<pr, pre, rea, eac, ach, chi, hin, ing, ng>

"teaching"与它们共享的 n-gram:

n-gram 出现在"teacher"? 出现在"preaching"?
tea
eac
ach
chi
hin
ing

步骤 3:组合生成向量

假设训练后的 n-gram 向量为:

则"teaching"的向量为:

由于大部分 n-gram 与"teacher"共享, 会在向量空间中接近

为什么这样有效?

语义继承:相似的词通常共享相似的子词。"teaching"和"teacher"都包含"teach"的语义核心。

泛化能力:即使整词未见过,只要其子词在训练集中出现过(通过其他词), FastText 就能生成合理的表示。

实际应用场景

  • 专有名词:新人名、地名(如"Zuckerberg")可以从子词"berg"等推断
  • 拼写错误:用户输入"recieve"(正确是"receive"),仍能生成接近"receive"的向量
  • 新词:社交媒体上的新词(如"selfie")可以从"self"等子词推断
  • 复合词:德语复合词可以从组成部分推断

这让 FastText 特别适合处理动态变化的语言环境。

超参数选择

n-gram 长度

  • 太短():噪声大,"th"出现在太多无关词中
  • 太长():过于稀疏,很多词的 n-gram 独一无二
  • 推荐,英语常用 3-4,形态丰富的语言(如土耳其语)用 4-6

子词数量限制

完整存储所有 n-gram 会占用大量内存(百万级)。 FastText 用哈希技巧将 n-gram 映射到固定大小的向量表(如 200 万桶),冲突的 n-gram 共享向量。

形态语言的优势

FastText 在形态丰富的语言上表现尤为出色:

土耳其语:大量后缀附加,如"evlerinizden"(从你们的房子),拆分为"ev"(房子)+"ler"(复数)+"iniz"(你们的)+"den"(从)。即使整词未见过, FastText 可以从子词推断。

芬兰语: 15 种格变,如"talo"(房子)可以变化为"talossa"(在房子里)、"talosta"(从房子)、"taloon"(到房子)。 FastText 共享词干"talo"的语义。

德语复合词:"Donaudampfschifffahrtsgesellschaftskapit ä n"(多瑙河蒸汽船公司船长),虽然罕见,但可以从"Donau"(多瑙河)、"dampf"(蒸汽)、"schiff"(船)等子词推断。

FastText 的权衡

优点

  • 可以处理 OOV 词
  • 利用形态信息,拼写相近的词向量相近
  • 对拼写错误有一定鲁棒性

缺点

  • 训练和存储开销更大(需要几百万个 n-gram 向量)
  • 词义不受限于上下文,"bank"(银行)和"bank"(河岸)的子词完全相同,无法区分
  • 中文等字符语言需要特殊处理(通常用字或词作为单位,而不是字符)

实践建议

  • 形态丰富语言、专业领域、 OOV 严重:选 FastText
  • 大规模通用语料、英语: Word2Vec 或 GloVe 足够
  • 需要上下文化表示(多义词):用 BERT 等预训练模型

统计语言模型

词向量的学习目标是预测上下文,这实际上是在建模语言的概率分布。理解语言模型对于理解词向量至关重要。

语言模型的定义

语言模型的任务是建模一个句子的概率。根据概率链式法则:

语言模型的核心问题:如何估计条件概率

N-gram 模型

完整的历史 可能很长,且很多序列从未出现,无法直接估计。 N-gram 模型的假设:当前词只依赖前 个词

Unigram):词之间独立

Bigram):当前词只依赖前一个词

Trigram):当前词依赖前两个词

参数估计

使用最大似然估计( MLE)从训练语料中统计:

Bigram 概率

其中 是二元组 在语料中的出现次数, 是词 的出现次数。

实例:语料库中"I love"出现 100 次,"I"出现 1000 次,则

平滑技术

稀疏性问题:很多 n-gram 在训练集中从未出现, MLE 估计的概率为 0,这会导致整个句子的概率为 0(因为是连乘)。

平滑技术给未见过的 n-gram 分配一个小的非零概率。

加法平滑( Add-k Smoothing)

在所有计数上加一个小的常数

其中 是词汇表大小。特例 称为 Laplace 平滑。

问题:给所有未见 n-gram 分配相同概率太粗糙,实际效果不佳。

Kneser-Ney 平滑

最先进的平滑方法之一,核心思想是使用低阶模型补充高阶模型

绝对折扣:

其中 是折扣参数, 是归一化系数, 衡量词 能跟在多少不同词后面(延续概率)。

直觉:对于常见 n-gram,减去固定折扣;节省的概率质量分配给未见过的 n-gram,权重由低阶模型决定。

评价指标:困惑度

困惑度( Perplexity)衡量语言模型的预测能力:

解释:困惑度表示模型在每个位置平均需要从多少个词中选择。 PPL=100 意味着模型平均在 100 个词中"纠结"。困惑度越低,模型越好。

实例

  • 随机猜测( Unigram 均匀分布):(词汇表大小)
  • 完美模型:(总能正确预测)
  • 实际 Trigram 模型:(英语)

N-gram 的局限

长距离依赖缺失: Trigram 只看前两个词,无法捕捉"The cat, which was sitting on the mat, ____"中"cat"和空白位置的关系。

数据稀疏: 4-gram 、 5-gram 的大部分组合从未出现,即使使用平滑,估计也不可靠。

维度爆炸: Trigram 需要存储 个概率, 时是 1250 亿个参数。

无泛化能力:"I love cats"和"I love dogs"完全独立,即使"cats"和"dogs"语义相近,模型也无法利用这一点。

这些问题驱动了神经语言模型的诞生。

神经语言模型

神经语言模型用神经网络直接估计,突破了传统 N-gram 模型的局限。

前馈神经语言模型( NNLM)

Bengio 等人在 2003 年提出的 NNLM 是第一个成功的神经语言模型,也是词向量的早期尝试。

模型结构

输入层:前 个词的独热编码,通过查表映射到词向量:

隐藏层

输出层( softmax):

关键优势

参数共享:词向量在所有位置共享,"love"无论出现在哪个位置,都用同一个向量表示。这大幅减少了参数量(从降到)。

平滑泛化:相似词的向量相近,导致它们的条件概率分布也相近。如果模型学到"I love cats"概率高,自动推断"I love dogs"概率也高(只要"cats"和"dogs"向量接近)。

连续空间:不同于离散的 N-gram 计数,神经模型在连续空间中插值,对未见序列也能给出合理概率。

与 Word2Vec 的联系

NNLM 训练的副产品是词向量矩阵(输入层的查找表),这些词向量捕捉了词的语义。但 NNLM 的主要目标是语言模型,训练开销大( softmax 层遍历整个词汇表)。

Word2Vec 简化了 NNLM:

  • 去掉隐藏层(浅层网络)
  • 用负采样或层次 softmax 代替 softmax
  • 专注于学习词向量,而不是完整的语言模型

可以说,Word2Vec 是 NNLM 的轻量级、专用化版本

RNN 语言模型

循环神经网络( RNN)可以处理任意长度的历史,突破了 N-gram 的固定窗口限制。

模型结构

在每个时间步

隐藏状态递归地编码了 的所有信息。

优势

无限历史:理论上可以记忆整个句子的信息,不受固定窗口限制。

参数共享:所有时间步共享权重矩阵,参数量与序列长度无关。

动态表示:相同的词在不同上下文中的隐藏状态不同,自然处理多义词。

实践中的问题

梯度消失/爆炸:反向传播时梯度指数衰减或增长,导致长距离依赖难以学习。

训练慢:循环结构无法并行化,训练大规模语料非常耗时。

解决方案: LSTM 和 GRU 引入门控机制缓解梯度问题; Transformer 用自注意力机制实现并行化(这已经超出本文范围,是现代 NLP 的主流)。

词向量的几何性质

词向量最令人惊叹的性质是它们的几何结构蕴含语义关系。这不是偶然,而是训练目标的必然结果。

余弦相似度

最常用的相似度度量是余弦相似度:

取值范围,越接近 1 越相似。

实例(使用预训练的 Word2Vec):

1
2
3
4
5
sim('king', 'queen') = 0.71
sim('king', 'man') = 0.65
sim('king', 'apple') = 0.08
sim('cat', 'dog') = 0.76
sim('cat', 'car') = 0.12

向量代数:类比推理

词向量最神奇的性质是支持向量运算来推理语义关系。

经典案例

解释

-$v_{} - v_{} v_{} $:添加"女性"属性 - 结果:保留"王室地位",改变"性别" → "女王"

用最近邻搜索验证:

更多类比

地理关系

语法关系

比较级

为什么有效?

从训练目标看, Skip-gram 最大化:

如果"king"和"queen"共享大部分上下文("royal"、"throne"、"crown"),但"king"更常与"man"、"he"共现,"queen"更常与"woman"、"she"共现,那么:

因此:

这暗示了向量的不同维度捕捉不同的语义属性(如性别、时态、数量等),类比推理本质上是在这些语义维度上的线性变换。

可视化: t-SNE 降维

词向量通常是 100-300 维,无法直接可视化。 t-SNE( t-distributed Stochastic Neighbor Embedding)将高维向量降到 2D 或 3D,同时尽量保持局部邻域结构。

t-SNE 原理

高维相似度:将欧氏距离转换为概率

低维相似度:用 t 分布(自由度为 1)

优化目标:最小化 KL 散度

使得低维表示 保持高维的邻域关系。

实践要点

困惑度参数:控制关注的邻居数量,通常设为 5-50 。困惑度小,关注极近邻;困惑度大,保留更全局的结构。

随机性: t-SNE 对初始化敏感,多次运行可能产生不同的图形(但聚类结构应该稳定)。

不保留全局距离: t-SNE 保留局部结构,不同聚类之间的距离没有意义。

可视化示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from gensim.models import Word2Vec

# 加载模型
model = Word2Vec.load("word2vec.model")
words = list(model.wv.index_to_key)[:1000] # 取前 1000 个词
vectors = [model.wv[w] for w in words]

# t-SNE 降维
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
vectors_2d = tsne.fit_transform(vectors)

# 绘图
plt.figure(figsize=(16, 12))
plt.scatter(vectors_2d[:, 0], vectors_2d[:, 1], alpha=0.5)
for i, word in enumerate(words):
plt.annotate(word, xy=(vectors_2d[i, 0], vectors_2d[i, 1]))
plt.show()

典型观察:

  • 语义相近的词聚成簇(国家名、动物名、颜色词)
  • 同义词紧密聚集( big/large/huge)
  • 反义词有时也聚在一起( hot/cold,因为共享相似的上下文)

实战:用 gensim 训练 Word2Vec

理论讲完了,现在动手训练自己的词向量模型。 gensim 是 Python 中最流行的词向量库。

环境准备

1
pip install gensim nltk

数据准备

使用 NLTK 的 Brown 语料库作为示例:

1
2
3
4
5
6
7
8
import nltk
from nltk.corpus import brown
nltk.download('brown')

# 加载语料,每个句子是一个词列表
sentences = list(brown.sents())
print(f"Total sentences: {len(sentences)}")
print(f"Example sentence: {sentences[0]}")

输出:

1
2
Total sentences: 57340
Example sentence: ['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]

训练 Skip-gram 模型

Word2Vec 训练是将大规模文本语料转换为词向量的过程。 gensim 库封装了 Word2Vec 的完整实现,包括 Skip-gram 、 CBOW 、负采样、层次 softmax 等算法,使用简单但功能强大。

问题背景:需要从原始文本语料中学习词的稠密向量表示。这个过程需要处理数百万到数十亿个词,计算词与上下文的共现关系,通过梯度下降优化词向量。 gensim 的 Word2Vec 类封装了所有这些复杂性,提供了简洁的 API 。

解决思路: Word2Vec 通过预测上下文来学习词向量。 Skip-gram 架构给定中心词预测周围词,通过最大化预测概率来更新词向量。负采样将多分类问题转化为二分类,大幅提升训练速度。训练过程是迭代的,需要多轮遍历语料才能收敛。

设计考虑:参数选择至关重要。 vector_size 控制表达能力, window 控制语义范围, min_count 过滤噪声词, negative 控制负采样数量。这些参数需要根据数据规模和任务需求调整。 gensim 支持多线程训练( workers 参数),可以充分利用多核 CPU 加速训练。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from gensim.models import Word2Vec
import logging

# 启用日志以查看训练进度
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# ========== 步骤 1:准备数据 ==========
# sentences 应该是词列表的列表
# 每个内部列表是一个句子,每个元素是一个词(字符串)
# 示例格式:[['I', 'love', 'NLP'], ['Machine', 'learning', 'is', 'amazing'], ...]
# 注意:文本应该已经完成分词和预处理

# ========== 步骤 2:创建 Word2Vec 模型 ==========
# Word2Vec 类的参数说明:
# - sentences: 训练语料,可以是列表或生成器(支持流式处理)
# - vector_size: 词向量维度(原参数名是 size, gensim 4.0+改为 vector_size)
# - window: 上下文窗口大小(中心词前后各 window 个词)
# - min_count: 词的最小出现次数,低于此值的词被忽略
# - workers: 并行训练的线程数(建议设置为 CPU 核心数)
# - sg: 训练算法, 1=Skip-gram, 0=CBOW
# - negative: 负采样数量(如果>0 使用负采样,=0 使用层次 softmax)
# - epochs: 训练轮数(原参数名是 iter, gensim 4.0+改为 epochs)
# - alpha: 初始学习率(默认 0.025)
# - min_alpha: 最小学习率(学习率会线性衰减到此值)
# - sample: 高频词子采样阈值(默认 1e-3, 0 表示不进行子采样)
# - hs: 是否使用层次 softmax( 0=否,使用负采样; 1=是)
# - cbow_mean: CBOW 模式下是否对上下文词向量求平均( 1=平均, 0=求和)

model = Word2Vec(
sentences=sentences, # 训练语料:词列表的列表
vector_size=100, # 词向量维度: 100-300 是常用范围
# 太小(<50):表达能力不足
# 太大(>500):过拟合,训练慢
# 推荐:通用语料 100-150,专业领域 200-300
window=5, # 上下文窗口大小:中心词前后各 5 个词
# 小窗口( 2-5):捕捉语法和词性关系
# 大窗口( 10-15):捕捉主题和领域关系
# 推荐: 5(平衡语法和语义)
min_count=5, # 最小词频:出现次数<5 的词被忽略
# 作用:过滤噪声词,减少词汇表大小
# 推荐:小数据集用 1-2,大数据集用 5-10
workers=4, # 并行线程数:利用多核 CPU 加速训练
# 推荐:设置为 CPU 核心数
# 注意: Windows 上可能不支持多进程,设置为 1
sg=1, # 训练算法: 1=Skip-gram, 0=CBOW
# Skip-gram:适合大数据集,低频词效果好
# CBOW:训练快,适合小数据集
# 推荐:默认使用 Skip-gram( sg=1)
negative=5, # 负采样数量:每个正样本采样 5 个负样本
# 小数据集(<1 亿词): 5-20
# 大数据集(>1 亿词): 2-5
# 0:使用层次 softmax(不推荐,速度慢)
epochs=10, # 训练轮数:遍历语料的次数
# 小数据集: 10-20 轮
# 大数据集: 5-10 轮
# 注意:训练时间 = 语料大小 × epochs / workers
alpha=0.025, # 初始学习率:控制参数更新幅度
min_alpha=0.0001, # 最小学习率:学习率线性衰减到此值
sample=1e-3, # 高频词子采样阈值:减少高频词的影响
# 值越大,高频词被丢弃的概率越大
# 0:不进行子采样
hs=0, # 是否使用层次 softmax: 0=否(使用负采样), 1=是
# 层次 softmax:适合小数据集,低频词效果好
# 负采样:速度快,适合大数据集
# 推荐:使用负采样( hs=0)
seed=42 # 随机种子:确保结果可复现
)

# ========== 步骤 3:训练过程说明 ==========
# Word2Vec 的训练过程:
# 1. 构建词汇表:统计词频,过滤 min_count 以下的词
# 2. 构建 Huffman 树(如果使用层次 softmax)或准备负采样分布
# 3. 初始化词向量:随机初始化或从预训练向量加载
# 4. 迭代训练:
# - 对每个句子中的每个词:
# - 生成训练样本(中心词-上下文词对)
# - 采样负样本(如果使用负采样)
# - 计算损失和梯度
# - 更新词向量
# - 学习率线性衰减: alpha -> min_alpha
# 5. 保存最终词向量

# ========== 步骤 4:保存模型 ==========
# 保存完整模型(包括词汇表、词向量、超参数等)
model.save("word2vec.model")
# 文件格式: Python pickle 格式,包含所有模型信息

# 也可以只保存词向量(更轻量)
# model.wv.save_word2vec_format("word2vec_vectors.txt", binary=False)
# 格式:第一行是"词汇表大小 向量维度",后续每行是"词 向量值 1 向量值 2 ..."

深入解读: Word2Vec 训练的关键细节

Word2Vec 训练看似简单,但涉及许多重要的设计决策和优化技巧:

1. 数据格式要求

gensim 的 Word2Vec 要求输入是词列表的列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ✅ 正确格式
sentences = [
['I', 'love', 'NLP'],
['Machine', 'learning', 'is', 'amazing']
]

# ❌ 错误格式
sentences = [
"I love NLP", # 字符串,不是词列表
"Machine learning is amazing"
]

# 转换方法
sentences = [text.split() for text in raw_texts] # 简单分词
# 或使用更复杂的分词
sentences = [jieba.lcut(text) for text in raw_texts] # 中文分词

2. 参数选择的经验法则

参数 小数据集(<1000 万词) 中等数据集( 1000 万-1 亿词) 大数据集(>1 亿词)
vector_size 50-100 100-200 200-300
window 5-10 5 5
min_count 1-2 5 10
negative 10-20 5-10 2-5
epochs 15-20 10-15 5-10

3. 训练速度优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 方法 1:使用生成器(节省内存)
def sentence_generator(file_path):
"""流式读取语料,不一次性加载到内存"""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
yield line.strip().split()

# 使用生成器训练(适合超大语料)
model = Word2Vec(sentences=sentence_generator('large_corpus.txt'), ...)

# 方法 2:增加 workers(多线程)
model = Word2Vec(sentences=sentences, workers=8) # 使用 8 个线程

# 方法 3:使用层次 softmax(小数据集)
model = Word2Vec(sentences=sentences, hs=1, negative=0) # 层次 softmax

4. 常见问题与解决方案

问题 原因 解决方案
内存溢出 语料太大,一次性加载 使用生成器或分批处理
训练速度慢 workers 设置不当或算法选择不当 增加 workers,使用负采样而非层次 softmax
词向量质量差 数据量不足或参数不当 增加数据量,调整 window 和 vector_size
某些词没有向量 词频低于 min_count 降低 min_count 或增加数据量
结果不可复现 未设置随机种子 设置 seed 参数

5. 训练监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 方法 1:使用回调函数监控训练
class EpochLogger:
"""记录每个 epoch 的训练信息"""
def __init__(self):
self.epoch = 0

def __call__(self):
self.epoch += 1
print(f"Epoch #{self.epoch} completed")

# 使用回调(注意: gensim 的 Word2Vec 不直接支持回调,需要自定义)
# 可以通过检查模型训练时间间接监控

# 方法 2:检查训练后的词汇表大小
print(f"Vocabulary size: {len(model.wv.key_to_index)}")
print(f"Total training words: {model.corpus_total_words}")

# 方法 3:评估词向量质量
# 使用词类比任务或相似度任务评估

6. 增量训练

gensim 支持在已有模型基础上继续训练:

1
2
3
4
5
6
7
8
9
10
11
12
# 加载已有模型
model = Word2Vec.load("word2vec.model")

# 准备新语料
new_sentences = [['new', 'words', 'here'], ...]

# 继续训练
model.build_vocab(new_sentences, update=True) # 更新词汇表
model.train(new_sentences, total_examples=len(new_sentences), epochs=5)

# 保存更新后的模型
model.save("word2vec_updated.model")

7. 模型评估

训练完成后,需要评估词向量质量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 方法 1:词相似度
similarity = model.wv.similarity('man', 'woman')
print(f"Similarity: {similarity:.4f}")

# 方法 2:查找相似词
similar_words = model.wv.most_similar('computer', topn=10)
for word, score in similar_words:
print(f"{word}: {score:.4f}")

# 方法 3:词类比任务
result = model.wv.most_similar(
positive=['woman', 'king'],
negative=['man'],
topn=5
)
# 期望结果:'queen'应该排在第一位

# 方法 4:评估词类比数据集
# accuracy = model.wv.evaluate_word_analogies('questions-words.txt')

8. 生产环境部署

实际部署时需要考虑:

  1. 模型大小:大型模型(数百万词)可能占用数 GB 内存
  2. 加载时间:模型加载可能需要几秒到几分钟
  3. 推理速度:查找相似词、计算相似度等操作的速度
  4. 版本管理:记录模型版本、训练参数、数据来源
1
2
3
4
5
6
# 优化模型大小:只保留常用词
model.wv.init_sims(replace=True) # 归一化向量,节省内存

# 导出为更轻量的格式
model.wv.save_word2vec_format('vectors.txt', binary=False)
# 只包含词和向量,不包含其他信息,文件更小

理解 Word2Vec 训练的每个参数和步骤,能够帮助你在实际项目中训练出高质量的词向量模型。

探索词向量

查找相似词

1
2
3
4
5
6
7
# 加载模型
model = Word2Vec.load("word2vec.model")

# 查找最相似的词
similar_words = model.wv.most_similar("man", topn=10)
for word, score in similar_words:
print(f"{word}: {score:.4f}")

输出示例:

1
2
3
4
5
6
woman: 0.7823
person: 0.7156
boy: 0.6934
men: 0.6891
himself: 0.6712
...

词向量类比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# king - man + woman = ?
result = model.wv.most_similar(
positive=['woman', 'king'],
negative=['man'],
topn=5
)
print("king - man + woman =", result[0][0])

# Paris - France + Italy = ?
result = model.wv.most_similar(
positive=['Paris', 'Italy'],
negative=['France'],
topn=5
)
print("Paris - France + Italy =", result[0][0])

注意: Brown 语料库较小,可能无法完美复现经典案例。使用大规模语料(如 Wikipedia 、 Common Crawl)效果更好。

计算相似度

1
2
3
4
5
6
# 两个词的余弦相似度
sim = model.wv.similarity('man', 'woman')
print(f"Similarity(man, woman): {sim:.4f}")

sim = model.wv.similarity('man', 'apple')
print(f"Similarity(man, apple): {sim:.4f}")

获取词向量

1
2
3
4
# 获取词的向量表示
vector = model.wv['man']
print(f"Shape: {vector.shape}")
print(f"First 10 dimensions: {vector[:10]}")

训练 CBOW 模型

只需改变一个参数:

1
2
3
4
5
6
7
8
9
10
model_cbow = Word2Vec(
sentences=sentences,
vector_size=100,
window=5,
min_count=5,
workers=4,
sg=0, # 0=CBOW
negative=5,
epochs=10
)

使用预训练向量

训练大规模语料耗时耗力,直接使用预训练向量更实用。 Google 提供的预训练 Word2Vec 包含 300 万个词和短语:

1
2
3
4
5
6
7
import gensim.downloader as api

# 下载预训练模型(第一次较慢,约 1.6GB)
model_pretrained = api.load("word2vec-google-news-300")

# 查找相似词
print(model_pretrained.most_similar("computer", topn=5))

其他预训练模型:

  • glove-wiki-gigaword-100: GloVe 向量, 100 维
  • glove-twitter-25:推特语料训练, 25 维
  • fasttext-wiki-news-subwords-300: FastText 向量, 300 维

评估词向量质量

词类比任务

使用标准数据集(如 Google 的 analogies dataset)评估:

1
2
3
4
5
# 下载词类比数据集
# https://raw.githubusercontent.com/nicholas-leonard/word2vec/master/questions-words.txt

accuracy = model.wv.evaluate_word_analogies('questions-words.txt')
print(f"Accuracy: {accuracy[0]:.2%}")

词相似度任务

使用人工标注的相似度数据集(如 WordSim-353)评估:

1
2
3
4
5
from scipy.stats import spearmanr

# 加载 WordSim-353 数据集(词对和人工评分)
# 计算模型预测的相似度
# 计算 Spearman 相关系数

相关系数越高,说明模型的相似度判断越接近人类。

中文词向量训练

中文需要先分词:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import jieba
from gensim.models import Word2Vec

# 读取中文语料
with open('chinese_corpus.txt', 'r', encoding='utf-8') as f:
texts = f.readlines()

# 分词
sentences = [list(jieba.cut(text.strip())) for text in texts]

# 训练模型
model_zh = Word2Vec(
sentences=sentences,
vector_size=100,
window=5,
min_count=5,
sg=1,
negative=5,
epochs=10
)

# 查找相似词
print(model_zh.wv.most_similar("计算机", topn=10))

推荐的中文预训练向量:

  • 清华大学开源的中文词向量:Chinese Word Vectors
  • 腾讯 AI Lab 开源的词向量:包含 800 万词汇, 200 维

❓ Q&A: 词向量常见问题

Q1: 为什么 Word2Vec 能捕捉语义,它又没有标注数据?

A: 这是自监督学习( self-supervised learning)的力量。虽然没有人工标注,但"预测上下文"这个任务本身就蕴含语义信息。根据分布式假设,共享相似上下文的词应该有相似表示。当模型学会预测上下文时,自然会将语义相近的词映射到附近的向量空间。这就像学习一门语言,你不需要字典,只需要大量阅读,就能从上下文推断词义。

Q2: 词向量的维度如何选择?越大越好吗?

A: 不是。维度太小(如 50)表达能力不足,无法区分细致的语义差异;维度太大(如 500)会过拟合,模型记住训练数据的噪声而不是真正的语义模式。实践中:

  • 通用场景: 100-150 维足够,性价比最高
  • 大规模语料: 200-300 维,可以捕捉更细致的语义
  • 小数据集: 50-100 维,避免过拟合
  • 下游任务微调:用交叉验证选择最佳维度

一个经验法则:当增加维度不再显著提升下游任务性能时,就到达了最佳点。

Q3: Skip-gram 和 CBOW 到底哪个好?什么时候用哪个?

A: 没有绝对答案,取决于数据和目标:

Skip-gram 优势

  • 大数据集上性能更好(充分的训练样本)
  • 对低频词学习更充分(每个词有多个训练样本)
  • 更擅长捕捉细致的语义关系

CBOW 优势

  • 小数据集上训练更快(样本利用效率高)
  • 对高频词和语法信息学习更好
  • 计算开销小(上下文词一次性处理)

推荐策略:默认使用 Skip-gram + 负采样,除非数据量很小(<1000 万词)或算力受限。

Q4: 负采样的负样本数量 K 应该设多少?

A: 看数据规模:

  • 小数据集(<1 亿词):,需要更多负样本来提供足够的对比信号
  • 大数据集(>1 亿词):,大量训练样本已经提供充足的梯度估计
  • 极大数据集(>10 亿词): 足够

原则:数据越多,负样本越少;数据越少,负样本越多。但 太大会导致训练变慢,且收益递减。

Q5: 词向量能处理多义词吗?"bank"(银行/河岸)怎么办?

A: 传统词向量( Word2Vec/GloVe/FastText)不能区分多义词,"bank"只有一个向量,是所有义项的混合。这是它们的根本局限。

解决方案

上下文化词向量: ELMo 、 BERT 等模型为每个词在特定句子中生成动态向量。"I went to the bank"和"The river bank"中的"bank"会得到不同的向量。

多原型词向量:为每个词学习多个向量(每个义项一个),如 Huang et al. (2012)的聚类方法。但需要确定义项数量,实践中较少使用。

实用建议:如果多义词是关键问题,直接用 BERT 等预训练模型;如果只是辅助特征,静态词向量足够。

Q6: FastText 对中文有用吗?

A: 效果有限。 FastText 为拼音文字(英语、德语、土耳其语)设计,利用字符 n-gram 捕捉形态信息。但中文是表意文字:

  • 字符级 n-gram 无意义:"学习"拆成"学"和"习"还算有意义,但拆成笔画或部首 n-gram 就完全失去信息。
  • 词级或字级更合适:对中文用词作为基本单位(需要分词),或用字(天然分隔)。

中文 FastText 改进

  • 用部首、笔画数等特征代替字符 n-gram
  • 用词内部的字组合(如"学习"→"学"+"习"+"学习")
  • 直接用字向量组合( BERT 等模型的做法)

实践中,对中文通常直接用基于字的模型或 BERT,效果优于强行套用 FastText 。

Q7: 如何判断训练的词向量质量好不好?

A: 多角度评估:

内在评估

  • 词类比任务: Google analogies dataset,测试"king - man + woman = queen"类推理,准确率越高越好
  • 词相似度任务: WordSim-353 等数据集,计算模型预测与人工标注的相关系数
  • 可视化检查: t-SNE 降维,看相似词是否聚类,反义词关系是否合理

外在评估(最重要):

  • 将词向量用于下游任务(文本分类、命名实体识别等),看性能是否提升
  • A/B 测试:与其他词向量或基线比较

常见问题排查

  • 如果高频词相似度好,但低频词很差 → 增加训练轮数或使用 Skip-gram
  • 如果词类比任务差 → 增大窗口大小或向量维度
  • 如果所有词都挤在一起 → 语料太小或训练不足

Q8: 为什么训练好的词向量需要归一化?

A: 并非必须,但有几个好处:

加速相似度计算:归一化后余弦相似度变成简单的内积(因为),省去除法和开方。

稳定数值:避免向量模长过大或过小导致的数值问题。

公平比较:高频词训练更多,向量模长可能更大。归一化消除这种偏差,让相似度只反映方向而非模长。

实现

1
2
3
4
5
6
7
# gensim 自动归一化
model.wv.vectors_norm # 归一化后的向量

# 手动归一化
import numpy as np
v = model.wv['king']
v_norm = v / np.linalg.norm(v)

注意:如果用向量做特征输入到神经网络,不一定要归一化(网络会学习合适的缩放)。

Q9: 预训练词向量在特定领域(如医学)上效果不好,怎么办?

A: 通用语料(如 Wikipedia)训练的词向量在专业领域表现差,因为:

  • 专业词汇可能不在词汇表( OOV)
  • 词的分布和共现模式不同("cell"在生物学和电子学中语义不同)

解决方案

领域语料微调

1
2
3
4
5
6
7
# 加载预训练模型
model = Word2Vec.load("pretrained_general.model")

# 在医学语料上继续训练
medical_sentences = load_medical_corpus()
model.build_vocab(medical_sentences, update=True) # 扩充词汇表
model.train(medical_sentences, total_examples=len(medical_sentences), epochs=5)

从头训练:如果有大量领域语料(>1 亿词),从头训练可能更好。

混合特征:同时使用通用词向量(捕捉基本语义)和领域词向量(捕捉专业知识)。

迁移到 BERT:用领域语料微调 BERT,效果通常优于静态词向量。

Q10: 词向量能捕捉情感吗?如何评估情感极性?

A: 部分可以,但不完美。词向量从上下文学习,"好"和"坏"可能因为都出现在评价场景中而相似("这个电影很好/坏")。

情感评估方法

手动检查

1
2
3
# 查找"excellent"的相似词
model.wv.most_similar("excellent")
# 如果结果都是正面词( great, wonderful),说明捕捉了情感

情感词典对比

加载情感词典(如 AFINN),计算同极性词的平均相似度是否高于异极性词。

分类任务测试

在情感分类任务上评估,如 IMDB 影评分类。如果词向量有区分度,分类器性能会更好。

专用情感词向量

用情感分类语料训练(如推特表情符号作为标签),或在目标函数中加入情感约束。

实践:对于情感分析任务,通常需要在通用词向量基础上微调,或直接用情感标注数据训练任务特定模型。


词向量是 NLP 从符号处理到深度学习转型的关键。从 Word2Vec 的简洁高效,到 GloVe 的全局视野,再到 FastText 的子词建模,每一步都在拓展我们对语言表示的理解。虽然如今更强大的上下文化模型( BERT 、 GPT)占据了主流,但词向量仍是理解现代 NLP 的基础,也是许多应用中简洁而有效的选择。

掌握词向量,你不仅学会了一项技术,更重要的是理解了如何让机器从数据中自动学习知识的范式——这正是深度学习的核心哲学。希望这篇文章能帮你打开通往 NLP 世界的大门。

  • 本文标题:自然语言处理(二)—— 词向量与语言模型
  • 本文作者:Chen Kai
  • 创建时间:2024-02-08 14:30:00
  • 本文链接:https://www.chenk.top/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86%EF%BC%88%E4%BA%8C%EF%BC%89%E2%80%94%E2%80%94-%E8%AF%8D%E5%90%91%E9%87%8F%E4%B8%8E%E8%AF%AD%E8%A8%80%E6%A8%A1%E5%9E%8B/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论