3、GloVe与FastText:全局矩阵分解与子词信息的融合
好,咱们继续往前走。
上一章聊了Word2Vec,那个基于局部窗口的玩法。说实话,当年我用Word2Vec做电商评论分析时,发现一个问题:它只看了上下文的一小块,全局的统计信息全浪费了。比如“苹果”这个词,在水果和手机两个语境下,它学到的向量其实挺模糊的。
这一章,我们来解决这个问题。主角有两个:GloVe 和 FastText。
3.1 GloVe:把全局统计拉进来一起训练
GloVe的全称是Global Vectors for Word Representation。说白了,它想干一件事:把整个语料库的共现矩阵信息,塞进词向量里。
Word2Vec只关心一个窗口内的词。而GloVe会统计:在整个语料中,词i和词j一起出现了多少次。这个次数叫共现计数。
我举个例子。假设语料里“深度学习”和“神经网络”经常一起出现,而“深度学习”和“香蕉”几乎不出现。GloVe会把这些全局信息编码到向量里。
核心思想:词向量的点积,应该能拟合共现次数的对数。
公式长这样:w_i · w_j + b_i + b_j = log(X_ij)
其中X_ij就是共现次数,b是偏置项。
嗯,这里要注意。GloVe的损失函数不是简单的MSE。它加了一个权重函数,让高频共现对贡献更大,但又不至于被极端高频词带偏。
我在项目中遇到过一个场景:用GloVe做法律文书相似度计算。因为法律术语的共现模式非常稳定,GloVe的效果明显优于Word2Vec。比如“原告”和“被告”的向量距离,GloVe给得更准。
3.1.1 训练流程
- 构建共现矩阵。窗口大小一般设10-15,比Word2Vec大一些。
- 对共现次数取对数,做平滑处理。
- 随机初始化词向量和偏置项。
- 用AdaGrad优化器,最小化加权平方误差。
我的小技巧:GloVe的窗口大小很敏感。做通用领域任务,窗口10就够了。如果是专业领域(比如医学、法律),我建议窗口设到20。因为专业术语的跨度往往更大。
3.1.2 代码示例
# 使用Gensim加载预训练的GloVe向量
from gensim.models import KeyedVectors
# 下载glove.6B.50d.txt
model = KeyedVectors.load_word2vec_format(
'glove.6B.50d.txt',
binary=False,
no_header=True
)
# 找相似词
result = model.most_similar('deep learning')
print(result)
# 词类比:国王 - 男人 + 女人 = ?
result = model.most_similar(
positive=['king', 'woman'],
negative=['man']
)
print(result)
3.2 FastText:把词拆成字符n-gram
接下来聊FastText。这个模型是Facebook在2016年提出的。它解决了一个Word2Vec和GloVe都搞不定的问题:没见过的新词怎么办?
你想想看,Word2Vec和GloVe都是把词当整体。遇到“GPT-4”这种新词,向量就是零。但FastText不一样,它把词拆成更小的单元——字符n-gram。
比如“apple”,设置n=3,会拆成:
- "ap", "app", "ppl", "ple", "le"
- 再加上整个词 "apple"
每个n-gram学一个向量。最终词的向量,就是这些子词向量的求和。
这么做的好处很明显:
- 能处理未登录词。比如“apples”,虽然没在训练集里,但“app”、“ple”这些子词见过,就能拼出来。
- 能捕捉形态学信息。比如“run”、“running”、“runs”共享“run”这个子词,向量自然相近。
我曾经用FastText做中文电商评论的情感分析。中文的词边界本来就不明显,加上各种新词(比如“绝绝子”、“YYDS”)。Word2Vec直接跪了,但FastText因为能拆成字和双字组合,效果好了不少。
3.2.1 训练细节
FastText的训练方式和CBOW/Skip-gram几乎一样。区别就在于:
- 输入不再是整个词,而是这个词的所有n-gram集合。
- 输出层还是用层次Softmax或负采样。
- n一般取3-6。太小了没意义,太大了又退化成整词。
注意:n-gram的数量会爆炸。一个10个字符的词,n=3到6,大概能产生30多个n-gram。所以FastText的模型文件通常比Word2Vec大3-5倍。内存不够的话,建议用量化版本。
3.2.2 代码示例
# 使用Gensim训练FastText
from gensim.models import FastText
# 假设sentences是分词后的列表
sentences = [
['我', '喜欢', '自然语言处理'],
['深度学习', '是', 'AI', '的', '核心']
]
# 训练模型
model = FastText(
sentences,
vector_size=100,
window=5,
min_count=1,
min_n=3, # 最小n-gram长度
max_n=6, # 最大n-gram长度
epochs=10
)
# 测试未登录词
vector = model.wv['GPT-4'] # 训练集里没有,但能生成向量
print(vector[:5])
# 找相似词
result = model.wv.most_similar('自然语言处理')
print(result)
3.3 GloVe vs FastText:怎么选?
这两个模型各有千秋。我整理了一个对比表,方便你快速决策。
| 维度 | GloVe | FastText |
|---|---|---|
| 核心思想 | 全局共现矩阵分解 | 子词n-gram求和 |
| 处理未登录词 | ❌ 不行 | ✅ 可以 |
| 训练速度 | 快(离线统计+优化) | 中等(n-gram多) |
| 模型大小 | 小(仅词向量) | 大(含n-gram向量) |
| 适用场景 | 通用领域、词义稳定 | 形态丰富、新词多 |
| 中文效果 | 一般(需分词) | 较好(可拆字) |
我的建议:
- 如果你的语料很干净,词表固定,用GloVe。速度快,效果稳。
- 如果你的语料里新词多、拼写错误多、或者做中文任务,用FastText。
- 其实,两个都跑一遍也不费事。选效果好的那个上线就行。
3.4 小结
这一章我们聊了两个重要的静态词向量模型。
- GloVe 把全局共现信息融入了向量。它比Word2Vec更稳定,尤其适合专业领域。
- FastText 通过子词n-gram,解决了未登录词问题。它更灵活,适合形态丰富的语言。
说实话,这两个模型现在依然有实用价值。虽然BERT等预训练模型很火,但很多工业场景下,静态词向量因为速度快、资源消耗低,仍然是首选。
下一章,我们会进入动态词向量的世界。ELMo会告诉我们:同一个词,在不同语境下,应该有不同向量。嗯,那才是真正的语义理解。