import pprint
%matplotlib inline
Word2Vec 模型
本文介绍Gensim的Word2Vec模型,并在Lee Corpus上演示其用法。
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s',
level=logging.INFO)
如果你之前错过了令人振奋的算法,那么word2vec现在是深度学习算法的新星之一,因此受到广泛的推荐,尽管它本身的网络层很浅。word2vec可以从大量未注释的纯文本中自动学习单词之间的关系。
word2vec的输出是具有显著线性关系的向量(每个单词就是一个向量),因此我们可以执行以下操作:
- vec("king") - vec("man") + vec("woman") =~ vec("queen")
- vec("Montreal Canadiens") – vec("Montreal") + vec("Toronto") =~ vec("Toronto Maple Leafs")
Word2vec在自动文本标记、推荐系统和机器翻译中非常有用。
本教程将:
- 引入“ Word2Vec”作为对传统 bag-of-words 模型的改进
- 使用预先训练的模型展示“ Word2Vec”的功能
- 演示根据您自己的数据训练新模型
- 演示加载和保存模型
- 介绍几个训练参数并演示其效果
- 讨论内存需求
- 通过应用降维来可视化Word2Vec嵌入
回顾Bag-of-words模型
注意:如果您已经熟悉模型,可以跳过模型回顾。
您可能从 core_concepts_vector 部分熟悉了词袋模型https://en.wikipedia.org/wiki/Bag-of-words_model 。该模型将每个文档转换为固定长度的整数矢量。 例如,给定句子:
John likes to watch movies. Mary likes movies too.
John also likes to watch football games. Mary hates football.
模型输出向量:
[1, 2, 1, 1, 2, 1, 1, 0, 0, 0, 0]
[1, 1, 1, 1, 0, 1, 0, 1, 2, 1, 1]
每个向量有10个元素,其中每个元素计算文档中特定单词出现的次数。元素的顺序是任意的。
在上面的示例中,元素的顺序对应于以下单词:
["John", "likes", "to", "watch", "movies", "Mary", "too", "also", "football", "games", "hates"]
.
词袋模型出奇地有效,但有几个缺点。
首先,他们会丢失所有有关单词顺序的信息:"John likes Mary"和"Mary likes John"对应于相同的向量。有一个解决方案:n-grams模型考虑长度为n的单词短语,将文档表示为固定长度的向量,以捕获单词顺序,但遭受数据稀疏和高维度的困扰。
其次,该模型不会尝试学习单词的含义,因此,向量之间的距离并不总是反映出含义上的差异。 Word2Vec模型解决了第二个问题。
Word2Vec模型简介
Word2Vec是一种较新的模型,它使用浅层神经网络将单词嵌入到低维向量空间中。 结果是一组词向量,在向量空间中靠在一起的词向量根据上下文具有相似的含义,而彼此远离的词向量具有不同的含义。 例如,“ strong”和“ powerful”将彼此靠近,而“ strong”和“ Paris”则相对较远。
该模型有两个版本,~gensim.models.word2vec.Word2Vec
类实现了两个版本:
- Skip-grams (SG)
- Continuous-bag-of-words (CBOW)
注意:不要让下面的实现细节吓到您。它们是高级材料,如果太多,则继续进行下一部分。
例如,“Word2Vec Skip-gram” 模型将通过在文本数据之间进行窗口移动,生成的成对的(word1,word2),并根据输入的多个单词对(word,word)训练一个1层隐藏层的神经网络, 为我们提供了输入附近单词的预测概率分布。 单词的one-hot 编码通过投影层(projection layer)进入隐藏层;这些投影的权重被解释成word embeddings。因此,如果隐藏层具有300个神经元,则此网络将为我们提供300维的word embeddings。
Continuous-bag-of-words Word2vec与skip-gram model非常相似。 它也是一个含有1层隐藏层的神经网络。 合成训练任务现在使用多个输入上下文单词的平均值来预测目标单词,而不是像skip-gram model中使用单个单词的值。 同样,将one-hot编码转换为和隐藏层相同维度的平均值向量的投影权重,也被解释为word embeddings。
Word2Vec 演示
让我们下载一个预先训练好的模型并进行试用,看看Word2Vec可以做什么。我们将获取的Word2Vec模型使用Google新闻数据训练,该模型涵盖大约300万个单词和短语。这样的模型可能需要花费数小时来训练,但是由于已经可用,因此使用Gensim进行下载和加载需要几分钟。
注意:该模型大约为2GB,因此你需要一个不错的网络连接才能继续。 否则,请跳至下面的“训练自己的模型”部分。
您也可以查看“在线word2vec演示”,在那里您可以自己尝试使用向量代数。该演示在整个Google新闻数据集 (约1000亿个单词) 上运行word2vec。
import gensim.downloader as api
wv = api.load('word2vec-google-news-300')
如果你本地已经下载好了GoogleNews-vectors-negative300.bin
模型,那么可以这样导入模型:
import gensim
model_path = r"C:\Users\two\Desktop\GoogleNews-vectors-negative300.bin"
wv = gensim.models.KeyedVectors.load_word2vec_format(model_path, binary=True)
C:\Users\two\AppData\Roaming\Python\Python36\site-packages\gensim\utils.py:1209: UserWarning: detected Windows; aliasing chunkize to chunkize_serial
warnings.warn("detected Windows; aliasing chunkize to chunkize_serial")
2020-01-21 15:28:51,172 : INFO : 'pattern' package not found; tag filters are not available for English
2020-01-21 15:28:51,179 : INFO : loading projection weights from C:\Users\two\Desktop\GoogleNews-vectors-negative300.bin
C:\Users\two\AppData\Roaming\Python\Python36\site-packages\smart_open\smart_open_lib.py:402: UserWarning: This function is deprecated, use smart_open.open instead. See the migration notes for details: https://github.com/RaRe-Technologies/smart_open/blob/master/README.rst#migrating-to-the-new-open-function
'See the migration notes for details: %s' % _MIGRATION_NOTES_URL
2020-01-21 15:29:25,376 : INFO : loaded (3000000, 300) matrix from C:\Users\two\Desktop\GoogleNews-vectors-negative300.bin
如果加载入完整的模型,可以看到提示:
INFO : loaded (3000000, 300) matrix from GoogleNews-vectors-negative300.bin
该word2vec模型的词库包含3000000个单词,每个单词的词向量有300维。
获取词库
常见的操作是检索模型的词汇表。 这很简单:
# .vocab return dict {word:class gensim.models.keyedvectors.Vocab}
# gensim.models.keyedvectors.Vocab: A single vocabulary item, used internally for collecting per-word frequency/sampling info,
# and for constructing binary trees (incl. both word leaves and inner nodes).
for i, word in enumerate(wv.vocab):
if i == 10:
break
print(word)
print("当前词库有",len(wv.vocab),"个单词")
</s>
in
for
that
is
on
##
The
with
said
当前词库有 3000000 个单词
# property
# list of all words
wv.index2word
print("当前词库有",len(wv.index2word),"个单词")
当前词库有 3000000 个单词
# property
# list of all entities (words)
wv.index2entity
print("当前词库有",len(wv.index2entity),"个单词")
当前词库有 3000000 个单词
获取词向量
获取词向量的维度信息:
wv.vector_size
300
该 word2vec 模型的词向量有300维。
可以轻松地获取全部词向量:
# property
# 全部的词向量
print("完整词向量矩阵的维度信息:",wv.vectors.shape)
wv.vectors
# 也可以使用 .syn0 属性获取完整的词向量
# 但 .syn0 属性在gensim4.0.0版本将会被移除,建议使用 .vectors
完整词向量矩阵的维度信息: (3000000, 300)
array([[ 1.1291504e-03, -8.9645386e-04, 3.1852722e-04, ...,
-1.5640259e-03, -1.2302399e-04, -8.6307526e-05],
[ 7.0312500e-02, 8.6914062e-02, 8.7890625e-02, ...,
-4.7607422e-02, 1.4465332e-02, -6.2500000e-02],
[-1.1779785e-02, -4.7363281e-02, 4.4677734e-02, ...,
7.1289062e-02, -3.4912109e-02, 2.4169922e-02],
...,
[-1.9653320e-02, -9.0820312e-02, -1.9409180e-02, ...,
-1.6357422e-02, -1.3427734e-02, 4.6630859e-02],
[ 3.2714844e-02, -3.2226562e-02, 3.6132812e-02, ...,
-8.8500977e-03, 2.6977539e-02, 1.9042969e-02],
[ 4.5166016e-02, -4.5166016e-02, -3.9367676e-03, ...,
7.9589844e-02, 7.2265625e-02, 1.3000488e-02]], dtype=float32)
获取标准化之后的词向量矩阵(但预训练模型没有这个属性,因此会抛出错误):
# wv.vector_size
# property
# 全部的词向量
print("完整词向量矩阵的维度信息:",wv.vectors_norm.shape)
wv.vectors_norm
# 也可以使用 .syn0norm 属性获取完整的词向量
# 但 .syn0norm 属性在gensim4.0.0版本将会被移除,建议使用 .vectors_norm
AttributeError: 'NoneType' object has no attribute 'shape'
对于出现在模型词库中的词,我们可以轻松获得它的向量表示:
vec_king = wv['king']
print("词向量的维度:",vec_king.shape)
pprint.pprint(vec_king)
# 可以这样获取多个单词的词向量
# wv[['king','car']]
词向量的维度: (300,)
array([ 1.25976562e-01, 2.97851562e-02, 8.60595703e-03, 1.39648438e-01,
-2.56347656e-02, -3.61328125e-02, 1.11816406e-01, -1.98242188e-01,
5.12695312e-02, 3.63281250e-01, -2.42187500e-01, -3.02734375e-01,
-1.77734375e-01, -2.49023438e-02, -1.67968750e-01, -1.69921875e-01,
3.46679688e-02, 5.21850586e-03, 4.63867188e-02, 1.28906250e-01,
1.36718750e-01, 1.12792969e-01, 5.95703125e-02, 1.36718750e-01,
1.01074219e-01, -1.76757812e-01, -2.51953125e-01, 5.98144531e-02,
3.41796875e-01, -3.11279297e-02, 1.04492188e-01, 6.17675781e-02,
1.24511719e-01, 4.00390625e-01, -3.22265625e-01, 8.39843750e-02,
3.90625000e-02, 5.85937500e-03, 7.03125000e-02, 1.72851562e-01,
1.38671875e-01, -2.31445312e-01, 2.83203125e-01, 1.42578125e-01,
3.41796875e-01, -2.39257812e-02, -1.09863281e-01, 3.32031250e-02,
-5.46875000e-02, 1.53198242e-02, -1.62109375e-01, 1.58203125e-01,
-2.59765625e-01, 2.01416016e-02, -1.63085938e-01, 1.35803223e-03,
-1.44531250e-01, -5.68847656e-02, 4.29687500e-02, -2.46582031e-02,
1.85546875e-01, 4.47265625e-01, 9.58251953e-03, 1.31835938e-01,
9.86328125e-02, -1.85546875e-01, -1.00097656e-01, -1.33789062e-01,
-1.25000000e-01, 2.83203125e-01, 1.23046875e-01, 5.32226562e-02,
-1.77734375e-01, 8.59375000e-02, -2.18505859e-02, 2.05078125e-02,
-1.39648438e-01, 2.51464844e-02, 1.38671875e-01, -1.05468750e-01,
1.38671875e-01, 8.88671875e-02, -7.51953125e-02, -2.13623047e-02,
1.72851562e-01, 4.63867188e-02, -2.65625000e-01, 8.91113281e-03,
1.49414062e-01, 3.78417969e-02, 2.38281250e-01, -1.24511719e-01,
-2.17773438e-01, -1.81640625e-01, 2.97851562e-02, 5.71289062e-02,
-2.89306641e-02, 1.24511719e-02, 9.66796875e-02, -2.31445312e-01,
5.81054688e-02, 6.68945312e-02, 7.08007812e-02, -3.08593750e-01,
-2.14843750e-01, 1.45507812e-01, -4.27734375e-01, -9.39941406e-03,
1.54296875e-01, -7.66601562e-02, 2.89062500e-01, 2.77343750e-01,
-4.86373901e-04, -1.36718750e-01, 3.24218750e-01, -2.46093750e-01,
-3.03649902e-03, -2.11914062e-01, 1.25000000e-01, 2.69531250e-01,
2.04101562e-01, 8.25195312e-02, -2.01171875e-01, -1.60156250e-01,
-3.78417969e-02, -1.20117188e-01, 1.15234375e-01, -4.10156250e-02,
-3.95507812e-02, -8.98437500e-02, 6.34765625e-03, 2.03125000e-01,
1.86523438e-01, 2.73437500e-01, 6.29882812e-02, 1.41601562e-01,
-9.81445312e-02, 1.38671875e-01, 1.82617188e-01, 1.73828125e-01,
1.73828125e-01, -2.37304688e-01, 1.78710938e-01, 6.34765625e-02,
2.36328125e-01, -2.08984375e-01, 8.74023438e-02, -1.66015625e-01,
-7.91015625e-02, 2.43164062e-01, -8.88671875e-02, 1.26953125e-01,
-2.16796875e-01, -1.73828125e-01, -3.59375000e-01, -8.25195312e-02,
-6.49414062e-02, 5.07812500e-02, 1.35742188e-01, -7.47070312e-02,
-1.64062500e-01, 1.15356445e-02, 4.45312500e-01, -2.15820312e-01,
-1.11328125e-01, -1.92382812e-01, 1.70898438e-01, -1.25000000e-01,
2.65502930e-03, 1.92382812e-01, -1.74804688e-01, 1.39648438e-01,
2.92968750e-01, 1.13281250e-01, 5.95703125e-02, -6.39648438e-02,
9.96093750e-02, -2.72216797e-02, 1.96533203e-02, 4.27246094e-02,
-2.46093750e-01, 6.39648438e-02, -2.25585938e-01, -1.68945312e-01,
2.89916992e-03, 8.20312500e-02, 3.41796875e-01, 4.32128906e-02,
1.32812500e-01, 1.42578125e-01, 7.61718750e-02, 5.98144531e-02,
-1.19140625e-01, 2.74658203e-03, -6.29882812e-02, -2.72216797e-02,
-4.82177734e-03, -8.20312500e-02, -2.49023438e-02, -4.00390625e-01,
-1.06933594e-01, 4.24804688e-02, 7.76367188e-02, -1.16699219e-01,
7.37304688e-02, -9.22851562e-02, 1.07910156e-01, 1.58203125e-01,
4.24804688e-02, 1.26953125e-01, 3.61328125e-02, 2.67578125e-01,
-1.01074219e-01, -3.02734375e-01, -5.76171875e-02, 5.05371094e-02,
5.26428223e-04, -2.07031250e-01, -1.38671875e-01, -8.97216797e-03,
-2.78320312e-02, -1.41601562e-01, 2.07031250e-01, -1.58203125e-01,
1.27929688e-01, 1.49414062e-01, -2.24609375e-02, -8.44726562e-02,
1.22558594e-01, 2.15820312e-01, -2.13867188e-01, -3.12500000e-01,
-3.73046875e-01, 4.08935547e-03, 1.07421875e-01, 1.06933594e-01,
7.32421875e-02, 8.97216797e-03, -3.88183594e-02, -1.29882812e-01,
1.49414062e-01, -2.14843750e-01, -1.83868408e-03, 9.91210938e-02,
1.57226562e-01, -1.14257812e-01, -2.05078125e-01, 9.91210938e-02,
3.69140625e-01, -1.97265625e-01, 3.54003906e-02, 1.09375000e-01,
1.31835938e-01, 1.66992188e-01, 2.35351562e-01, 1.04980469e-01,
-4.96093750e-01, -1.64062500e-01, -1.56250000e-01, -5.22460938e-02,
1.03027344e-01, 2.43164062e-01, -1.88476562e-01, 5.07812500e-02,
-9.37500000e-02, -6.68945312e-02, 2.27050781e-02, 7.61718750e-02,
2.89062500e-01, 3.10546875e-01, -5.37109375e-02, 2.28515625e-01,
2.51464844e-02, 6.78710938e-02, -1.21093750e-01, -2.15820312e-01,
-2.73437500e-01, -3.07617188e-02, -3.37890625e-01, 1.53320312e-01,
2.33398438e-01, -2.08007812e-01, 3.73046875e-01, 8.20312500e-02,
2.51953125e-01, -7.61718750e-02, -4.66308594e-02, -2.23388672e-02,
2.99072266e-02, -5.93261719e-02, -4.66918945e-03, -2.44140625e-01,
-2.09960938e-01, -2.87109375e-01, -4.54101562e-02, -1.77734375e-01,
-2.79296875e-01, -8.59375000e-02, 9.13085938e-02, 2.51953125e-01],
dtype=float32)
也可以使用.get_vector()
方法获取词向量,但.get_vector()
方法每一次只能获取一个词向量:
wv.get_vector("king")
array([ 1.25976562e-01, 2.97851562e-02, 8.60595703e-03, 1.39648438e-01,
-2.56347656e-02, -3.61328125e-02, 1.11816406e-01, -1.98242188e-01,
5.12695312e-02, 3.63281250e-01, -2.42187500e-01, -3.02734375e-01,
-1.77734375e-01, -2.49023438e-02, -1.67968750e-01, -1.69921875e-01,
3.46679688e-02, 5.21850586e-03, 4.63867188e-02, 1.28906250e-01,
1.36718750e-01, 1.12792969e-01, 5.95703125e-02, 1.36718750e-01,
1.01074219e-01, -1.76757812e-01, -2.51953125e-01, 5.98144531e-02,
3.41796875e-01, -3.11279297e-02, 1.04492188e-01, 6.17675781e-02,
1.24511719e-01, 4.00390625e-01, -3.22265625e-01, 8.39843750e-02,
3.90625000e-02, 5.85937500e-03, 7.03125000e-02, 1.72851562e-01,
1.38671875e-01, -2.31445312e-01, 2.83203125e-01, 1.42578125e-01,
3.41796875e-01, -2.39257812e-02, -1.09863281e-01, 3.32031250e-02,
-5.46875000e-02, 1.53198242e-02, -1.62109375e-01, 1.58203125e-01,
-2.59765625e-01, 2.01416016e-02, -1.63085938e-01, 1.35803223e-03,
-1.44531250e-01, -5.68847656e-02, 4.29687500e-02, -2.46582031e-02,
1.85546875e-01, 4.47265625e-01, 9.58251953e-03, 1.31835938e-01,
9.86328125e-02, -1.85546875e-01, -1.00097656e-01, -1.33789062e-01,
-1.25000000e-01, 2.83203125e-01, 1.23046875e-01, 5.32226562e-02,
-1.77734375e-01, 8.59375000e-02, -2.18505859e-02, 2.05078125e-02,
-1.39648438e-01, 2.51464844e-02, 1.38671875e-01, -1.05468750e-01,
1.38671875e-01, 8.88671875e-02, -7.51953125e-02, -2.13623047e-02,
1.72851562e-01, 4.63867188e-02, -2.65625000e-01, 8.91113281e-03,
1.49414062e-01, 3.78417969e-02, 2.38281250e-01, -1.24511719e-01,
-2.17773438e-01, -1.81640625e-01, 2.97851562e-02, 5.71289062e-02,
-2.89306641e-02, 1.24511719e-02, 9.66796875e-02, -2.31445312e-01,
5.81054688e-02, 6.68945312e-02, 7.08007812e-02, -3.08593750e-01,
-2.14843750e-01, 1.45507812e-01, -4.27734375e-01, -9.39941406e-03,
1.54296875e-01, -7.66601562e-02, 2.89062500e-01, 2.77343750e-01,
-4.86373901e-04, -1.36718750e-01, 3.24218750e-01, -2.46093750e-01,
-3.03649902e-03, -2.11914062e-01, 1.25000000e-01, 2.69531250e-01,
2.04101562e-01, 8.25195312e-02, -2.01171875e-01, -1.60156250e-01,
-3.78417969e-02, -1.20117188e-01, 1.15234375e-01, -4.10156250e-02,
-3.95507812e-02, -8.98437500e-02, 6.34765625e-03, 2.03125000e-01,
1.86523438e-01, 2.73437500e-01, 6.29882812e-02, 1.41601562e-01,
-9.81445312e-02, 1.38671875e-01, 1.82617188e-01, 1.73828125e-01,
1.73828125e-01, -2.37304688e-01, 1.78710938e-01, 6.34765625e-02,
2.36328125e-01, -2.08984375e-01, 8.74023438e-02, -1.66015625e-01,
-7.91015625e-02, 2.43164062e-01, -8.88671875e-02, 1.26953125e-01,
-2.16796875e-01, -1.73828125e-01, -3.59375000e-01, -8.25195312e-02,
-6.49414062e-02, 5.07812500e-02, 1.35742188e-01, -7.47070312e-02,
-1.64062500e-01, 1.15356445e-02, 4.45312500e-01, -2.15820312e-01,
-1.11328125e-01, -1.92382812e-01, 1.70898438e-01, -1.25000000e-01,
2.65502930e-03, 1.92382812e-01, -1.74804688e-01, 1.39648438e-01,
2.92968750e-01, 1.13281250e-01, 5.95703125e-02, -6.39648438e-02,
9.96093750e-02, -2.72216797e-02, 1.96533203e-02, 4.27246094e-02,
-2.46093750e-01, 6.39648438e-02, -2.25585938e-01, -1.68945312e-01,
2.89916992e-03, 8.20312500e-02, 3.41796875e-01, 4.32128906e-02,
1.32812500e-01, 1.42578125e-01, 7.61718750e-02, 5.98144531e-02,
-1.19140625e-01, 2.74658203e-03, -6.29882812e-02, -2.72216797e-02,
-4.82177734e-03, -8.20312500e-02, -2.49023438e-02, -4.00390625e-01,
-1.06933594e-01, 4.24804688e-02, 7.76367188e-02, -1.16699219e-01,
7.37304688e-02, -9.22851562e-02, 1.07910156e-01, 1.58203125e-01,
4.24804688e-02, 1.26953125e-01, 3.61328125e-02, 2.67578125e-01,
-1.01074219e-01, -3.02734375e-01, -5.76171875e-02, 5.05371094e-02,
5.26428223e-04, -2.07031250e-01, -1.38671875e-01, -8.97216797e-03,
-2.78320312e-02, -1.41601562e-01, 2.07031250e-01, -1.58203125e-01,
1.27929688e-01, 1.49414062e-01, -2.24609375e-02, -8.44726562e-02,
1.22558594e-01, 2.15820312e-01, -2.13867188e-01, -3.12500000e-01,
-3.73046875e-01, 4.08935547e-03, 1.07421875e-01, 1.06933594e-01,
7.32421875e-02, 8.97216797e-03, -3.88183594e-02, -1.29882812e-01,
1.49414062e-01, -2.14843750e-01, -1.83868408e-03, 9.91210938e-02,
1.57226562e-01, -1.14257812e-01, -2.05078125e-01, 9.91210938e-02,
3.69140625e-01, -1.97265625e-01, 3.54003906e-02, 1.09375000e-01,
1.31835938e-01, 1.66992188e-01, 2.35351562e-01, 1.04980469e-01,
-4.96093750e-01, -1.64062500e-01, -1.56250000e-01, -5.22460938e-02,
1.03027344e-01, 2.43164062e-01, -1.88476562e-01, 5.07812500e-02,
-9.37500000e-02, -6.68945312e-02, 2.27050781e-02, 7.61718750e-02,
2.89062500e-01, 3.10546875e-01, -5.37109375e-02, 2.28515625e-01,
2.51464844e-02, 6.78710938e-02, -1.21093750e-01, -2.15820312e-01,
-2.73437500e-01, -3.07617188e-02, -3.37890625e-01, 1.53320312e-01,
2.33398438e-01, -2.08007812e-01, 3.73046875e-01, 8.20312500e-02,
2.51953125e-01, -7.61718750e-02, -4.66308594e-02, -2.23388672e-02,
2.99072266e-02, -5.93261719e-02, -4.66918945e-03, -2.44140625e-01,
-2.09960938e-01, -2.87109375e-01, -4.54101562e-02, -1.77734375e-01,
-2.79296875e-01, -8.59375000e-02, 9.13085938e-02, 2.51953125e-01],
dtype=float32)
.get_vector()
方法等效于.word_vec(word, use_norm=False)
,但.word_vec(word, use_norm=False)
方法可以通过use_norm
参数控制是否返回L2归一化后的词向量:
"""
use_norm (bool, optional) – If True - resulting vector will be L2-normalized (unit euclidean length).
"""
wv.word_vec('king', use_norm=False)
array([ 1.25976562e-01, 2.97851562e-02, 8.60595703e-03, 1.39648438e-01,
-2.56347656e-02, -3.61328125e-02, 1.11816406e-01, -1.98242188e-01,
5.12695312e-02, 3.63281250e-01, -2.42187500e-01, -3.02734375e-01,
-1.77734375e-01, -2.49023438e-02, -1.67968750e-01, -1.69921875e-01,
3.46679688e-02, 5.21850586e-03, 4.63867188e-02, 1.28906250e-01,
1.36718750e-01, 1.12792969e-01, 5.95703125e-02, 1.36718750e-01,
1.01074219e-01, -1.76757812e-01, -2.51953125e-01, 5.98144531e-02,
3.41796875e-01, -3.11279297e-02, 1.04492188e-01, 6.17675781e-02,
1.24511719e-01, 4.00390625e-01, -3.22265625e-01, 8.39843750e-02,
3.90625000e-02, 5.85937500e-03, 7.03125000e-02, 1.72851562e-01,
1.38671875e-01, -2.31445312e-01, 2.83203125e-01, 1.42578125e-01,
3.41796875e-01, -2.39257812e-02, -1.09863281e-01, 3.32031250e-02,
-5.46875000e-02, 1.53198242e-02, -1.62109375e-01, 1.58203125e-01,
-2.59765625e-01, 2.01416016e-02, -1.63085938e-01, 1.35803223e-03,
-1.44531250e-01, -5.68847656e-02, 4.29687500e-02, -2.46582031e-02,
1.85546875e-01, 4.47265625e-01, 9.58251953e-03, 1.31835938e-01,
9.86328125e-02, -1.85546875e-01, -1.00097656e-01, -1.33789062e-01,
-1.25000000e-01, 2.83203125e-01, 1.23046875e-01, 5.32226562e-02,
-1.77734375e-01, 8.59375000e-02, -2.18505859e-02, 2.05078125e-02,
-1.39648438e-01, 2.51464844e-02, 1.38671875e-01, -1.05468750e-01,
1.38671875e-01, 8.88671875e-02, -7.51953125e-02, -2.13623047e-02,
1.72851562e-01, 4.63867188e-02, -2.65625000e-01, 8.91113281e-03,
1.49414062e-01, 3.78417969e-02, 2.38281250e-01, -1.24511719e-01,
-2.17773438e-01, -1.81640625e-01, 2.97851562e-02, 5.71289062e-02,
-2.89306641e-02, 1.24511719e-02, 9.66796875e-02, -2.31445312e-01,
5.81054688e-02, 6.68945312e-02, 7.08007812e-02, -3.08593750e-01,
-2.14843750e-01, 1.45507812e-01, -4.27734375e-01, -9.39941406e-03,
1.54296875e-01, -7.66601562e-02, 2.89062500e-01, 2.77343750e-01,
-4.86373901e-04, -1.36718750e-01, 3.24218750e-01, -2.46093750e-01,
-3.03649902e-03, -2.11914062e-01, 1.25000000e-01, 2.69531250e-01,
2.04101562e-01, 8.25195312e-02, -2.01171875e-01, -1.60156250e-01,
-3.78417969e-02, -1.20117188e-01, 1.15234375e-01, -4.10156250e-02,
-3.95507812e-02, -8.98437500e-02, 6.34765625e-03, 2.03125000e-01,
1.86523438e-01, 2.73437500e-01, 6.29882812e-02, 1.41601562e-01,
-9.81445312e-02, 1.38671875e-01, 1.82617188e-01, 1.73828125e-01,
1.73828125e-01, -2.37304688e-01, 1.78710938e-01, 6.34765625e-02,
2.36328125e-01, -2.08984375e-01, 8.74023438e-02, -1.66015625e-01,
-7.91015625e-02, 2.43164062e-01, -8.88671875e-02, 1.26953125e-01,
-2.16796875e-01, -1.73828125e-01, -3.59375000e-01, -8.25195312e-02,
-6.49414062e-02, 5.07812500e-02, 1.35742188e-01, -7.47070312e-02,
-1.64062500e-01, 1.15356445e-02, 4.45312500e-01, -2.15820312e-01,
-1.11328125e-01, -1.92382812e-01, 1.70898438e-01, -1.25000000e-01,
2.65502930e-03, 1.92382812e-01, -1.74804688e-01, 1.39648438e-01,
2.92968750e-01, 1.13281250e-01, 5.95703125e-02, -6.39648438e-02,
9.96093750e-02, -2.72216797e-02, 1.96533203e-02, 4.27246094e-02,
-2.46093750e-01, 6.39648438e-02, -2.25585938e-01, -1.68945312e-01,
2.89916992e-03, 8.20312500e-02, 3.41796875e-01, 4.32128906e-02,
1.32812500e-01, 1.42578125e-01, 7.61718750e-02, 5.98144531e-02,
-1.19140625e-01, 2.74658203e-03, -6.29882812e-02, -2.72216797e-02,
-4.82177734e-03, -8.20312500e-02, -2.49023438e-02, -4.00390625e-01,
-1.06933594e-01, 4.24804688e-02, 7.76367188e-02, -1.16699219e-01,
7.37304688e-02, -9.22851562e-02, 1.07910156e-01, 1.58203125e-01,
4.24804688e-02, 1.26953125e-01, 3.61328125e-02, 2.67578125e-01,
-1.01074219e-01, -3.02734375e-01, -5.76171875e-02, 5.05371094e-02,
5.26428223e-04, -2.07031250e-01, -1.38671875e-01, -8.97216797e-03,
-2.78320312e-02, -1.41601562e-01, 2.07031250e-01, -1.58203125e-01,
1.27929688e-01, 1.49414062e-01, -2.24609375e-02, -8.44726562e-02,
1.22558594e-01, 2.15820312e-01, -2.13867188e-01, -3.12500000e-01,
-3.73046875e-01, 4.08935547e-03, 1.07421875e-01, 1.06933594e-01,
7.32421875e-02, 8.97216797e-03, -3.88183594e-02, -1.29882812e-01,
1.49414062e-01, -2.14843750e-01, -1.83868408e-03, 9.91210938e-02,
1.57226562e-01, -1.14257812e-01, -2.05078125e-01, 9.91210938e-02,
3.69140625e-01, -1.97265625e-01, 3.54003906e-02, 1.09375000e-01,
1.31835938e-01, 1.66992188e-01, 2.35351562e-01, 1.04980469e-01,
-4.96093750e-01, -1.64062500e-01, -1.56250000e-01, -5.22460938e-02,
1.03027344e-01, 2.43164062e-01, -1.88476562e-01, 5.07812500e-02,
-9.37500000e-02, -6.68945312e-02, 2.27050781e-02, 7.61718750e-02,
2.89062500e-01, 3.10546875e-01, -5.37109375e-02, 2.28515625e-01,
2.51464844e-02, 6.78710938e-02, -1.21093750e-01, -2.15820312e-01,
-2.73437500e-01, -3.07617188e-02, -3.37890625e-01, 1.53320312e-01,
2.33398438e-01, -2.08007812e-01, 3.73046875e-01, 8.20312500e-02,
2.51953125e-01, -7.61718750e-02, -4.66308594e-02, -2.23388672e-02,
2.99072266e-02, -5.93261719e-02, -4.66918945e-03, -2.44140625e-01,
-2.09960938e-01, -2.87109375e-01, -4.54101562e-02, -1.77734375e-01,
-2.79296875e-01, -8.59375000e-02, 9.13085938e-02, 2.51953125e-01],
dtype=float32)
不幸的是,该word2vec模型无法推断出陌生单词的向量。这是Word2Vec的一个局限:如果你需要这个功能,请查看FastText模型。
try:
vec_cameroon = wv['cameroon']
except KeyError:
print("The word 'cameroon' does not appear in this model")
The word 'cameroon' does not appear in this model
相似性任务
Word2Vec支持多个单词相似性任务。你可以看到相似度如何随着单词变得越来越少而直观地降低。
pairs = [
('car', 'minivan'), # a minivan is a kind of car
('car', 'bicycle'), # still a wheeled vehicle
('car', 'airplane'), # ok, no wheels, but still a vehicle
('car', 'cereal'), # ... and so on
('car', 'communism'),
]
for w1, w2 in pairs:
print('%r\t%r\t%.2f' % (w1, w2, wv.similarity(w1, w2)))
'car' 'minivan' 0.69
'car' 'bicycle' 0.54
'car' 'airplane' 0.42
'car' 'cereal' 0.14
'car' 'communism' 0.06
找出5个与car或minivan最相似的词:
"""
most_similar(positive=None, negative=None, topn=10, restrict_vocab=None, indexer=None)
restrict_vocab: int 用于限制搜索最相似单词的向量范围。
例如,restrict_vocab=10000将只检查词库顺序中的前10000个词向量。
如果词库的排序是按顺序的,设置这个参数可能会有意义。
找出最相似(或最不相似)的前topn个单词。
"""
wv.most_similar(positive=['car', 'minivan'], topn=5)
[('SUV', 0.8532191514968872),
('vehicle', 0.8175784349441528),
('pickup_truck', 0.7763689160346985),
('Jeep', 0.7567334175109863),
('Ford_Explorer', 0.7565719485282898)]
找出5个与car或minivan最不相似的词:
wv.most_similar(negative=['car','minivan'], topn=5)
[('Philippe_Giaro_P.Geol', 0.31101420521736145),
('K.Kahne_###-###', 0.3042159676551819),
('C.Bowyer_###-###', 0.278561532497406),
('M.Truex_Jr._###-###', 0.27755749225616455),
('By_SEAN_BARRON', 0.27275702357292175)]
.most_similar_cosmul()
方法与.most_similar()
方法相似,但是.most_similar_cosmul()
方法使用multiplicative combination objective方法去计算单词之间的距离。.most_similar_cosmul()
返回的排名与.most_similar()
相同。
multiplicative combination objective计算方法出自 Omer Levy and Yoav Goldberg “Linguistic Regularities in Sparse and Explicit Word Representations”
"""
most_similar_cosmul(positive=None, negative=None, topn=10)
找最相似的前n个单词
"""
wv.most_similar_cosmul(positive=['car', 'minivan'], topn=5)
[('SUV', 0.7949184775352478),
('vehicle', 0.7668868899345398),
('pickup_truck', 0.733077883720398),
('Jeep', 0.7184048891067505),
('Ford_Explorer', 0.7173909544944763)]
单词water与列表中哪个单词最相似?
"""
most_similar_to_given(entity1, entities_list)
从entities_list获取与entity1最相似的entity。
"""
wv.most_similar_to_given(entity1='air', entities_list=['car', 'minivan','fire', 'water', 'land', 'sea'])
'water'
以下哪个不属于该序列?
wv.doesnt_match(['fire', 'water', 'land', 'sea', 'air', 'car'])
C:\Users\two\AppData\Roaming\Python\Python36\site-packages\gensim\models\keyedvectors.py:893: FutureWarning: arrays to stack must be passed as a "sequence" type such as list or tuple. Support for non-sequence iterables such as generators is deprecated as of NumPy 1.16 and will raise an error in the future.
vectors = vstack(self.word_vec(word, use_norm=True) for word in used_words).astype(REAL)
'car'
在词库中,哪些单词比SUV更接近car?
"""
words_closer_than(w1, w2)
w1 (str) – Input word.
w2 (str) – Input word.
在词库中获取所有比w2更接近w1的单词。
"""
wv.words_closer_than('car','SUV')
['vehicle', 'cars']
"""
closer_than(entity1, entity2)
获取所有比entity2更接近entity1的entities。
"""
wv.closer_than('car','SUV')
['vehicle', 'cars']
wv.get_keras_embedding()
Using TensorFlow backend.
2020-01-03 11:23:01,818 : WARNING : From C:\Users\two\Anaconda3\lib\site-packages\keras\backend\tensorflow_backend.py:74: The name tf.get_default_graph is deprecated. Please use tf.compat.v1.get_default_graph instead.
<keras.layers.embeddings.Embedding at 0x2663d025eb8>
# wv.wmdistance(['car','minivan'], ['car']) errror:No module named 'pyemd'
# 查看 word2vec model的全部属性
[i for i in dir(wv) if not i.startswith("_")]
获取余弦距离
"""
distance(w1, w2)
w1: str – Input word
w2: str – Input word
计算两个单词之间的余弦距离,距离越小越相似。
"""
wv.distance("car","vehicle")
0.21789032220840454
"""
distances(word_or_vector, other_words=())
word_or_vector: str, numpy.ndarray – Word or vector from which distances are to be computed.
other_words: iterable of str – 如果other_words为空,则返回word_or_vectors和vocab中所有单词之间的距离。
计算单词word_or_vector和other_words中所有单词的余弦距离。
"""
wv.distances(word_or_vector="car",other_words=("vehicle",'SUV','truck','minivan','car'))
array([0.21789044, 0.28390366, 0.32642102, 0.30929637, 0. ],
dtype=float32)
获取余弦相似度
"""
similarity(w1, w2)
w1 (str) – Input word.
w2 (str) – Input word.
计算两个单词之间的余弦相似度。
"""
wv.similarity("car","car")
1.0
"""
n_similarity(ws1, ws2)
ws1 (list of str) – Sequence of words.
ws2 (list of str) – Sequence of words.
计算两组单词之间的余弦相似度。
"""
wv.n_similarity(['car','minivan'], ['car'])
0.89490217
"""
# 静态方法
cosine_similarities(vector_1, vectors_all)
vector_1 (numpy.ndarray) shape (dim,).
vectors_all (numpy.ndarray) shape (num_vectors, dim).
计算一个向量和一组其他向量之间的余弦相似度。
"""
wv.cosine_similarities([1,2,3], [[1,2,3],[4,5,6]])
array([1. , 0.97463185])
计算两个单词之间的相对余弦相似度:
"""
relative_cosine_similarity(wa, wb, topn=10)
给定前n个相似的单词,计算两个单词之间的相对余弦相似度。
"""
wv.relative_cosine_similarity(wa='car', wb= 'minivan', topn=10)
0.1001322352889656
获取距离排名
"""
rank(entity1, entity2)
相对于所有entitie到entity1的距离,entity2到entity1的距离的排名。
"""
print(wv.rank(entity1='car', entity2='cars'))
print(wv.rank(entity1='car', entity2='car'))
2
1
训练自己的模型
首先,你需要一些数据来训练模型。 对于以下示例,我们将使用Lee Corpus
数据,gensim库已带有该数据集。
这个语料库足够小,可以完全加载入内存中,但是我们将实现一个对内存友好的迭代器,该迭代器逐行读取它,用来演示gensim如何处理更大的语料库。
from gensim.test.utils import datapath
from gensim import utils
class MyCorpus(object):
"""产生句子(lists of str)的迭代器。"""
def __iter__(self):
corpus_path = datapath('lee_background.cor')
for line in open(corpus_path):
# 假设每行有一个文档,tokens被空格分开
yield utils.simple_preprocess(line)
2020-01-02 21:16:01,714 : INFO : adding document #0 to Dictionary(0 unique tokens: [])
2020-01-02 21:16:01,716 : INFO : built Dictionary(12 unique tokens: ['computer', 'human', 'interface', 'response', 'survey']...) from 9 documents (total 29 corpus positions)
如果我们想进行任何自定义的预处理,例如:解码非标准编码数据、字母小写化、删除数字、提取命名实体。所有这些都可以在MyCorpus
迭代器内完成,而word2vec
不需要知道这些处理。word2vec
只需输入的迭代器产生一个又一个句子(list of utf-8 words) 。
让我们继续,在我们的语料库上训练模型。 暂时不必担心训练参数,我们稍后将对其进行讨论。
import gensim.models
sentences = MyCorpus()
model = gensim.models.Word2Vec(sentences=sentences)
2020-01-02 21:16:05,695 : INFO : collecting all words and their counts
2020-01-02 21:16:05,698 : INFO : PROGRESS: at sentence #0, processed 0 words, keeping 0 word types
2020-01-02 21:16:06,042 : INFO : collected 6981 word types from a corpus of 58152 raw words and 300 sentences
2020-01-02 21:16:06,047 : INFO : Loading a fresh vocabulary
2020-01-02 21:16:06,126 : INFO : effective_min_count=5 retains 1750 unique words (25% of original 6981, drops 5231)
2020-01-02 21:16:06,128 : INFO : effective_min_count=5 leaves 49335 word corpus (84% of original 58152, drops 8817)
2020-01-02 21:16:06,140 : INFO : deleting the raw counts dictionary of 6981 items
2020-01-02 21:16:06,142 : INFO : sample=0.001 downsamples 51 most-common words
2020-01-02 21:16:06,145 : INFO : downsampling leaves estimated 35935 word corpus (72.8% of prior 49335)
2020-01-02 21:16:06,156 : INFO : estimated required memory for 1750 words and 100 dimensions: 2275000 bytes
2020-01-02 21:16:06,157 : INFO : resetting layer weights
2020-01-02 21:16:06,683 : INFO : training model with 3 workers on 1750 vocabulary and 100 features, using sg=0 hs=0 sample=0.001 negative=5 window=5
2020-01-02 21:16:06,863 : INFO : worker thread finished; awaiting finish of 2 more threads
2020-01-02 21:16:06,877 : INFO : worker thread finished; awaiting finish of 1 more threads
2020-01-02 21:16:06,884 : INFO : worker thread finished; awaiting finish of 0 more threads
2020-01-02 21:16:06,886 : INFO : EPOCH - 1 : training on 58152 raw words (35883 effective words) took 0.2s, 180122 effective words/s
2020-01-02 21:16:07,060 : INFO : worker thread finished; awaiting finish of 2 more threads
2020-01-02 21:16:07,062 : INFO : worker thread finished; awaiting finish of 1 more threads
2020-01-02 21:16:07,075 : INFO : worker thread finished; awaiting finish of 0 more threads
2020-01-02 21:16:07,077 : INFO : EPOCH - 2 : training on 58152 raw words (35909 effective words) took 0.2s, 192286 effective words/s
2020-01-02 21:16:07,249 : INFO : worker thread finished; awaiting finish of 2 more threads
2020-01-02 21:16:07,251 : INFO : worker thread finished; awaiting finish of 1 more threads
2020-01-02 21:16:07,268 : INFO : worker thread finished; awaiting finish of 0 more threads
2020-01-02 21:16:07,269 : INFO : EPOCH - 3 : training on 58152 raw words (36011 effective words) took 0.2s, 190390 effective words/s
2020-01-02 21:16:07,485 : INFO : worker thread finished; awaiting finish of 2 more threads
2020-01-02 21:16:07,490 : INFO : worker thread finished; awaiting finish of 1 more threads
2020-01-02 21:16:07,504 : INFO : worker thread finished; awaiting finish of 0 more threads
2020-01-02 21:16:07,506 : INFO : EPOCH - 4 : training on 58152 raw words (35955 effective words) took 0.2s, 154656 effective words/s
2020-01-02 21:16:07,709 : INFO : worker thread finished; awaiting finish of 2 more threads
2020-01-02 21:16:07,711 : INFO : worker thread finished; awaiting finish of 1 more threads
2020-01-02 21:16:07,723 : INFO : worker thread finished; awaiting finish of 0 more threads
2020-01-02 21:16:07,724 : INFO : EPOCH - 5 : training on 58152 raw words (35937 effective words) took 0.2s, 167155 effective words/s
2020-01-02 21:16:07,726 : INFO : training on a 290760 raw words (179695 effective words) took 1.0s, 172497 effective words/s
建立模型后,我们可以使用与上面演示相同的方法。
模型的主要部分是model.wv
,其中wv
代表word vector。
vec_king = model.wv['king'];vec_king
array([-0.00835394, -0.0045849 , 0.02337644, 0.06137834, 0.03927568,
0.0771808 , -0.00613491, 0.04881869, -0.01778515, -0.05783534,
0.05000733, 0.04546838, -0.04622583, 0.02119355, -0.08289969,
0.06297314, 0.00819165, -0.04722812, -0.01712785, -0.06220391,
-0.01792748, -0.01274053, 0.03496742, -0.0297276 , -0.06460014,
0.04213679, -0.02229733, 0.07136393, 0.00484056, -0.00886152,
-0.00471885, -0.00707228, 0.00073703, 0.00370342, -0.0162351 ,
0.01090373, 0.02818023, -0.04841179, 0.04993173, 0.04033299,
-0.0018242 , -0.00435686, 0.08839191, -0.06075187, -0.00611064,
0.00549908, -0.00981818, 0.0147628 , -0.03261513, 0.00605273,
0.03322693, 0.03558705, 0.03365535, -0.01211257, -0.05132781,
0.00949616, -0.00190306, 0.03689624, -0.01641419, -0.00697564,
0.03875671, 0.01708069, 0.00355519, 0.01152966, 0.04929205,
0.02247121, -0.01232615, 0.0412309 , 0.00039095, -0.01177677,
-0.03727527, 0.07211189, -0.02746879, 0.01342012, -0.03975392,
0.01483131, 0.02386127, 0.01227524, -0.01146569, -0.00367378,
0.00885449, -0.01065395, 0.01139999, -0.03370672, -0.00587148,
0.02534425, 0.01000963, -0.04751983, -0.01368179, -0.0111518 ,
0.03696112, 0.02186877, -0.03961398, -0.00126779, 0.02945407,
-0.01498374, 0.00616166, -0.01830531, -0.0072393 , -0.01315761],
dtype=float32)
检索词汇的方法相同:
for i, word in enumerate(model.wv.vocab):
if i == 10:
break
print(word)
hundreds
of
people
have
been
forced
to
their
homes
in
存储和加载模型
如果语料库较大,训练模型会花费不少时间。如果训练好的模型按预期工作,可以将其保存到磁盘。 这样一来,不必在以后再花时间进行训练。
你可以使用 gensim 的标准方法区储存和加载模型:
import tempfile
with tempfile.NamedTemporaryFile(prefix='gensim-model-', delete=False) as tmp:
temporary_filepath = tmp.name
model.save(temporary_filepath)
#
# The model is now safely stored in the filepath.
# You can copy it to other machines, share it with others, etc.
#
# To load a saved model:
#
new_model = gensim.models.Word2Vec.load(temporary_filepath)
这种做法将保存模型的全部信息,它在内部使用pickle,可以选择将模型的内部大型NumPy矩阵直接从磁盘文件转换到虚拟内存中,以实现进程间内存共享。
此外,还可以只保存模型的词嵌入层权重:
译者注:这种保存格式应该与原始C工具的保存格式相同
model.wv.save_word2vec_format()
您可以使用文本或二进制格式加载由原始C工具创建的模型:
model = gensim.models.KeyedVectors.load_word2vec_format('/tmp/vectors.txt',
binary=False)
也可以输入gzipped/bz2文件,无需解压缩
model = gensim.models.KeyedVectors.load_word2vec_format('/tmp/vectors.bin.gz',
binary=True)
训练参数
Word2Vec
接受几个同时影响训练速度和质量的参数。
min_count
min_count
用于修剪内部词汇表。在十亿个单词的语料库中仅出现一两次的单词可能是无趣的错别字和垃圾。此外,没有足够的数据来对这些单词进行任何有意义的训练,因此最好忽略它们:
# default value of min_count=5
model = gensim.models.Word2Vec(sentences, min_count=10)
size
size
是gensim Word2Vec将单词映射到的N维空间的维数(N)。较大的值需要更多的训练数据,但可以产生更好(更准确)的模型。合理的值在数十到数百之间。
# default value of size=100
model = gensim.models.Word2Vec(sentences, size=200)
workers
workers
是最后一个主要的参数(全部参数列表见这里,它用于并行化训练,加快训练速度:
# default value of workers=3 (tutorial says 1...)
model = gensim.models.Word2Vec(sentences, workers=4)
workers
只有在使用Cython
解析器的时候才生效,如果没有Cython,因为存在GIL,所以只能使用一个cpu核心,这样的话,word2vec的训练速度会变得很慢很慢。
Memory
Word2vec 模型参数的核心是存储为矩阵(NumPy 数组)。 每个数组大小都是词汇表的长度乘以size
参数浮点数(4字节的单精度)。
在RAM中保存了三个这样的矩阵(正在努力将该数目减少到两个,甚至一个)。因此,如果您的输入的词汇表有100,000唯一的单词,并且您要求的隐藏层大小为200,则该模型将需要大约 $$ 100000 \times 200 \times 4 \times 3字节 \approx 229 MB $$ 存储 vocabulary tree 需要一些额外的内存(100,000个单词将花费几MB的储存)。因此,内存占用量由上述三个矩阵决定,除非您的单词是很长很长的字符串。
Evaluating
Word2Vec
training is an unsupervised task, there’s no good way to objectively evaluate the result. Evaluation depends on your end application.
Google has released their testing set of about 20,000 syntactic and semantic test examples, following the “A is to B as C is to D” task. It is provided in the 'datasets' folder.
For example a syntactic analogy of comparative type is bad:worse;good:?. There are total of 9 types of syntactic comparisons in the dataset like plural nouns and nouns of opposite meaning.
The semantic questions contain five types of semantic analogies, such as capital cities (Paris:France;Tokyo:?) or family members (brother:sister;dad:?).
Gensim supports the same evaluation set, in exactly the same format:
model.accuracy('./datasets/questions-words.txt')
This accuracy
takes an optional parameter
<http://radimrehurek.com/gensim/models/word2vec.html#gensim.models.word2vec.Word2Vec.accuracy>
_
restrict_vocab
which limits which test examples are to be considered.
In the December 2016 release of Gensim we added a better way to evaluate semantic similarity.
By default it uses an academic dataset WS-353 but one can create a dataset specific to your business based on it. It contains word pairs together with human-assigned similarity judgments. It measures the relatedness or co-occurrence of two words. For example, 'coast' and 'shore' are very similar as they appear in the same context. At the same time 'clothes' and 'closet' are less similar because they are related but not interchangeable.
model.evaluate_word_pairs(datapath('wordsim353.tsv'))
.. Important::
Good performance on Google's or WS-353 test set doesn’t mean word2vec will
work well in your application, or vice versa. It’s always best to evaluate
directly on your intended task. For an example of how to use word2vec in a
classifier pipeline, see this tutorial
<https://github.com/RaRe-Technologies/movie-plots-by-genre>
_.
在线训练/增量训练
高级用户可以加载一个模型,并通过更多的句子来继续训练模型:
model = gensim.models.Word2Vec.load(temporary_filepath)
more_sentences = [
['Advanced', 'users', 'can', 'load', 'a', 'model',
'and', 'continue', 'training', 'it', 'with', 'more', 'sentences']
]
model.build_vocab(more_sentences, update=True)
model.train(more_sentences, total_examples=model.corpus_count, epochs=model.iter)
# cleaning up temporary file
import os
os.remove(temporary_filepath)
您可能需要将total_words
参数,具体取决于你想要的学习速率衰减。
请注意,无法增量训练使用C工具KeyedVectors.load_word2vec_format()
生成的模型,但可以将它们用于查询/相似性,因为模型丢失了对训练至关重要的信息(vocab tree)。
Training Loss Computation
The parameter compute_loss
can be used to toggle computation of loss
while training the Word2Vec model. The computed loss is stored in the model
attribute running_training_loss
and can be retrieved using the function
get_latest_training_loss
as follows :
# instantiating and training the Word2Vec model
model_with_loss = gensim.models.Word2Vec(
sentences,
min_count=1,
compute_loss=True,
hs=0,
sg=1,
seed=42
)
# getting the training loss value
training_loss = model_with_loss.get_latest_training_loss()
print(training_loss)
Benchmarks
Let's run some benchmarks to see effect of the training loss computation code on training time.
We'll use the following data for the benchmarks:
. Lee Background corpus: included in gensim's test data
. Text8 corpus. To demonstrate the effect of corpus size, we'll look at the
first 1MB, 10MB, 50MB of the corpus, as well as the entire thing.
import io
import os
import gensim.models.word2vec
import gensim.downloader as api
import smart_open
def head(path, size):
with smart_open.open(path) as fin:
return io.StringIO(fin.read(size))
def generate_input_data():
lee_path = datapath('lee_background.cor')
ls = gensim.models.word2vec.LineSentence(lee_path)
ls.name = '25kB'
yield ls
text8_path = api.load('text8').fn
labels = ('1MB', '10MB', '50MB', '100MB')
sizes = (1024 ** 2, 10 * 1024 ** 2, 50 * 1024 ** 2, 100 * 1024 ** 2)
for l, s in zip(labels, sizes):
ls = gensim.models.word2vec.LineSentence(head(text8_path, s))
ls.name = l
yield ls
input_data = list(generate_input_data())
We now compare the training time taken for different combinations of input
data and model training parameters like hs
and sg
.
For each combination, we repeat the test several times to obtain the mean and standard deviation of the test duration.
# Temporarily reduce logging verbosity
logging.root.level = logging.ERROR
import time
import numpy as np
import pandas as pd
train_time_values = []
seed_val = 42
sg_values = [0, 1]
hs_values = [0, 1]
fast = True
if fast:
input_data_subset = input_data[:3]
else:
input_data_subset = input_data
for data in input_data_subset:
for sg_val in sg_values:
for hs_val in hs_values:
for loss_flag in [True, False]:
time_taken_list = []
for i in range(3):
start_time = time.time()
w2v_model = gensim.models.Word2Vec(
data,
compute_loss=loss_flag,
sg=sg_val,
hs=hs_val,
seed=seed_val,
)
time_taken_list.append(time.time() - start_time)
time_taken_list = np.array(time_taken_list)
time_mean = np.mean(time_taken_list)
time_std = np.std(time_taken_list)
model_result = {
'train_data': data.name,
'compute_loss': loss_flag,
'sg': sg_val,
'hs': hs_val,
'train_time_mean': time_mean,
'train_time_std': time_std,
}
print("Word2vec model #%i: %s" % (len(train_time_values), model_result))
train_time_values.append(model_result)
train_times_table = pd.DataFrame(train_time_values)
train_times_table = train_times_table.sort_values(
by=['train_data', 'sg', 'hs', 'compute_loss'],
ascending=[False, False, True, False],
)
print(train_times_table)
Adding Word2Vec "model to dict" method to production pipeline
Suppose, we still want more performance improvement in production.
One good way is to cache all the similar words in a dictionary.
So that next time when we get the similar query word, we'll search it first in the dict.
And if it's a hit then we will show the result directly from the dictionary.
otherwise we will query the word and then cache it so that it doesn't miss next time.
# re-enable logging
logging.root.level = logging.INFO
most_similars_precalc = {word : model.wv.most_similar(word) for word in model.wv.index2word}
for i, (key, value) in enumerate(most_similars_precalc.items()):
if i == 3:
break
print(key, value)
Comparison with and without caching
for time being lets take 4 words randomly
import time
words = ['voted', 'few', 'their', 'around']
Without caching
start = time.time()
for word in words:
result = model.wv.most_similar(word)
print(result)
end = time.time()
print(end - start)
Now with caching
start = time.time()
for word in words:
if 'voted' in most_similars_precalc:
result = most_similars_precalc[word]
print(result)
else:
result = model.wv.most_similar(word)
most_similars_precalc[word] = result
print(result)
end = time.time()
print(end - start)
Clearly you can see the improvement but this difference will be even larger when we take more words in the consideration.
Visualising the Word Embeddings
The word embeddings made by the model can be visualised by reducing dimensionality of the words to 2 dimensions using tSNE.
Visualisations can be used to notice semantic and syntactic trends in the data.
Example:
- Semantic: words like cat, dog, cow, etc. have a tendency to lie close by
- Syntactic: words like run, running or cut, cutting lie close together.
Vector relations like vKing - vMan = vQueen - vWoman can also be noticed.
.. Important:: The model used for the visualisation is trained on a small corpus. Thus some of the relations might not be so clear.
from sklearn.decomposition import IncrementalPCA # inital reduction
from sklearn.manifold import TSNE # final reduction
import numpy as np # array handling
def reduce_dimensions(model):
num_dimensions = 2 # final num dimensions (2D, 3D, etc)
vectors = [] # positions in vector space
labels = [] # keep track of words to label our data again later
for word in model.wv.vocab:
vectors.append(model.wv[word])
labels.append(word)
# convert both lists into numpy vectors for reduction
vectors = np.asarray(vectors)
labels = np.asarray(labels)
# reduce using t-SNE
vectors = np.asarray(vectors)
tsne = TSNE(n_components=num_dimensions, random_state=0)
vectors = tsne.fit_transform(vectors)
x_vals = [v[0] for v in vectors]
y_vals = [v[1] for v in vectors]
return x_vals, y_vals, labels
x_vals, y_vals, labels = reduce_dimensions(model)
def plot_with_plotly(x_vals, y_vals, labels, plot_in_notebook=True):
from plotly.offline import init_notebook_mode, iplot, plot
import plotly.graph_objs as go
trace = go.Scatter(x=x_vals, y=y_vals, mode='text', text=labels)
data = [trace]
if plot_in_notebook:
init_notebook_mode(connected=True)
iplot(data, filename='word-embedding-plot')
else:
plot(data, filename='word-embedding-plot.html')
def plot_with_matplotlib(x_vals, y_vals, labels):
import matplotlib.pyplot as plt
import random
random.seed(0)
plt.figure(figsize=(12, 12))
plt.scatter(x_vals, y_vals)
#
# Label randomly subsampled 25 data points
#
indices = list(range(len(labels)))
selected_indices = random.sample(indices, 25)
for i in selected_indices:
plt.annotate(labels[i], (x_vals[i], y_vals[i]))
try:
get_ipython()
except Exception:
plot_function = plot_with_matplotlib
else:
plot_function = plot_with_plotly
plot_function(x_vals, y_vals, labels)
总结
在本教程中,我们学习了如何在自定义数据上训练word2vec模型以及如何对其进行评估。希望您也能在机器学习任务使用这个受欢迎的工具!