《TensorFlow自然语言处理》—3.4.2 使用神经网络学习词嵌入

举报
华章计算机 发表于 2019/07/21 22:02:33 2019/07/21
【摘要】 本节书摘来自华章计算机《TensorFlow自然语言处理》一书中的第3章,第3.4.2节,[澳] 图珊·加内格达拉(Thushan Ganegedara) 著 马恩驰 陆 健 译。

3.4.2 使用神经网络学习词嵌入

一旦数据是(输入,输出)格式,我们就可以使用神经网络来学习词嵌入。首先,让我们确定学习词嵌入所需的变量。为了存储词嵌入,我们需要一个V×D矩阵,其中V是词汇量大小,D是词嵌入的维度(即向量中表示单个单词的元素数量)。D是用户定义的超参数,D越大,学习到的词嵌入表达力越强。该矩阵将被称为嵌入空间或嵌入层。

接下来,我们有一个softmax层,其权重大小为D×V,偏置大小为V.

每个词将被表示为大小为V的独热编码向量,其中一个元素为1,所有其他元素为0。因此,输入单词和相应的输出单词各自的大小为V。让我们把第i个输入记为xi,xi的对应嵌入为zi,对应的输出为yi。

此时,我们定义了所需的变量。接下来,对于每个输入xi,我们将从对应于输入的嵌入层中查找嵌入向量。该操作向我们提供zi,它是大小为D的向量(即长度为D的嵌入向量)。然后,我们做以下转换以计算xi的预测输出:

 image.png

这里,logit(xi)表示非标准化分数(即logits),i是V大小的预测输出(表示输出是V大小的词汇表的单词的概率),W是D×V权重矩阵,b是V×1偏置矢量,softmax是softmax激活。我们将可视化skip-gram模型的概念(图3.7)和实现(图3.8)图。以下是符号的总结:

  • V:这是词汇量的大小

  • D:这是嵌入层的维度

  • xi:这是第i个输入单词,表示为独热编码向量

  • zi:这是与第i个输入单词对应的嵌入(即表示)向量

  • yi:这是与xi对应的输出单词的独热编码向量

  • i:这是xi的预测输出

  • logit(xi):这是输入xi的非标准化得分

  • Ⅱwj:这是单词wj的独热编码表示

  • W:这是softmax权重矩阵

  • b:这是softmax的偏置

通过使用现有单词和计算得到的实体,我们现在可以使用负对数似然损失函数来计算给定数据点(xi,yi)的损失。如果你想知道P(wj | wi)是什么,它可以从已定义的实体派生出来。接下来,让我们讨论如何从i计算P(wj | wi)并得到一个正式的定义。

 image.png

图3.7 skip-gram模型的概念图

 image.png

图3.8 skip-gram模型的实现图

为什么原始的词嵌入论文使用两个嵌入层

原始论文(由Mikolov和其他人于2013年发表)使用两个不同的V×D嵌入空间来表示目标空间中的单词(用作目标时的单词)和上下文空间中的单词(用作上下文的单词)。这样做的一个动机是,同一个单词通常不会出现在自身的上下文中。因此,我们希望尽可能减少此类事件发生的可能性。例如,对于目标单词dog,在其上下文中不太可能找到单词dog(P(dog | dog)~0)。直觉上,如果我们将(xi = dog和yi = dog)数据点提供给神经网络,如果神经网络将dog预测为dog的上下文单词,我们就要求神经网络给出更高的损失。换句话说,我们要求单词dog的词嵌入与单词dog的词嵌入距离非常远。这会产生一个强烈的矛盾,因为相同词嵌入之间的距离将为0。因此,如果我们只有一个嵌入空间,我们就无法实现这一点。但是,为目标词和上下文词提供两个单独的嵌入空间就允许我们拥有此属性,因为这样一来同一个单词就有两个单独的嵌入向量。但是,实际上,只要你避免在输入输出元组中输入和输出是同一个词,使就可以使用单个嵌入空间,并且无须使用两个不同的嵌入层。

