一、词义表示
在计算机中,我们如何去表示一个单词呢?在传统的NLP算法中,我们将单词表示为离散的符号,那么这些单词就可以用one-hot向量来表示。在向量的某一位置为1,其余位置为0。这样的向量会非常长。
那么这样表示的问题在于它没有给出词汇之间的内在关系。单词向量之间是互相垂直的,我们没有办法计算它们之间的相似性。
那么我们要怎么做呢?这里我们要用到NLP中一个概念:分布相似性。分布相似性就是指你只需通过某个词语的上下文就能得到表示其含义的值。
例如,我们要得知“banking”的含义,我们要做的就是找到数千个包含“banking”的例句,然后观察它每一次出现的场合,统计所有出现过的单词,然后通过某种方式用这些上下文中的词来表示“banking”的含义。
1.1 词向量
每一个单词我们用一个密集向量表示。
我们可以用两个向量之间的点积来计算相似性,还可以进行改进,用递归、循环等等。这样以来,这些词汇就可以用来预测上下文的其他词汇,反之亦然。
二、Word2vec
Word2vec是学习词向量的一个框架,思想如下:
Word2vec主要有两个算法:Skip-grams(SG)和 Continuous Bag of Words(CBOW)。还有两种训练方法:Hierarchical softmax和Negative sampling。但这节课我们主要介绍Skip-gram模型。下面是Skip-gram模型的图解。
Skip-gram模型的主要思想是在每一个估算步都选择一个词汇作为中心词汇,例如上图选择的是“banking”,然后我们尝试去预测它一定范围内的上下文词汇。所以这个模型将会定义一个概率分布,即给定一个中心词汇,某个单词在它的上下文出现的概率。我们会选取词汇的向量表示使得概率分布值最大。但我们要注意的是这个模型只有一个概率分布,并不是说对这个单词左边的词汇和右边的词汇分别有一个概率分布。
上面给出的公式 L(θ) L ( θ ) 表示,我们拿到很长的文本,然后遍历文本中所有位置,然后对于文本中的每一个位置,我们都会定义一个围绕中心词汇的大小为 2m 2 m 的窗口,这样就得到一个中心词汇预测上下文词汇的概率分布。我们的目标就是选择词汇向量使得这个预测概率 L(θ) L ( θ ) 最大。
θ
θ
是我们需要优化的模型参数。除了词汇的表示,还有其他一些参数也可以进行优化调整,如窗口大小等,但我们这里暂不考虑。
对公式稍作调整,就可以得到下面的损失函数
J(θ)
J
(
θ
)
。对函数取log,求积变成了求和,前面乘以
1T
1
T
,相当于对每个词汇进行归一化处理,相比于最大化,我们更喜欢处理最小化问题,因此前面加一个负号。我们的目标就是最小化
J(θ)
J
(
θ
)
。
那么我们如何计算 P(wt+j|wt;θ) P ( w t + j | w t ; θ ) ?如下所示,一个单词我们用两个向量来表示(中心词汇时和上下文词汇时)。
我们首先求两个单词向量的点积。这是一种用点积衡量向量相似性的方法,两个向量之间越相似,点积就会越大。然后我们将其转化为softmax的形式,这样就把数值转化为了概率。
下面我们来看skip-gram的完整模型:
输入 xk x k 是one-hot向量, W W 是所有中心词汇的表达组成的矩阵,我们用与矩阵相乘就可以选出这个矩阵相应的列 hi h i ,代表的就是这个中心词汇的表示。 W′ W ′ 由上下文词汇表达组成。假设我们需要预测 C C 个位置的上下文词汇,如上图,对于每一个位置,我们让与 W′ W ′ 相乘,再进行softmax运算,得到所有上下文词汇出现的概率( 1×V 1 × V )。
三、梯度优化
我们的损失函数如下,优化目标就是最小化这个损失函数 J(Θ) J ( Θ ) 。
接下来我们就要求 logp(o|c) log p ( o | c ) 对中心词汇 vc v c 的偏导,下面贴出求导过程:
【补充】关于对向量求导 即前导不变后导转置。
接下来我们就可以用梯度下降算法来优化目标函数。
Python代码如下:
但是当我们的数据量很大时(例如400亿词汇量),我们不可能让所有的词汇对目标函数一一求导,所以我们一般选用随机梯度下降(Stochastic Gradient Descent,SGD)算法来替代。意思是,我们只选取文本中的一个位置,这样我们就有了一个中心词汇和它的上下文词汇,我们移动一个位置就对所有参数求导,然后用这个位置的梯度估计值来代替,这种方法十分的粗糙,每前进一步并不能保证是朝着最小化方向,但在实际操作中,这是很有效的。因为SGD的速度会比批处理梯度下降快很多数量级,而且这些噪音有助于神经网络的训练。