第3章:Word2Vec实战:使用Gensim训练自己的词向量、参数调优与结果可视化
好,咱们进入实战环节了。
前面两章讲了Embedding的理论基础,说白了就是告诉你「词向量是什么」以及「为什么它能用」。但光说不练假把式,这一章我们直接上手——用Gensim训练一套自己的词向量。
我个人习惯把这一步叫做「从文本到数字的魔法时刻」。你想想看,一堆乱七八糟的文字,经过几行代码,就能变成有语义的向量。我第一次跑通的时候,还挺有成就感的。
3.1 环境准备与数据预处理
先别急着写代码。数据预处理这一步,我踩过不少坑。
Gensim的Word2Vec对输入格式有要求:它要的是一个句子列表,每个句子又是一个词列表。说白了就是 List[List[str]] 这种结构。
我在项目中遇到过最典型的问题:有人把「我喜欢自然语言处理」直接传进去,结果模型把「我喜欢自然语言处理」当成一个词来学。嗯,这显然不对。
正确的做法是这样的:
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