3.4.2.1 制定实际的损失函数

让我们更仔细地查看我们的损失函数。我们得出的损失应该如下所示:

 image.png

但是,根据我们目前掌握的信息,计算这一特定损失并不是很容易。

首先,让我们理解P(wj | wi)代表什么。为此,我们将从单个单词表示法转为单个数据点表示法。也就是说,我们会说P(wj | wi)由第n个数据点给出,其中wi的独热编码向量作为输入(xn),wj的独热编码表示作为真实输出(yn)。这由以下等式给出:

 image.png

logit(xn)项表示给定输入xn获得的非标准化预测得分(即logit)向量(V大小),而logit(xn)wj是wj的独热编码表示中非零的索引所对应的得分值(从现在开始我们称之为wj的索引)。然后,我们将wj索引处的logit值相对于整个词汇表中所有单词所对应的所有logit值进行标准化。这种特定类型的归一化称为softmax激活(或归一化)。现在,通过将其转换为对数空间,我们得到以下等式:

 image.png

为了有效地计算logit函数,我们可以调整变量,得出以下表示法:

 image.png

这里,Ⅱwj是wj的独热编码向量。现在,logit操作缩减为对乘积求和。由于对应于单词wj,Ⅱwj仅有一个非零元素,因此在计算中将仅使用向量的该索引。这比通过扫描词汇量大小的向量找到对应于非零元素的索引的logit向量中的值更有计算效率。

现在,通过将我们获得的计算赋给logit,对于损失函数,我们得到以下结果:

 image.png

让我们考虑一个例子来理解这个计算:

 image.png

我们可以如下创建输入输出元组:

 image.png

现在,我们为上面的单词假定以下独热编码表示:

 image.png

接下来,让我们考虑输入输出元组(like,I)。当我们通过skip-gram学习模型传播输入like时,让我们假设我们按该顺序获得了Like、I和NLP这些的单词的以下logit:

 image.png

现在,词汇表中每个单词的softmax输出如下所示:

 image.png

上面的损失函数表明我们需要最大化P(I | like)以使损失最小化。现在让我们将这个例子应用于这个损失函数:

 image.png

有了这个损失函数,对于减号之前的项,y向量中只有一个非零元素对应于单词I,因此,我们只考虑概率P(I | like),这就是我们要的。

但是,这不是我们想要的理想解决方案。从实际角度来看,该损失函数的目标是,使预测给定单词的上下文单词的概率最大化,同时使预测给出单词的“所有”非上下文单词的概率最小化。我们很快就会发现,有一个良好定义的损失函数并不能在实践中有效地解决我们的问题,我们需要设计一个更聪明的近似损失函数,来在可行的时间内学习良好的词嵌入。

3.4.2.2 有效的近似损失函数

我们很幸运有一个在数学上和感觉上都很正确的损失函数,但是,困难并没有就此结束。如果我们像前面讨论的那样尝试以封闭形式计算损失函数,我们将不可避免地面对算法执行得非常缓慢的问题,这种缓慢是由于词汇量大而导致的性能瓶颈。我们来看看我们的损失函数:

 image.png

你会看到计算单个示例的损失需要计算词汇表中所有单词的logit。与通过数百个输出类别就足以解决大多数现有的真实问题的计算机视觉问题不同,skip-gram并不具备这些特性。因此,我们需要在不失去模型效果的前提下寻找有效的损失近似方案。

我们将讨论两种主流的近似选择:

  • 负采样

  • 分层softmax

(1)对softmax层进行负采样

在这里,我们将讨论第一种方法:对softmax层进行负采样。负采样是对噪声对比估计(NCE)方法的近似。NCE要求,一个好的模型应该通过逻辑回归来区分数据和噪声。

