06 高级特征工程和NLP算法
在这一章中,我们将看到一个奇妙而简单的概念,叫做单词到矢量(word2vec)。这个概念是由谷歌的Tomas Mikolov领导的一个研究小组提出的。众所周知,谷歌为我们提供了许多伟大的产品和概念。word2vec就是其中之一。在NLP中,开发能够处理单词、短语、句子等语义的工具或技术是非常重要的,而Word2vec模型能够很好地确定单词、短语、句子、段落和文档的语义。我们将跳进这个矢量化的世界,在里面生活一段时间。你不觉得这很神奇吗?我们将从概念开始,以一些有趣和实用的例子结束。那么,我们开始吧。
6.1 词嵌入
我们已经在第5章,特征工程和NLP算法中介绍了单词嵌入。我们研究了NLP中的语言模型和特征工程技术,其中词汇表中的单词或短语映射到实数向量。将单词转换成实数的技术称为单词嵌入。我们一直在使用矢量化,以及基于术语频率反转文档频率(tf-idf)的矢量化。那么,让我们跳进word2vec的世界。
6.2 word2vec基础
在这里,我们将尝试使用word2vec在单词级别处理语义。然后,我们将把我们的概念扩展到段落和文档级别。通过查看图6.1,您将看到我们将在本书中介绍的不同类型的语义:
语义是处理NLP领域意义的一个分支。我们已经在第三章“理解句子结构”中介绍了词汇语义。所以,这里我们将讨论更多关于分布语义的内容。语义学中还有其他技术或类型,例如形式语义学、组合语义学;但现在,在本书中,我们将不讨论这些类型或技术。
6.2.1 分布语义
分布语义学是一个研究领域,它的研究重点是根据语言项在大量文本数据样本中的分布性质,开发量化和分类语言项之间语义相似性的技术或理论。我想在这里举一个例子,让你知道我所说的分布语义是什么意思。假设你有旅行博客的文本数据。现在,作为一个人,你知道面食、面条、汉堡等是可食用的食物,而果汁、茶、咖啡等是可饮用的食物。作为一个人,我们可以很容易地将可饮用和可食用的食品分类,因为我们有与每种食品相关的特定上下文,但是机器不能真正了解这些语义。所有描述的食物项目都很可能与数据集中的某些词一起出现。所以,这里我们关注的是单词在语料库中的分布,也就是说,语言项目或具有相似分布的单词具有相似的含义。这被称为分布假设。我再举一个例子。假设您有一组研究论文。数据集中的一些研究论文属于工程类,其他的属于法律类。工程类、方程类、方法类等带有文字的文档与工程类相关,因此它们应该是一个组的一部分,法律类、律师类、法律研究所等文字与法律领域的研究论文相关,因此它们应该分组在一起。利用word2vec等分布语义技术,可以对不同的域词进行向量分离。所有含义相似的词都被分组在一起,因为它们在语料库上的分布相似。您可以参考图6.2,它显示了我们给定的分布语义示例的向量空间的图示,其中相似的上下文词组合在一起:
我们在这一章中主要集中在被称为word2vec的分布语义技术上。
6.2.2 定义word2vec
word2vec是利用两层神经网络开发的。它以大量的文本数据或文本文集作为输入,并从给定的文本生成一组向量。换句话说,我们可以说它产生了高维向量空间。这个向量空间有几百个维度。当我说word2vec模型从文本中生成一组向量或向量空间时,您真的想知道我这里的意思。这里,我们使用的是两层神经网络,它现在是一个黑盒,执行某种逻辑,并在向量空间中为我们生成向量。在向量空间中,语料库中的每个唯一单词都被分配一个对应的向量。因此,向量空间只是大型文本语料库中所有单词的向量表示。所以,我想你明白了,对吧?在我们所学的基础上,您可以说word2vec是生成嵌入单词的模型之一。请回顾第5章,特征工程和NLP算法的矢量化部分。我还想指出一点,即word2vec是一种强大的、无监督的嵌入技术。
6.2.3 无监督分布语义模型中的必需品
本节我们介绍Word2vec为我们解决的众多挑战。这些挑战的解决使我们真正需要word2vec。因此,首先我们将研究一些挑战,然后看看Word2vec模型如何解决这些挑战。
挑战
6.3 word2vec模型从黑盒到白盒
6.3.1 基于分布相似性的表示
6.3.2 了解word2vec模型的组件
6.3.3 了解word2vec模型的逻辑
6.3.4 了解word2vec模型背后的算法和数学
6.3.5 关于word2vec模型的一些事实
6.3.6 word2vec模型的应用
这里列出了一些我们正在努力解决的挑战:
1、当我们开发一个NLP应用程序时,有一个基本问题——我们知道机器不能理解我们的文本,我们需要将文本数据转换成数字格式。
2、有一些将文本数据转换成数字格式的方法,但是我们应用了一些简单的技术,其中一种是独热编码,但是这种技术的问题如下:
- 假设你有句话:I like apple juice.现在,假设您对句子中的每个单词应用一个独热编码。如果语料库中有数千个句子,那么向量维等于语料库中的整个词汇表,如果这些高维列被用于开发一个NLP应用程序,那么我们需要对这些高维列进行高计算能力和矩阵运算,因为它们花费的时间太长。
- 对于语音识别词汇,大小平均为20000个单词。如果我们正在开发一个机器翻译系统,那么也许我们会使用更多的词汇,比如500000个单词。处理这些巨大的向量是一个很大的挑战。
- 另一个问题是,当您对一个句子中的某个特定单词应用一个独热编码时,整个条目的值为零,但实际表示该单词的值除外,该值为1。为了简单起见,假设我们接受这样一句话:I like apple juice。暂时考虑一下,我们的语料库中只有一个句子。现在,如果我尝试在单词apple上应用一个热编码,那么apple的一个热表示,如下所示。
I like apple juice
Apple 0 0 1 0
juice 0 0 0 1
3、一个独热编码并不能揭示单词之间上下文相似的事实。为了理解这一点,我想举个例子,如果你的语料库有单词cat和cats,那么一个热编码并不能揭示事实,单词cat和cats是非常相似的单词。
4、如果我对一个独热编码向量应用一个和操作,那么它将不会表示任何上下文相似性。举个例子,如果我在苹果和果汁的一个热向量上应用一个and操作意味着一个点积,那么答案是0。事实上,这些单词可以同时出现,并且也有很强的上下文关系,但是仅一个热编码并不表示任何关于单词相似性的重要信息。
5、如果你想找到准确的单词相似度,那么WordNet就帮不了你。WordNet是由专家制作的,而WordNet所包含的内容更主观,因为它是由人类用户创建的。
6、使用WordNet需要花费大量的时间和精力。
7、有些新词,如Coding Ninja, Wizard等,是WordNet的新词,可能不会出现在网站上。由于缺乏这类词汇,我们无法从WordNet中导出其他语义关系。上述每一个挑战都在解决这些挑战的技术的发展中发挥了重要作用。在过去的二十年里,人们一直在努力开发一种高效、简洁和相关的文字数字表示。最后,在2013年,Tomas Mikolov和他在Google的研究团队提出了Word2vec模型,它以一种有效的方式解决了以前的许多挑战。word2vec非常善于发现单词的相似度,同时保留了以前无法处理的单词之间的语义关系,例如独热编码或WordNet。
我已经介绍了很多关于word2vec的背景知识,所以让我们开始了解word2vec模型的表示、组件和其他参数。
6.4 基于表示的分布相似度
这在NLP中是一个相当古老和强大的想法。分布相似性的概念是,通过考虑某个特定单词出现的上下文,你可以获得许多表示该单词含义的价值,并且它与上下文高度相关。一位著名语言学家约翰·费斯的名言是:“You shall know the word by the company it keeps.”
让我们举个例子:如果我想找到“银行”这个词的含义,我将收集数千个包含“银行”这个词的句子,然后我将从“银行”这个词开始观察其他单词,并试图理解“银行”这个词的使用环境。所以,看看这些例子,了解分布相似性:
1:The banking sector is regulated by the government
2:Banking institutions need some technology to change their traditional operations.
在前面的句子中,单词banking更常与诸如government、department、operations等单词连用。所有这些单词对于理解单词banking的上下文和含义都非常有用。
这些其他单词对于表示单词banking的含义非常有用。当单词banking出现在句子中时,还可以使用单词banking来预测最常见的经常出现的单词或短语。
为了理解我们如何更好地表示一个特定单词的含义,以及对出现在这个给定单词上下文中的其他单词进行预测,我们需要理解相关单词的分布表示。
一个词的分布表示是一种矢量形式,在其中该词可以表示。单词以稠密向量的形式表示,必须选择稠密向量,以便它能够很好地预测在该单词上下文中出现的其他单词。现在,我们预测的其他单词中的每一个都有其他单词附加在它们上面,因此我们使用相似性度量,例如向量点积。这是一种递归方法,每个单词都将预测在相同上下文中出现的其他单词,而其他预测的单词也执行相同的操作通过预测其他单词。因此,我们需要一个聪明的算法来执行这种递归操作。在这里,请不要混淆分布相似性的术语和分布表示。基于分布相似性的表示实际上是语义学理论的一部分,它有助于我们理解在日常生活中使用的词的意义;而一个词的分布表示是一个矢量形式的词的表示。要生成一个词的矢量形式,我们可以使用一种热编码或任何其他技术,但这里的主要点是为一个也带有相似性度量意义的词生成矢量,以便您理解该词的上下文意义。当我们讨论分布相似性时,word2vec就出现了。
6.5 word2vec模型的组成部分
在本节中,我们将了解word2vec模型的主要三个组成部分,如下所示:
6.5.1 word2vec的输入
首先,我们应该了解开发word2vec模型的输入,因为这是一个基本的东西,您可以从中开始构建word2vec。
因此,我想声明,我们将使用原始文本语料库作为开发Word2vec模型的输入。
在实际应用中,我们使用大型语料库作为输入。为了简单起见,我们将使用一个相当小的语料库来理解本章中的概念。在本章的后面部分,我们将使用大型语料库通过使用Word2vec模型概念来开发一些很酷的东西。
6.5.2 word2vec的输出
这一部分对于您的理解非常重要,因为在这一点之后,无论您理解什么,都只是为了实现您在这里设置的输出。因此,到目前为止,我们知道我们要发展一个词的向量表示,它承载了这个词的意义,并且表达了分布相似性度量。
现在,我将开始定义我们的目标和输出。我们要定义一个模型,目的是预测一个中心词和出现在其上下文中的词。所以,我们可以说,我们想要预测给定单词的上下文的概率。在这里,我们建立了简单的预测目标。
如您所见,前面的图中给出了一些简单的例句。如果我们从第一句话中提取单词apple,并根据我们的目标,将单词apple转换为矢量形式,这样,通过使用该矢量形式的apple,我们就可以预测单词eat出现在单词apple上下文中的概率。同样的逻辑也适用于其他句子。例如,在第三句话中,我们试图找出单词scooter的向量,这有助于我们预测单词的概率,如在给定单词scooter的上下文中驾驶和工作。因此,总的来说,我们的直截了当的目标是,我们需要将每个单词转换成矢量格式,这样它们就能够很好地预测出现在其上下文中的单词,并且通过给出上下文,我们可以预测最适合给定上下文的单词的概率。
6.5.3 word2vec模型的构建模块
到目前为止,我们已经知道了我们的输入和输出,所以现在您可能在想:我们如何通过使用我们的输入来实现我们的目标。正如我提到的,我们需要一个聪明的算法来帮助我们实现我们的目标。研究人员为我们做了这项工作,并得出结论,我们可以使用神经网络技术。
我们之所以使用神经网络技术,是因为当我们试图从大量数据中学习时,神经网络是很好的算法。如果你想建立一个简单,可扩展,易于训练的模型,那么神经网络是最好的方法之一。
这种神经网络在产生分布相似性方面创造了奇迹。谷歌使用维基百科的大型语料库生成了word2vec模型。请参阅下图,它给出了输入的概述,以及一些来自google word2vec模型的著名输出。对于我们来说,word2vec模型仍然是一个强大的黑盒,可以产生一些伟大的结果。见下图中word2vec的黑箱表示:
上图显示我们已经提供了文本数据作为word2vec模型的输入。word2vec模型将文本数据转换为矢量形式,这样我们就可以对单词的矢量表示进行数学运算。word2vec最著名的例子是:如果你有国王、男人和女人的向量。然后,如果你运用数学运算,从国王向量中减去男人的向量值,然后把女人这个词的向量值加到它上面,我们就会得到一个表示皇后这个词相同向量值的合成向量。下面是这个例子的数学表示:
king - man + woman = queen.
架构组件
让我们看看构建Word2vec模型所涉及的架构组件。
word2vec模型的主要架构组件是其神经网络。word2vec模型的神经网络有两层,从这个意义上说,它不是一个深层的神经网络。事实上,word2vec并不使用深层神经网络来生成单词的矢量形式。
这是word2vec模型的关键和主要组件之一,我们需要对其功能进行解码,以清楚了解word2vec是如何工作的。
6.6 word2vec模型的逻辑
我们将开始分解word2vec模型,并尝试理解它的逻辑。word2vec是一个软件,它使用了一系列算法。
如图所示,有三个主要构建块。我们将详细检查其中的每一个:词汇生成器、上下文生成器、双层神经网络
6.6.1 词汇表构建器
词汇生成器是word2vec模型的第一个构建块。它采用原始文本数据,主要以句子的形式。词汇生成器用于从给定的文本文集构建词汇。它将从你的语料库中收集所有独特的单词并构建词汇表。在python中,有一个名为gensim的库。我们将使用gensim为语料库生成word2vec。gensim中有一些可用的参数,我们可以根据您的应用程序需要使用这些参数从语料库中构建词汇表。参数列表如下:
min_count:
此参数用作阈值。这将忽略总频率低于指定值的所有单词。例如,如果将Min_Count设置为5,那么词汇生成器的输出不包含少于5次的单词。词汇生成器输出仅包含出现在语料库中超过或等于五次的单词。
build_vocab(sentences, keep_raw_vocab=False, trim_rule=None,progress_per=10000, update=False):
此语法用于从一系列句子构建词汇(可以是仅一次的生成器流)。每个句子必须是Unicode字符串列表。
词汇表中的每个词都与词汇表对象有关联,词汇表对象包含一个索引和一个计数。
6.6.2 上下文环境构建器
上下文生成器使用词汇生成器的输出以及作为上下文窗口一部分的单词作为输入并生成输出。
首先,让我们了解上下文窗口的概念。这个上下文窗口是一种滑动窗口。您可以根据将在其中使用word2vec的NLP应用程序定义窗口大小。通常,NLP应用程序使用的上下文窗口大小为5到10个字。如果您决定使用5个窗口大小,那么我们需要考虑从中心词左侧的5个词和中心词右侧的5个词。这样,我们就可以获取关于中心词周围所有单词的信息。
这里,我想说明一个例子,对于这个例子,上下文窗口的大小等于一,因为我们有一个一句话的语料库。我有句话:I like deep learning,而deep是中心词。那么,您应该根据窗口大小来考虑周围的单词。所以,在这里,我需要考虑单词like和earning。在下一个迭代中,我们的中心词将是learning,它的周围词是deep的,在句尾是一个句号(.)。我希望上下文窗口的概念在您的头脑中是清晰的。现在,我们需要链接这个概念,看看上下文生成器是如何使用这个概念和词汇生成器的输出的。词汇生成器对象有单词索引和单词在语料库中的频率。通过使用单词的索引,上下文生成器可以知道我们要查看哪个单词,并且根据上下文窗口的大小,它可以考虑其他周围的单词。这些中心词和其他周围词是上下文生成器的输入。现在,您已经清楚地了解了上下文构建器的输入是什么。让我们尝试了解上下文生成器的输出。此上下文生成器生成单词配对。参见下图,了解单词删节的概念:
这些词对将被赋予神经网络。网络将从每个词对出现的次数中学习基本的统计信息。因此,举例来说,神经网络可能会得到更多的训练例子(deep, learning)而不是(deep, communication)。当训练结束后,如果你把单词“deep”作为输入,那么它输出的learning的概率要比它输出的communication概率高得多。
所以这个词对是上下文生成器的输出,它将传递给下一个组件,这是一个两层的神经网络。
到目前为止,我们已经看到了word2vec构建块的两个主要组件。现在,我们的下一个重点将是最后一个组件,即神经网络。
6.6.3 两层的神经网络
在本节中,我们将研究神经网络的输入和输出。除此之外,我们还将关注神经网络的结构部分,这将使我们了解单个神经元的外观、应该有多少个神经元、激活函数是什么等等。word2vec神经网络的结构细节
word2vec使用神经网络进行训练。因此,对我们来说,了解神经网络的基本结构是非常重要的。神经网络的结构细节如下:
有一个输入层
第二层是隐藏层
第三层和最后一层是输出层
word2vec神经网络层的详细信息
如我们所知,神经网络中有两层用于生成字向量。我们将开始详细查看每个层及其输入和输出。这里,我们在本节中不包括word2vec模型背后的数学。在这一章的后面,我们还将研究word2vec背后的数学知识,我将在那个时候让您知道,为了更好地解释,我们将绘制您的点。
让我们简单地了解每一层的任务:
输入层:输入层的神经元数量与词汇表中训练用词的数量一样多。
隐层:以神经元为单位的隐层大小是产生的词向量的维数。
输出层:输出层与输入层具有相同数量的神经元第一个输入层的输入是具有一个独热编码的单词。假设我们学习单词向量的词汇大小是v,这意味着语料库中有不同单词的v个数。在这种情况下,表示自身的单词的位置编码为1,而所有其他位置编码为0。假设这些词的维数是n,那么,对隐藏层连接的输入可以用我们的输入矩阵wi(输入矩阵符号)表示,大小为vn,矩阵wi的每一行代表一个词汇词。同样,从隐藏层到输出层的连接意味着隐藏层的输出可以通过隐藏层输出矩阵wo(隐藏层矩阵符号)来描述。wo矩阵的大小为nv。在这种情况下,wo矩阵的每一列表示给定词汇表中的一个词。请参阅下图以获得输入和输出的清晰图像。除此之外,我们还将看一个简短的例子来理解这个概念:
现在让我们用例子来谈谈。我要一套非常小的语料库。我们的小语料库中的句子如下:
the dog saw a cat
the dog chased a cat
the cat climbed a tree
前三句话有八(8)个单词。我们需要按字母顺序排列它们,如果我们想访问它们,那么我们将引用每个单词的索引。请参阅下表:
Words Index
a 1
cat 2
chased 3
climbed 4
dog 5
saw 6
the 7
tree 8
所以,这里我们的v值等于8。在我们的神经网络中,我们需要八个输入神经元和八个输出神经元。现在假设我们在隐藏层中有三(3)个神经元。因此,在这种情况下,我们的WI和WO值定义如下:
WI = [V * N] = [8 * 3]
WO = [N * V] = [3 * 8]
在训练开始之前,这些矩阵(wi和wo)通过使用小的随机值初始化,这在神经网络训练中很常见。为了便于说明,我们假设将WI和WO初始化为以下值:
这样我们的神经网络就可以了解猫和爬升这两个词之间的关系。因此,换句话说,我们可以解释,当单词cat作为输入,输入到神经网络中时,神经网络应该为单词爬升提供高概率。因此,在嵌入单词时,单词cat被称为上下文单词,而单词collated被称为目标单词。输入向量x代表单词cat,它将是[0 1 0 0 0 0 0 0]t。请注意,只有向量的第二个分量是1。这背后的原因是输入词cat在语料库排序列表中占据第二个位置。以同样的方式,目标词被爬升,爬升的目标向量看起来像[0 0 0 1 0 0 0 0 0]t。
第一层的输入为[0 1 0 0 0 0 0 0]t。
使用以下公式计算隐藏层输出ht:
Ht = XtWI = [-0.490796 -0.229903 0.065460]
通过前面的计算,我们可以发现,在这里,由于一个独热编码表示,隐藏神经元的输出模仿wi矩阵第二行的权重。现在我们需要检查隐藏层和输出层的类似计算。隐藏层和输出层的计算定义如下:
HtWO = [0.100934 -0.309331 -0.122361 -0.151399 0.143463 -0.051262 -0.079686 0.112928]
这里,我们的最终目标是获得输出层中单词的概率。从输出层,我们生成的概率反映了下一个词在输入时与上下文词的关系。因此,数学表达式如下:
Probability (wordk|wordcontext) for k = 1…V
这里,我们讨论的是概率,但是我们的输出是以一组向量的形式,所以我们需要将输出转换为概率。我们需要注意的是,最后一个输出层的神经元输出之和应该加在一个输出层上。在word2vec中,我们使用softmax函数将输出层神经元的激活值转换为概率。
Softmax函数
在本节中,我们将介绍SoftMax函数。SoftMax函数用于将输出向量转换为概率形式。我们使用的是SoftMax函数,因为我们希望将最后一层的输出转换为概率,SoftMax函数可以很容易地将向量值转换为概率值。在这里,KTH神经元的输出将通过以下方程式计算,其中,激活(n)表示第n个输出层神经元的激活值:
公式:
利用这个方程,我们可以计算出语料库中8个词的概率,概率值如下:
[ 0.143073 0.094925 0.114441 0.111166 0.149289 0.122874 0.119431 0.144800 ]
import numpy as np
def stablesoftmax(x):
"""Compute the softmax of vector x in a numerically stable way"""
shiftx = x - np.max(x)
exps = np.exp(shiftx)
return exps / np.sum(exps)
print(stablesoftmax([0.100934, -0.309331, -0.122361, -0.151399, 0.143463 ,-0.051262, -0.079686 ,0.112928]))
[0.1430733 0.09492547 0.11444131 0.11116595 0.14928931 0.1228742
0.1194308 0.14479966]
如你所见,概率0.11116595是为所选的目标词爬升。我们知道,目标向量是[0 0 0 1 0 0 0 0 0]t,所以我们可以通过预测来计算误差。为了产生一个预测误差或误差向量,我们需要从目标向量中减去概率向量,一旦我们知道了误差向量或误差值,我们就可以根据它来调整权重。这里,我们需要调整矩阵wi和wo的权重值。在网络中传播错误并重新调整wi和wo的权值的技术称为反向传播。
因此,训练可以通过从语料库中选取不同的上下文-目标词对来继续。这就是word2vec学习单词之间关系的方式,以便开发语料库中单词的向量表示。
6.6.4 算法的主要流程
连续词袋(CBOW)
在连续词袋(CBOW)算法中,上下文由给定目标词的多个词表示。回想一下我们在前面一节中提到的例子,我们的上下文词是cat,目标词是爬升的。例如,我们可以使用cat和tree作为上下文词来预测作为目标词的爬升单词。在这种情况下,我们需要改变神经网络的结构,特别是输入层。现在,我们的输入层可能不代表单个单词一个独热编码向量,但我们需要放置另一个代表单词树的输入层。
如果增加上下文单词,则需要放置一个额外的输入层来表示每个单词,并且所有这些输入层都连接到隐藏层。
Skip-gram
skip-gram(SG)模型逆转了目标词和上下文词的用法。这里,目标字以一个热编码向量的形式作为输入层的输入。隐藏层保持不变。神经网络的输出层重复多次以生成所选数量的上下文词。
让我们以cat和tree这两个词为例,将其作为上下文词,并将爬升为目标词。SG模型中的输入向量将是爬升单词的一个热编码的单词向量[0 0 0 1 0 0 0 0]t,这次,我们的输出向量应该是单词cat和单词树的向量。因此,对于cat,输出向量应该是[0 1 0 0 0 0 0 0],对于树,输出向量应该是[0 0 0 0 0 0 0 0 0 1]。这次的输出将不是一个单一的概率向量,而是两个不同的概率向量,因为我们有两个词作为上下文词。在这里,误差向量的计算方法与我们之前定义的方法相同。跳变图中的小变化是所有输出层的误差矢量相加,通过反向传播调整权重。这意味着我们需要通过培训确保每个输出层的矩阵wo的权重保持一致。
6.7 word2vec模型背后的算法和数学理论
这一节非常重要,我们将在这里讨论Word2vec中使用的核心算法。到本节结束时,不会有任何秘密留给您去理解word2vec的概念。因此,本节将word2vec黑盒转换为word2vec白盒。在这里,我还将包括数学部分,这样读者可以更好地理解核心概念。如果你不懂数学,别担心,因为我会为你提供一些你可能会发现非常有用的资源。
6.7.1 word2vec算法中的基本数学理论
首先,我们需要有一些基本的数学概念,以便更好地理解算法。我们需要的数学主题如下:
向量:向量有大小和方向。所以,当我们在向量空间中画一个向量的时候,它既有大小也有方向。您可以对向量执行基本的数学运算。
矩阵:矩阵是数字的网格或单词的频率计数。它有行和列。我们可以通过计算矩阵包含的行数和列数来定义矩阵的维度。
偏导数:如果有一个函数包含一个以上的变量,我们对这类函数对其中一个变量进行导数,并保持其他变量不变,那么我们就是这样做偏导数用于向量演算偏导数的。
偏导链规则:链规则是用来计算两个或多个函数组成的导数的公式。
6.7.2 词汇表构建阶段用到的技术
当从数据集中生成词汇表时,您可以使用优化技术,而有损计数是Word2vec模型最常用的方法。
- 有损计数
有损计数算法用于识别频率计数超过用户给定阈值的数据集中的元素。此算法将数据流作为输入,而不是数据集的有限集。
利用有损计数,可以定期从频率表中删除非常低的计数元素。不管怎样,最常被访问的单词几乎永远不会有低计数,如果有,它们就不会在那里停留太久。
在这里,频率阈值通常由用户定义。当我们给出一个min_count=4的参数时,我们会删除数据集中出现的少于四次的单词,我们不会考虑它们。
- 在词汇建设阶段使用有损计数
有损计数是非常有用的,尤其是当你有一个大语料库,你不想考虑那些很少出现的单词。
此时,因为用户可以将最小词频计数设置为阈值,因此出现在阈值频率计数以下的单词将不会包含在词汇表中。
所以,如果你有一个大的语料库,你想优化训练的速度,那么我们可以使用这个算法。
换句话说,你可以说,通过使用这个算法,你缩小了你的词汇量,因此,你可以加快训练过程。
- 应用
除了word2vec之外,在网络流量测量和Web服务器日志分析中还使用了有损计数算法。
6.7.3 上下文环境构建过程中使用的技术
在生成单词上下文对时,上下文生成器使用以下技术:
动态窗口缩放或动态上下文窗口
子采样
修剪
如您所见,动态窗口缩放是上下文生成器的一部分。我们将看到它是如何有用的,以及当我们使用它时它会产生什么样的影响。动态窗口缩放也称为动态上下文窗口。
-
了解动态上下文窗口技术
在word2vec实现中,动态上下文窗口是一种可选技术,可用于生成更精确的输出。您也可以将这些技术视为超参数。
动态上下文窗口技术针对目标词对上下文词使用权重模式。
所以这里的直觉是靠近目标词的词比远离目标词的词更重要。
让我们看看在构建单词时,它是如何有用的。动态上下文窗口认为相邻的上下文词对预测目标词更为重要,本文采用均匀抽样的方法对1到L之间的实际窗口大小进行加权,例如假设上下文窗口大小为5,而现在上下文词的权重是均匀分布的,因此附近大多数单词的权重为5/5,下一个上下文单词的权重为4/5,依此类推。因此,上下文词的最终权重将是5/5、4/5、3/5、2/5、1/5。因此,通过提供权重,可以微调最终结果。 -
子采样
子抽样也是我们在构建单词对时使用的技术之一,正如我们所知,这些单词对是样本训练数据。
子抽样是删除最常见单词的方法。这项技术对于删除停止词非常有用。
这些技术还可以随机删除单词,并且这些随机选择的单词更频繁地出现在语料库中。因此,删除的单词比某些阈值t更频繁,概率为p,其中f标记单词的语料库频率,我们在实验中使用t=10-5。
这也是一个它非常有用的超参数,因为我们正在从语料库和上下文窗口中删除最频繁和不必要的单词,这样,我们就提高了训练样本集的质量。
- 修剪
当我们使用上下文生成器为训练目的构建单词对时,也会使用修枝。当你有大量的词汇需要处理时,如果你包含了不太频繁的词汇,那么你需要删除它们。您还可以使用python中GENSIM库给定的max_vocab_size参数来限制总词汇表的大小。
让我们看看修剪对于生成word2vec是多么有用。修剪是用来修剪训练样本的大小,并使其质量更好。如果不从数据集中删减很少出现的单词,那么模型的准确性可能会降低。这是一种提高精确度的黑客手段。
6.8 神经网络算法
神经网络使用的算法
在这里,我们将研究单个神经元的结构。我们还将研究这两种算法的细节,因此,我们将了解Word2vec如何从单词生成向量。
6.8.1 基本神经元结构
我们已经看到了整个神经网络结构,但是我们还没有看到每个神经元是由什么组成的,以及神经元的结构是什么。因此,在本节中,我们将研究每个输入神经元的结构。
基本神经元结构
训练单个神经元
单神经元应用
多层神经网络
反向传播
word2vec模型背后的数学
在这里,我们将大量地包括数学公式。如果你不是数学背景,那就别担心。我会用简单的语言给你解释,这样你就知道每一部分都发生了什么。
这个结构接受一个输入,也有权重作为输入,它们计算加权和。这里,x1到xk是输入值,w1到wk是相应的权重。
让我们举个例子来理解这个方程的用法。所以,如果输入x=[1 5 6]和w=[0.5 0.2 0.1],加权和u等于[10.5+50.2+6*0.1],那么我们的最终答案是u=[0.5+1+0.6]=2.1。这只是一个简单的例子,让你对给定方程的实际工作有一些具体的实际直觉。这都是关于我们的输入。现在我们将讨论输出。为了产生输出,我们可以从神经元的基本结构上说,我们的输出是加权和u的函数,这里,y是输出,f(u)是加权和的函数。在神经网络中,我们可以使用不同的可用函数,这些函数称为激活函数。这些函数如下:
阶跃 函数
Sigmoid 函数
在本章中,我们没有详细介绍激活函数,但是我们将在第9章“NLP和NLG问题的深入学习”中详细介绍激活函数。因此,我们将把给定的两个函数作为word2vec的激活函数。我们将使用阶跃函数或sigmoid函数,而不是同时使用两者来开发word2vec。
这里,f(u)是阶跃函数,f(u)是sigmoid函数。
6.8.2 训练一个简单的神经元
现在看看如何使用激活函数来训练单个神经元了,让我们了解损耗函数来计算预测输出的误差。
其主要思想是定义误差函数,它实际上告诉我们预测中的误差程度;我们将实际尝试使我们的误差值尽可能低。所以,换句话说,我们实际上正在努力改进我们的预测。在训练过程中,我们使用误差函数输入和计算误差,更新神经元的权重,重复我们的训练过程。我们将继续这个过程,直到得到最大、最佳和准确输出的最小错误率。
下面列出了两个最重要的概念:
定义误差函数(损失函数)
对word2vec中梯度下降的理解
定义误差函数
这里,我们的输入是向量x,词汇是x1到xk,输出y是输出向量,因此,为了计算误差e,我们需要定义误差函数或损失函数,我们使用的是l2损失函数。让我们从理解二级损失函数的基本概念开始,然后我们将看到它在word2vec中的用处。
有两种类型的损失函数,主要用于机器学习(ML)和深度学习(DL)。顺便说一下,我们将在接下来的章节中讨论ML和DL,分别是第8章,NLP问题的机器学习(ML)和第9章,NLP和NLG问题的深入学习。损失函数有两种标准类型,但在这里我们将只看最小平方误差(l2),在接下来的章节中,即第8章,NLP问题的机器学习和第9章,NLP和NLG问题的深入学习,我们将详细看各种损失函数,并比较这些损失函数。损失函数的两种标准类型是:
- 最小绝对偏差(L1)
- 最小二乘误差(L2)
最小二乘误差也称为二级损失函数。一般来说,损失函数希望在从数据集学习的同时实现其最小值,而二级损失函数也希望在错误值最小的情况下实现其值。因此,精确地说,L2函数希望最小化估计值和现有目标值之间的平方差。
E
=
1
2
(
t
−
y
)
2
E = \frac{1}{2}{(t-y)^{2}}
E=21(t−y)2
这里,t是目标向量值,y是估计向量值或预测向量值,e是误差函数。我们已经定义了二级损失函数。将如何处理这个二级误差函数,得到一个最小的误差值,这就是我们需要理解梯度下降的概念的地方。
了解word2vec中的梯度下降
现在,让我们了解我们将如何处理L2函数,以及它如何有助于实现准确的输出。
正如我们前面所说,我们想要最小化这个函数值,这样我们就可以准确地预测目标值,为了达到这个目的,我们将利用公式中给出的L2函数方程的偏导数来计算y。推导推导的过程,然后使用这个推导来尽量减小误差值,称为梯度下降。
∂
E
∂
x
=
y
−
t
\frac{\partial E}{\partial x} = y -t
∂x∂E=y−t
我们知道输出y依赖于f(u),f(u)依赖于输入权重wi。因此,我们需要应用链规则并生成损失函数值。如果我们使用偏导链规则,那么我们将得到下面的方程,它将在word2vec中有用。
根据误差值计算二级损失函数后,更新神经网络输入权重,这种迭代将继续进行,直到达到最小误差值或误差率。
到目前为止,我们一直在推导一个神经元的方程,所以了解这个神经元对我们有什么作用是很重要的。这是我们的下一个讨论点。
6.8.3 单个神经元的应用
我们已经学习了很多关于单个神经元的技术和数学知识,所以我真的想带您了解一下Word2vec模型在单个神经元上的应用。那么,让我们开始吧!
如果你想建立一个模型来识别可食用和不可食用的单词,那么我们可以使用一个神经元来建立这个模型。这种将单词分为可食用类或不可食用类的应用程序称为二元分类任务。对于这种任务,神经元被用来获取一个独热编码的载体。
作为输入,单个神经元将学习哪些单词与可食用项相关,哪些单词与可食用项无关。
这种应用之所以能如此简单地建立起来,是因为当你不断地提供一个热词向量,并使用sigmoid或阶跃函数作为激活函数时,它就变成了一个标准的分类问题,用数学可以很容易地解决这类问题。我们在前面的章节中定义了这一点,因为对于可食用项,输出向量具有相同的值,对于不可食用项生成的向量,它们表示相同的输出向量。最后,我们将能够构建查找表。这种标准分类问题让我们想起了逻辑回归,我们应用了相同的逻辑回归概念,但这里我们使用的是单个神经元结构。
6.8.4 多层神经网络
多层神经网络是我们用于Word2vec的结构。此函数将输入作为一个独热编码的字向量,并将此向量以及加权和传递给隐藏层。通过使用激活功能,即在这种情况下,输出是从隐藏层生成的,并且该输出被传递到下一层,即输出层。我们已经在本章的“两层神经网络”一节中看到了一个例子。在这一部分中,我们没有研究数学方面,所以在这里我将带您了解神经网络的数学方面。
现在,让我们看看给定神经网络的数学方程。在这里,我将向您提供高级的直觉,这将帮助您了解流程,并且您将了解输入和输出函数。
u
i
=
∑
k
=
1
K
w
k
i
x
k
u_{i} = \sum_{k=1}^{K}{w_{ki}x_{k}}
ui=∑k=1Kwkixk
h i = f ( u i ) h_{i} = f(u_{i}) hi=f(ui)
u j ′ = ∑ k = 1 K w k i ′ h k u_{j}^{'} = \sum_{k=1}^{K}{w_{ki}^{'}h_{k}} uj′=∑k=1Kwki′hk
y
j
=
f
(
u
j
′
)
y_{j} = f(u_{j}^{'} )
yj=f(uj′)
第一个方程是输入层的加权和,输入层的结果将传递给隐藏层。ui是输入层的加权和。第二个方程给出了隐层的激活函数。激活函数hi使用sigmoid函数并生成中间输出。
隐藏层的加权和将传递给输出层,第三个方程显示了隐藏层加权和的计算。u’j是隐藏层的加权和,它将传递到输出层。yj使用隐藏层的加权和,也就是u’j,这里的激活函数也是sigmoid。
我们已经通过使用基本的数学表示法看到了输入和输出的流程。
现在,一个主要的问题是如何使用这个结构来训练Word2vec模型,答案是,我们使用反向传播来训练模型,我们将在下一节中看到。
6.8.5 反向传播算法
我们已经看到了如何使用二级损失函数计算误差,二级损失函数希望最小化估计值和现有目标值之间的平方差。我们将把同样的概念应用于多层神经网络。
因此,我们不仅需要定义损失函数,还需要提取函数的梯度并更新神经网络的权重,以生成最小的误差值。这里,我们的输入和输出是向量。
在计算多层神经网络的误差函数时,您需要非常小心索引,以及计算误差函数值的层。如上图所示,我们将从输出索引开始,将错误反向传播到隐藏层,并更新权重。在第五个等式中,您可以看到我们需要计算输出层的误差函数,以便反向传播误差,我们可以更新输入层的权重。在多层神经网络中,处理索引是一项具有挑战性的任务。但是编码起来很容易,因为您只需要编写一个for循环来计算每个层的渐变。
现在,我们将把word2vec的所有数学方程和概念放在一起,并理解word2vec神经网络的最终数学部分。
6.8.6 word2vec背后的数学理论
在这一节中,我们将结合前面所有的方程和概念来研究数学的最后一部分,并且我们将以概率的形式导出最终方程。在前一节中,我们已经看到了概念和基本直觉、计算和示例,word2vec神经网络层的详细信息。word2vec神经网络使用一个独热编码的字向量作为输入,然后将该向量值传递到下一层,即隐藏层,这只是作为输入,输入到隐藏层的加权和值。最后一个输出层生成向量值,但是为了理解输出,我们将把向量转换成概率格式,并且借助SoftMax技术,我们还将把输出字向量转换成概率格式。在接下来的部分中,我们将看到所有用于从输出向量生成概率的不同技术。
在第一个方程中,我们可以看到输入词向量和权重的加权和,在第二个方程中得到h。我们将h和隐藏层v’wj的字向量的加权和相乘。在这里,重量和指数已经改变了。这个乘法是uj。这里,UJ是激活功能。然后我们将使用uj的值生成概率。所以,最后的方程是SoftMax函数。让我们用输入输出字矢量格式替换第三个方程中的uj来简化方程,然后您将得到最终的方程。
这一次,我们的输出是一个SoftMax函数,所以为了使用反向传播更新权重,我们需要定义损失函数。在这里,我们将以SoftMax函数的形式定义损失函数,所以我们将使用SoftMax函数的负对数概率,然后执行梯度下降。
这里,我想介绍一下输出向量值是如何更新的。所以,它是一个输出层的更新规则。
在这个方程中,我们取原始输出向量,减去输出节点的预测误差ej,h是隐藏层的值。所以,这个方程的意义是,如果我们把单词climbed作为输入,我们想预测单词cat作为输出,那么我们如何更新单词climbed的向量值,使其更接近单词cat的向量?所以在简单的语言中,我们可以说我们将climbed向量的一部分添加到单词cat的向量上,除此之外,我们还需要更新其他单词的输出向量,因为所有不是我们的目标单词的其他单词都应该更新它们的输出向量,以便它们与目标单词的相似性更低。更新输入向量的规则也很有用;更新输入向量的公式如下所示。
这个方程有点复杂。这里,直觉就是输入向量,它将从预测误差的加权和中减去。这意味着,这次,我们要更新输入向量cat。我们将更新单词cat的向量值,使其接近单词climbed的向量。在这里,共同出现的词起着重要的作用。我们几乎完成了word2vec模型的数学部分。在word2vec模型中,我们看到了许多数学方程。现在我们将讨论用于生成最终向量和预测概率的技术。
6.9 生成最终词向量和概率预测结果的技术
在本节中,我们将看到如何生成最终向量。我们也会用一些有效生成输出的启发式方法。所以,我们也将讨论这些启发式方法。
正如我们已经看到的,要生成单词vector,我们还需要更新输入输出向量。假设我们的词汇表中有一百万个单词,那么更新输入和输出向量将花费大量时间,而且效率低下。我们必须解决这个挑战。因此,我们使用一些优化的方法来执行相同的操作
操作和这些技术如下:
分层SoftMax
负抽样
所以,让我们开始了解这些技术。
分层SoftMax
在层次结构的SoftMax中,我们不将每个输出向量映射到相应的单词,而是将输出向量视为二进制树的形式。
所以,这里,输出向量并不是预测这个词的概率,而是预测二叉树中你想要往哪个方向走。所以,要么您想访问这个分支,要么您想访问另一个分支。在这种情况下,考虑到红色激活点向上(这里是浅灰色)和蓝色激活点向下(这里是深灰色),所以你可以看到,在这里,我们可以高概率地预测单词juice。
在这里,优点是,如果您想反向传播一个错误,那么您只需要更新一个输出向量,该错误将传播到预测时激活的三个节点。我们使用哈夫曼二叉树构造来生成二叉树。
负抽样
负抽样也是一种优化方法。在这个方法中,我们将更新输出字的向量,但不更新其他字的所有向量。我们只是从输出向量以外的词中提取样本。因此,我们从负样本单词集中选择一个样本,因此该技术的名称是负样本。
6.10 word2vec相关的一些事情
以下是在实际使用word2vec模型时应记住的一些事实:
-
到目前为止,你会发现word2vec使用神经网络,而这个神经网络不是一个深层的神经网络。它只有两个层次,但是它能很好地发现单词的相似性。
-
word2vec神经网络使用一个简单的逻辑激活函数,不使用非线性函数。
-
隐藏层的激活函数只是线性的,因为它直接将输入的加权和传递给下一层。
现在,我们已经看到了word2vec的几乎所有主要方面,所以在下一节中,我们将介绍word2vec的应用。
6.11 word2vec的应用
依赖关系分析器使用word2vec在解析时生成更好、准确的单词之间的依赖关系。
名称实体识别也可以使用word2vec,因为word2vec非常擅长发现命名实体识别(ner)中的相似性。所有类似的实体都可以聚集在一起,您将获得更好的结果。
情绪分析使用它来保持语义相似性,以产生更好的情绪结果。语义相似度帮助我们了解人们用哪种短语或词来表达自己的观点,在情感分析中使用word2vec概念可以产生很好的洞察力和准确性。
我们还可以构建一个应用程序,通过使用一个人的写作风格来预测他的名字。
如果您希望以高精度和简单的统计信息进行文档分类,那么Word2vec就是为您准备的。您可以使用这个概念并对文档进行分类,而不使用任何人工标签。
词聚类是word2vec的基本产物。所有具有相似含义的词都聚集在一起。
谷歌使用Word2vec和深度学习来改进他们的机器翻译产品。在许多用例中,您可以使用word2vec概念。这里,我们将实现一些有趣的例子。我们将构建有趣的应用程序,并对它们进行可视化处理,这样您就可以更好地理解这个概念。
6.11.1 实现一些简单例子
在这一部分中,我们将实现著名的word2vec示例,即添加女人和国王,减去男人,然后合成向量显示皇后的向量值。我们不打算在我们的数据上训练word2vec模型,然后建立我们自己的word2vec模型,因为有大量的数据是谷歌已经训练了他们的word2vec模型,并为我们提供了预先训练过的模型。现在,如果你想在这么多的数据上复制培训过程,那么我们需要大量的计算资源,所以我们将使用来自谷歌的预先培训过的word2vec模型。您可以从此链接下载预先培训的模型:https://code.google.com/archive/p/Word2vec/
单击此链接后,您需要转到标题为“预训练单词和短语向量”的部分,下载名为GoogleNews-vectors-negative300.bin.gz
我们将使用genism库来构建我们著名的例子。
著名的例子(国王-男人+女人)
from gensim import models
w = models.KeyedVectors.load_word2vec_format(r'E:\Google_data\GoogleNews-vectors-negative300.bin', binary=True)
print('King - man + woman:')
King - man + woman:
print(w.wv.most_similar(positive=['woman', 'king'], negative=['man']))
d:\Program Files\Anaconda3\lib\site-packages\ipykernel\__main__.py:1: DeprecationWarning: Call to deprecated `wv` (Attribute will be removed in 4.0.0, use self instead).
if __name__ == '__main__':
[('queen', 0.7118191719055176), ('monarch', 0.6189674139022827), ('princess', 0.5902431011199951), ('crown_prince', 0.5499460697174072), ('prince', 0.5377321243286133), ('kings', 0.5236844420433044), ('Queen_Consort', 0.5235945582389832), ('queens', 0.5181134343147278), ('sultan', 0.5098593235015869), ('monarchy', 0.5087411403656006)]
print('Similarity between man and woman:')
Similarity between man and woman:
print(w.similarity('woman', 'man'))
0.76640123
现在,如果您想使用由Google提供,然后使用以下链接:https://code.google.com/archive/p/word2vec/。去标题为从何处获取培训数据并下载所有然后,通过从给定的Github链接获取引用来训练数据集
https://github.com/lasseregin/gensim-word2vec-model,您可以复制整个培训过程,但这需要很多时间,因为这种训练需要大量的计算能力。
6.11.2 word2vec的优势
如我们所见,word2vec是一种生成分布相似性的非常好的技术。它还有其他的优点,我在这里列出:
-
word2vec概念真的很容易理解。它们不是那么复杂,以至于你真的不知道幕后发生了什么。
-
使用word2vec很简单,它有非常强大的体系结构。与其他技术相比,训练速度很快。
-
培训的人力投入非常少,因为这里不需要人工标记的数据。
-
这种技术既适用于少量数据集,也适用于大量数据集。所以它是一个易于缩放的模型。
-
一旦您了解了概念和算法,那么您也可以在数据集中复制整个概念和算法。
-
它在捕获语义相似性方面做得非常好。
-
由于这是一种无监督的方法,人类的努力是非常少的,所以这是一种节省时间的方法。
6.11.3 word2vec的挑战
虽然word2vec概念非常有效,但有些地方您可能会觉得复杂或具有挑战性。在这里,我将提出最常见的挑战。这些要点如下:
-
Word2vec模型易于开发,但很难调试,因此在为数据集开发Word2vec模型时,调试能力是主要挑战之一。
-
它不处理歧义。因此,如果一个词有多种含义,在现实世界中我们可以找到许多这样的词,那么在这种情况下,嵌入将反映这些意义在向量空间中的平均值。
6.11.4 在实际应用中使用word2vec
本节将向您介绍哪些类型的NLP应用程序使用word2vec,以及NLP应用程序如何使用此概念。除此之外,我还将在整个社区讨论一些最常见的问题,以便您在现实生活中试用word2vec时对它有一个清晰的了解。
NLP应用如文档分类、情感分析等可以使用Word2vec技术。尤其是在文档分类中,word2vec实现由于保留了语义相似性,所以可以获得更好的结果。
对于情感分析,我们可以应用word2vec,它让您了解单词如何在数据集中分布,然后您可以使用自定义参数,如上下文窗口大小、子采样等。您应该首先生成词袋(bow),然后开始在该bow上训练word2vec并生成单词向量。这些向量可以作为ML算法的输入特征,然后生成情绪分析输出。
现在,是时候讨论一些人们在试图理解和在自己的数据集中使用word2vec技术时通常会问的问题了。- 我们需要什么样的语料库?:word2vec技术可应用于文本数据集。因此,您不能使用任何特定类型的文本数据。因此,根据我的视图,您可以将word2vec应用于任何数据集。
- 我应该经常删除停用词吗?:在google的word2vec原始模型中,删除一些停用词,如word2vec中的a已删除,但该词尚未删除。因此,不必强制删除以下文字:
它完全取决于您的NLP应用程序。如果您正在开发情绪分析应用程序,那么您可以删除所有停止词,但是如果您正在开发机器翻译应用程序,那么您应该删除一些停止词,而不是全部。如果您使用word2vec开发单词集群来理解语言的语法,那么您不应该删除任何单词。
- 我应该删除所有停用词吗?:此问题与上一个问题相关。这个问题的直截了当的答案是否定的。对于每个NLP应用程序,不强制您盲目地删除所有停用词。每个NLP应用程序都是不同的,因此您应该根据尝试构建的NLP应用程序做出决定:
如果你看一下google原来的word2vec模型,你会发现在这个模型中,单词a不存在,这意味着表示单词a的向量不存在,而是表示单词the的向量存在。
- 我们将加载最初的google word2vec模型,使用简单的代码行,我们将了解一些关于停用词的事实。
if 'the' in w.wv.vocab:
print(u"单词the的向量")
print(w.wv['the'])
else:
print(u"词汇表中不包含单词the的向量")
单词the的向量
[ 0.08007812 0.10498047 0.04980469 0.0534668 -0.06738281 -0.12060547
0.03515625 -0.11865234 0.04394531 0.03015137 -0.05688477 -0.07617188
0.01287842 0.04980469 -0.08496094 -0.06347656 0.00628662 -0.04321289
0.02026367 0.01330566 -0.01953125 0.09277344 -0.171875 -0.00131989
0.06542969 0.05834961 -0.08251953 0.0859375 -0.00318909 0.05859375
-0.03491211 -0.0123291 -0.0480957 -0.00302124 0.05639648 0.01495361
-0.07226562 -0.05224609 0.09667969 0.04296875 -0.03540039 -0.07324219
0.03271484 -0.06176758 0.00787354 0.0035553 -0.00878906 0.0390625
0.03833008 0.04443359 0.06982422 0.01263428 -0.00445557 -0.03320312
-0.04272461 0.09765625 -0.02160645 -0.0378418 0.01190186 -0.01391602
-0.11328125 0.09326172 -0.03930664 -0.11621094 0.02331543 -0.01599121
0.02636719 0.10742188 -0.00466919 0.09619141 0.0279541 -0.05395508
0.08544922 -0.03686523 -0.02026367 -0.08544922 0.125 0.14453125
0.0267334 0.15039062 0.05273438 -0.18652344 0.08154297 -0.01062012
-0.03735352 -0.07324219 -0.07519531 0.03613281 -0.13183594 0.00616455
0.05078125 0.04516602 0.0100708 -0.15039062 -0.06005859 0.05761719
-0.00692749 0.01586914 -0.0213623 0.10351562 -0.00029182 -0.046875
-0.01635742 -0.07861328 -0.06933594 0.01635742 -0.03149414 -0.01373291
-0.03662109 -0.08886719 -0.0480957 -0.01318359 -0.07177734 0.00588989
-0.04614258 0.03979492 0.10058594 -0.04931641 0.07568359 0.03881836
-0.16699219 -0.09619141 -0.10107422 0.02905273 -0.05786133 -0.01928711
-0.04296875 -0.08398438 -0.01989746 0.05151367 0.00848389 -0.03613281
-0.14941406 -0.01855469 -0.03637695 -0.07666016 -0.03955078 -0.06152344
-0.02001953 0.04150391 0.03686523 -0.07226562 0.00592041 -0.06298828
0.00738525 -0.01586914 0.01611328 -0.01452637 0.00772095 0.10107422
-0.00558472 0.01428223 -0.07617188 0.05639648 -0.01293945 0.03063965
-0.02490234 -0.09863281 0.0324707 -0.02807617 -0.08105469 0.02062988
0.01611328 -0.04199219 -0.03491211 -0.03759766 0.05493164 0.01373291
0.02685547 -0.05859375 -0.07177734 -0.12011719 -0.02282715 -0.1640625
-0.00361633 -0.05981445 0.07080078 -0.07714844 0.05175781 -0.04296875
-0.04833984 0.0300293 -0.06591797 -0.03173828 -0.04882812 -0.03491211
0.05883789 -0.01464844 0.18066406 0.05688477 0.05249023 0.05786133
0.11669922 0.05200195 -0.0534668 0.01867676 -0.015625 0.00576782
-0.07324219 -0.11621094 0.04052734 0.0625 -0.04321289 0.01055908
0.02172852 0.04248047 0.03271484 0.04418945 0.05761719 0.02612305
-0.01831055 -0.02697754 -0.00674438 0.00509644 -0.11621094 0.00364685
0.05761719 -0.05957031 -0.08837891 0.0135498 0.04541016 -0.04638672
-0.0177002 -0.0625 0.03442383 -0.02416992 0.03088379 0.09570312
0.07958984 0.03930664 0.0279541 -0.0859375 0.08105469 0.06640625
-0.00041962 -0.06933594 0.03588867 -0.03417969 0.04492188 -0.00772095
-0.00741577 -0.04760742 0.01397705 -0.09960938 0.0246582 -0.09960938
0.11474609 0.03173828 0.02209473 0.07226562 0.03686523 0.02563477
0.01367188 -0.02734375 0.00592041 -0.06738281 0.05053711 -0.02832031
-0.04516602 -0.01733398 0.02111816 0.03515625 -0.04296875 0.06640625
0.12207031 0.12353516 0.0039978 0.04516602 -0.01855469 0.04833984
0.04516602 0.08691406 0.02941895 0.03759766 0.03442383 -0.07373047
-0.0402832 -0.14648438 -0.02441406 -0.01953125 0.0065918 -0.0018158
-0.01092529 0.09326172 0.06542969 0.01843262 -0.09326172 -0.01574707
-0.07128906 -0.08935547 -0.07128906 -0.03015137 -0.01300049 0.01635742
-0.01831055 0.01483154 0.00500488 0.00366211 0.04760742 -0.06884766]
d:\Program Files\Anaconda3\lib\site-packages\ipykernel\__main__.py:1: DeprecationWarning: Call to deprecated `wv` (Attribute will be removed in 4.0.0, use self instead).
if __name__ == '__main__':
d:\Program Files\Anaconda3\lib\site-packages\ipykernel\__main__.py:3: DeprecationWarning: Call to deprecated `wv` (Attribute will be removed in 4.0.0, use self instead).
app.launch_new_instance()
if 'a' in w.wv.vocab:
print(u"单词a的向量")
print(w.wv['a'])
else:
print(u"词汇表中不包含单词a的向量")
词汇表中不包含单词a的向量
d:\Program Files\Anaconda3\lib\site-packages\ipykernel\__main__.py:1: DeprecationWarning: Call to deprecated `wv` (Attribute will be removed in 4.0.0, use self instead).
if __name__ == '__main__':
你不认为,这里,我们为每个单词生成了两个向量吗?:我想告诉您,我们已经为每个单词生成了两个向量。这背后的原因是一个句子中的词是来自一个目标词和一个上下文词,所以当一个词作为目标词出现时,我们将生成向量,当一个词作为上下文词出现时,我们也将生成向量。我们在最后的输出中考虑目标词向量,但是可以使用这两个向量。如何使用这两个向量并从中产生意义,这是一个百万美元的问题!
6.11.5 何时使用word2vec
word2vec捕获语义相似性;这是我们在处理前面问题的答案时需要记住的最重要的一点。
如果您有一个要使用分布语义的NLP应用程序,那么word2vec就是为您准备的!一些NLP应用程序将使用此概念生成特征以及word2vec模型的输出向量,或者类似的,向量将用作ml算法的输入特征。
您应该知道哪些NLP应用程序可以使用word2vec。如果您知道应用程序列表,那么就很容易决定是否应该使用它。假设您可以使用k-mean集群进行文档分类;如果您希望文档分类带有一些语义属性,那么可以使用word2vec好。如果你想建立一个问答系统,那么你需要在语义层面上区分问题的技术。由于我们需要一些语义级别的信息,所以可以使用word2vec。
现在,我们已经对概念和理论有了足够的了解,所以我们将开始我们最喜欢的部分,即编码,这次它真的很有趣。
6.11.6 开发一些有意思的东西
在这里,我们将训练我们的word2vec模型。我要使用的数据集是《Game of Thrones》的文本数据。因此,我们的正式目标是开发word2vec来探索A Song of Ice and Fire.实体之间的语义相似性(《Game of Thrones》)。好的部分是,我们还在上面做可视化,以便在实践中更好地理解这个概念。代码包含内联注释,您可以看到输出的片段。我们已经使用了t-sne技术来减少单词向量的尺寸,因此我们可以使用二维向量进行可视化。如果你想在一台2到4 GB RAM的普通计算机上运行t-sne技术需要很多时间。因此,您需要更多的RAM来在您的端成功地运行T-SNE代码,并且如果您有内存限制,您可以跳过可视化部分。您可以看到可视化图像。一旦将模型保存到磁盘上,就可以轻松地使用它并生成输出。我已经给出了图6.41到图6.45中的样本输出。
import codecs
import glob
import logging
import multiprocessing
import os
import pprint
import re
import nltk
import gensim.models.word2vec as w2v
import sklearn.manifold
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
d:\Program Files\Anaconda3\lib\site-packages\gensim\utils.py:855: UserWarning: detected Windows; aliasing chunkize to chunkize_serial
warnings.warn("detected Windows; aliasing chunkize to chunkize_serial")
%pylab inline
Populating the interactive namespace from numpy and matplotlib
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
nltk.download("punkt")
nltk.download("stopwords")
[nltk_data] Downloading package punkt to
[nltk_data] C:\Users\Administrator/nltk_data...
[nltk_data] Package punkt is already up-to-date!
[nltk_data] Downloading package stopwords to
[nltk_data] C:\Users\Administrator/nltk_data...
[nltk_data] Package stopwords is already up-to-date!
True
book_filenames = sorted(glob.glob(".\gameofthrones2vec\data\*.txt"))
print("Found books:")
book_filenames
Found books:
['.\\gameofthrones2vec\\data\\got1.txt',
'.\\gameofthrones2vec\\data\\got2.txt',
'.\\gameofthrones2vec\\data\\got3.txt',
'.\\gameofthrones2vec\\data\\got4.txt',
'.\\gameofthrones2vec\\data\\got5.txt']
corpus_raw = u""
for book_filename in book_filenames:
print("Reading '{0}'...".format(book_filename))
with codecs.open(book_filename, "r", "utf-8") as book_file:
corpus_raw += book_file.read()
print("Corpus is now {0} characters long".format(len(corpus_raw)))
print()
Reading '.\gameofthrones2vec\data\got1.txt'...
Corpus is now 1770659 characters long
Reading '.\gameofthrones2vec\data\got2.txt'...
Corpus is now 4071041 characters long
Reading '.\gameofthrones2vec\data\got3.txt'...
Corpus is now 6391405 characters long
Reading '.\gameofthrones2vec\data\got4.txt'...
Corpus is now 8107945 characters long
Reading '.\gameofthrones2vec\data\got5.txt'...
Corpus is now 9719485 characters long
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
raw_sentences = tokenizer.tokenize(corpus_raw)
#convert into a list of words
#rtemove unnnecessary,, split into words, no hyphens
#list of words
def sentence_to_wordlist(raw):
clean = re.sub("[^a-zA-Z]"," ", raw)
words = clean.split()
return words
#sentence where each word is tokenized
sentences = []
for raw_sentence in raw_sentences:
if len(raw_sentence) > 0:
sentences.append(sentence_to_wordlist(raw_sentence))
print(raw_sentences[5])
print(sentence_to_wordlist(raw_sentences[5]))
Heraldic crest by Virginia Norey.
['Heraldic', 'crest', 'by', 'Virginia', 'Norey']
token_count = sum([len(sentence) for sentence in sentences])
print("The book corpus contains {0:,} tokens".format(token_count))
The book corpus contains 1,818,103 tokens
#ONCE we have vectors
#step 3 - build model
#3 main tasks that vectors help with
#DISTANCE, SIMILARITY, RANKING
# Dimensionality of the resulting word vectors.
#more dimensions, more computationally expensive to train
#but also more accurate
#more dimensions = more generalized
num_features = 300
# Minimum word count threshold.
min_word_count = 3
# Number of threads to run in parallel.
#more workers, faster we train
num_workers = multiprocessing.cpu_count()
# Context window length.
context_size = 7
# Downsample setting for frequent words.
#0 - 1e-5 is good for this
downsampling = 1e-3
# Seed for the RNG, to make the results reproducible.
#random number generator
#deterministic, good for debugging
seed = 1
thrones2vec = w2v.Word2Vec(
sg=1,
seed=seed,
workers=num_workers,
size=num_features,
min_count=min_word_count,
window=context_size,
sample=downsampling
)
thrones2vec.build_vocab(sentences)
2019-01-30 09:45:48,620 : INFO : collecting all words and their counts
2019-01-30 09:45:48,621 : INFO : PROGRESS: at sentence #0, processed 0 words, keeping 0 word types
2019-01-30 09:45:48,658 : INFO : PROGRESS: at sentence #10000, processed 140984 words, keeping 10280 word types
2019-01-30 09:45:48,695 : INFO : PROGRESS: at sentence #20000, processed 279730 words, keeping 13558 word types
2019-01-30 09:45:48,732 : INFO : PROGRESS: at sentence #30000, processed 420336 words, keeping 16598 word types
2019-01-30 09:45:48,766 : INFO : PROGRESS: at sentence #40000, processed 556581 words, keeping 18324 word types
2019-01-30 09:45:48,800 : INFO : PROGRESS: at sentence #50000, processed 686247 words, keeping 19714 word types
2019-01-30 09:45:48,836 : INFO : PROGRESS: at sentence #60000, processed 828497 words, keeping 21672 word types
2019-01-30 09:45:48,875 : INFO : PROGRESS: at sentence #70000, processed 973830 words, keeping 23093 word types
2019-01-30 09:45:48,913 : INFO : PROGRESS: at sentence #80000, processed 1114967 words, keeping 24252 word types
2019-01-30 09:45:48,949 : INFO : PROGRESS: at sentence #90000, processed 1260481 words, keeping 26007 word types
2019-01-30 09:45:48,984 : INFO : PROGRESS: at sentence #100000, processed 1393203 words, keeping 26884 word types
2019-01-30 09:45:49,019 : INFO : PROGRESS: at sentence #110000, processed 1532150 words, keeping 27809 word types
2019-01-30 09:45:49,058 : INFO : PROGRESS: at sentence #120000, processed 1680961 words, keeping 28486 word types
2019-01-30 09:45:49,094 : INFO : collected 29026 word types from a corpus of 1818103 raw words and 128868 sentences
2019-01-30 09:45:49,094 : INFO : Loading a fresh vocabulary
2019-01-30 09:45:49,280 : INFO : min_count=3 retains 17277 unique words (59% of original 29026, drops 11749)
2019-01-30 09:45:49,281 : INFO : min_count=3 leaves 1802699 word corpus (99% of original 1818103, drops 15404)
2019-01-30 09:45:49,377 : INFO : deleting the raw counts dictionary of 29026 items
2019-01-30 09:45:49,379 : INFO : sample=0.001 downsamples 50 most-common words
2019-01-30 09:45:49,380 : INFO : downsampling leaves estimated 1404424 word corpus (77.9% of prior 1802699)
2019-01-30 09:45:49,380 : INFO : estimated required memory for 17277 words and 300 dimensions: 50103300 bytes
2019-01-30 09:45:49,451 : INFO : resetting layer weights
print("Word2Vec vocabulary length:", len(thrones2vec.wv.vocab))
Word2Vec vocabulary length: 17277
thrones2vec.train(sentences,total_examples=thrones2vec.corpus_count)
2019-01-30 09:46:25,278 : INFO : training model with 12 workers on 17277 vocabulary and 300 features, using sg=1 hs=0 sample=0.001 negative=5 window=7
2019-01-30 09:46:26,364 : INFO : PROGRESS: at 2.53% examples, 170184 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:27,405 : INFO : PROGRESS: at 6.25% examples, 207523 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:28,434 : INFO : PROGRESS: at 9.86% examples, 218422 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:29,459 : INFO : PROGRESS: at 13.22% examples, 222304 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:30,490 : INFO : PROGRESS: at 16.56% examples, 221137 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:31,508 : INFO : PROGRESS: at 19.79% examples, 224435 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:32,551 : INFO : PROGRESS: at 23.34% examples, 226202 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:33,556 : INFO : PROGRESS: at 26.84% examples, 227666 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:34,634 : INFO : PROGRESS: at 30.27% examples, 227046 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:35,644 : INFO : PROGRESS: at 33.93% examples, 230248 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:36,658 : INFO : PROGRESS: at 37.22% examples, 228683 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:37,760 : INFO : PROGRESS: at 40.63% examples, 229408 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:38,794 : INFO : PROGRESS: at 43.99% examples, 228968 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:39,814 : INFO : PROGRESS: at 47.76% examples, 230475 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:40,864 : INFO : PROGRESS: at 51.11% examples, 230304 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:41,886 : INFO : PROGRESS: at 54.51% examples, 230532 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:42,890 : INFO : PROGRESS: at 58.06% examples, 231383 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:43,911 : INFO : PROGRESS: at 61.04% examples, 230664 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:44,922 : INFO : PROGRESS: at 64.32% examples, 230181 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:45,968 : INFO : PROGRESS: at 68.38% examples, 231649 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:47,027 : INFO : PROGRESS: at 71.52% examples, 231027 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:48,055 : INFO : PROGRESS: at 74.99% examples, 231102 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:49,069 : INFO : PROGRESS: at 78.27% examples, 230934 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:50,091 : INFO : PROGRESS: at 81.59% examples, 231338 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:51,136 : INFO : PROGRESS: at 84.93% examples, 230955 words/s, in_qsize 24, out_qsize 1
2019-01-30 09:46:52,165 : INFO : PROGRESS: at 88.60% examples, 231030 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:53,203 : INFO : PROGRESS: at 91.86% examples, 231028 words/s, in_qsize 23, out_qsize 0
2019-01-30 09:46:54,246 : INFO : PROGRESS: at 95.57% examples, 231499 words/s, in_qsize 24, out_qsize 0
2019-01-30 09:46:55,252 : INFO : PROGRESS: at 98.96% examples, 231931 words/s, in_qsize 11, out_qsize 1
2019-01-30 09:46:55,254 : INFO : worker thread finished; awaiting finish of 11 more threads
2019-01-30 09:46:55,305 : INFO : worker thread finished; awaiting finish of 10 more threads
2019-01-30 09:46:55,340 : INFO : worker thread finished; awaiting finish of 9 more threads
2019-01-30 09:46:55,345 : INFO : worker thread finished; awaiting finish of 8 more threads
2019-01-30 09:46:55,379 : INFO : worker thread finished; awaiting finish of 7 more threads
2019-01-30 09:46:55,380 : INFO : worker thread finished; awaiting finish of 6 more threads
2019-01-30 09:46:55,383 : INFO : worker thread finished; awaiting finish of 5 more threads
2019-01-30 09:46:55,424 : INFO : worker thread finished; awaiting finish of 4 more threads
2019-01-30 09:46:55,439 : INFO : worker thread finished; awaiting finish of 3 more threads
2019-01-30 09:46:55,444 : INFO : worker thread finished; awaiting finish of 2 more threads
2019-01-30 09:46:55,450 : INFO : worker thread finished; awaiting finish of 1 more threads
2019-01-30 09:46:55,468 : INFO : worker thread finished; awaiting finish of 0 more threads
2019-01-30 09:46:55,469 : INFO : training on 9090515 raw words (7021952 effective words) took 30.1s, 232918 effective words/s
7021952
if not os.path.exists("trained"):
os.makedirs("trained")
thrones2vec.save(os.path.join("trained", "thrones2vec.w2v"))
2019-01-30 09:48:45,205 : INFO : saving Word2Vec object under trained\thrones2vec.w2v, separately None
2019-01-30 09:48:45,206 : INFO : not storing attribute syn0norm
2019-01-30 09:48:45,207 : INFO : not storing attribute cum_table
2019-01-30 09:48:45,891 : INFO : saved trained\thrones2vec.w2v
thrones2vec = w2v.Word2Vec.load(os.path.join("trained", "thrones2vec.w2v"))
2019-01-30 09:48:56,118 : INFO : loading Word2Vec object from trained\thrones2vec.w2v
2019-01-30 09:48:56,463 : INFO : loading wv recursively from trained\thrones2vec.w2v.wv.* with mmap=None
2019-01-30 09:48:56,463 : INFO : setting ignored attribute syn0norm to None
2019-01-30 09:48:56,464 : INFO : setting ignored attribute cum_table to None
2019-01-30 09:48:56,465 : INFO : loaded trained\thrones2vec.w2v
tsne = sklearn.manifold.TSNE(n_components=2, random_state=0)
all_word_vectors_matrix = thrones2vec.wv.syn0
all_word_vectors_matrix_2d = tsne.fit_transform(all_word_vectors_matrix)
points = pd.DataFrame(
[
(word, coords[0], coords[1])
for word, coords in [
(word, all_word_vectors_matrix_2d[thrones2vec.vocab[word].index])
for word in thrones2vec.vocab
]
],
columns=["word", "x", "y"]
)
points.head(10)
word | x | y | |
---|---|---|---|
0 | bales | -4.374798 | -3.460205 |
1 | everyone | 4.483074 | 2.357007 |
2 | dumping | -1.916285 | -1.344550 |
3 | Twelve | 0.498883 | 1.097254 |
4 | Norvos | -5.129789 | -0.927183 |
5 | gallows | -4.279059 | 0.271438 |
6 | truculent | 0.002145 | 1.444465 |
7 | Todric | -2.223365 | -2.191449 |
8 | adding | -1.848638 | -1.437703 |
9 | robes | 1.226944 | -4.097425 |
sns.set_context("poster")
points.plot.scatter("x", "y", s=10, figsize=(20, 12))
<matplotlib.axes._subplots.AxesSubplot at 0x50104860>
def plot_region(x_bounds, y_bounds):
slice = points[
(x_bounds[0] <= points.x) &
(points.x <= x_bounds[1]) &
(y_bounds[0] <= points.y) &
(points.y <= y_bounds[1])
]
ax = slice.plot.scatter("x", "y", s=35, figsize=(10, 8))
for i, point in slice.iterrows():
ax.text(point.x + 0.005, point.y + 0.005, point.word, fontsize=11)
plot_region(x_bounds=(4.0, 4.2), y_bounds=(-1.5, -0.1))
plot_region(x_bounds=(0, 1), y_bounds=(1, 2.5))
thrones2vec.wv.most_similar("Stark")
[('Eddard', 0.761224091053009),
('Lyanna', 0.6482791304588318),
('Winterfell', 0.6433993577957153),
('Brandon', 0.6370483636856079),
('Robb', 0.632075309753418),
('Karstark', 0.6203835606575012),
('Arryn', 0.6174726486206055),
('Benjen', 0.6107982397079468),
('direwolf', 0.6078931093215942),
('Hornwood', 0.6060791015625)]
thrones2vec.most_similar("Aerys")
[('Daeron', 0.7696206569671631),
('Jaehaerys', 0.7633997797966003),
('Mad', 0.7595773339271545),
('reign', 0.7406856417655945),
('Rhaegar', 0.7307367324829102),
('Unworthy', 0.724441409111023),
('appointment', 0.7096531987190247),
('II', 0.7020297050476074),
('knighthood', 0.7015577554702759),
('Beggar', 0.6977512240409851)]
thrones2vec.most_similar("direwolf")
[('wolf', 0.6931310296058655),
('Rickon', 0.6445047855377197),
('Ghost', 0.6442906856536865),
('pup', 0.6380815505981445),
('SHAGGYDOG', 0.6200188994407654),
('eagle', 0.6114967465400696),
('GHOST', 0.6096920371055603),
('Stark', 0.6078931093215942),
('wight', 0.6035048365592957),
('crannogman', 0.5946488976478577)]
def nearest_similarity_cosmul(start1, end1, end2):
similarities = thrones2vec.most_similar_cosmul(
positive=[end2, start1],
negative=[end1]
)
start2 = similarities[0][0]
print("{start1} is related to {end1}, as {start2} is related to {end2}".format(**locals()))
return start2
nearest_similarity_cosmul("Stark", "Winterfell", "Riverrun")
nearest_similarity_cosmul("Jaime", "sword", "wine")
nearest_similarity_cosmul("Arya", "Nymeria", "dragons")
Stark is related to Winterfell, as Tully is related to Riverrun
Jaime is related to sword, as mulled is related to wine
Arya is related to Nymeria, as Dany is related to dragons
'Dany'
6.11.7 练习
在本练习中,您需要从《哈利波特》一书的文本数据中生成Word2vec。
6.12 word2vec概念的扩展
word2vec概念可以扩展到不同的文本级别。这个概念可以应用于段落级别或文档级别,除此之外,还可以生成全局向量,称为glove。我们会努力去理解他们。在这里,我们将得到每个概念的概述。
下面是使用word2vec概念构建的以下扩展概念:
Para2vec
Doc2vec
GloVe
6.12.1 para2vec
para2vec代表段落向量。段落向量是一种使用固定长度特征表示的无监督算法。它从可变长度的文本(如句子、段落和文档)中派生出这种特征表示。
利用神经网络可以导出para2vec。大多数方面与word2vec相同。通常,三个上下文词被考虑并输入神经网络。然后,神经网络试图预测第四个上下文词。在这里,我们试图最大化日志概率,预测任务通常是通过一个多类分类器执行的。我们使用的函数是SoftMax。
请注意,这里的上下文是固定长度的,并通过在段落上使用滑动窗口生成上下文单词。段落向量与从同一段落生成的所有上下文共享,但不跨段落共享。
para2vec的优点是学会从未标记的数据中预测单词,以便在没有足够的标记数据集时使用这些技术。
6.12.2 doc2vec
doc2vec(文档向量)是word2vec的扩展。它学习将文档标签和单词关联起来,而不是将单词与其他单词关联起来。这里,您需要文档标签。您可以使用固定长度的向量表示整个句子。这也使用了word2vec概念。如果将带有标签的句子输入神经网络,那么它将对给定的数据集进行分类。因此,简而言之,您标记文本,然后使用这个标记的数据集作为输入,并对给定的数据集应用doc2vec技术。该算法将为给定的文本生成标记向量。
import logging
import gensim.models as g
import codecs
# doc2vec parameters
vector_size = 300
window_size = 15
min_count = 1
sampling_threshold = 1e-5
negative_size = 5
train_epoch = 100
dm = 0 # 0 = dbow; 1 = dmpv
worker_count = 1 # number of parallel processes
# pretrained word embeddings
pretrained_emb = "./doc2vecdata/pretrained_word_embeddings.txt"
# None if use without pretrained embeddings
# input corpus
train_corpus = "./doc2vecdata/train_docs.txt"
# output model
saved_path = "./doc2vecdata/model.bin"
# enable logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
# train doc2vec model
docs = g.doc2vec.TaggedLineDocument(train_corpus)
model = g.Doc2Vec(docs, size=vector_size, window=window_size, min_count=min_count, sample=sampling_threshold,
workers=worker_count, hs=0, dm=dm, negative=negative_size, dbow_words=1, dm_concat=1,
iter=train_epoch)
# save model
model.save(saved_path)
print("training is over....!\n" )
print("testing started....!\n")
#parameters
model="./doc2vecdata/model.bin"
test_docs="./doc2vecdata/test_docs.txt"
output_file="./doc2vecdata/test_vectors.txt"
#inference hyper-parameters
start_alpha=0.01
infer_epoch=1000
#load model
m = g.Doc2Vec.load(model)
print(m.wv.most_similar(positive=['family', 'dog']))
test_docs = [ x.strip().split() for x in codecs.open(test_docs, "r", "utf-8").readlines() ]
#infer test vectors
output = open(output_file, "w")
for d in test_docs:
output.write( " ".join([str(x) for x in m.infer_vector(d, alpha=start_alpha, steps=infer_epoch)]) + "\n" )
output.flush()
output.close()
2019-01-30 10:18:45,778 : INFO : collecting all words and their counts
2019-01-30 10:18:45,784 : INFO : PROGRESS: at example #0, processed 0 words (0/s), 0 word types, 0 tags
2019-01-30 10:18:45,822 : INFO : collected 11097 word types and 1000 unique tags from a corpus of 1000 examples and 84408 words
2019-01-30 10:18:45,822 : INFO : Loading a fresh vocabulary
2019-01-30 10:18:45,861 : INFO : min_count=1 retains 11097 unique words (100% of original 11097, drops 0)
2019-01-30 10:18:45,861 : INFO : min_count=1 leaves 84408 word corpus (100% of original 84408, drops 0)
2019-01-30 10:18:45,939 : INFO : deleting the raw counts dictionary of 11097 items
2019-01-30 10:18:45,940 : INFO : sample=1e-05 downsamples 3599 most-common words
2019-01-30 10:18:45,941 : INFO : downsampling leaves estimated 22704 word corpus (26.9% of prior 84408)
2019-01-30 10:18:45,941 : INFO : estimated required memory for 11097 words and 300 dimensions: 33381300 bytes
2019-01-30 10:18:45,978 : INFO : resetting layer weights
2019-01-30 10:18:46,293 : INFO : training model with 1 workers on 11098 vocabulary and 300 features, using sg=1 hs=0 sample=1e-05 negative=5 window=15
2019-01-30 10:18:46,293 : INFO : expecting 1000 sentences, matching count from corpus used for vocabulary survey
2019-01-30 10:18:47,313 : INFO : PROGRESS: at 1.29% examples, 30252 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:48,363 : INFO : PROGRESS: at 2.59% examples, 29776 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:49,441 : INFO : PROGRESS: at 4.00% examples, 30092 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:50,442 : INFO : PROGRESS: at 5.29% examples, 30218 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:51,448 : INFO : PROGRESS: at 6.59% examples, 30309 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:18:52,524 : INFO : PROGRESS: at 8.00% examples, 30397 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:18:53,528 : INFO : PROGRESS: at 9.29% examples, 30432 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:54,531 : INFO : PROGRESS: at 10.59% examples, 30445 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:55,555 : INFO : PROGRESS: at 11.89% examples, 30369 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:56,561 : INFO : PROGRESS: at 13.14% examples, 30371 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:57,561 : INFO : PROGRESS: at 14.48% examples, 30433 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:18:58,580 : INFO : PROGRESS: at 15.76% examples, 30362 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:18:59,623 : INFO : PROGRESS: at 17.04% examples, 30291 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:00,661 : INFO : PROGRESS: at 18.36% examples, 30258 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:01,696 : INFO : PROGRESS: at 19.64% examples, 30196 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:02,723 : INFO : PROGRESS: at 20.96% examples, 30167 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:03,747 : INFO : PROGRESS: at 22.23% examples, 30160 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:04,779 : INFO : PROGRESS: at 23.54% examples, 30144 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:19:05,783 : INFO : PROGRESS: at 24.83% examples, 30155 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:06,801 : INFO : PROGRESS: at 26.10% examples, 30158 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:07,834 : INFO : PROGRESS: at 27.43% examples, 30145 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:08,868 : INFO : PROGRESS: at 28.71% examples, 30109 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:09,906 : INFO : PROGRESS: at 30.00% examples, 30080 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:10,940 : INFO : PROGRESS: at 31.29% examples, 30067 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:11,977 : INFO : PROGRESS: at 32.59% examples, 30054 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:13,008 : INFO : PROGRESS: at 33.89% examples, 30036 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:14,050 : INFO : PROGRESS: at 35.14% examples, 30016 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:15,053 : INFO : PROGRESS: at 36.48% examples, 30047 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:16,134 : INFO : PROGRESS: at 37.89% examples, 30067 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:17,138 : INFO : PROGRESS: at 39.14% examples, 30084 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:19:18,221 : INFO : PROGRESS: at 40.59% examples, 30112 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:19,307 : INFO : PROGRESS: at 42.00% examples, 30129 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:20,312 : INFO : PROGRESS: at 43.29% examples, 30147 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:21,395 : INFO : PROGRESS: at 44.72% examples, 30170 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:22,483 : INFO : PROGRESS: at 46.10% examples, 30187 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:23,563 : INFO : PROGRESS: at 47.54% examples, 30216 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:24,635 : INFO : PROGRESS: at 48.96% examples, 30240 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:19:25,714 : INFO : PROGRESS: at 50.36% examples, 30266 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:26,775 : INFO : PROGRESS: at 51.76% examples, 30288 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:27,781 : INFO : PROGRESS: at 53.04% examples, 30297 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:28,873 : INFO : PROGRESS: at 54.48% examples, 30314 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:29,948 : INFO : PROGRESS: at 55.89% examples, 30327 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:30,949 : INFO : PROGRESS: at 57.14% examples, 30335 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:32,029 : INFO : PROGRESS: at 58.59% examples, 30354 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:33,099 : INFO : PROGRESS: at 60.00% examples, 30372 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:34,184 : INFO : PROGRESS: at 61.43% examples, 30394 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:35,251 : INFO : PROGRESS: at 62.83% examples, 30405 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:36,329 : INFO : PROGRESS: at 64.23% examples, 30421 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:19:37,392 : INFO : PROGRESS: at 65.64% examples, 30445 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:38,465 : INFO : PROGRESS: at 67.04% examples, 30455 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:39,543 : INFO : PROGRESS: at 68.48% examples, 30473 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:40,600 : INFO : PROGRESS: at 69.89% examples, 30492 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:41,603 : INFO : PROGRESS: at 71.14% examples, 30495 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:42,676 : INFO : PROGRESS: at 72.59% examples, 30513 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:43,751 : INFO : PROGRESS: at 74.00% examples, 30523 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:44,818 : INFO : PROGRESS: at 75.43% examples, 30544 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:45,880 : INFO : PROGRESS: at 76.83% examples, 30555 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:46,940 : INFO : PROGRESS: at 78.23% examples, 30574 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:47,984 : INFO : PROGRESS: at 79.64% examples, 30598 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:19:49,036 : INFO : PROGRESS: at 81.04% examples, 30616 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:50,043 : INFO : PROGRESS: at 82.36% examples, 30621 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:51,097 : INFO : PROGRESS: at 83.76% examples, 30634 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:52,098 : INFO : PROGRESS: at 85.04% examples, 30638 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:53,175 : INFO : PROGRESS: at 86.48% examples, 30650 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:54,259 : INFO : PROGRESS: at 87.89% examples, 30651 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:55,327 : INFO : PROGRESS: at 89.29% examples, 30662 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:56,381 : INFO : PROGRESS: at 90.72% examples, 30676 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:57,465 : INFO : PROGRESS: at 92.10% examples, 30680 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:58,547 : INFO : PROGRESS: at 93.54% examples, 30689 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:19:59,621 : INFO : PROGRESS: at 94.96% examples, 30694 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:20:00,627 : INFO : PROGRESS: at 96.23% examples, 30693 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:20:01,680 : INFO : PROGRESS: at 97.64% examples, 30709 words/s, in_qsize 1, out_qsize 0
2019-01-30 10:20:02,747 : INFO : PROGRESS: at 99.04% examples, 30716 words/s, in_qsize 2, out_qsize 0
2019-01-30 10:20:03,478 : INFO : worker thread finished; awaiting finish of 0 more threads
2019-01-30 10:20:03,479 : INFO : training on 8440800 raw words (2370696 effective words) took 77.2s, 30715 effective words/s
2019-01-30 10:20:03,479 : INFO : saving Doc2Vec object under ./doc2vecdata/model.bin, separately None
2019-01-30 10:20:03,480 : INFO : not storing attribute syn0norm
2019-01-30 10:20:03,480 : INFO : not storing attribute cum_table
2019-01-30 10:20:03,917 : INFO : saved ./doc2vecdata/model.bin
2019-01-30 10:20:03,922 : INFO : loading Doc2Vec object from ./doc2vecdata/model.bin
training is over....!
testing started....!
2019-01-30 10:20:04,180 : INFO : loading docvecs recursively from ./doc2vecdata/model.bin.docvecs.* with mmap=None
2019-01-30 10:20:04,180 : INFO : loading wv recursively from ./doc2vecdata/model.bin.wv.* with mmap=None
2019-01-30 10:20:04,181 : INFO : setting ignored attribute syn0norm to None
2019-01-30 10:20:04,182 : INFO : setting ignored attribute cum_table to None
2019-01-30 10:20:04,182 : INFO : loaded ./doc2vecdata/model.bin
2019-01-30 10:20:04,210 : INFO : precomputing L2-norms of word weight vectors
[('bag', 0.7747215628623962), ('harp', 0.7731959223747253), ('harmonica', 0.7725900411605835), ('plum', 0.7714046239852905), ('burlap', 0.7702646851539612), ('peach', 0.7702361345291138), ('clingstone', 0.7696243524551392), ('tow', 0.7680270075798035), ('andirons', 0.7678180932998657), ('feeder', 0.7667309045791626)]
6.12.3 doc2vec的应用
使用doc2vec可以很容易地实现文档聚类
我们可以对较大的文本数据块执行情绪分析,我想您可以考虑很大的文本块,并为较大的文本块生成情绪输出。
它也用于产品推荐
6.12.4 GloVe
Glove代表全局向量。手套是一种无监督的学习算法。此算法生成单词的矢量表示。这里,通过使用聚合的全局单词共现矩阵和来自语料库的其他统计信息来执行培训,并且由此产生的表示为单词向量空间提供了有趣的线性子结构。因此,共现矩阵是Glove的输入。Glove使用余弦相似性或欧几里得距离来获得相似词的概念。如果你采取最近的邻居,那么你可以看到这样的词汇,是非常罕见的,在他们频繁使用。Glove仍然可以在相似的串中捕捉到这些罕见的词。让我们来看一个著名的例子:
例如,当我们有目标单词frog时,下面是最接近的单词:
Frog
Frogs
Toad
Litoria
Leptodactylidae
Rana
Lizard
Eleutherodactylus
另一个例子是与聚集在一起的比较最高级形式相关的单词,如果使用可视化工具,您可以看到以下输出。
import itertools
from gensim.models.word2vec import Text8Corpus
from glove import Corpus, Glove
# for installing text8 corpus you should follow this commands
# wget http://mattmahoney.net/dc/text8.zip -P /tmp
# unzip text8.zip
sentences = list(itertools.islice(Text8Corpus('text8'), None))
corpus = Corpus()
corpus.fit(sentences, window=10)
glove = Glove(no_components=100, learning_rate=0.05)
glove.fit(corpus.matrix, epochs=30, no_threads=8, verbose=True)
glove.add_dictionary(corpus.dictionary)
print(glove.most_similar('frog', number=10))
print(glove.most_similar('girl', number=10))
print(glove.most_similar('car', number=10))
Performing 30 training epochs with 8 threads
Epoch 0
Epoch 1
Epoch 2
Epoch 3
Epoch 4
Epoch 5
Epoch 6
Epoch 7
Epoch 8
Epoch 9
Epoch 10
Epoch 11
Epoch 12
Epoch 13
Epoch 14
Epoch 15
Epoch 16
Epoch 17
Epoch 18
Epoch 19
Epoch 20
Epoch 21
Epoch 22
Epoch 23
Epoch 24
Epoch 25
Epoch 26
Epoch 27
Epoch 28
Epoch 29
[('giant', 0.6836798611154555), ('shark', 0.6833859114687076), ('dome', 0.6727507074384271), ('cerebral', 0.6604029901658698), ('mysterious', 0.6497938986040399), ('moth', 0.6467772645531514), ('panda', 0.6403929027919639), ('frontalis', 0.6390234745914105), ('feresa', 0.6369013795142578)]
[('young', 0.7749116843490816), ('man', 0.7581912061764434), ('woman', 0.7401628699886873), ('wise', 0.7079582873401654), ('baby', 0.7041182102677449), ('spider', 0.7010923126174493), ('boy', 0.6773506568995419), ('girls', 0.6711925917518561), ('boys', 0.6587910674726931)]
[('driver', 0.8947171264186013), ('race', 0.8595923421869935), ('taxi', 0.772452822136707), ('cars', 0.7406445557519962), ('touring', 0.704436577338735), ('racing', 0.6908868050601202), ('crash', 0.6845369759552499), ('accident', 0.6839008273019639), ('vehicle', 0.6405130836423941)]
6.12.5 练习
这个练习对你来说更像是阅读练习。你应该阅读关于para2vec、doc2vec和glove的研究论文。除此之外,您还可以检查是否有任何方法可以找到连续字符串的向量表示,例如DNA模式。本练习的主要目的是让您了解研究工作是如何完成的。您还可以考虑向量表示的其他一些方面,并尝试解决这些挑战。
6.13 深度学习中向量化的重要性
从我的角度来看,这更像是与你的讨论。众所周知,计算机不能直接理解nl,所以我们需要将nl输出转换为数字格式。我们有各种嵌入技术,以及一些基本的统计技术,如索引、tf-idf、一个独热编码等。通过使用所有这些技术或其中一些技术,您可以将文本输入转换为数字格式。您选择的技术完全取决于NLP应用程序。所以,我们为什么要把nl输入转换成数字格式,背后有两个要点。这基本上是因为计算机只能理解数字数据,所以我们必须将文本数据转换为数字数据,计算机非常擅长对给定的数字数据进行计算。当我们转换文本数据时,我想到了两个要点。
让我们了解什么是深度学习。在这里,我想给你一个简单的想法。别担心,我们将在第9章深入学习NLU和NLG问题中看到更多细节。当一个神经网络有多层深时,称为深层神经网络。当我们使用许多分层的深层神经网络,并使用它们来开发使用大量数据和大量计算能力的NLP应用程序时,这被称为深度学习。
现在我们来谈谈矢量化。矢量化是一个坚实的数学概念,容易理解和处理。现在,当我们想要处理高维向量形式的数据时,python有很多好的库,可以让我们的生活更轻松。深度学习模式很大程度上依赖于矢量化和矩阵概念,因此为了更好地掌握深度学习,您应该了解向量和矩阵。处理输入数据(如视频或音频)的深度学习应用程序也使用向量。视频和图像被转换成密集的矢量格式,当讨论文本输入时,word2vec是从单词生成矢量的基本构建块。Google TensorFlow使用Word2vec作为其基本构建块,它使用这些概念并改进了Google机器翻译、Google语音识别和Google视觉应用程序的结果。因此,向量和矩阵给了我们很大的自由,在它们的处理和意义上。
除此之外,我还需要给你一些想法。我想让你关注我们如何即兴发挥处理文本的方式。毫无疑问,word2vec是将单词转换为矢量形式的最简单、最有效的方法之一,但我肯定会鼓励对研究工作感兴趣的读者将这一概念扩展到他们的母语中,或成为创造性的,并有助于构建非常有创新性的技术,帮助NLP社区实现一些挑战,如歧义词。好吧,这些都是我对你的想法!
6.14 总结
在本章中,我们已经了解了如何使用word2vec来查找语义。简单的矢量化技术对我们有很大帮助。我们已经看到了它的一些应用。我们已经讨论了word2vec模型的技术特性。我向您介绍了许多新的数学术语和统计术语,以便让您更好地了解模型。我们已经将word2vec黑盒转换为word2vec白盒。为了更好地理解,我还实现了基本的和扩展的示例。我们使用了大量的库和API来开发Word2vec模型。我们也看到了在深度学习中进行矢量化的优势。然后,我们扩展了对Word2vec的理解,发展了Para2vec、Doc2vec和Glove的概念。下一章将基本上给你一个关于如何使用基于规则的技术来开发NLP应用程序,以及各种NLP应用程序如何使用一种非常简单但非常有效的技术,称为规则或逻辑来为NLP应用程序开发基本而有效的原型。谷歌在他们的机器翻译项目中使用了基于规则的技术,苹果也使用了这一技术,最后,但并非最不重要的是,谷歌使用了基于规则的系统来制作他们的自动驾驶汽车的早期原型。我们将讨论基于规则的系统及其体系结构。我们还将看到基于规则的NLP应用程序的体系结构是什么。我将为您提供一个思想过程,通过使用这个思想过程,您还可以为您的NLP应用程序制定规则。我们将实现基本的语法规则和基于模式的规则。我们还将从头开始开发一个基于模板的基本聊天机器人。
致谢
《Python自然语言处理》1 2 3,作者:【印】雅兰·萨纳卡(Jalaj Thanaki),是实践性很强的一部新作。为进一步深入理解书中内容,对部分内容进行了延伸学习、练习,在此分享,期待对大家有所帮助,欢迎加我微信(验证:NLP),一起学习讨论,不足之处,欢迎指正。
参考文献