【自然语言处理】word2vec模型

文章目录

  • 1 N-gram模型
  • 2 Word Embedding
  • 3 word2vec模型
    • 3.1 CBOW模型
    • 3.2 Skip-Gram模型
    • 3.3 Hierarchical Softmax
    • 3.4 负采样

1 N-gram模型

  在自然语言处理(Natural Language Processing,NLP)中,N-gram模型是一个重要的统计语言模型,它通过在一个大的语料库进行统计,使得我们的模型可以计算出某个语句出现的概率。如有一个句子由 w 1 , w 2 , . . . w n w_1,w_2,...w_n w1,w2,...wn组成,则它出现的概率为
P ( w 1 , w 2 , w 3 , . . , w n ) = P ( w 1 ∣ s t a r t ) P ( w 2 ∣ w 1 , s t a r t ) P ( w 3 ∣ w 2 , w 1 , s t a r t ) . . . P ( w n ∣ s t a r t , w 1 , w 2 , . . . , w n − 1 ) P(w_1,w_2,w_3,..,w_n)=P(w_1|start)P(w_2|w_1,start)P(w_3|w_2,w_1,start)...P(w_n|start,w_1,w_2,...,w_{n-1}) P(w1,w2,w3,..,wn)=P(w1start)P(w2w1,start)P(w3w2,w1,start)...P(wnstart,w1,w2,...,wn1)
  由于这个模型的参数过多,并且也难以统计。N-gram模型对上式进行了简化,假设某个词出现的概率基于它前面出现的若干个词,则式子可以用下面的式子表示:
P ( w 1 , w 2 , w 3 , . . , w n ) = P ( w 1 ∣ s t a r t ) P ( w 2 ∣ w 1 ) . . . P ( w n ∣ w n − 1 ) P(w_1,w_2,w_3,..,w_n)=P(w_1|start)P(w_2|w_1)...P(w_n|w_{n-1}) P(w1,w2,w3,..,wn)=P(w1start)P(w2w1)...P(wnwn1)
  这里假设每个词只与前面一个词相关,其中每个条件概率可以统计的方式进行估算
P ( w n ∣ w n − 1 ) = C o u n t ( w n , w n − 1 ) C o u n t ( w n − 1 ) P(w_n|w_{n-1})=\frac{Count(w_n,w_{n-1})}{Count(w_{n-1})} P(wnwn1)=Count(wn1)Count(wn,wn1)
  上面的式子是基于前面一个词汇的条件概率,涉及到2个词,所以是2-gram。如果考虑基于前n-1个的条件概率,则是N-gram。
  N-gram模型有一个致命的弱点,就是它永远没有足够的数据,数据有很大的稀疏性。比如语料中可能存在“小狗会跑”和“小猫会跳”,但是由于没有“小狗会跳”和“小猫会跑”的语料,我们的模型永远不能够得到“小狗会跳”和“小猫会跑”这个句子。事实上,当n大于3时基本就无法处理了,参数空间太大。实际上,在深度学习中我们可以用RNN,LSTM来克服N-gram模型无法关联距离较远的词汇的缺点。