考虑到这个属性,让我们重新设计学习词嵌入的目标。我们不需要完全概率模型,该模型对给定单词给出词汇表中所有单词的确切概率。我们需要的是高质量的词向量。因此,我们可以简化我们的问题,将其变为区分实际数据(即输入输出对)与噪声(即K个虚拟噪声输入输出对)。噪声指的是使用不属于给定单词的上下文的单词所创建的错误输入输出对。我们还将摆脱softmax激活,并将其替换为sigmoid激活(也称为逻辑函数)。这使得我们能够在使输出保持在[0,1]之间的同时,消除损失函数对完整词汇表的依赖。我们可以可视化图3.9中的负采样过程。

 image.png

图3.9 负采样处理

确切地说,我们的原始损失函数由以下等式给出:

 image.png

之前的等式变为:

 image.png

这里,σ表示sigmoid激活,其中σ (x) = 1/(1 + exp (- x))。请注意,为了清楚起见,我在原始损失函数中用log(exp(logit(xn)wj))替换了logit(xn)wj。你可以看到新的损失函数仅取决于与词汇表中的k项相关的计算。

经过一些简化后,我们得出以下等式:

 image.png

我们花一点时间来理解这个等式所说的内容。为简化起见,我们假设k = 1,这样得到以下等式:

 image.png

这里,wj表示wi的上下文单词,wq表示其非上下文单词。这个等式基本上说的是,为了使J(θ)最小化,我们应该使σ(logit(xn)wi)≈1,这意味着logit(xn)wj需要是一个大的正值。然后,σ(- logit(xn)wq)≈1意味着logit(xn)wq需要是一个大的负值。换句话说,对于表示真实目标单词和上下文单词的真实数据点应该获得大的正值,而表示目标单词和噪声的伪数据点应该获得大的负值。这与使用softmax函数获得的效果相同,但具有更高的计算效率。

这里σ表示sigmoid激活函数。直观地看,在计算损失的时候,我们做了如下2步:

  • 计算wj的非零列的损失(推向正值)

  • 计算K个噪声样本的损失(拉向负值)

(2)分层softmax

分层softmax比负采样略复杂,但与负采样的目标相同,也就是说,近似softmax而不必计算所有训练样本的词汇表中所有单词的激活状态。但是,与负采样不同,分层softmax仅使用实际数据,并且不需要噪声采样。图3.10是可视化的分层softmax模型。

要了解分层softmax,让我们考虑一个例子:

 image.png

其词汇表如下:

 image.png

使用这个词汇表,我们构建一个二叉树,其中,词汇表中所有单词都以叶节点的形式出现。我们还将添加一个特殊的标记PAD,以确保所有叶节点都有两个成员。

 image.png

图3.10 分层softmax

然后,最后一个隐藏层将完全连接到分层结构中的所有节点(参见图3.11)。注意,与经典的softmax层相比,该模型具有相似的总权重,但是,对于给定的计算,它仅使用其中一部分。

 image.png

图3.11 分层softmax是如何连接到嵌入层的

假设我们需要推断P(NLP | like)的概率,其中like是输入词,那么我们只需要权重的子集即可计算概率,如图3.12所示。

 image.png

图3.12 用分层softmax计算概率

具体地,以下是概率计算的过程。

 image.png

现在我们知道如何计算P(wj | wi),我们可以使用原始的损失函数。

注意,该方法仅使用连接到路径中的节点的权重进行计算,从而提高了计算效率。

(3)学习分层结构

虽然分层softmax是有效的,但一个重要的问题仍然没有答案。

我们如何确定树的分支更准确地说,哪个词会跟随哪个分支有几种方法可以实现这一目标:

  • 随机初始化层次结构:此方法确实存在一些性能下降,因为随机分配无法保证在单词之间是最佳分支。

  • 使用WordNet确定层次结构:WordNet可用于确定树中单词的合适顺序,该方法明显比随机初始化有更好的性能。

(4)优化学习模型

由于我们有了一个精心设计的损失函数,因此优化就是从TensorFlow库调用正确函数。要使用的优化过程是随机优化过程,这意味着我们不会一次输入完整数据集,而只是在许多步中随机提供批量数据。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。