第3章:Word2Vec实战:使用Gensim训练自己的词向量、参数调优与结果可视化

好,咱们进入实战环节了。

前面两章讲了Embedding的理论基础,说白了就是告诉你「词向量是什么」以及「为什么它能用」。但光说不练假把式,这一章我们直接上手——用Gensim训练一套自己的词向量。

我个人习惯把这一步叫做「从文本到数字的魔法时刻」。你想想看,一堆乱七八糟的文字,经过几行代码,就能变成有语义的向量。我第一次跑通的时候,还挺有成就感的。

3.1 环境准备与数据预处理

先别急着写代码。数据预处理这一步,我踩过不少坑。

Gensim的Word2Vec对输入格式有要求:它要的是一个句子列表,每个句子又是一个词列表。说白了就是 List[List[str]] 这种结构。

注意: 千万别直接把一整段文本扔进去。Gensim不会帮你分词,它只会按空格切。中文的话,你得先做分词处理。

我在项目中遇到过最典型的问题:有人把「我喜欢自然语言处理」直接传进去,结果模型把「我喜欢自然语言处理」当成一个词来学。嗯,这显然不对。

正确的做法是这样的:

import jieba
from gensim.models import Word2Vec

# 原始文本
raw_texts = [
    "我喜欢自然语言处理",
    "词向量是深度学习的基础",
    "Gensim是一个很好用的工具库"
]

# 分词处理
sentences = [list(jieba.cut(text)) for text in raw_texts]
print(sentences)
# 输出:[['我', '喜欢', '自然语言', '处理'], ['词向量', '是', '深度', '学习', '的', '基础'], ['Gensim', '是', '一个', '很好', '用', '的', '工具', '库']]
小技巧: 如果你处理的是英文,直接用 .split() 就行。但中文不行,必须用分词工具。我个人常用jieba,够用。

3.2 训练你的第一个Word2Vec模型

数据准备好了,训练就简单了。Gensim封装得非常好,几行代码搞定:

# 训练模型
model = Word2Vec(
    sentences=sentences,
    vector_size=100,   # 词向量维度
    window=5,          # 上下文窗口大小
    min_count=1,       # 最小词频
    sg=0,              # 0=CBOW, 1=Skip-gram
    workers=4          # 并行线程数
)

# 保存模型
model.save("my_word2vec.model")

跑完这段代码,你就有了一个词向量模型。是不是很简单?

但别高兴太早。参数怎么设,才是真正的学问。

3.3 核心参数详解与调优

我刚开始用Word2Vec的时候,参数全是默认值。后来发现,默认值不一定适合你的数据。这里我把几个关键参数掰开揉碎讲一讲。

参数 默认值 说明 我的建议
vector_size 100 词向量维度 小语料用50-100,大语料用200-300
window 5 上下文窗口大小 语法任务用小窗口(2-5),语义任务用大窗口(5-10)
min_count 5 忽略出现次数少于该值的词 语料大时设10-20,小时设1-3
sg 0 训练算法:0=CBOW,1=Skip-gram 小语料用CBOW,大语料用Skip-gram
negative 5 负采样数量 5-20之间,越大训练越慢但效果越好
epochs 5 迭代次数 一般5-15,语料小可以多跑几轮
核心原则: 参数没有绝对的好坏,取决于你的数据和任务。我建议先跑一组默认参数,看看效果,再针对性调整。

3.3.1 vector_size:维度选多大?

维度太小,语义信息不够。维度太大,容易过拟合,而且训练慢。

我曾经在一个百万级的中文语料上试过:50维和200维的效果差了将近15%的准确率。但再往上加到300维,提升就不明显了。

所以我的经验是:先试100维,看效果再调

3.3.2 window:窗口大小怎么定?

这个参数很有意思。窗口越小,模型越关注「邻近词」的关系。窗口越大,越能捕捉「远距离」的语义。

举个例子:

  • window=2时,「苹果」和「吃」的关系会更紧密
  • window=10时,「苹果」和「手机」的关系可能会更强

为什么?因为「苹果手机」这种搭配,中间可能隔着好几个词。窗口小了就学不到。

3.3.3 sg:CBOW还是Skip-gram?

这个问题很多人问。我直接说结论:

  • CBOW(sg=0):用上下文预测当前词。训练快,对高频词友好。
  • Skip-gram(sg=1):用当前词预测上下文。训练慢,但对低频词效果更好。

如果你语料很大(比如几亿词),用Skip-gram。如果语料小,用CBOW更稳妥。

3.4 结果可视化:把词向量画出来

训练完了,怎么看效果?光看数字没感觉。我习惯把词向量降维到2D,然后画出来。

这里用t-SNE或者PCA都行。我个人偏爱t-SNE,效果更直观。

from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

# 提取词向量和对应的词
words = list(model.wv.index_to_key[:100])  # 取前100个词
vectors = [model.wv[word] for word in words]

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

# 画图
plt.figure(figsize=(12, 8))
for i, word in enumerate(words):
    plt.scatter(vectors_2d[i, 0], vectors_2d[i, 1])
    plt.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]), fontsize=9)

plt.title("Word2Vec 词向量可视化 (t-SNE)")
plt.show()
怎么看图? 语义相近的词会在图上聚在一起。比如「苹果」「香蕉」「水果」应该离得近,「跑步」「游泳」「运动」应该在一块。如果发现「苹果」和「电脑」挨着,说明模型学到了「苹果」作为品牌的含义。

3.5 模型评估:不只是看图画

可视化只是辅助。真正评估模型,还得靠定量指标。

Gensim提供了几个内置的评估方法:

# 找相似词
print(model.wv.most_similar("苹果", topn=10))

# 找不同
print(model.wv.doesnt_match(["苹果", "香蕉", "橘子", "电脑"]))

# 词类比:国王 - 男人 + 女人 = ?
print(model.wv.most_similar(positive=["国王", "女人"], negative=["男人"]))

我一般会先跑几个直观的例子。比如「苹果」的相似词里有没有「香蕉」「梨」?如果有,说明语义学得不错。如果全是「iPhone」「iPad」,那说明语料偏向科技领域。

注意: 词类比任务(国王-男人+女人)对模型要求很高。如果你的语料不够大,或者领域太窄,结果可能很离谱。别灰心,这不代表模型没用。

3.6 避坑指南:我踩过的那些坑

最后分享几个实战中容易翻车的地方:

  • 数据量太小: 我曾经拿几千条微博训练,结果词向量基本是随机噪声。Word2Vec需要大量数据,至少几十万条起步。
  • 未登录词太多: 如果语料里很多词只出现一两次,min_count设太小会导致模型参数爆炸。我建议min_count至少设5。
  • 训练轮数不够: 默认epochs=5,但小语料可能需要10-20轮才能收敛。可以观察loss曲线来判断。
  • 忘记保存模型: 嗯,这个我干过。训练了一下午,结果没保存。后来我写了个自动保存的回调函数。

好了,这一章的内容就到这里。你学会了怎么用Gensim训练词向量,怎么调参,怎么可视化,怎么评估。下一章我们会讲怎么把这些词向量用到实际任务中——比如文本分类和相似度计算。

公众号:蓝海资料掘金营,微信deep3321