首先计算机只认识01数字,要对文本进行处理就需要将单词进行向量化
单词的向量化表示方法
-
独热表示one-hot
最早对于单词向量化使用的是独热表示。每个单词对应一个向量,这个向量维度等于词汇表的大小,也就是说我有一个词汇表,里面有一万个单词,那么单词的独热表示向量维度就是一万维,对于词汇表中的每个具体的词,只需将其对应的位置置为1,其他位置置0。例子:我们有5个词组成的词汇表,词”Queen”在词汇表中的序号为2, 那么它的词向量就是(0,1,0,0,0)。同样的道理,词”Woman”是序号3,词向量就是(0,0,0,1,0)。
One hot representation用来表示词向量非常简单,但是却有很多问题。1、任意两个词之间都是孤立的,根本无法表示出在语义层面上词与词之间的相关信息,比如苹果、香蕉都是水果,他们之间肯定有相似性,one-hot却无法表达,而这一点是致命的。2、我们的词汇表一般都非常大,比如达到百万级别,这样每个词都用百万维的向量来表示简直是内存的灾难。能不能把词向量的维度变小呢?
-
词的分布式表示 distributed representation
Dristributed representation可以解决One hot representation的问题,它的思路是通过训练,将每个词都映射到一个低维向量上。所有的这些向量就构成了向量空间,进而可以用普通的统计学的方法来研究词与词之间的关系,向量维度一般需要我们在训练时自己来指定。
统计语言模型
如何计算一段文本序列在某种语言下出现的概率?之所为称其为一个基本问题,是因为它在很多NLP任务中都扮演着重要的角色。例如,在机器翻译的问题中,如果我们知道了目标语言中每句话的概率,就可以从候选集合中挑选出最合理的句子做为翻译结果返回。
统计语言模型给出了这一类问题的一个基本解决框架。对于一段文本序列,我们可以认为是一句话:
它的概率可以表示为:
即将序列的联合概率转化为一系列条件概率的乘积,也就是我们认为第t个单词的出现是依赖前t-1个单词的,那么问题变成了如何去预测这些给定t-1个单词的条件下的预测第t个单词的概率:
如果我们将所有的文本序列都这样处理,那么它的参数空间将是巨大的,这样一个模型在实际中并没有什么用。我们采用其简化版本——Ngram模型:
我们认为第t个单词,只与其前n-1个单词相关,常见的如bigram模型(N=2)和trigram模型(N=3)。事实上,由于模型复杂度和预测精度的限制,我们很少会考虑N>3的模型。
我们可以用最大似然法去求解Ngram模型的参数——等价于去统计每个Ngram的条件词频。
词向量( word embedding),基于神经网络的分布表示
-
Neural Network Language Model 神经网络语言模型
2003年,Bengio等人提出NNLM模型,模型的基本思想可以概括如下:
- 假定词表中的每一个word都对应着一个连续的特征向量;
- 假定一个连续平滑的概率模型,输入一段词向量的序列,可以输出这段序列的联合概率;
- 同时学习词向量的权重和概率模型里的参数。
值得注意的一点是,这里的词向量也是要学习的参数。
假设训练集为w1,...,wT的单词序列,单词wt∈V,V是大量且有限的词汇集。目标是学习一个模型f,使得:
,模型的约束
模型采用了一个简单的前馈神经网络 【注意这里是f,不是p,f相当于整个网络结构,最终输出的是一个概率向量,对应的是词表中每个单词在给定的n-1个单词条件下的概率】 来拟合一个词序列的条件概率 。整个模型的网络结构见下图:
我们可以将整个模型拆分成两部分加以理解:
-
矩阵C∈,即可以把V中任意一个词i映射为一个实值向量C(i)∈,它表示的就是单词i的分布式特征向量(distributed feature vector)。在实践中,C被表示成一个|V|×m的矩阵,即矩阵的每一行C(i)代表一个词的词向量,每个向量的维度为m这些向量作为模型的输入
-
其次是一个简单的前馈神经网络g。它由一个tanh隐层和一个softmax输出层组成。通过一个函数g把输入的上下文单词的特征向量 映射为下一个单词的条件概率分布函数,当然,这个单词在字典V中,g输出的的向量的第i个元素就是第i个单词的条件概率:
我们从图中可以看到,首先才词表矩阵C中查找每个单词对应的向量,然后进行拼接,形成一个(n−1)m维的列向量,经过隐含层tanh函数的激活,再经过softmax输出层的输出,这就得到了函数g的输出向量,需要注意的一点是:在输入层到输出层有直接相连的,这一层连接是可选的,也就是图中虚线的部分,下面讲述存在这一连接的情况:
目标函数的训练是最大化对数似然函数:
其中,θ为待训练参数,R(θ)为正则化项。而正则化项只约束于网络的权重和矩阵C,并不约束于偏置项
未经过softmax的归一化的输出的 向量为:
其中,,这个y就是一个|V|维的列向量
然后softmax归一化:
我们是要训练参数,现在来看看参数集θ包含哪些参数项:
b (|V|维):隐层-输出层的bias
d (h维):输入-隐层的bias
U (|V|*h matrix):隐层-输出层的权重矩阵
H (h*(n-1)m matrix):输入-隐层的权重矩阵
C (|V|*m):词向量
则,θ:
通过SGD进行参数更新:
这就是完整的神经网络语言模型(NNLM)结构。
-
word2vec模型
Mikolov(2013)等人提出了一个新型的模型结构——word2vec模型,此模型的优点为能训练大量的语料,可以达到上亿的单词,并且可以使单词向量维度较低,在50-100之间。它能够捕捉单词之间的相似性,对单词使用代数运算就能计算相似的单词,例如:vector(“King”)-vector(“Man”)+vector(“Woman”)=vector(“Queen”)
word2vec模型结构
word2vec模型有两种方法来实现,一个是基于CBOW(continuous bag of word),另一个是基于skip-gram模型。这两种结构如下图:
基于CBOW模型是根据目标单词的上下文经过映射来预测目标单词,而基于skip-gram模型刚好相反,使用目标单词经过映射层来预测上下文单词。 而这两个模型又可以使用两种方法实现,即使用hierachical softmax和negtive sampling来实现。
基于Hierarchical Softmax的模型
神经网络语言模型有三层,输入层(词向量),隐藏层和输出层(softmax层)。里面最大的问题在于从隐藏层到输出的softmax层的计算量很大,因为要计算所有词的softmax概率,再去找概率最大的值。
word2vec对这个模型做了改进,首先,对于从输入层到隐藏层的映射,没有采取神经网络的线性变换加激活函数的方法,而是采用简单的对所有输入词向量求和并取平均的方法。比如输入的是三个4维词向量:(1,2,3,4),(9,6,11,8),(5,10,7,12)那么我们word2vec映射后的词向量就是(5,6,7,8)。由于这里是从多个词向量变成了一个词向量。
第二个改进就是从隐藏层到输出的softmax层这里的计算量个改进。为了避免要计算所有词的softmax概率,word2vec采样了霍夫曼树来代替从隐藏层到输出softmax层的映射。关于霍夫曼树请参考博客:https://blog.csdn.net/itplus/article/details/37969979或者http://www.cnblogs.com/pinard/p/7160330.html,这里不再赘述
由于我们把之前所有都要计算的从输出softmax层的概率计算变成了一颗二叉霍夫曼树,那么我们的softmax概率计算只需要沿着树形结构进行就可以了。如下图所示,我们可以沿着霍夫曼树从根节点一直走到我们的叶子节点的词
和之前的神经网络语言模型相比,我们的霍夫曼树的所有内部节点就类似之前神经网络隐藏层的神经元,其中,根节点的词向量对应我们的投影后的词向量,也就是我们上文提到的 向量,而所有叶子节点就类似于神经网络softmax输出层的神经元,叶子节点的个数就是词汇表的大小。在霍夫曼树中,隐藏层到输出层的softmax映射不是一下子完成的,而是沿着霍夫曼树一步步完成的,因此这种softmax取名为"Hierarchical Softmax"。
如何“沿着霍夫曼树一步步完成”呢?在word2vec中,我们采用了二元逻辑回归的方法,即规定沿着左子树走,那么就是负类(霍夫曼树编码1),沿着右子树走,那么就是正类(霍夫曼树编码0)。判别正类和负类的方法是使用sigmoid函数,即:
其中 是当前内部节点的词向量,而 则是我们需要从训练样本求出的逻辑回归的模型参数。
使用霍夫曼树有什么好处呢?首先,由于是二叉树,之前计算量为V,现在变成了log2V。第二,由于使用霍夫曼树是高频的词靠近树根,这样高频词需要更少的时间会被找到,这符合我们的贪心优化思想。
容易理解,被划分为左子树而成为负类的概率为P(−)=1−P(+)。在某一个内部节点,要判断是沿左子树还是右子树走的标准就是看P(−),P(+)谁的概率值大。而控制P(−),P(+)谁的概率值大的因素一个是当前节点的词向量,另一个是当前节点的模型参数θ 。
对于上图中的,如果它是一个训练样本的输出,那么我们期望对于里面的隐藏节点n(,1)的P(−)概率大,n(,2)的P(−)概率大,n(,3)的P(+)概率大。
回到基于Hierarchical Softmax的word2vec本身,我们的目标就是找到合适的所有节点的词向量和所有内部节点θ, 使训练样本达到最大似然。那么如何达到最大似然呢?
我们使用最大似然法来寻找所有节点的词向量和所有内部节点θ。先拿上面的例子来看,我们期望最大化下面的似然函数:
对于所有的训练样本,我们期望最大化所有样本的似然函数乘积。
为了便于我们后面一般化的描述,我们声明一些定义:
1.我们定义输入的词为 ,其从输入层词向量求和平均后的霍夫曼树根节点词向量为,
2.从根节点到所在的叶子节点,包含的节点总数为 ,
3.从根节点出发到达对应叶子结点的路径为
4.在霍夫曼树中从根节点开始到叶子结点,经过的第 个节点表示为
5.:词的哈夫曼编码,,表示路径中第 i 个结点对应的编码,根节点不对应编码,∴ i≠1
6.:路径对应的非叶子结点对应模型参数表示为,其中,没有是因为模型参数仅仅针对于霍夫曼树的内部节点。
定义w经过的霍夫曼树某一个节点 j 的逻辑回归概率为,其表达式为:
那么对于某一个目标输出词,其最大似然为:
在word2vec中,由于使用的是随机梯度上升法,所以并没有把所有样本的似然乘起来得到真正的训练集最大似然,仅仅每次只用一个样本更新梯度,这样做的目的是减少梯度计算量。这样我们可以得到的对数似然函数如下:
要得到模型中w词向量和内部节点的模型参数θ, 我们使用梯度上升法即可。首先我们求模型参数的梯度
同理,可以求出的梯度表达式如下:
有了梯度表达式,我们就可以用梯度上升法进行迭代来一步步的求解我们需要的所有的和。
基于Hierarchical Softmax的CBOW模型
由于word2vec有两种模型:CBOW和Skip-Gram,首先来看基于Hierarchical Softmax的CBOW如何使用。
首先我们要定义词向量的维度大小M,以及CBOW的上下文大小 2c,这样我们对于训练样本中的每一个词,其前面的 c 个词和后面的 c 个词作为了CBOW模型的输入,该词本身作为样本的输出,期望softmax概率最大。
在做CBOW模型前,我们需要先将词汇表建立成一颗霍夫曼树。
对于从输入层到隐藏层(投影层),这一步比较简单,就是对w周围的2c个词向量求和取平均即可,即:
然后用梯度上升法进行迭代来一步步的求解所有的和,注意这里的是由 2c 个词向量相加而成,我们做梯度更新完毕后会用梯度项直接更新原始的各个xi(i=1,2,,,,2c),即:
其中η为梯度上升法的步长
基于Hierarchical Softmax的CBOW模型算法流程:
输入:基于CBOW的语料训练样本,词向量的维度大小M,CBOW的上下文大小2c,步长η
输出:霍夫曼树的内部节点模型参数θ,所有的词向量w
1. 基于语料训练样本建立霍夫曼树。
2. 随机初始化所有的模型参数θ,所有的词向量w
3. 进行梯度上升迭代过程,对于训练集中的每一个样本(context(w),w)做如下处理:
a. e=0,计算
b. for j=2 to ,计算:
c. 对于context(w)中的每一个词向量xi(共2c个)进行更新:
d. 如果梯度收敛,则结束梯度迭代,否则回到步骤3继续迭代。
基于Hierarchical Softmax的Skip-Gram模型
基于Hierarchical Softmax的Skip-Gram输入的只有一个词w,输出的为2c个词向量context(w)
我们对于训练样本中的每一个词,该词本身作为样本的输入, 其前面的c个词和后面的c个词作为了Skip-Gram模型的输出,,期望这些词的softmax概率比其他的词大。
在做Skip-Gram模型前,同样我们需要先将词汇表建立成一颗霍夫曼树。
对于从输入层到隐藏层(投影层),这一步比CBOW简单,由于只有一个词,所以,即就是词w对应的词向量。第二步,通过梯度上升法来更新我们的和,注意这里的周围有2c个词向量,此时如果我们期望最大。此时我们注意到由于上下文是相互的,在期望最大化的同时,反过来我们也期望最大(这个是什么道理我也没搞懂)。那么是使用好还是好呢?word2vec使用了后者,这样做的好处就是在一个迭代窗口内,我们不是只更新xw一个词,而是xi,i=1,2...2c共2c个词。这样整体的迭代会更加的均衡。因为这个原因,Skip-Gram模型并没有和CBOW模型一样对输入进行迭代更新,而是对2c个输出进行迭代更新。
基于Hierarchical Softmax的Skip-Gram模型算法流程,梯度迭代使用了随机梯度上升法:
输入:基于Skip-Gram的语料训练样本,词向量的维度大小M,Skip-Gram的上下文大小2c,步长η
输出:霍夫曼树的内部节点模型参数θ,所有的词向量w
1. 基于语料训练样本建立霍夫曼树。
2. 随机初始化所有的模型参数θ,所有的词向量w
3. 进行梯度上升迭代过程,对于训练集中的每一个样本(w,context(w))做如下处理:
a. for i =1 to 2c:
① e=0
② for j=2 to ,计算:
③
b. 如果梯度收敛,则结束梯度迭代,算法结束,否则回到步骤a继续迭代。
Hierarchical Softmax的的缺点,使用霍夫曼树来代替传统的神经网络,可以提高模型训练的效率。但是如果我们的训练样本里的中心词w是一个很生僻的词,那么就得在霍夫曼树中辛苦的向下走很久了。能不能不用搞这么复杂的一颗霍夫曼树,将模型变的更加简单呢?
Negative Sampling就是这么一种求解word2vec模型的方法,它摒弃了霍夫曼树,采用了Negative Sampling(负采样)的方法来求解,下面我们就来看看Negative Sampling的求解思路。
基于Negative Sampling的模型
Negative Sampling(负采样):我们有一个训练样本,中心词是w,它周围上下文共有2c个词,记为context(w)。由于这个中心词w,的确和context(w)相关存在,因此它是一个真实的正例。通过Negative Sampling采样,我们得到neg个和w不同的中心词,这样context(w)和wi就组成了neg个并不真实存在的负例。利用这一个正例和neg个负例,我们进行二元逻辑回归,得到负采样对应每个词wi对应的模型参数θi,和每个词的词向量。
从上面可以看出,Negative Sampling由于没有采用霍夫曼树,每次只是通过采样neg个不同的中心词做负例,就可以训练模型,因此整个过程要比Hierarchical Softmax简单。
不过有两个问题还需要弄明白:1)如何通过一个正例和neg个负例进行二元逻辑回归呢? 2) 如何进行负采样呢?
Negative Sampling的模型梯度计算
Negative Sampling也是采用了二元逻辑回归来求解模型参数,通过负采样,我们得到了neg个负例(context(w),wi) i=1,2,..neg,为了统一描述,我们将正例定义为。
这里使用的参数仍然是前面定义的那些参数,唯一的区别就是 θ 已经不是哈夫曼树上的非叶子节点代表的参数空间了,这里θ是词汇表每个词对应的模型参数,维度和输入x的维度一样,所以不存在类似 这样的下标了
在逻辑回归中,我们的正例应该期望满足:
我们的负例期望满足:
我们期望可以最大化下式:
模型的似然函数为:
此时对应的对数似然函数为:
和Hierarchical Softmax类似,我们采用随机梯度上升法,仅仅每次只用一个样本更新梯度,来进行迭代更新得到我们需要的 这里我们需要求出的梯度。
首先我们计算的梯度:
同样的方法,我们可以求出的梯度如下:
有了梯度表达式,我们就可以用梯度上升法进行迭代来一步步的求解我们需要的
Negative Sampling负采样方法:
现在我们来看看如何进行负采样,得到neg个负例。word2vec采样的方法并不复杂,如果词汇表的大小为V,那么我们就将一段长度为1的线段分成V份,每份对应词汇表中的一个词。当然每个词对应的线段长度是不一样的,高频词对应的线段长,低频词对应的线段短。每个词w的线段长度由下式决定:
在word2vec中,分子和分母都取了3/4次幂如下:
在采样前,我们将这段长度为1的线段划分成M等份,这里M>>V,这样可以保证每个词对应的线段都会划分成对应的小块。而M份中的每一份都会落在某一个词对应的线段上。在采样的时候,我们只需要从M个位置中采样出neg个位置就行,此时采样到的每一个位置对应到的线段所属的词就是我们的负例词。
在word2vec中,M取值默认为。
基于Negative Sampling的CBOW模型
有了上面Negative Sampling负采样的方法和逻辑回归求解模型参数的方法,我们就可以总结出基于Negative Sampling的CBOW模型算法流程了。梯度迭代过程使用了随机梯度上升法:
输入:基于CBOW的语料训练样本,词向量的维度大小Mcount,CBOW的上下文大小2c,步长η, 负采样的个数neg
输出:词汇表每个词对应的模型参数θ,所有的词向量xw
1. 随机初始化所有的模型参数θ,所有的词向量w
2. 对于每个训练样本(context(w0),w0),负采样出neg个负例中心词wi,i=1,2,...neg
3. 进行梯度上升迭代过程,对于训练集中的每一个样本(context(w0),w0,w1,...wneg)做如下处理:
a. e=0,计算
b. for i=0 to neg,计算:
c. 对于context(w)中的每一个词向量xi(共2c个)进行更新:
d. 如果梯度收敛,则结束梯度迭代,否则回到步骤3继续迭代。
基于Negative Sampling的Skip-Gram模型
基于Negative Sampling的Skip-Gram模型算法,梯度迭代过程使用了随机梯度上升法:
输入:基于Skip-Gram的语料训练样本,词向量的维度大小Mcount,Skip-Gram的上下文大小2c,步长η,负采样的个数neg。
输出:词汇表每个词对应的模型参数θ,所有的词向量
1. 随机初始化所有的模型参数θ,所有的词向量
2. 对于每个训练样本(context(w0),w0),负采样出neg个负例中心词wi,i=1,2,...neg
3. 进行梯度上升迭代过程,对于训练集中的每一个样本(context(w0),w0,w1,...wneg)做如下处理:
a. for i =1 to 2c:
① e=0
② for j=0 to neg,计算:
③
b. 如果梯度收敛,则结束梯度迭代,算法结束,否则回到步骤a继续迭代。