3、GloVe与FastText:全局矩阵分解与子词信息的融合

好,咱们继续往前走。

上一章聊了Word2Vec,那个基于局部窗口的玩法。说实话,当年我用Word2Vec做电商评论分析时,发现一个问题:它只看了上下文的一小块,全局的统计信息全浪费了。比如“苹果”这个词,在水果和手机两个语境下,它学到的向量其实挺模糊的。

这一章,我们来解决这个问题。主角有两个:GloVeFastText

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 训练流程

  1. 构建共现矩阵。窗口大小一般设10-15,比Word2Vec大一些。
  2. 对共现次数取对数,做平滑处理。
  3. 随机初始化词向量和偏置项。
  4. 用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会告诉我们:同一个词,在不同语境下,应该有不同向量。嗯,那才是真正的语义理解。