更新Word2Vec模型的多种尝试

Word2Vec是一种广泛使用的自然语言处理技术,它可以将文本转换为向量形式,并且可以在向量空间中对这些向量进行操作,例如计算相似性、聚类等。在这篇文章中,将讲述更新Word2Vec模型的多种尝试。

Word2Vec简介

Word2Vec是一种由Google于2013年发布的自然语言处理工具包。它可以将文本中的单词转换为向量形式,并且可以在向量空间中对这些向量进行操作。Word2Vec包括两种模型:CBOW和Skip-gram。

CBOW(Continuous Bag-of-Words)模型会尝试根据上下文单词来预测中心单词。Skip-gram模型则相反,它会尝试根据中心单词来预测上下文单词。在实践中,Skip-gram模型通常比CBOW模型更好。

训练Word2Vec模型

要训练Word2Vec模型,需要一个大型的文本语料库。可以使用Python中的gensim库来训练Word2Vec模型。首先,需要将文本分成单词,然后将单词列表传递给gensim.models.Word2Vec类的构造函数。

以下是一个简单的例子:

1
2
3
4
from gensim.models import Word2Vec

sentences = [["cat", "say", "meow"], ["dog", "say", "woof"]]
model = Word2Vec(sentences, min_count=1)

上面的代码将创建一个Word2Vec模型,用于训练由两个句子组成的语料库。min_count参数设置单词出现的最小次数。如果一个单词在语料库中出现的次数小于这个值,那么这个单词将被忽略。

可以使用以下代码来查看单词向量:

1
2
vector = model.wv["cat"]
print(vector)

也可以使用以下代码来查找与给定单词最相似的单词:

1
2
similar_words = model.wv.most_similar("cat")
print(similar_words)

更新Word2Vec模型

在某些情况下,希望在不重新训练整个Word2Vec模型的情况下更新它。gensim库提供了两种更新Word2Vec模型的方法。

第一种方法是使用gensim.models.Word2Vec类的build_vocab()方法来构建新的单词表。然后,可以使用train()方法来更新模型。以下是一个简单的例子:

1
2
model.build_vocab([["bird", "fly", "high"]], update=True)
model.train([["bird", "fly", "high"]], total_examples=1, epochs=1)

上面的代码将向模型添加一个新的句子,然后更新模型。注意,这里需要设置update参数为True。

第二种方法是使用gensim.models.Word2Vec类的build_vocab()方法来构建新的单词表。然后,就可以使用gensim.models.KeyedVectors类的add_vectors()方法来添加新的单词向量。以下是一个简单的例子:

1
2
3
model.build_vocab([["bird", "fly", "high"]], update=True)
new_vector = [1, 2, 3]
model.wv.add_vectors(["bird"], [new_vector])

上面的代码将添加一个新的单词向量,然后更新模型。

Google 预训练的 Word2Vec 模型

Google 发布了一款基于 Google News 数据集的预训练 Word2Vec 模型,包含了 300 维向量,覆盖了 300 万个单词和短语。该模型可从此链接下载,二进制文件(GoogleNews-vectors-negative300.bin)解压后大小为 3.4 GB。

在 Python 代码中使用预训练模型需要使用 gensim 库中的 KeyedVectors 类:

1
2
3
4
from gensim.models import KeyedVectors

filename = 'GoogleNews-vectors-negative300.bin'
model = KeyedVectors.load_word2vec_format(filename, binary=True)

使用预训练好的模型可以快速构建起权威的语料库,但在深入使用之后,经常会碰到词汇表缺失的问题,连”forgot”这种常用词,都不在词汇表中,无法进行匹配。

这是因为为了保证效率,Google 预训练的 Word2Vec 模型中并不会保留全部词汇,而是选择性的存储高频词汇,若需要将其用到不同的领域之中,需要对模型的词汇进行更新与微调。

一开始先尝试了手动地往Google 预训练的 Word2Vec 模型中补充缺失的词向量,但遇到了许多错误,查询资料后才发现:

预训练模型的一个缺点是,由于缺少隐藏权重、词汇频率和二叉树,无法继续训练,因此无法在预训练模型上进行迁移学习。

后来又顺着逆向的思维来看,既然预训练模型缺少信息,无法更新,那反过来可不可以用预训练模型来更新自己新建的模型呢?于是尝试使用 intersect_word2vec_format 方法替换自己模型中的词向量与预训练模型中的词向量:

1
your_word2vec_model.intersect_word2vec_format('GoogleNews-vectors-negative300.bin', lockf=1.0, binary=True)

虽然此方法不是迁移学习,但它非常类似。如果有一个小的自定义数据集,并想使用 Google 的预训练模型进行迁移学习,可以使用以下代码:

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

sentences = [["坏", "机器人"], ["好", "人类"], ["是的", "这", "是", "Word2Vec", "模型"]]

# size 选项需要设置为 300,以与 Google 的预训练模型相同

word2vec_model = Word2Vec(size=300, window=5, min_count=1, workers=2)

word2vec_model.build_vocab(sentences)

# 将单词向量指定为 Google 预训练模型中的向量和上面定义的句子

# lockf 必须设置为 1.0 才能允许继续训练

word2vec_model.intersect_word2vec_format('./word2vec/GoogleNews-vectors-negative300.bin', lockf=1.0, binary=True)

# 使用自己的数据继续训练

word2vec_model.train(sentences, total_examples=3, epochs=5)

此代码将词向量分配给 Google 预训练模型中的词汇表和上面定义的句子,然后使用自己的数据继续训练。 size 选项需要设置为 300,以与 Google 的预训练模型相同。 lockf 选项需要设置为 1.0 才能允许继续训练。

因为我使用 gensim是 4.0.1 版本的 Word2Vec 模型时,还遇到以下错误:

1
IndexError: index 0 is out of bounds for axis 0 with size 0

在插入向量之前,还需要手动设定一下lockf 值:

1
model.wv.vectors_lockf = np.ones(len(model.wv), dtype=REAL)

结论

在这篇文章中,尝试了多种训练和更新Word2Vec模型的方法。虽然最后以新训练模型成功补上了缺失的词汇,并利用Google News的预训练模型进行了迁移学习,但还是达不到词汇量与准确度上的两全其美。

查资料的过程中发现了Doc2vec,说是支持在线训练,并能自动推断未知词汇,倒是能满足需求的样子,下一步可能会去看看它的使用。

参考资料:

Gensin教程:https://rutumulkar.com/blog/2015/word2vec/

Google预训练模型代码:https://code.google.com/archive/p/word2vec/

更新W2V模型:https://phdstatsphys.wordpress.com/2018/12/27/word2vec-how-to-train-and-update-it/