fastText,GloVe原理
fastText
fasttext是facebook开源的一个词向量与文本分类工具,在2016年开源,典型应用场景是“带监督的文本分类问题”。提供简单而高效的文本分类和表征学习的方法,性能比肩深度学习而且速度更快。
在此之前word2vec将上下文关系转化为多分类任务,进而训练逻辑回归模型,这里的类别数量是 |V| 词库大小。通常的文本数据中,词库少则数万,多则百万,在训练中直接训练多分类逻辑回归并不现实。word2vec中提供了两种针对大规模多分类问题的优化手段, negative sampling 和 hierarchical softmax。在优化中,negative sampling 只更新少量负面类,从而减轻了计算量。hierarchical softmax 将词库表示成前缀树,从树根到叶子的路径可以表示为一系列二分类器,一次多分类计算的复杂度从|V|降低到了树的高度。
1. fastText原理
fastText 模型输入一个词的序列(一段文本或者一句话),输出这个词序列属于不同类别的概率。序列中的词和词组组成特征向量,特征向量通过线性变换映射到中间层,中间层再映射到标签。fastText 在预测标签时使用了非线性激活函数,但在中间层不使用非线性激活函数。fastText 模型架构和 Word2Vec 中的 CBOW 模型很类似。不同之处在于,fastText 预测标签,而 CBOW 模型预测中间词。
2. 模型架构
其中 x 1 , x 2 , . . . , x N − 1 , x N x_1,x_2,...,x_{N−1},x_N x1,x2,...,xN−1,xN 表示一个文本中的n-gram向量,每个特征是词向量的平均值。这和cbow相似,cbow用上下文去预测中心词,而此处用全部的n-gram去预测指定类别。
目标函数
- N N N: 样本个数
- y n y_n yn: 第n个样本对应的类别
- f f f: 损失函数 softmax/ns(negative sampling)/hs(hierarchical softmax)
- x n x_n xn: 第n个样本的归一化特征
- A A A: 权重矩阵(构建词,embedding层)
- B B B: 权重矩阵(隐层到输出层)
3. 层次SoftMax
对于有大量类别的数据集,fastText使用了一个分层分类器(而非扁平式架构)。不同的类别被整合进树形结构中(想象下二叉树而非 list)。在某些文本分类任务中类别很多,计算线性分类器的复杂度高。为了改善运行时间,fastText 模型使用了层次 Softmax 技巧。层次 Softmax 技巧建立在哈弗曼编码的基础上,对标签进行编码,能够极大地缩小模型预测目标的数量。
fastText 也利用了类别(class)不均衡这个事实(一些类别出现次数比其他的更多),通过使用 Huffman 算法建立用于表征类别的树形结构。因此,频繁出现类别的树形结构的深度要比不频繁出现类别的树形结构的深度要小,这也使得进一步的计算效率更高。
4. N-gram子词特征
fastText方法不同与word2vec方法,引入了两类特征并进行embedding。其中n-gram颗粒度是词与词之间,n-char是单个词之间。用hashing来减少N-gram的存储
- fastText 可以用于文本分类和句子分类。不管是文本分类还是句子分类,我们常用的特征是词袋模型。但词袋模型不能考虑词之间的顺序,因此 fastText 还加入了 N-gram 特征。两类特征的存储均通过计算hash值的方法实现。
- 在 fastText中,每个词被看做是 n-gram字母串包。为了区分前后缀情况,"<", ">"符号被加到了词的前后端。除了词的子串外,词本身也被包含进了 n-gram字母串包。以 where 为例,n=3 的情况下,其子串分别为<wh, whe, her, ere, re>,以及其本身 。
好处:
- 对于低频词生成的词向量效果会更好。因为它们的n-gram可以和其它词共享。
- 对于训练词库之外的单词,仍然可以构建它们的词向量。我们可以叠加它们的字符级n-gram向量。
5. fastText 词向量与word2vec对比
FastText= word2vec中 cbow + h-softmax的灵活使用
相似处:
- 图模型结构很像,都是采用embedding向量的形式,得到word的隐向量表达。
- 都采用很多相似的优化方法,比如使用Hierarchical softmax优化训练和预测中的打分速度。
不同处:
- 模型的输入层:word2vec的输入层,是 context window 内的term;而fasttext 对应的整个sentence的内容,包括term,也包括 n-gram的内容。
- 模型的输出层:word2vec的输出层,对应的是每一个term,计算某term的概率最大;而fasttext的输出层对应的是分类的label。不过不管输出层对应的是什么内容,其对应的vector都不会被保留和使用。
- 两者本质的不同,体现在 h-softmax的使用:Word2vec的目的是得到词向量,该词向量最终是在输入层得到,输出层对应的 h-softmax
也会生成一系列的向量,但最终都被抛弃,不会使用。fastText则充分利用了h-softmax的分类功能,遍历分类树的所有叶节点,找到概率最大的label(一个或者N个)
6. 不平衡分类
把原来的softmax看做深度为1的树,词表V中的每一个词语表示一个叶子节点。如果把softmax改为二叉树结构,每个word表示叶子节点,那么只需要沿着通向该词语的叶子节点的路径搜索,而不需要考虑其它的节点。这就是为什么fastText可以解决不平衡分类问题,因为在对某个节点进行计算时,完全不依赖于它的上一层的叶子节点(即权重大于它的叶结点),也就是数目较大的label不能影响数目较小的label(即图5中B无法影响A和C)。
7. fastText 实现
pip install fasttext
分类
import fasttext
// 模型训练
classifier = fasttext.supervised("fasttext_train.txt","fasttext.model",label_prefix = "__label__")
fasttext.supervised():
- 第一个参数为训练集,即用来拟合模型的数据
- 第二个参数为模型存储的绝对路径
- 第三个为文本与标签的分隔符
import fasttext
// 加载模型
classifier = fasttext.load_model("fasttext.model.bin",label_prefix = "__label__")
// 测试模型 其中 fasttext_test.txt 就是测试数据,格式和 fasttext_train.txt 一样
result = classifier.test("fasttext_test.txt")
print "准确率:",result.precision
print "回归率:",result.recall
// 使用模型,以测试集中第一个文档为例
f = open("fasttext_test.txt")
line = f.readlines()[0]
f.close()
result = classifier.predict([line])
print result
from fastText import train_supervised, load_model
train_supervised(input, lr=0.1, dim=100,
ws=5, epoch=5, minCount=1,
minCountLabel=0, minn=0,
maxn=0, neg=5, wordNgrams=1,
loss="softmax", bucket=2000000,
thread=12, lrUpdateRate=100,
t=1e-4, label="__label__",
verbose=2, pretrainedVectors=""):
"""
训练一个监督模型, 返回一个模型对象
@param input: 训练数据文件路径
@param lr: 学习率
@param dim: 向量维度
@param ws: cbow模型时使用
@param epoch: 次数
@param minCount: 词频阈值, 小于该值在初始化时会过滤掉
@param minCountLabel: 类别阈值,类别小于该值初始化时会过滤掉
@param minn: 构造subword时最小char个数
@param maxn: 构造subword时最大char个数
@param neg: 负采样
@param wordNgrams: n-gram个数
@param loss: 损失函数类型, softmax, ns: 负采样, hs: 分层softmax
@param bucket: 词扩充大小, [A, B]: A语料中包含的词向量, B不在语料中的词向量
@param thread: 线程个数, 每个线程处理输入数据的一段, 0号线程负责loss输出
@param lrUpdateRate: 学习率更新
@param t: 负采样阈值
@param label: 类别前缀
@param verbose: ??
@param pretrainedVectors: 预训练的词向量文件路径, 如果word出现在文件夹中初始化不再随机
@return model object
"""
模型的保存与加载
// 模型的保存与加载
from fastText import load_model
model.save_model(path)
load_model(path)
词向量训练
fasttext不仅可以进行文本分类,也可以训练词向量,准备语料时,只需要去掉原始数据中的label标签即可。
from fastText import train_supervised, load_model
train_unsupervised(input, model="skipgram", lr=0.05, dim=100,
ws=5, epoch=5, minCount=5,
minCountLabel=0, minn=3,
maxn=6, neg=5, wordNgrams=1,
loss="ns", bucket=2000000,
thread=12, lrUpdateRate=100,
t=1e-4, label="__label__",
verbose=2, pretrainedVectors=""):
"""
训练词向量,返回模型对象
输入数据不要包含任何标签和使用标签前缀
@param model: 模型类型, cbow/skipgram两种
其他参数参考train_supervised()方法
@return model
"""
pass
参数方面的建议:
- loss function 选用 hs(hierarchical softmax)要比 ns(negative sampling)训练速度更快,准确率也更高
- wordNgram 默认为1,建议设置为 2 或以上更好
- 如果词数不是很多,可以把 bucket 设置小一些,否则会预留太多的 bucket 使模型太大
参考:
https://www.cnblogs.com/tsdblogs/p/10479660.html
https://www.cnblogs.com/huangyc/p/9768872.html
https://blog.csdn.net/qq_32023541/article/details/80839800
https://blog.csdn.net/ymaini/article/details/81489599
GloVe
GloVe: Global Vectors for Word Representation
GloVe的全称叫Global Vectors for Word Representation,它是一个基于全局词频统计(count-based & overall statistics)的词表征(word representation)工具,它可以把一个单词表达成一个由实数组成的向量,这些向量捕捉到了单词之间一些语义特性,比如相似性(similarity)、类比性(analogy)等。我们通过对向量的运算,比如欧几里得距离或者cosine相似度,可以计算出两个单词之间的语义相似性。
1. 共现矩阵
根据语料库(corpus)构建一个共现矩阵(Co-ocurrence Matrix)X,矩阵中的每一个元素 X i j X_{ij} Xij 代表单词 i i i 和上下文单词 j j j 在特定大小的上下文窗口(context window)内共同出现的次数。
例子:
语料库:i love you but you love him i am sad
采用一个窗口宽度为5(左右长度都为2)的统计窗口,那么就有以下窗口内容:
以窗口5为例说明如何构造共现矩阵:中心词为love,语境词为 but、you、him、i;则执行: X l o v e , b u t + = 1 X_{love,but}+=1 Xlove,but+=1 X l o v e , y o u + = 1 X_{love,you}+=1 Xlove,you+=1 X l o v e , h i m + = 1 X_{love,him}+=1 Xlove,him+=1 X l o v e , i + = 1 X_{love,i}+=1 Xlove,i+=1使用窗口将整个语料库遍历一遍,即可得到共现矩阵X。一般而言,这个 X i j X_{ij} Xij 次数的最小单位是1,但是GloVe不这么认为:它根据两个单词在上下文窗口的距离 d d d ,提出了一个衰减函数(decreasing weighting)用于计算权重,也就是说距离越远的两个单词所占总计数(total count)的权重越小: d e c a y = 1 / d decay = 1/d decay=1/d
2. GloVe模型推导
变量定义
- X i j X_{ij} Xij :表示单词 j j j 出现在单词 i i i 的上下文中的次数;
- X i X_{i} Xi :表示单词 i i i 的上下文中所有单词出现的总次数,即 X i = ∑ k X i k X_{i} = \sum^{k} X_{ik} Xi=∑kXik