word2vec通过学习文本然后用词向量的方式表征词的语义信息,然后使得语义相似的单词在嵌入式空间中的距离很近。Skip-gram是给定单词来预测上下文,CBOW就相反。Negative Sampling是对于给定的词,并生成负采样词集合的一种策略。已知有一个词,这个词可以看做一个正例,而它的上下文词集可以看做是负例,但是负例的样本太多,而在语料库中,各个词出现的频率是不一样的,所以在采样时可以要求高频词选中的概率较大,低频词选中的概率较小,这样就转化为一个带权采样问题,大幅度提高了模型的性能。
fastText简而言之,就是把文档中所有词通过lookup table变成向量,取平均后直接用线性分类器得到分类结果。 FastText没有非线性的隐藏层,结构相对简单且模型训练的更快。fastText和ACL-15上的deep averaging network [1] (DAN,如下图)非常相似,区别就是去掉了中间的隐层。
Glovec融合了矩阵分解和全局统计信息的优势,统计语料库的词-词之间的共现矩阵,加快模型的训练速度而且又可以控制词的相对权重。
分层softmax
标准的Softmax回归中,要计算y=j时的Softmax概率:,我们需要对所有的N个概率做归一化,这在样本数很大时非常耗时。 于是,分层softmax诞生了,使用树的层级结构代替扁平化的标准softmax,使得在计算时,只需计算一条路径上的所有节点的概率值。
下图是一个分层Softmax示例:
树的结构是根据类标的频数构造的霍夫曼树。K个不同的类标组成所有的叶子节点,K-1个内部节点作为内部参数,从根节点到某个叶子节点经过的节点和边形成一条路径,路径长度被表示为。于是,就可以被写成:
其中:
表示sigmoid函数;
表示n节点的左孩子;
可以被表示为:
于是,从根节点走到叶子节点,实际上是在做了3次二分类的逻辑回归。
通过分层的Softmax,计算复杂度一下从O(|N|)降低到O(log|N|)。
n-gram特征
它是一种基于语言模型的算法,基本思想是将文本内容按照字节顺序进行大小为N的滑动窗口操作,最终形成长度为N的字节片段序列。
看下面的例子:
我来到达观数据参观
相应的bigram特征为:
我来 来到 到达 达观 观数 数据 据参 参观
注意一点:n-gram中的gram根据粒度不同,有不同的含义。它可以是字粒度,也可以是词粒度的。上面所举的例子属于字粒度的n-gram,词粒度的n-gram看下面例子:
我 来到 达观数据 参观
相应的bigram特征为:
我/来到 来到/达观数据 达观数据/参观
终于到我们的fastText出场了。这里有一点需要特别注意,一般情况下,使用fastText进行文本分类的同时也会产生词的embedding,即embedding是fastText分类的产物。除非你决定使用预训练的embedding来训练fastText分类模型,这另当别论。
1 字符级别的n-gram
word2vec把语料库中的每个单词当成原子的,它会为每个单词生成一个向量。这忽略了单词内部的形态特征, 为了克服这个问题,fastText使用了字符级别的n-grams来表示一个单词。对于单词“apple”,假设n的取值为3,则它的trigram有:
“
”
这带来两点好处:
对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。
2 模型架构
之前提到过,fastText模型架构和word2vec的CBOW模型架构非常相似。下面是fastText模型架构图:
注意:此架构图没有展示词向量的训练过程。可以看到,和CBOW一样,fastText模型也只有三层:输入层、隐含层、输出层(Hierarchical Softmax),输入都是多个经向量表示的单词,输出都是一个特定的target,隐含层都是对多个词向量的叠加平均。
不同的是,CBOW的输入是目标单词的上下文,fastText的输入是多个单词及其n-gram特征,这些特征用来表示单个文档;CBOW的输入单词被onehot编码过,fastText的输入特征是被embedding过;CBOW的输出是目标词汇,fastText的输出是文档对应的类标。
值得注意的是,fastText在输入时,将单词的字符级别的n-gram向量作为额外的特征;在输出时,fastText采用了分层Softmax,大大降低了模型训练时间。这两个知识点在前文中已经讲过,这里不再赘述。
fastText相关公式的推导和CBOW非常类似,这里也不展开了。
3 核心思想
现在抛开那些不是很讨人喜欢的公式推导,来想一想fastText文本分类的核心思想是什么?
仔细观察模型的后半部分,即从隐含层输出到输出层输出,会发现它就是一个softmax线性多类别分类器,分类器的输入是一个用来表征当前文档的向量;模型的前半部分,即从输入层输入到隐含层输出部分,主要在做一件事情:生成用来表征文档的向量。那么它是如何做的呢?叠加构成这篇文档的所有词及n-gram的词向量,然后取平均。叠加词向量背后的思想就是传统的词袋法,即将文档看成一个由词构成的集合。
于是fastText的核心思想就是:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。这中间涉及到两个技巧:字符级n-gram特征的引入以及分层Softmax分类。
4 fastText和word2vec的区别
相似处:
图模型结构很像,都是采用embedding向量的形式,得到word的隐向量表达。
都采用很多相似的优化方法,比如使用Hierarchical softmax优化训练和预测中的打分速度。
不同处:
模型的输出层:word2vec的输出层,对应的是每一个term,计算某term的概率最大;而FastText的输出层对应的是分类的label,不过不管输出层对应的是什么内容,起对应的vector都不会被保留和使用。
模型的输入层:word2vec的输出层,是 context window 内的term;而fasttext 对应的整个sentence的内容,包括term,也包括 n-gram的内容。
两者本质的不同,体现在 h-softmax的使用:
Word2vec的目的是得到词向量,该词向量最终是在输入层得到,输出层对应的 h-softmax,也会生成一系列的向量,但最终都被抛弃,不会使用。
fastText则充分利用了h-softmax的分类功能,遍历分类树的所有叶节点,找到概率最大的label(一个或者N个)。
词向量训练的预处理步骤:
1.对输入的文本生成一个词汇表,每个词统计词频,按照词频从高到低排序,取最频繁的V个词,构成一个词汇表。每个词存在一个one-hot向量,向量的维度是V,如果该词在词汇表中出现过,则向量中词汇表中对应的位置为1,其他位置全为0。如果词汇表中不出现,则向量为全0,词汇表size:(V*V);
2.将输入文本的每个词都生成一个one-hot向量,此处注意保留每个词的原始位置,因为是上下文相关的,文本size:[word_nums,V];
3.确定词向量的维数N。
CBOW的处理步骤:
1.确定窗口大小window,对每个词生成2*window个训练样本,(i-window, i),(i-window+1, i),...,(i+window-1, i),(i+window, i)。
2.确定batch_size,注意batch_size的大小必须是2*window的整数倍,这确保每个batch包含了一个词汇对应的所有样本。
3.训练算法有两种:层次Softmax和Negative Sampling 。
4.神经网络迭代训练一定次数,得到输入层到隐藏层的参数矩阵,矩阵中每一行的转置即是对应词的词向量 :
参数矩阵解释:
隐藏层到输出层
向量y中的每个元素表示我用 I、like、eat、apple 四个词预测出来的词是当元素对应的词的概率,比如是like的概率为0.05,是to的概率是0.80。由于我们想让模型预测出来的词是to,那么我们就要尽量让to的概率尽可能的大,所以我们目标是最大化函数
有了最大化的目标函数,我们接下来要做的就是求解这个目标函数,首先求 ,然后求梯度,再梯度下降,具体细节在此省略,因为这种方法涉及到softmax层,softmax每次计算都要遍历整个词表,代价十分昂贵,所以实现的时候我们不用这种方法,而是用第4节中的层次softmax和负采样。
神经网络像是一个黑盒子,这其中的概念很难理解,这里给出我对词向量训练的个人理解:对于每个词s,训练数据对应的标记是另一个词t,训练其实是想找到一种映射关系,让s映射到t。但很显然我们不是希望找到一个线性函数,使得给定s一定能得到t,我们希望的是能够通过s得到一类词T,包含t。对于T中的每个t,由于在s上下文中出现的频次不同,自然能得到一个概率,频次越高说明s与t相关性越高。
对于词向量,或者说参数矩阵W,可以认为是一个将词映射到语义空间的桥梁,s与t相关性越高,则认为其在语义空间中越近,那么对应的桥梁也越靠近。如果用向量来理解的话就是向量之前的夹角越小,我们使用向量来表示这个词的信息,重要的是得到了语义信息。在实际应用中,生成一段文本,我们可以判断词与词的向量之间相似度,如果过低则就需要怀疑是否正确了。
HMM是假定满足HMM独立假设。CRF没有,所以CRF能容纳更多上下文信息。
CRF计算的是全局最优解,不是局部最优值。
CRF是给定观察序列的条件下,计算整个标记序列的联合概率。而HMM是给定当前状态,计算下一个状态。
CRF比较依赖特征的选择和特征函数的格式,并且训练计算量大 。
编码器部分之前有博客专门说,这里不重复。说说解码器部分。
解码器部分结构和编码器略有不同,decoder第一级的注意力的key,query,value均来自前一层的输出,但加入了Mask操作,即我们只能attend到前面已经翻译过的输出的词语,因为翻译过程我们当前还并不知道下一个输出词语,这是我们之后才会推测到的。
而decoder第二级注意力也被称作encoder-decoder attention layer,即它的query来自于之前一级的decoder层的输出,但其key和value来自于encoder的输出,这使得decoder的每一个位置都可以attend到输入序列的每一个位置。
编码器和解码器的连接:
编码器通过处理输入序列开启工作。顶端编码器的输出之后会变转化为一个包含向量K(键向量)和V(值向量)的注意力向量集 。 这些项链将被每个解码器用于自身的 “编码-解码注意力层”,而这些层可以帮助解码器关注输入序列哪些位置合适。
解码器解码:
在完成编码阶段后,则开始解码阶段。解码阶段的每个时间步都会输出一个输出序列的元素(在这个例子里,是英语翻译的句子)。接下来的每个时间步重复了这个过程,直到到达一个特殊的终止符号,它表示transformer的解码器已经完成了它的输出。每个时间步的输出在下一个时间步被提供给底端解码器 。
最终的线性变换和Softmax层
线性变换:
解码器最终会输出一个实数向量。解码器输出后的线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的(字典维度),被称作对数几率(logits)的向量里。不妨假设我们的模型从训练集中学习一万个不同的英语单词(我们模型的“输出词表”)。因此对数几率向量为一万个单元格长度的向量,其中每个单元格对应某一个单词的分数。
softmax层:
Softmax 层便会把那些分数变成概率(都为正数、和为1)。概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出。