一文读懂Word2vec

现在网络上关于word2vec的文章很多,其中很多都只是说了个大概,看了之后会云里雾里,因此博主把词向量的前世今生总结了一下。文章有点长,但是我保证如果能认真看完,会对word2vec有个整体的认识

背景
Word2vec是2013年Google推出的一个NLP的工具,它的用途,顾名思义,就是将词转化为词向量。
我们都知道,在进行自然语言处理工作时要将人类的语言转化为数字向量才能被计算机所识别

one-hot representation
那么怎么样将词转化为词向量呢?最初的想法是构造一个词汇表,这个词汇表中包含了很多词。我们假设这个词汇表词的个数为N,那么词汇表的每一个词我们都可以用一个N维的向量来表示,这个向量的每一个位置代表词汇表中对应词的位置,如果某一个词出现,我们就在这个向量对应的位置用1表示,其他位置用0表示。举个例子:如果词汇表包含5个词,分别为(a, b, c, d, e),那么我们可以用一个5维的向量去表示这个词汇表的每一个词,如果为a,我们可以用(1,0,0,0,0)表示,如果为b,我们可以用(0,1,0,0,0)表示。以此类推。这就是所谓的one-hot representation(或者称独热,或者叫one-hot编码)
由此我们实现了将语言表示为向量的过程。但是one-hot会存在两个很严重的问题。

  • 第一,one-hot编码太稀疏了,虽然能表达每一个词,但是当我们词汇表非常大时,比如千万级别的,那么我们就必须用千万级别的维度去表示每一个词,这会非常占用计算机的内存,而且维度这么高,可能也会产生维度灾难。
  • 第二。one-hot是一个词袋模型(不懂的话可以搜索下)。不考虑词与词之间的上下文顺序,也假设词与词之间是相互独立的。但是一个句子中词与词之间怎么可能是没有上下文顺序,而且相互独立的呢?

正是由于one-hot这两个缺点,限制了它的应用。由此产生想法:我们能不能把one-hot向量通过某种方法,映射到更低维度上,同时又能表示词与词之间的位置和相互关系呢?答案是可以的,这里就要使用到语言模型了。比较有名的是NNLM(神经网络语言模型),这个语言模型会训练一个四层的神经网络(DNN)让计算机自己去学习把高维的向量转化到低维,至于这个低维是多少维,我们可以在训练的时候自己指定(NNML中是300维)。

NNLM(Neural Network Language Model):神经网络语言模型
NNLM是根据一个词w的前n-1个词context(w)来预测w(n可自己指定,NNLM中取4)。它会训练一个四层的神经网络。这四层分别为:

输入层(Input layer):每个词的one-hot向量(假设词汇表有8w个词,则形状为8w*1)

映射层(Projection layer):矩阵D * one-hot向量, 然后concatenate。表示这三个词的词向量(其中矩阵D是随机初始化的(300 * 8w),当D更新过后,就是我们所需要的词向量)。这样做的目的是根据one-hot向量得到对应的随机初始化的词向量(相乘之后形状为300 * 1,表示该词用随机初始化的300维的向量表示,然后在1这个维度上进行concatenate,得到300 * 3的矩阵,其中3表示3个词,300表示每个词用300维的随机初始化的向量表示)

隐藏层(Hidden layer):全连接+tanh激活(隐藏层神经元100个,则隐藏层和输出层矩阵大小为3*100维)

输出层(Output layer):全连接+softmax(输出层的维度为8w维,分别对应词汇表中每个词的概率大小)

我们的目的是让每一条训练文本出现待预测词w的概率最大,因此也就等价于最大化对数似然函数:在这里插入图片描述
(其中公式中C代表词汇表中每一个词),由此我们有了目标可以求损失从而进行反向传播更新参数,训练完成后得到的矩阵D就是我们最终得到的词向量矩阵。流程图如下:在这里插入图片描述

Word2vec原理
由于NNML参数量非常大,为了简化参数,Google的大牛就发明了Word2vec,Word2vec包含了两个模型:CBOW和Skip-gram

  1. CBOW(Continuous Bag-of-Words):连续词袋模型

    CBOW是根据一个词的上下文来预测这个词。

    输入层(Input layer):待预测词的上下文(这里的上下文一般是在这个词的前后各取几个词。可以是2个,可以是5个等,自己定义)的随机初始化的词向量

    映射层(Projection layer):这里作者直接取这些随机初始化的词向量求和累加操作(因为想降低维度,所以不像NNML那样concat,在后续梯度更新的时候会将梯度重新分配给各个词向量从而进行更新)

    隐藏层(Hidden layer):作者直接把隐藏层去掉了,因为这样可以减少参数(这里我也不太理解这么做的科学依据在哪里)

    输出:层次softmax概率化后最大的那个概率值所对应的词

    然后接下来的流程其实和NNML的流程一样,求损失,求梯度,BP反向传播,更新参数,这样我们就得到了训练的副产品:词向量在这里插入图片描述

  2. Skip-gram:跳字模型
    Skip-gram和CBOW一样,只是Skip-gram是用这个词去预测它的上下文,原理都是一样的,这里我就不再赘述在这里插入图片描述

  3. 优化方法
    在CBOW和Skip-gram这两个模型中,即使把隐藏层去掉了,但是假如词汇表是千万级别的,求一个千万级别的softmax概率,计算量依然太大了。因此,作者采用了两种优化方式来降低计算量:分别是层次softmax(Hierarchical Softmax)和负采样(Negative Sampling)的优化方法

    层次softmax(Hierarchical Softmax):为了避免计算所有词的softmax概率,作者采用了霍夫曼编码来代替隐藏层到输出层的softmax映射(具体可搜索霍夫曼编码)这样做的好处是:
    1.大大减少了计算量(以前的计算量为V,V是词汇表的大小,构造霍夫曼树之后的计算量是log2(V)(因为每一次都是一次二分类)
    2.由于高频词靠近树根,这样高频词需要更少的时间会被找到,这符合我们的贪心优化思想

    负采样(Negative Sampling):也是把它转化为一个二分类的问题。我们用带权采样的算法选择随机选择一个负样本集,然后我们的目标是让正样本出现的概率最大,让负样本出现的概率最小。负采样的好处是:
    1.提高了训练速度
    2.改善所得词向量的质量
    3.不再采用复杂的霍夫曼编码而是选用相对简单的随机负采样,因此是层次softmax的一种替代
    关于这两种优化方法,推荐一篇我认为很不错的博文:博文地址

4.word2vec的劣势
word2vec不可以表示一词多义,即动态词向量。一旦训练好,那么词向量就已经固定。如果想要在不同的上下文表示同一个词的不同含义,word2vec在这方面做不到的。想要表示动态词向量,可以参考ELMO、BERT

5.word2vec的使用
调用gensim接口即可使用:gensim.models.Word2Vec()

猜你喜欢

转载自blog.csdn.net/zhdywdl/article/details/88564963