Task04:基于fasttext的文本分类
fasttext 原理说明
要说fasttext的原理,就不得不谈到word2vec。其实二者本身有着天然的联系。word2vec的主要学习方法有CBOW和Skip-gram,主要优化方法有hierarchical softmax和negative sampling。相关理论可以参考
https://blog.youkuaiyun.com/hongyesuifeng/article/details/84651900
https://blog.youkuaiyun.com/hongyesuifeng/article/details/90286126
word2vec主要通过词向量的形式来学习词表征,通常文本分类任务会将相应词向量加和平均。fasttext是一个高效的文本分类的库。
其和word2vec主要的不同点有:
1 加入了n-gram特征,该类特征通过实验可以比较好的特征分类的效果,在使用传统TFIDF+分类器进行文本分类的时候,加入n-gram特征也可以一定程度提升效果。
2 通过hash编码的方式来处理n-gram特征,可以缩减空间。
3 通过词的n-gram形成字词的表示,这里可以比较好的处理未登陆词(OOV)的问题。
fasttext模型架构为:
这里和Word2vec不同点是,这里的输入已经是embedding过的词向量了,不是one-hot编码进行表示,在学习x1,x2…Xn等上游任务中已经学会了embedding表示。这边的输入向量不止文档的词表征还加入了n-gram等字词的词向量表示。
使用fasttext库进行文本分类
这里主要通过fasttext包进行文本分类,这里主要提出中间遇到的几个问题:
1 fasttext安装的问题,直接使用pip install fasttext因为gcc的版本不够,所以不能直接安装,这里的解决方式有两种一个是升级gcc的版本。我通过第二个方法解决该问题,下载更老一个版本的fasttext,满足版本要求。
下载了0.9.1版本
pip install fasttext==0.9.1
安装后就可以直接使用import fasttext啦!
import pandas as pd
import numpy as np
import fasttext
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
# 转换为FastText需要的格式
train_df = pd.read_csv('./train_set.csv', sep='\t')
test_df = pd.read_csv('./test_a.csv')
train_df['label_ft'] = '__label__' + train_df['label'].astype(str)
train_df[['text','label_ft']].to_csv('train.csv', index=None, header=None, sep='\t')
#print(dir(fasttext))
model = fasttext.train_supervised('train.csv', lr=0.1, wordNgrams=2,
verbose=2, minCount=1, epoch=25, loss="hs")
predict = [model.predict(x) for x in test_df['text']]
训练的f1得分约0.9,最后预测结果提交的线上得分是0.9167。线上线下基本保持一致。
使用pytorch实现fasttext
import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
data = pd.read_csv('./train_set.csv', sep='\t', nrows=100)
#print(train_df.head())
vocab = set(data['text'])
label = data['label']
class FastText(nn.Module):
def __init__(self, vocab, w2v_dim, classes, hidden_size):
super(FastText, self).__init__()
self.embed = nn.Embedding(len(vocab), w2v_dim)
self.embed.weight.requires_grad = True
self.fc = nn.Sequential(
nn.Linear(w2v_dim,hidden_size),
nn.BatchNorm1d(hidden_size),
nn.ReLU(),
nn.Linear(hidden_size, classes)
)
def forward(self, x):
x = self.embed(x)
out = self.fc(x)
return out
def train_model(net, epoch, lr, data, label):
print("train model......")
net.train()
optimizer = optim.Adam(net.parameters(),lr=lr)
Loss = nn.CrossEntropyLoss()
for i in range(epoch):
optimizer.zero_grad()
output = net(data)
loss = Loss(output, label)
loss.backward()
optimizer.step()
print("train epoch=" + str(i) + ",loss=" + str(loss.item()))
print('Finished Training')
def model_test(net, test_data, test_label):
net.eval() # 将模型设置为验证模式
correct = 0
total = 0
with torch.no_grad():
outputs = net(test_data)
# torch.max()[0]表示最大值的值,troch.max()[1]表示回最大值的每个索引
_, predicted = torch.max(outputs.data, 1) # 每个output是一行n列的数据,取一行中最大的值
total += test_label.size(0)
correct += (predicted == test_label).sum().item()
print('Accuracy: %d %%' % (100 * correct / total))
if __name__ == "__main__":
#这里没有写具体数据的处理方法,毕竟大家所做的任务不一样
batch_size = 64
epoch = 10 # 迭代次数
w2v_dim = 300 # 词向量维度
lr = 0.001
hidden_size = 128
classes = 2
# 定义模型
net = FastText(vocab=vocab, w2v_dim=w2v_dim, classes=classes, hidden_size=hidden_size)
# 训练
print("开始训练模型")
train_model(net, epoch, lr, data, label)
# 保存模型
print("开始测试模型")
model_test(net, test_data, test_label)
fasttext源码学习
源码部分可以参考这几个博客:
https://heleifz.github.io/14732610572844.html
https://zhuanlan.zhihu.com/p/64960839
https://my.oschina.net/u/3800567/blog/2877570