第9章如何使用Gensim开发Word Embedding模型
Word Embedding模型是一种在自然语言处理中表示文本的现代方法。像Word2Vec和GloVe这样的嵌入算法是神经网络模型用于机器翻译等自然语言处理问题所取得的最新成果的关键。在本教程中,您将了解在Python中如何使用Gensim为自然语言处理应用程序训练和加载字嵌入模型。完成本教程后,您将了解:
- 如何在文本数据上训练自己的Word2Vec单词嵌入模型。
- 如何使用主成分分析可视化训练的单词嵌入模型。
- 如何从谷歌和斯坦福加载预先训练好的Word2Vec和GloVe字嵌入模型。
9.1 教程概述
本教程分为以下几部分:
- Word Embedding模型
- Gensim库
- 开发Word2Vec词嵌入模型
- 可视化词嵌入模型
- 加载Google的Word2Vec词嵌入模型
- 加载斯坦福的GloVe嵌入模型
9.2 Word Embedding模型
词嵌入是一种提供单词的密集向量表示的方法,可以捕获单词的含义。词嵌入是对简单的词袋模型编码方案(如字数和频率)的改进,任何一个文档在词袋模型方案的编码下最终形成的是一个巨大的稀疏的向量(通常为0值),仅仅捕获是文档的内容,而不是词的意思。
词嵌入模型是在大规模文本语料库上通过使用一定的算法训练一组固定长度密集和连续值向量获得的。每个单词由嵌入空间中的一个点表示,这些点是根据围绕目标单词的单词学习和移动的。词本身由自己的伴生词(文本中词两侧的词)来定义的,可以通过嵌入来学习单词的意思。单词向量空间表示提供了一个投影,其中具有相似含义的单词在空间内局部聚类
在文本表示中使用词嵌入模型是深度神经网络在处理机器翻译等问题上具有突破性表现的关键方法之一。在本教程中,我们将了解如何使用两种不同的词嵌入方法:斯坦福大学的GloVe和谷歌的Word2Vec。
9.3 Gensim Python库
Gensim是一个用于自然语言处理的开源Python库,主要关注主题建模。它被称为“人类主题建模”。Gensim由捷克自然语言处理研究员Radim Rehurek及其公司RaRe Technologies开发并维护。它不是一个包罗万象的NLP研究库(如NLTK);相反,Gensim是一个成熟,专注,高效的NLP工具套件,用于主题建模。最值得注意的是,它支持Word2Vec词嵌入的实现,可以从文本中学习新的单词向量。
它还提供了加载几种不同格式的预训练词嵌入模型,以及使用和查询加载词嵌入模型的工具。我们将在本教程中使用Gensim库。Gensim可以使用pip或者easy install命令安装。例如,您可以通过Terminal键入以下内容来使用pip安装Gensim:
sudo pip install -U gensim
代码清单9.1:使用pip安装Gensim库。
如果您需要有关在不同系统上安装Gensim的帮助,可以查看Gensim安装说明(在本章末尾链接)。
9.4 开发Word2Vec嵌入
Word2Vec是一种用于从文本语料库中学习词嵌入模型的算法。有两种主要的训练算法可用于从文本学习词嵌入模型:连续的词袋(CBOW)和Skip-Gram。我们不会深入讨论这些算法,只会简单介绍一下如何选择目标单词的单词窗口,提供上下文,确定单词的含义。该方法由Tomas Mikolov开发,他以前在Google,目前在Facebook。
Word2Vec模型需要大量文本,例如整个维基百科语料库。但是我们不会用这类语料库,仅仅使用一个小文本例子来演示训练词嵌入模型的原理。Gensim提供了使用Word2Vec模型的Word2Vec类。从文本学习单词嵌入模型涉及到文本加载、将文本分割成句子并将它作为参数传递给Word2Vec实例的构造函数。例如:
sentences = ...
model = Word2Vec(sentences)
代码清单9.2:创建Word2Vec模型的示例
具体而言,每个句子必须被标记化,意味着分成单词并准备好(例如,可能预先过滤并且可能转换为优选情况)。句子可以是加载到内存中的文本,也可以是逐步加载文本的迭代器,这是大规模文本语料库加载的方法。Word2Vec构造函数有很多参数;下面是一些值得注意的参数:
- size :(默认为100)嵌入的维数,例如表示每个标记(单词)的密集向量的长度。
- window :(默认值5)目标字与目标字周围的字之间的最大距离。
- min count:(默认值5)训练模型时要考虑的最小字数;小于此计数的单词将被忽略。
- workers :(默认值3)训练时使用的线程数。
- sg :(默认为0或CBOW)训练算法,CBOW(0)或Skip-gram(1)。
刚开始时,默认值已经足够完成任务的了。如果您拥有多核CPU或者多个CPU,就像大多数现代计算机一样,我强烈建议您增加worker以匹配核心数量(例如8)。在训练模型之后,可以通过wv属性访问它。这是可以进行查询的实际单词矢量模型。例如,您可以打印所学习的令牌(单词)词汇,如下所示:
words = list(model.wv.vocab)
print(words)
代码清单9.3:总结模型词汇表中单词的示例
您可以查看特定标记的嵌入向量,如下所示:
print(model[ ' word ' ])
代码清单9.4:打印特定单词的嵌入示例
最后,通过调用单词矢量模型上的save_word2vec_format()函数,可以将训练过的模型保存到文件中。默认情况下,模型以二进制格式保存以节省空间。例如:
model.wv.save_word2vec_format( 'model.bin' )
代码清单9.5:保存单词嵌入的示例
入门时,您可以将学习的模型保存为ASCII格式并查看内容。您可以通过在调用save_word2vec_format()函数时设置binary=False来执行此操作,例如:
model.wv.save_word2vec_format('model.txt',binary=False)
代码清单9.6:以ASCII格式保存单词嵌入的示例
然后可以通过调用Word2Vec.load()函数再次加载保存的模型。例如:
model = Word2Vec.load( ' model.bin ' )
代码清单9.7:加载已保存的单词嵌入的示例
我们可以将所有这些与一个有效的例子结合起来。我们不会从文件中加载大型文本文档或语料库,而是使用预先标记化的小型内存列表。训练模型并将单词的最小计数设置为1,以便不忽略任何单词。在学习模型之后,我们总结,打印词汇表,然后为单词“sentence”打印单个向量。最后,模型以二进制格式保存到文件中,加载,然后进行汇总。
from gensim.models import Word2Vec
# define training data
sentences = [['this', 'is', 'the', 'first', 'sentence', 'for', 'word2vec'],
['this', 'is', 'the', 'second', 'sentence'],
['yet', 'another', 'sentence'],
['one', 'more', 'sentence'],
['and', 'the', 'final', 'sentence']]
# train model
model = Word2Vec(sentences, min_count=1)
# summarize the loaded model
print(model)
# summarize vocabulary
words = list(model.wv.vocab)
print(words)
# access vector for one word
print(model['sentence'])
# save model
model.save('model.bin')
# load model
new_model = Word2Vec.load('model.bin')
print(new_model)
代码清单9.8:在Gensim中演示Word2Vec模型的示例
运行该示例将打印以下输出。
注意:鉴于神经网络的随机性,您的具体结果可能会有所不同。考虑运行几次示例。
Word2Vec(vocab=14, size=100, alpha=0.025)
['this', 'is', 'the', 'first', 'sentence', 'for', 'word2vec', 'second', 'yet', 'another', 'one', 'more', 'and', 'final']
[-3.7065123e-03 4.9204577e-04 2.8846778e-06 3.5853996e-03
7.9159712e-04 2.4395641e-03 -3.3981546e-03 2.8660761e-03
-3.0486698e-03 -7.8586268e-04 9.6859931e-06 2.8936660e-03
2.9422545e-03 -4.7677895e-03 2.9825056e-03 -3.0169794e-03
-2.9951574e-03 -2.6047480e-04 -7.9289934e-04 -4.4475406e-04
-3.6437630e-03 -1.0169746e-03 3.1778298e-03 -4.4280002e-03
1.5488741e-03 -1.0386879e-03 1.2010697e-03 1.3661557e-03
-3.9456869e-03 1.0107562e-03 -1.2765173e-03 3.1288727e-03
-3.4487594e-03 -1.3538970e-03 -3.2709050e-03 -1.4035561e-03
-4.3136226e-03 4.8198770e-03 -2.0322914e-03 2.1563005e-04
8.7983959e-04 -4.8829303e-03 -2.9812632e-03 -3.0672867e-03
2.4462037e-03 -2.3583306e-03 -3.7808712e-03 -3.7351635e-03
2.9824423e-03 4.7589988e-03 2.4690463e-03 2.4670158e-03
2.1042312e-03 4.9570207e-03 -4.7571156e-03 -1.3520241e-04
4.8285467e-03 3.4307216e-03 4.6298448e-03 3.7489098e-03
-3.6141381e-03 2.8721318e-03 -4.5301816e-03 -1.1559706e-03
7.0973259e-04 -4.2370688e-03 1.6485394e-03 -2.7538128e-03
1.1574271e-03 -4.1462886e-03 2.5458567e-04 3.3621371e-03
-4.0812837e-03 -3.6826839e-03 -2.2578686e-03 -4.4340272e-03
3.7620952e-03 4.5184614e-03 1.6152336e-03 -1.6366757e-03
3.6083555e-03 2.5181063e-03 2.9905178e-03 -4.1286880e-03
3.6001171e-03 -3.6579790e-03 -2.7309055e-03 2.5491889e-03
-1.6339973e-03 4.6183495e-03 -1.0622183e-03 -2.8355005e-03
5.9242453e-04 1.1817104e-03 2.8928400e-03 -4.0550088e-03
-1.6167299e-03 -3.9138724e-03 1.2339132e-03 -7.0600200e-04]
Word2Vec(vocab=14, size=100, alpha=0.025)
代码清单9.9:Gensim中Word2Vec模型的示例输出
您可以看到,通过一些准备文本文档的工作,您可以使用Gensim轻松创建自己的单词嵌入模型。
9.5 可视化Word Embedding模型
在学获得了文本数据的单词嵌入模型之后,可以通过图形化的方式来观看其详细信息。您可以使用经典投影方法将高维单词向量降维到二维并在图绘制它们。可视化可以为您的学习模型提供定性诊断,我们可以从训练好的模型中检索所有向量,如下所示:
X = model[model.wv.vocab]
代码清单9.10:访问模型词汇表
然后我们可以在矢量上使用投影方法将其降维,例如scikit-learn中提供的那些方法,然后使用Matplotlib将投影绘制为散点图。让我们看一下使用Principal Component Analysis或PCA的示例。
9.5.1 使用PCA绘制单词向量
我们可以使用scikit-learn PCA类创建单词向量的二维PCA模型,如下所示。
pca = PCA(n_components=2)
result = pca.fit_transform(X)
代码清单9.11:将二维 PCA模型拟合到单词向量的示例
可以使用Matplotlib如下绘制得到的投影,将两个维度分别赋给x和y坐标。
pyplot.scatter(result[:, 0], result[:, 1])
代码清单9.12:绘制PCA向量的散点图的示例
我们可以更进一步,用图标本身注释图表上的点。没有任何修饰偏移的粗略版本如下所示。
words = list(model.wv.vocab)
for i, word in enumerate(words):
pyplot.annotate(word, xy=(result[i, 0], result[i, 1]))
代码清单9.13:在散点图上绘制单词的示例
将这一切与上一节中的模型结合在一起,下面列出了完整的示例。
from gensim.models import Word2Vec
from sklearn.decomposition import PCA
from matplotlib import pyplot
# define training data
sentences = [['this', 'is', 'the', 'first', 'sentence', 'for', 'word2vec'],
['this', 'is', 'the', 'second', 'sentence'],
['yet', 'another', 'sentence'],
['one', 'more', 'sentence'],
['and', 'the', 'final', 'sentence']]
# train model
model = Word2Vec(sentences, min_count=1)
# summarize the loaded model
print(model)
# summarize vocabulary
words = list(model.wv.vocab)
print(words)
# access vector for one word
print(model['sentence'])
# save model
model.save('model.bin')
# load model
new_model = Word2Vec.load('model.bin')
print(new_model)
# fit a 2d PCA model to the vectors
X = model[model.wv.vocab]
pca = PCA(n_components=2)
result = pca.fit_transform(X)
# create a scatter plot of the projection
pyplot.scatter(result[:, 0], result[:, 1])
words = list(model.wv.vocab)
for i, word in enumerate(words):
pyplot.annotate(word, xy=(result[i, 0], result[i, 1]))
pyplot.show()
代码清单9.14:演示如何绘制单词向量的示例
运行该示例将创建一个散点图,其中的点用单词注释。鉴于这样一个小小的语料库用于拟合模型,很难从图中得出很多意义。
注意:鉴于神经网络的随机性,您的具体结果可能会有所不同。考虑运行几次示例。
图9.1:Word2Vec模型的PCA投影的散点图
9.6 加载Google的Word2Vec嵌入
训练自己的单词向量可能是给定NLP问题的最佳方法。但是它可能不但需要很长时间,还需要一台具有大量RAM和磁盘空间的高速计算机,以及在输入数据和训练算法方面的一些专业知识。另一种方法是简单地使用现有的预训练单词嵌入模型。除了Word2Vec的论文和代码外,Google还在 Word2Vec Google Code Project上发布了预训练的Word2Vec模型。
预先训练的模型只不过是包含分词及其相关词向量的文件。Google的Word2Vec模型是在其新闻数据(约1000亿字)上训练得到的;它包含300万个单词和短语,词向量是300维的。这是一个1.53GB的文件。你可以在这里下载:
- GoogleNews-vectors-negative300.bin.gz. https://drive.google.com/file/d/0B7XkCwpI5KDYNlNUTTlSS21pQmM/edit?usp=sharing
解压缩后,二进制文件(GoogleNews-vectors-negative300.bin)为3.4GB字节。Gensim库提供了加载此文件的工具,您可以调用KeyedVectors.load_word2vec_format()函数将此模型加载到内存中:
from gensim.models import KeyedVectors
filename = 'GoogleNews-vectors-negative300.bin'
model = KeyedVectors.load_word2vec_format(filename, binary=True)
代码清单9.15:在Gensim中加载Google单词向量的示例
请注意,此示例可能需要具有8 GB或更多内存的工作站才能执行。在我的现代工作站上,加载大约需要43秒。你可以做一个有趣的事情是用单词做一点线性代数算法。例如,上面讲得一个例子:
queen = (king - man) + woman
代码清单9.16:单词向量的算术示例
这就是计算queen词的向量等于king向量中减去man向量并加上woman向量。King里的man-ness被woman-ness取代就成了queen。一个非常酷的概念。Gensim提供了一个接口most similar()函数,用于在训练或加载的模型上中执行这种类型的操作。例如:
result = model.most_similar(positive=[ 'woman' , 'king' ], negative=[ 'man' ], topn=1)
print(result)
代码清单9.17:Gensim中单词向量的算术示例
我们可以将所有这些放在一起,如下所示。
from gensim.models import KeyedVectors
# load the google word2vec model
filename = 'GoogleNews-vectors-negative300.bin'
model = KeyedVectors.load_word2vec_format(filename, binary=True)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
print(result)
代码清单9.18:使用Google字向量演示算术的示例
运行该示例加载Google预训练的Word2Vec模型,然后计算(king-man)+woman=?单词的操作变成了向量进行操作。正如我们所料,答案是女王。
[('queen', 0.7118192911148071)]
代码清单9.19:使用Google字向量输出算术
有关您可以尝试的更有趣的算术示例,请参阅更多阅读部分中的一些文章。
9.7 加载斯坦福的GloVe嵌入
斯坦福大学的研究人员也开发了一套像Word2Vec一样的词嵌入模型训练算法,称为全局向量词表示(Global Vectors for Word Representation)法,简称为GloVe。我不会在这详细介绍Word2Vec和GloVe之间的差异,但一般来说,NLP从业者似乎更喜欢GloVe。
与Word2Vec一样,GloVe研究人员也提供预训练的单词向量,可供选择。您可以下载GloVe预训练模型,可以很容易加载它与Gensim一起配合使用:第一步是将GloVe文件格式转换为Word2Vec文件格式,唯一的区别是多了一个小标题行,转换可以通过调用glove2word2vec()函数完成。例如(注意,这个例子只是一个带有模拟输入文件名的演示):
from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = 'glove.txt'
word2vec_output_file = 'word2vec.txt'
glove2word2vec(glove_input_file, word2vec_output_file)
代码清单9.20:将文件从GloVe转换为Word2Vec格式的示例
转换后,文件可以像上面的Word2Vec文件一样加载。让我们来看一个具体例子,您可以从GloVe网站下载最小的GloVe预训练模型,它是一个822MB的zip文件,有4种不同的模型(50,100,200和300维向量),是在维基百科60亿个单词数据上训练所得和涵盖了400,000个单词词汇。直接下载链接在这里:
- glove.6B.zip
使用模型的100维版本,我们可以将文件转换为Word2Vec格式,如下所示:
from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = 'glove/glove.6B.100d.txt'
word2vec_output_file = 'glove.6B.100d.txt.word2vec'
glove2word2vec(glove_input_file, word2vec_output_file)
代码清单9.21:将特定GloVe文件转换为Word2Vec格式的示例
您现在拥有Word2Vec格式的GloVe模型的副本,文件名为glove.6B.100d.txt.word2vec。现在我们可以加载它并执行相同的(king-man)+woman=?按照上一节进行测试。完整的代码清单如下。请注意,转换后的文件是ASCII格式,而不是二进制格式,因此我们在加载设置binary=False。
from gensim.models import KeyedVectors
# load the Stanford GloVe model
filename = 'glove.6B.100d.txt.word2vec'
model = KeyedVectors.load_word2vec_format(filename, binary=False)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=[ 'woman' , 'king' ], negative=[ 'man' ], topn=1)
print(result)
代码清单9.22:使用转换后的GloVe字向量进行算术运算的示例
将所有这些结合在一起,下面列出了完整的示例。
from gensim.models import KeyedVectors
from gensim.scripts.glove2word2vec import glove2word2vec
# convert glove to word2vec format
glove_input_file = 'glove/glove.6B.100d.txt'
word2vec_output_file = 'glove.6B.100d.txt.word2vec'
glove2word2vec(glove_input_file, word2vec_output_file)
# load the converted model
filename = 'glove.6B.100d.txt.word2vec'
model = KeyedVectors.load_word2vec_format(filename, binary=False)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=[ 'woman' , 'king' ], negative=[ 'man' ], topn=1)
print(result)
代码清单9.23:演示如何加载和使用GloVe字嵌入的示例运行该示例打印相同的女王结果。
[('queen', 0.7698541283607483)]
代码清单9.24:使用转换的GloVe字向量的算术输出示例
0 条 查看最新 评论
没有评论