2 Word Embedding

  我们如何在计算机中表示一个词呢?最简单的方法就是使用one-hot向量来表示。用n维向量表示n个词汇,每个vector中,只有某一位为1,其他位都为0,表示某个词汇。比如,我们有苹果,香蕉和柠檬三个词汇,可以分别用 [ 1 , 0 , 0 ] , [ 0 , 1 , 0 ] , [ 0 , 0 , 1 ] [1,0,0],[0,1,0],[0,0,1] [1,0,0],[0,1,0],[0,0,1]来表示。
  它的坏处有两点:

  • 第一,词汇与词汇之间没有联系,词汇之间是相互独立的。如果用one-hot来表示词的话,我们无法从中看出词之间的关联,比如“dog”和“cat”都是动物,“苹果”和“香蕉”都是水果,他们的词向量之间应该很相似。
  • 第二,当语料库较大,比如有10万个词,则每一个词都是一个10万维的向量,训练难度剧增。
      基于以上的缺点,人们想到了使用较小的向量来表示,比如用一个100维的向量来表示,其中每一维代表一定的特征,比如性别,颜色,大小,是否为动物,是否为事物,会跑,会跳……这样我们就将词向量压缩到了一定的大小,避免了维度灾难。同时又使得词与词之间存在一定的相关性。比如dog和cat在某些维度上会比较相近,使用某些距离度量方式,我们可以算出distance(“dog”,“cat”)是比较小的。用这种方式表示的词向量叫做分布式词向量,可以看做是one-hot向量中的1被分布在各个维度之中。那么如何得到这个低维度的向量呢?我们需要进行通过训练得到这个向量。

3 word2vec模型

  word2vec模型包含了Skip-gram和CBOW模型两个语言模型,它们都是通过神经网络来训练得到词向量。

3.1 CBOW模型

  CBOW(Continuous Bag-of-Word Model)又称连续词袋模型,是一个三层神经网络。该模型的特点是输入已知上下文,输出对当前单词的预测。CBOW的三层模型如下(以“I love Natural Language Processing”为例,窗口长度为2):

  • 输入层:假设语料库只有5个词,用5维one-hot向量分别表示上面的词汇。假设我们扫描一遍,总共得到以下5个对应关系:([love,Natural],I),([I,Natural,Language],Iove),([I,love,Language,Processing],Natural),([Natural,Language],Processing),其中用中括号括起来的就是我们的输入,将其用one-hot向量表示,组织成矩阵的形式。假设窗口长度用C表示,总共的语料数为N则输入的矩阵为 2 C × N 2C\times N 2C×N
  • 隐藏层:隐藏层的权重矩阵W实际上就是我们要学习的参数,假设我们要将原始的one-hot向量映射成K维,那W的维度就是 N × K N \times K N×K,不考虑偏置的情况下,其中一个ont-hot向量跟参数矩阵相乘得到的向量,就是我们需要的分布式词向量。如下图所示,由于是one-hot向量,假设1的位置为4,所以相乘实际上就是在W矩阵中取出第4行。
    【自然语言处理】word2vec模型_第1张图片
    当所有的输入都转换成分布式词向量之后,对其算求和平均,得到隐藏层的输出 h h h h h h 1 × K 1\times K 1×K的向量。
  • 输出层:隐藏层的输出需要经过一个 K × N K \times N K×N的矩阵后作为输出层的输入,假设为矩阵U,再使用softmax计算得到输出层的输出,即
    y i = exp ⁡ ( U i ) ∑ j = 1 N exp ⁡ ( U j ) y_i=\frac{\exp(U_i)}{\sum\limits_{j=1}^N\exp(U_j)} yi=j=1Nexp(Uj)exp(Ui)
    y i y_i yi代表输出第i个词的概率。

  训练的目标是期望训练样本特定词对应的softmax概率最大,我们定义交叉熵损失函数,使用反向传播算法进行参数的求解,就可以求得我们需要的W矩阵。CBOW模型也就学习完毕。

3.2 Skip-Gram模型

  Skip-Gram模型跟CBOW模型是反过来的,同样是三层神经网络,但是Skip-Gram模型的特点是输入已知单词,输出对上下文的预测。这里就简单地过一下,大体上和CBOW模型差不多。
  仍旧以“I love Natural Language Processing”为例,窗口长度为2为例,对于Skip-Gram模型的有以下的对应关系:(I,[love,Natural]),(Iove,[I,Natural,Language]),(Natural,[I,love,Language,Processing]),(Processing,[Natural,Language])。则输入的维度为 1 × N 1\times N 1×N,隐藏层的权重矩阵W维度为 N × K N\times K N×K,输出神经元有 2 C 2C 2C个,每个神经元的权重矩阵维数为 K × N K\times N K×N。输出是softmax概率排前 2 C 2C 2C 2 C 2C 2C个词,训练的目标是期望训练样本特定的 2 C 2C 2C个上下文对应的softmax概率最大。Skip-Gram模型大体上就是这样。

