单词嵌入与Word2Vec

为什么要用单词嵌入

RNN虽然可以解决长期记忆问题,但是还有一个问题没有解决.自然语言不仅和前后语境相关,单词本身也后很多含义.比如说下面几个词:

苹果 香蕉 科学家 农民

我们可以很容易发现苹果和香蕉是一类,因为他们都是水果.而科学家和农民是一类,因为他们都是人.

但是在RNN不能发现这些关系,RNN训练时单词是以one-hot编码的形式输入的,无法计算两个单词的距离,所以,无法从one-hot编码中找出哪些词是相似的.

\text{苹果} = \begin{bmatrix} 1\\0\\0\\0 \end{bmatrix} \quad \text{香蕉} = \begin{bmatrix} 0\\1\\0\\0 \end{bmatrix} \quad \text{科学家} = \begin{bmatrix} 0\\0\\1\\0 \end{bmatrix} \quad \text{农民} = \begin{bmatrix} 0\\0\\0\\1 \end{bmatrix} \quad

为了解决这个问题就出现了单词嵌入,英文为Word Embeddings.Embedding在数学上表示一个maping, 也就是一个function,该函数能将单词映射到另一个空间,映射后保留原有的结构,比如在X所属的空间上X1 < X2,那么映射后在Y所属空间上同理 Y1 < Y2,在新的空间中我们可以计算两个单词向量直接的距离,从而明确单词之间的关系.

举个例子,我们会把单词映射到一个新的空间,这个空间有年龄,甜度,口感,教育程度,平均工资这几个纬度:

苹果 香蕉 科学家 农民
年龄 -1 -2 43 30
甜度 5 6 0.1 0.2
口感 10 15 -1.2 -2
教育程度 2 3 150 50
平均工资 -0.2 -0.1 50000 20000

于是,Embedding后单词的向量为:

e_\text{苹果} = \begin{bmatrix} -1\\5\\10\\2\\-0.2 \end{bmatrix} \quad e_\text{香蕉} = \begin{bmatrix} -2\\6\\15\\3\\-0.1 \end{bmatrix} \quad e_\text{科学家} = \begin{bmatrix} 43\\0.1\\-1.2\\150\\50000 \end{bmatrix} \quad e_\text{农民} = \begin{bmatrix} 30\\0.2\\-2\\50\\20000 \end{bmatrix} \quad

现在,我们就通过向量间的距离找出相关关系.

单词嵌入就是用一个向量代表一个词,这个向量会包含这个词的所代表的信息。

词预测的副产物-单词嵌入矩阵

我们要建立一个语言模型,这个模型的目的是预测一段话中下一个词出现的概率:

I want a glass of orange ____.

image

首先通过矩阵E与单词One-hot编码相乘计算出每个单词的单词嵌入向量:

e_c = E \cdot o_c

接下来把这些单词嵌入向量输入到一个神经网络中,最后通过softmax输入下一个单词的概率.

接下来迭代模型:

l(\hat{y},y) = -\sum_{i=1}^{n} y_i\log{\hat{y}_i}

模型的中E为模型的参数,是所有单词的单词嵌入所组成的矩阵.事实证明这种方法能学习到非常合理的单词嵌入,因为当数据量非常大时,通常会得到非常类似的话,比如说下面两句:

单词预测的结果都是juice,但前面一个词是orange,另一个词为apple.这就会促使模型调整orange与apple的单词嵌入非常相近,最终达到在单词嵌入空间中物以类聚的效果.

还可以从另一个角度来理解单词嵌入,训练的过程一直用一个向量去代替一个词,这么做久了,这个向量当然能很好的代替这个词了。

Word2Vec

后来人们发现,我们不需要整个句子来训练模型,仅适用目标词附近的词就可以取得不错的效果,这就是Word2Vec算法.

Word2Vec是目前最常用的词嵌入模型之一,它2013年google提出来的.Word2Vec是一种浅层神经网络模型,有两种网络结构,分别是CBOW与Skip-gram.

CBOW的目标是根据上下文出现的词语来预测当前词的生成概率;而Skip-gram是根据当前词来预测上下文中各词的生成概率.他们的网络结构都是一样的:

image

CBOW的输入层输入附近的词,每个词用N维One-hot表示,输出为N个词出现的概率;Skip-gram输入的是N个词出现的概率,来预测附近的词.所以他们正好是相反的,互为镜像.

在第一层网络会生出一个 N\times K 维的参数,在第二层网络会生成一个 K\times N 维的参数.可以选择其中一个作为N个单词的K维词向量.

单词嵌入的另一个好处就是,它可以使每个单词的词向量变短,如果是词袋模型,每个词向量的长度为 N ,既单词的总个数,这样向量太长了.使用单词嵌入可以把 N 维的词向量映射到 K 维,这样可以大大减小词向量的维度.

负采用法

Word2Vec有一个缺点,当单词数量K非常大时Softmax的计算非常慢:

P(t|c) = {\frac {e^{{w} _{t}^T \cdot e_c}}{\sum _{k=1}^{K}e^{{w} _{k}^T \cdot e_c }}}

负采用法采用多个二分类代替Softmax,这样每次预测只需计算一个二分类即可.还是以juice为目标词为例,对juice附近的词,标记为正样本,然后从词典里随机抽取几个与juice完全不相关的词作为负样本,如下:

x1 x2 y
orange juice 1
king juice 0
sky juice 0

使用上述数据训练逻辑回归二分类,可以得:

P(y =1|c,t) = sigmoid({w} _{t}^T \cdot e_c)

使用K个逻辑回归可以代替逻辑回归代替Softma计算P(t|c).重要的是每次迭代只需更新一个逻辑回归就可以了,效率很快.

GloVe

GloVe是一个更为简洁的单词嵌入算法,全称为global vectors for word representation .

通过上面的算法可以看出来,单词嵌入向量与其在目标词附近出现的频率直接相关,GloVe算法直接将词向量与词频建立关系:

w_i^Te_j + b_i + b_j = log(X_{ij})

其中 X_{ij} 为单词i在单词j附近出现的频率. b_i , b_j 是主词和上下文词的常数偏倚.通俗点讲,假设单词a与单词b在单词c附近出现的频率相近,那么单词a与单词b的单词嵌入就相近,反之假设单词a与单词b在单词c附近出现的频率相差很远,那么这两个单词的单词嵌入差距也很大.

因为 X_{ij} X_{ji} 是相等的,所以公式相当于:

e_i^Te_j + b_i + b_j = log(X_{ij})

于是定义损失函数:

J = \sum_{i=1}^V \sum_{j=1}^V f(X_{ij}) ( e_i^T e_j + b_i + b_j - \log X_{ij})^2

f(X_{ij}) 是权重,为了处理停用词,以及 X_{ij} 为0的情况.


参考:
https://www.coursera.org/learn/nlp-sequence-models
https://cndocr.github.io/text2vec-doc-cn/glove.html

posted @ 2018-11-26 16:07:28
评论加载中...
发表评论