NLP——新闻文本分类:TASK3 深度学习Fasttext
Fasttext是一种深度学习词向量的表示方法,它是一种三层神经网络,包含输入层,隐含层和输出层。
模型架构:fastText 模型输入一个词的序列(一段文本或者一句话),输出这个词序列属于不同类别的概率。序列中的词和词组组成特征向量,特征向量通过线性变换映射到中间层,中间层再映射到标签。fastText 在预测标签时使用了非线性激活函数,但在中间层不使用非线性激活函数。
层次softmax:在某些文本分类任务中类别很多,计算线性分类器的复杂度高。为了改善运行时间,fastText 模型使用了层次 Softmax 技巧。层次 Softmax 技巧建立在哈夫曼编码的基础上,对标签进行编码,能够极大地缩小模型预测目标的数量。
N-gram 特征:fastText 可以用于文本分类和句子分类。不管是文本分类还是句子分类,我们常用的特征是词袋模型。但词袋模型不能考虑词之间的顺序,因此 fastText 还加入了 N-gram 特征。
上面的介绍实在是难以理解,接下来说点人能听懂的解释。
FastText的核心就是N-gram。主要解决的问题是,当text中有词库中未出现过的单词,是否可以通过学习词语的一部分来判断词的意思。比如使用4-gram:
walking:(^wal,walk,alki,lkin,king,ing$)
有词库中已知单词可以知道,walk是走,ing是正在进行的意思,很明显可以看出walking就是正在走。
将上述n-gram方法用在SkipGram中,即为FastText。
调用示例:
##coding=utf-8
import pandas as pd
from sklearn.metrics import f1_score
import numpy
train_df=pd.read_csv('train_set.csv',encoding='gbk', sep=' ')
train_df['label_ft'] = '__label__'+train_df['label'].astype(str)
train_df[['text','label_ft']].iloc[:-5000].to_csv('train.csv',index=None,header=None,sep=' ')
import fasttext.FastText as ff
model = ff.train_supervised('train.csv',lr=1.0,wordNgrams=2,verbose=2,minCount=1,epoch=25,loss='hs')
val_pred=[model.predict(x)[0][0].split('__')[-1] for x in train_df.iloc[-5000:]['text']]
print(f1_score(train_df['label'].values[-5000:].astype(str),val_pred,average='macro'))
可得到结果
Read 177M words
Number of words: 6858
Number of labels: 14
Progress: 100.0% words/sec/thread: 647070 lr: 0.000000 avg.loss: 0.091541 ETA: 0h 0m 0s
0.913031467414968
采用分层交叉验证集调参
将训练集划分为训练集和验证集,通过在验证集上进行验证模型精度,找到模型是否过拟合还是欠拟合。如下是进行10折交叉验证,每折使用9/10的数据进行训练,剩余1/10作为验证集检验模型的效果。需要注意每折的划分必须保证标签的分布与整个数据集的分布一致。
交叉验证(Cross Validation),有的时候也称作循环估计(Rotation Estimation),是一种统计学上将数据样本切割成较小子集的实用方法,该理论是由Seymour Geisser提出的。
在给定的建模样本中,拿出大部分样本进行建模型,留小部分样本用刚建立的模型进行预报,并求这小部分样本的预报误差,记录它们的平方加和。这个过程一直进行,直到所有的样本都被预报了一次而且仅被预报一次。把每个样本的预报误差平方加和,称为PRESS(predicted Error Sum of Squares)。
常用的精度测试方法主要是交叉验证,例如10折交叉验证(10-fold cross validation),将数据集分成十份,轮流将其中9份做训练1份做验证,10次的结果的均值作为对算法精度的估计,一般还需要进行多次10折交叉验证求均值,例如:10次10折交叉验证,以求更精确一点。这个方法的优势在于,同时重复运用随机产生的子样本进行训练和验证,每次的结果验证一次。
#分层交叉验证
import pandas as pd
from sklearn.metrics import f1_score
from sklearn.model_selection import StratifiedKFold
import fasttext.FastText as ff
import warnings
import numpy as np
warnings.filterwarnings('ignore')
#转换为FastText需要的格式
train_df = pd.read_csv('train_set.csv',sep=' ',nrows=15000)
train_df['label_ft'] = '__label__' + train_df['label'].astype(str)
X = train_df['text']
y = train_df['label_ft']
sKFolder = StratifiedKFold(n_splits=10, random_state=0, shuffle=False)#折叠交叉验证
f1_scores = []
for i, (train_index, validation_index) in enumerate(sKFolder.split(X,y)):
filename = 'train_fasttext_' + str(i) + '.csv'
train_df[['text','label_ft']].iloc[train_index].to_csv(filename,index=None,header=None,sep=' ')
model = ff.train_supervised(filename,lr=1.0,wordNgrams=2,verbose=2,minCount=1,epoch=25,loss='hs')
val_pred = [model.predict(x)[0][0].split('__')[-1] for x in train_df.iloc[validation_index]['text']]#有效性索引
score = f1_score(train_df['label'].values[validation_index].astype(str),val_pred,average='macro')
print("第{}折交叉验证的f1_score is : ".format(i),score)
f1_scores.append(score)
print("10折交叉验证的f1_score平均分为:", np.mean(f1_scores))#求平均分数