3.3 Hierarchical Softmax

  从上面的训练过程可以知道,从输入层到隐藏层的权重矩阵是我们需要的矩阵,自然是不能省掉的。而隐藏层到输出层的权重矩阵对我们来说却没有什么作用,却有 K × N K \times N K×N个权重需要学习。因此我们考虑对其进行优化。
  根据数据结构的知识,我们知道哈弗曼树可以用来对数据进行编码,使得需要发送的编码最短。于是我们想到利用哈弗曼树来提高我们的效率。我们让叶节点个数为N,表示所有的词汇,利用语料库中的词频,构建哈弗曼树。这样离树根越近的叶节点越高频,并且每个非叶子节点使用一个sigmoid函数来判断往左还是往右。沿着左边走为正类,编码为0,沿着右边走为负类,编码为1。以CBOW模型为例,我们从输出层的输入是 1 × K 1 \times K 1×K的向量,我们让其输入到哈弗曼树的树根,根据树根的sigmoid即其参数计算得到应该往左还是往右。由于我们知道最终应该走到哪个叶子节点,所以我们的训练过程就是在让这颗哈弗曼树所有的非叶子节点上面的参数符合我们的样本。
  由于是二叉树,计算量会从之前的 K × N K \times N K×N变成 log ⁡ ( K × N ) \log (K \times N) log(K×N),同时哈弗曼树使得高频词更容易被找到。做完这一步优化,我们只需要写出表达式,求出偏导,利用反向传播求解矩阵W和哈弗曼树的参数即可。
  在Skip-Gram模型中,同样可以使用上面的优化。它并没有和CBOW模型一样对输入进行迭代更新,而是对2c个输出进行迭代更新。

3.4 负采样

  负采样(negative sampling)通过使每一个训练样本仅仅改变一小部分的权重而不是所有权重,从而解决梯度下降法需要更新大量权重的缺点。它是用来提高训练速度并且改善所得到词向量的质量的一种方法。不同于原本每个训练样本更新所有的权重,负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降过程中的计算量。
  在CBOW模型中,假如对于([love,Natural],I),样本,最后的输出应该只有I这个词的神经元为1,其他词应该为0。正常来说,我们应该通过梯度下降修正权重,使得I对应的神经元出现1的概率增大,其他神经元出现1的概率降低。这时我们需要更新的权重个数为 K × N K \times N K×N。而负采样就是通过随机选取较少的负样本来更新对应的权重。负样本就是我们希望其输出为0的样本,比如对于([love,Natural],I),样本,在已知上下文love,Natural的情况下,输出为1的样本为I,输出为0的样本就是Language和Processing。通常情况下语料会很多,不止这里的5个,假设语料有1万个词,我们可以负采样得到Language和Processing。在最终的计算中,我们只需要更新正确输出“I”的权重,以及应该输出0的“Language”和“Processing”的权重。这样就达到了简化计算量的目的。
  负采样的方法很简单,根据词频将词汇分段,假设有V个词,则分成V段。通常我们会将词频计算公式的分子分母同时取0.75次幂,这个幂实际上是一种“平滑”策略,能够让低频词多一些出场机会,高频词贡献一些出场机会。由于概率之和为1,可以将词汇看成是长度为1上占着不同比例的线段。我们选定一个比V更大的M,将1划分成M等份。这样每个V都会分到1个或者多个M。采样时,我们只需要从M个位置中选出neg个位置,其对应的词就是我们负采样得到的词,如果采集到上下文的词,将其丢弃即可。

你可能感兴趣的:(机器学习之旅)