词向量对比word2vec https://zhuanlan.zhihu.com/p/75391062
0、实战经验
word2vec vs fastText区别?
思想:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。
word2vec vs fastText区别?
1)都可以无监督学习词向量,fastText训练词向量时会考虑字词subword;
2)fastText还可以进行有监督学习进行文本分类,其主要特点:结构与CBOW类似,但学习目标是人工标注的分类结果;
3)分层Softmax的叶子结点(类别)相对w2v(所有词汇)少很多,样本中标签多的类别被分配短的搜寻路径
-
引入字符级的N-gram特征,考虑词序特征;(一定程度上捕捉词序信息)。中文n-gram针对的是word,而不是char。对应到中文,应该对应的是分词之后的词,而不是字。英文是char字符级的n-gram、
-
引入subword来处理长词,处理未登陆词问题,以及低频词(n-gram共享)
-
采用hierarchical softmax对输出的分类标签建立哈夫曼树,样本中标签多的类别被分配短的搜寻路径
训练快原因:fastText在输入时,将单词的字符级别的n-gram向量作为额外的特征;在输出时,fastText采用了分层Softmax。
做文本分类时,和Word2vec的CBOW有两个区别:
-
使用类别标签替换了中心词。
-
使用句子中所有单词作为输入,而不再是单单的针对滑动窗口中的单词。
文本分类:深入剖析hierarchical softmax(一般利用CBOW)
-
输入层:利用n个上下文词的one-hot编码与词向量矩阵相乘,找到每个单词的词向量
-
投影层:将n个上下文词的词向量相加求和得到X
-
输出层:对应一个哈夫曼树,以每个词在语料库中的频次构造出来的哈夫曼树,叶节点有V个,即词汇表的大小。非叶子节点有V-1个。
哈夫曼树详解:每一个叶节点有对应的唯一从根节点出发路径,可用0,1进行编码,左1右0。路径上的非叶子节点都对应一个向量,该向量是参数向量,最终更新的也是该向量。
如何确定条件概率:现有一个上下文向量X,经过未知节点之后找到正确的中心词,在找的过程中,每经过一个子节点,都要进行一次判断,看是往左走还是往右走,刚好哈夫曼树左为1右为0,即每走一步都可看作是一个二分类,总结一句话就是:上下文词找到中心词的过程就是上下文词经过多个二分类之后最终到达目标词,每一步都要进行判断。
时间复杂度:从O(N)降到O(logN)
无监督训练词向量(一般利用Skip-gram)
使用负采样的skip-gram的基础上,将每个中心词视为子词subword的集合,并学习子词的词向量。
举个例子,现在我们的中心词是 'where',设定子词大小为3,那么子词集合分为两个部分,注意是两个部分。
- 第一部分普通子词形如这样: '<wh”,“whe”,“her”,“ere”,“re>'
- 第二部分就是特殊子词,也就是整词 '<where>'
- 那么对应到模型是,原来我的输入是 'where' 的词向量,现在在Fasttext就是所有子词的词向量的和。
注意哦,这里是所有子词,是包含特殊子词,也就是整词的。对于背景词,直接使用整词就可以。
简单来说,就是输入层使用子词(普通子词加上整词),输出层使用整词。
如果遇到了OOV怎么办?使用普通子词的向量和来表示就可以。
其实这里的子词,在名字上和文本分类文章的ngram很类似,不过,这里使用的是就char的n-gram,缓解的问题并不是语序,而是利用了词序形态的规律。对应到中文,其实就是偏旁部首。我记得阿里好像有发一个关于fasttext的中文版本,训练的就是偏旁部首。
损失函数
loss {ns, hs, softmax},负采样, 霍夫曼层次softmax,softmax
- softmax loss简单来说,就是将神经网络的logit用softmax包裹起来,再丢到交叉熵里面去。
- 看到知乎上说什么softmax loss是不严谨的说法。实际上,很多顶会论文大佬们都是用softmax loss作为softmax function+cross entropy loss的简称。
- 总结一下,softmax是激活函数,交叉熵是损失函数,softmax loss是使用了softmax funciton的交叉熵损失。
Hash解决n-gram带来的参数增多训练变慢的问题
使用了n-gram信息之后,词表肯定是变大了的。
比如想要n=1 or n=2 or n=3等等吧,n的取值范围越大,你的词表越大。这就会出现问题:参数越多训练越慢。
针对这个问题,怎么解决呢?使用哈希。
- 举个简单例子,不一定准确,"我/爱/中国/共产党",我在更新的时候,把'我','爱','中国','共产党'我们都使用同一个参数来代表(这种情况很难遇见,理解一下就好),那么在更新训练参数的时候,我只需要更新一个参数就把这个四个词都更新了,当然会快一点。
- 但是会出现一个问题,就是精度的问题。这个过程,不知道大家有咩有想到和albert很类似。哈希这个过程我自己感觉有点共享参数的意思。
- 为了节省空间,fastText在原作者的实现中并不是每一个n-gram都学习一个单独的embedding,而是首先将n-gram进行hash,hash到同一个位置的多个n-gram是会共享一个embedding的。
1、fastText原理
https://zhuanlan.zhihu.com/p/32965521
FastText是将句子中的每个词通过一个lookup层映射成词向量,对词向量叠加取平均作为句子的向量,然后直接用线性分类器进行分类,FastText中没有非线性的隐藏层,结构相对简单而且模型训练的更快。
在文本分类任务中,fastText(浅层网络)往往能取得和深度网络相媲美的精度,却在训练时间上比深度网络快许多数量级。在标准的多核CPU上, 能够训练10亿词级别语料库的词向量在10分钟之内,能够分类有着30万多类别的50多万句子在1分钟之内。
1.1、预备知识
- Softmax回归:又被称作多项逻辑回归(multinomial logistic regression),它是逻辑回归在处理多类别任务上的推广
- 分层Softmax:树的结构是根据类标的频数构造的霍夫曼树
- n-gram特征
- word2vec:CBOW模型架构和fastText模型非常相似
二、fasttext分类
注意,一般情况下,使用fastText进行文本分类的同时也会产生词的embedding,即embedding是fastText分类的产物。除非你决定使用预训练的embedding来训练fastText分类模型,这另当别论。
(1)字符级别的n-gram
word2vec把语料库中的每个单词当成原子的,它会为每个单词生成一个向量。这忽略了单词内部的形态特征,比如:“apple” 和“apples”,“达观数据”和“达观”,这两个例子中,两个单词都有较多公共字符,即它们的内部形态类似,但是在传统的word2vec中,这种单词内部形态信息因为它们被转换成不同的id丢失了。
为了克服这个问题,fastText使用了字符级别的n-grams来表示一个单词。对于单词“apple”,假设n的取值为3,则它的trigram有
“<ap”, “app”, “ppl”, “ple”, “le>”
其中,<表示前缀,>表示后缀。于是,我们可以用这些trigram来表示“apple”这个单词,进一步,我们可以用这5个trigram的向量叠加来表示“apple”的词向量。
这带来两点好处:
1. 对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
2. 对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。
(2)模型架构
输入是一句话,x1到xn就是这句话的单词或者是n-gram。每一个都对应一个向量,然后对这些向量取平均就得到了文本向量,然后用这个平均向量取预测标签。当类别不多的时候,最简单的softmax;当标签数量巨大的时候,要用到hierarchical softmax。
论文中的两个tricks:
- hierarchical softmax:类别数较多时,通过构建一个霍夫曼编码树来加速softmax layer的计算,和之前word2vec中的trick相同
- N-gram features: 只用unigram的话会丢掉word order信息,所以通过加入N-gram features进行补充,用hashing来减少N-gram的存储
但是也有人指出论文中选取的数据集都是对句子词序不是很敏感的数据集,所以得到文中的试验结果并不奇怪。
fasttext vs CBOW
- 和CBOW一样,fastText模型也只有三层:输入层、隐含层、输出层(Hierarchical Softmax),输入都是多个经向量表示的单词,输出都是一个特定的target,隐含层都是对多个词向量的叠加平均。
- 不同的是,CBOW的输入是目标单词的上下文,fastText的输入是多个单词及其n-gram特征,这些特征用来表示单个文档;CBOW的输入单词被onehot编码过,fastText的输入特征是被embedding过;CBOW的输出是目标词汇,fastText的输出是文档对应的类标。
值得注意的是,fastText在输入时,将单词的字符级别的n-gram向量作为额外的特征;在输出时,fastText采用了分层Softmax,大大降低了模型训练时间。
(3)核心思想
仔细观察模型的后半部分,即从隐含层输出到输出层输出,会发现它就是一个softmax线性多类别分类器,分类器的输入是一个用来表征当前文档的向量;
模型的前半部分,即从输入层输入到隐含层输出部分,主要在做一件事情:生成用来表征文档的向量。那么它是如何做的呢?叠加构成这篇文档的所有词及n-gram的词向量,然后取平均。叠加词向量背后的思想就是传统的词袋法,即将文档看成一个由词构成的集合。
于是fastText的核心思想就是:将整篇文档的词及n-gram向量叠加平均得到文档向量,然后使用文档向量做softmax多分类。
这中间涉及到两个技巧:字符级n-gram特征的引入以及分层Softmax分类。
(4)分类效果
为何fastText的分类效果常常不输于传统的非线性分类器?
假设我们有两段文本: 我 来到 达观数据 ;俺 去了 达而观信息科技
这两段文本意思几乎一模一样,如果要分类,肯定要分到同一个类中去。但在传统的分类器中,用来表征这两段文本的向量可能差距非常大。传统的文本分类中,你需要计算出每个词的权重,比如tfidf值, “我”和“俺” 算出的tfidf值相差可能会比较大,其它词类似,于是,VSM(向量空间模型)中用来表征这两段文本的文本向量差别可能比较大。
但是fastText就不一样了,它是用单词的embedding叠加获得的文档向量,词向量的重要特点就是向量的距离可以用来衡量单词间的语义相似程度,于是,在fastText模型中,这两段文本的向量应该是非常相似的,于是,它们很大概率会被分到同一个类中。
使用词embedding而非词本身作为特征,这是fastText效果好的一个原因;另一个原因就是字符级n-gram特征的引入对分类效果会有一些提升 。
(5)embedding
fastText单词的embedding跟常见的embedding方法没什么不同,都是先随机初始化,然后再通过反向传播学习参数,维度就是人工指定的一个超参数,是词向量的维度。
embedding并不是输入,是fastText需要学习的隐层参数。
不过有两点要注意的地方,第一是如果你说的fastText的embedding是通过supervised的方式来训练一个文本分类器并同时学习embedding的话,那么这个embedding的学习过程就是有监督的,与word2vec等无监督的模型是有一定区别的;
第二是fastText还会学习n-gram(这里的n-gram其实有两种,分别是char-n-gram和word-n-gram)的embedding,这使得它可以在一定程度上捕捉词序信息。为了节省空间,fastText在原作者的实现中并不是每一个n-gram都学习一个单独的embedding,而是首先将n-gram进行hash,hash到同一个位置的多个n-gram是会共享一个embedding的。