自然语言处理任务中要处理的对象是单词或者词组,单词可以看做是类别型特征,虽然tree-based模型可以采用类别特征,但包括神经网络在内的大部分机器学习模型只能处理数值型特征。因此,在使用模型时通常需要将单词等特征转化为数值。最常见的方法是one-hot encoding。但这种方法编码出来的特征非常稀疏,不利于特征学习,而且无法度量单词之间的相似度。google在13年提出的word2vec方法利用一个浅层的神经网络将稀疏的特征向量映射到稠密的低维空间中,其动机是:位于相同上下文的单词应当有相似的语义,利用的是单词的共现性。 准确的说,学习出单词的embedding只是模型的一个“副作用”,word2vec是一个框架,它包含两个建模函数,或者说是两个建模角度,分别是CBOW和Skip-Grams。
基本原理:
CBOW:通过上下文预测中间的单词
最大化似然函数
\[LL = \prod_{t=1}^Tp(w_t|context(w_t))\]
这个\(context(w_t)\)可以有多种方式处理。
Skip-Grams: 通过中间单词预测上下文
目标是最大化似然函数
\[LL = \prod_{i=1}^T\prod_{-c\le j\le c}p(w_{t+j}|w_t)\]
其中
\[p(w_o|w_i)=\frac{exp(v^{'T}_ov_i)}{\sum_{c=1}^{D}exp(v^{'T}_cv_i)}\]
对每个单词都对应两个向量\(v^{'}和v\)。
细节
CBOW
基本原理如图所示,假设词典*有\(D\)个单词,给定一句话的上下文有\(c\)个单词,所以需要先对每个单词做one-hot 编码,\(x_i\)实际上是一个大小为\(D\times 1\)的向量,矩阵\(W_1\in R^{D\times e}\) 每一行都可以看做是一个单词的embedding,这是模型的参数,也是我们想得到的单词embedding。 中间的隐层
\[ h =\frac{1}{c}\sum_{i=1}^c x_i^{T}W_1,h\in R^{1\times e} \]
系数矩阵\(W_2 \in R^{e\times D}\) 将隐层的数据重新映射到整个字典空间中.
\[o = softmax(h\times W_2), o \in R^{1\times D},o_{i}\in [0,1]\]
输出概率最大的单词作为候选。这里的\(W_1,W_2\)分别对应上面公式中的\(v^{'},v\).
Skip-Grams
Skip-Grams正好与CBOW的流程相反,其输入层\(I\)就是一个单词的one-hot编码,矩阵\(W_1 \in R^{D\times e}\),
\[h = x_i\times W_1, h\in R^{1\times e}\]
输出层对应多个单词,对应每个单词都有一个softmax损失。将所有\(c\)个softmax损失相加就是总的损失。
问题
由于单词的空间\(D\)非常庞大,在计算softmax损失的时候需要对所有\(D\)个单词进行累加,这一方面非常耗时,另一方面会导致权重更新效率低下,因为每次只需要更新\(c\)个单词对应的权重,但却需要遍历所有单词。
Hierarchical Softmax
统计所有样本出现的频次,建立哈夫曼树,树的深度为\(logD\),每个叶子节点都对应一个单词\(w\),设\(n(w,i)\)表示从根节点出发能到达叶子节点\(w\)的路径上的第\(i\)个节点,并且\(n(w,1)=root\),每个内部节点(包括根节点)都可以看做是神经网络中的一个二类分类节点,节点系数为\(v_{n(w,i)}\).
以CBOW举例,获得隐节点向量\(h\)之后,就将\(h\)输入到哈夫曼树的根节点,在每个节点执行二类分类任务。\(\sigma(x)=\frac{1}{1+e^{-x}}\),当\(\sigma(h*v_{n(w,i)})>0\)时,就传递到左子树,反之,传递到右子树,直到叶子节点,叶子节点所在的单词就是我们要预测的值。
所以实际上层次softmax最多只需要计算\(logD\)次,每次都是一个二类分类问题。
Negative Sampling
\[p(w_o|w_i)=\frac{exp(v^{'T}_ov_i)}{\sum_{c=1}^{D}exp(v^{'T}_cv_i)}\]
上式的分母是所有单词,实际上我们可以对单词分类,将我们当前关注的单词\(W_i\)对应的上下问认为是正类,将所有其他单词认为是负类,在分类的时候只需要区分当前单词是正类还是负类就行了,不需要具体计算每一个单词的概率。所以其实上式可以简化成:
\[p(w_0|w_i) = \sigma(v^{'T}_ov_i)=\frac{1}{1+e^{-v^{'T}_ov_i}}(当w_0属于正类) \\
p(w_0|w_i) = 1-\sigma(v^{'T}_ov_i)=1-\frac{1}{1+e^{-v^{'T}_ov_i}}=\sigma(-v^{'T}_ov_i)(当w_0属于负类)\]
这里的正类和负类只是相对于\(w_i\)来说的。
对比
如果采用softmax版本,对每个样本的最大似然函数:
\[ln(p(w_o|w_i))=v^{'T}_ov_i-ln(\sum_{c=1}^{D}exp(v^{'T}_cv_i))\]
如果采用负采样的二分类版本,在更新某个样本时的损失函数为:
\[ln(p(w_o|w_i))=ln\sigma(v^{'T}_ov_i)+\sum_{k}^KE_{w\sim P_n(w)}ln\sigma(-v^{'T}_ov_i)\]