NLP --- >word2vec

概述

Word2vec在NLP里占有非常重要的地位,是很多深度学习技术的基础,那它解决了什么问题?是什么?为什么能解决呢?下面详细地介绍各个部分。

Word2vec解决什么问题?
我们知道,在一般的机器学习中,数据分为两大类,一类是数值型,另一类是字符型数据:对于数值型数据,能够有效地处理,可以直接用于数据拟合,回归分析中;对于字符型数据,如常见的性别(男,女),省份等,我们会把他们one-hot编码,这样由原来的一列数据增加若干列数据,当我们的一列数据具有大量不同的值时,扩增的列也将大幅增加,这在机器学习中会极大影响模型的学习,降低学习的效果。

而在NLP中,我们的数据全部是字符型数据,one-hot编码根本不现实!当然,也可以这样做,我们得到每个词的维度将是词汇表的大小,至少数万级别。

为此,我们需要找到其他的方法,将每个词的表示降维,如果从one-hot的结果出发,我们利用PCA, SGD等方法也可以降维,但代价是巨大的,不仅消耗大量计算资源,而且可扩展性差,上述降维技术要求把所有的数据一次性输入,若我们增加一些数据,则需要重新训练。

Word2vec怎么解决的
泛化地说:word2vec得到每个词的词向量并不是一步完成的,首先为每个词初始化一个随机向量,每次训练一个滑动窗口内的数据(一般是5个词),将滑动窗口内某个(些)词作为训练数据,其他词作为预测数据完成一次训练,更新词的向量参数,这样经过多次迭代后,每个词的向量会达到稳定,完成词向量的学习。

具体地说:

Word2vec分为两个模型:CBOW(Continuous Bag-of-Words Model) 模型和 Skip-gram模型,它们的区别如图:
在这里插入图片描述

CBOW模型

首先介绍CBOW模型,上图给出了模型的结构,包括三层:输入层,投影层和输出层;每次的输入和输出都是在一个滑动窗口内。举例而言, w w w为一个词, C o n t e x t c ( w ) Context_c(w) Contextc(w)为词前后长度为c的所有词,这2c+1个词组成一个滑动窗口;

  • 输入层:输入内容为中心词 w w w外的所有词,具体内容是把每个词转化为表示为one-hot编码,此时每个词的维度为词汇表的大小。
  • 投影层:输入层为 2 c ⋅ V 2c \cdot V 2cV的维度,输入到投影层有一个参数矩阵 V ⋅ m V\cdot m Vm(其中m为我们预设的词向量维度) ,经计算得到 2 c ⋅ m 2c \cdot m 2cm的矩阵,投影层将 2 c 2c 2c个向量做求和累加,即 x w = ∑ i = 1 2 c v w x_w=\sum_{i=1}^{2c}v_w xw=i=12cvw
  • 输出层:经过投影层后,我们得到 1 ∗ m 1*m 1m维的向量,这就是我们模型的输出,那怎么将他和真实的label(也即是 w w w)关联在一起,构造合适的损失函数进行学习?这里有三种思路:

传统做法

首先想到的是将得到的向量与新的矩阵M(维度为 V ∗ m V*m Vm)计算相似度,得到 1 ∗ V 1*V 1V个值,然后进行softmax处理,得到 1 ⋅ m 1\cdot m 1m维向量,将其与为真实词对应的向量 v m v_m vm比较设置目标函数,进行更新,即完成一次参数更新。

上述过程的简单代码表示即:

# 输入层-投影层
EMBEDDING_DIM = 5 # you can choose your own number
W1 = tf.Variable(tf.random_normal([vocab_size, EMBEDDING_DIM]))
b1 = tf.Variable(tf.random_normal([EMBEDDING_DIM])) #bias
hidden_representation = tf.add(tf.matmul(x,W1), b1)

# 输出层
prediction = tf.nn.softmax(tf.add( tf.matmul(hidden_representation, W1), b1))

# 设置目标函数
cross_entropy_loss = tf.reduce_mean(-tf.reduce_sum(y_label * tf.log(prediction), reduction_indices=[1]))

# 更新
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy_loss)

sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
sess.run(train_step, feed_dict={
   x: x_train, y_label: y_train})

注意此时,我们得到两个矩阵,前面为input_embedding, 后面为output_embedding,训练后输入和输出的向量效果几乎一样,而把这两个矩阵设为同样的权重则效果更差。

Hierarchical Softmax

  • 首先介绍Humman Tree

由名字可知,Huffman Tree是一种树结构,它的定义是:

给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,
称这样的二叉树为最优二叉 树,也称为霍夫曼树(Huffman Tree).

我们以每个词出现频率作为权重,构建Huffman Tree,具体过程如下[1]:

输入: 权值为 ( w 1 , w 2 , . . . , w n ) (w_1, w_2, ...,w_n) (w1,w2,...wn)的n个节点
输出:一颗Huffman 树

  1. ( w 1 , w 2 , . . . , w n ) (w_1, w_2, ...,w_n) (w1,w2,...wn)看做是有n棵树的森林,每个树仅有一个节点。
    2)在森林中选择根节点权值最小的两棵树进行合并,得到一个新的树,这两颗树分布作为新树的左右子树。新树的根节点权重为左右子树的根节点权重之和。
    3)将之前的根节点权值最小的两棵树从森林删除,并把新树加入森林。
  2. 重复步骤2)和3)直到森林里只有一棵树为止。

举个例子:
我们有(a,b,c,d,e,f)共6个节点,节点的权值分布是(20,4,8,6,16,3)。

首先是最小的b和f合并,得到的新树根节点权重是7.此时森林里5棵树,根节点权重分别是20,8,6,16,7。此时根节点权重最小的6,7合并,得到新子树,依次类推,最终得到下面的霍夫曼树。

  • 为什么使用Huffman tree

由传统做法虽然可以求得词向量,但计算量很大,耗资源严重,为了解决上述问题,避免计算所有词的softmax概率,引入Huffman Tree;具体的做法是:

对于我们要预测的标签,也就是中间的词,先将其进行Huffman编码,实际上事先需要对所有的词进行Huffman编码,这里对于所有词汇组成的Huffman Tree,我们可以约定左子树编码为1,右子树为0,这样我们可能得到中心词 w w w的编码为 010 010 010

由真实值的编码和隐藏层的向量,怎么利用设置目标函数呢?

这里,我们采用二元逻辑回归的方法,即如果编码为1,那就是负类,沿左子树走;如果编码为0,那沿着右子树走,就是正类,举例,当为1时:

P ( + ) = σ ( x w T θ ) = 1 1 + e − x w T θ P(+) = \sigma(x_w^T\theta) = \frac{1}{1+e^{-x_w^T\theta}} P(+)=σ(xwTθ)=1+exwTθ1
具体而言,即:
P ( d j w ∣ x w , θ j − 1 w ) = { σ ( x w T θ j − 1 w ) d j w = 0 1 − σ ( x w T θ j − 1 w ) d j w = 1 P(d_j^w|x_w, \theta_{j-1}^w)= \begin{cases} \sigma(x_w^T\theta_{j-1}^w)& {d_j^w=0}\\ 1- \sigma(x_w^T\theta_{j-1}^w) & {d_j^w = 1} \end{cases} P(djwxw,θj1w)={ σ(xwTθj1w)1σ(xwTθj1w)djw=0djw=1

其中 x w x_w xw

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值