一个使用fasttext训练的新闻文本分类器/模型

时间:2021-01-18 16:03:00

fastext是什么?

Facebook AI Research Lab 发布的一个用于快速进行文本分类和单词表示的库。优点是很快,可以进行分钟级训练,这意味着你可以在几分钟时间内就训练好一个分类模型。

本文主要内容?

使用fasttext训练一个效果不错的新闻文本分类器/模型。

使用到的技术和环境?

1. python 3.7、fasttext 0.9.1(截至2020/3/29最新版本) Windows 10 (实验过程中使用的环境)

2. 1核2G 1Mbps 腾讯云服务器 Ubuntu 18.04 (最终的模型产出于此,如果你手头有Linux系统,那最好不过了)

需要注意什么?

1. 博主并非是专业的NLP学习者,所以以下内容是参考诸多博客、官方doc以及GitHub上的项目说明而来,算是拾人牙慧。但总结一些坑,便于后来者食用。

2. 强烈建议使用Linux or Mac OS 系统来训练,哪怕你是要在Windows下使用(训练的模型是可以多系统之间通用的,比如我在Linux-Ubuntu中训练,在Windows上可以正常使用)。但是在Windows下训练也是可行的,至少可以通过python安装fasttext库来使用,但是会有问题——无法进行自动超参数优化(至少目前如此)。

重要的文档?

官方的文档及博客 GitHub fastext 项目 


Let's start

Step1: 准备训练集和测试集 

这里的参考训练测试集来自 一位博主博客,他已经进行过中文分词,所以可以直接拿来训练。

下载地址(如果地址失效,请在博客下方留言评论,或者尝试联系上方QQ/Email)

news_fasttext_train.txt 训练集365M
news_fasttext_test.txt 测试集310M

如果上述链接失效,可从下述链接获取:

链接:https://pan.baidu.com/s/1izR-0oUFhZ4v5lrVYFng6A
提取码:n5w6

Step2: 在机器上构建fasttext

1. Windows 10 os : 过程中发现许多人在安装时遇到了问题,这里建议直接使用python pip工具安装

pip/pip3 install fastext

安装成功后,import它即可。

2. Linux  os : 按照官网教程,下面照搬过来

命令行键入:

$ git clone https://github.com/facebookresearch/fastText.git
$ cd fastText
$ make

如果没有git工具,按照提示安装一下。

Step3 : 进行训练

是的,你已经可以开始训练了,而训练....也只需要一行命令,即为简单,且可以在几分钟内完成。

1. 使用默认参数进行训练:

命令行键入:

$ ./fasttext supervised -input news_fasttext_train.txt -output model_xxxx

其中-input后跟训练集的路径,要修改为自己放置训练集的path,如果就放在fasttext文件夹下,那么直接按照上面运行即可。-output是模型的名字,训练完成后会产生一个model_xxxx.bin的文件,即是模型,可以自行设置模型文件名。

2. 自己设定参数进行训练:

命令行键入:

$ ./fasttext supervised -input news_fasttext_train.txt -output model_xxxx -lr 

上面的命令新增设定了-lr学习率和-epoch训练集送入的次数,当然还有其他的参数,请自行前往官网或者GitHub项目查看并设定,再进行训练。

3. 自动超参数优化

找到最佳超参数对于构建有效模型至关重要。但是,手动搜索最佳超参数很困难。但是,fasttext可以为你找到对于测试集来说最佳的超参数,然后使用这些超参数,再用训练集进行训练。而使用自动超参数优化,只需要在命令行中加入-autotune-validation 测试集path。

命令行键入:

$ ./fasttext supervised -input news_fasttext_train.txt -output model_xxxx -autotune-validation news_fasttext_test.txt

这样一来,就可以不用自己费力调参,直接得到对于测试集来说最佳的模型,从我使用的情况来看,确实如此。下图中,我展示了两个新闻主题的训练过程中的数据,最后使用此功能得到了相较此前最好的效果。证明,使用自动超参数优化来做,比自己摸索调参要来的更快、效果更好。

一个使用fasttext训练的新闻文本分类器/模型

Step4 : 计算一下评价数据

precision、recall、f1-score ,尤其后者是评价模型优劣的重要数据,我们来计算一下。

这里要使用到python来写脚本:(脚本来自上面博客,但是在py3.7下运行会出错,我进行了修改)

 1 # -*- coding: utf-8 -*-
 2 # @Author  : yocichen
 3 # @Email   : yocichen@126.com
 4 # @File    : test.py
 5 # @Software: PyCharm
 6 # @Time    : 2020/3/27 21:49
 7
 8 import fasttext
 9
10 # 1. 加载模型
11 # 模型文件名自行修改
12 classifier = fasttext.load_model('Model/model_0328_1854.bin')
13
14 # 2. 读入测试集文件,进行预处理
15 labels_right = []
16 texts = []
17 with open("Data/news_fasttext_test.txt", encoding='utf-8') as fr:
18     for line in fr:
19         line = line.rstrip()
20         labels_right.append(line.split("\t")[1].replace("__label__", ""))
21         texts.append(line.split("\t")[0])
22
23 labels_predict = []
24 for t in texts:
25     res = classifier.predict(t)
26     labels_predict.append(res[0][0].replace('__label__', ''))
27
28 text_labels = list(set(labels_right)) # 训练集中的标签类别
29 text_predict_labels = list(set(labels_predict)) # 预测结果中的标签类别
30
31 A = dict.fromkeys(text_labels,0)  #预测正确的各个类的数目
32 B = dict.fromkeys(text_labels,0)   #测试数据集中各个类的数目
33 C = dict.fromkeys(text_predict_labels,0) #预测结果中各个类的数目
34 for i in range(0,len(labels_right)):
35     B[labels_right[i]] += 1
36     C[labels_predict[i]] += 1
37     if labels_right[i] == labels_predict[i]:
38         A[labels_right[i]] += 1
39
40 print('A:', A)
41 print('B', B)
42 print('C', C)
43
44 # 3. 计算准确率,召回率,F值
45 for key in B:
46     try:
47         r = float(A[key]) / float(B[key])
48         p = float(A[key]) / float(C[key])
49         f = p * r * 2 / (p + r)
50         print("%s:\t p:%f\t r:%f\t f:%f" % (key,p,r,f))
51     except:
52         print("error:", key, "right:", A.get(key,0), "real:", B.get(key,0), "predict:",C.get(key,0))

python script

运行结果:

一个使用fasttext训练的新闻文本分类器/模型

Step5 :实战测试一下

我在各大新闻网站随机摘抄了20条新闻(片段),其中大部分是财经新闻,来小小的测试一下我们的分类器/模型。

下载地址:

news_sample.txt 新闻片段 9.95kb

链接:https://pan.baidu.com/s/1bURmHsQn_v5UevZqY8vBeg
提取码:numq

stop_words.txt 停用词 17.2kb

链接:https://pan.baidu.com/s/1Qzpk4KAOlI5Wmm7iuIaelQ
提取码:gfda

下面编写脚本来加载上面训练好的模型,进行简单测试

 1 # -*- coding: GBK -*-
 2 # @Author  : yocichen
 3 # @Email   : yocichen@126.com
 4 # @File    : predict.py
 5 # @Software: PyCharm
 6 # @Time    : 2020/3/27 13:15
 7
 8 import fasttext
 9 import sys, os
10 import jieba
11 from preprocess import *
12
13 # 加载模型
14 model = fasttext.load_model('Model/model_0328_1854.bin')
15
16 with open('Data/news_sample.txt', encoding='utf-8') as f:
17     for line in f:
18         handle_text = seg(line.lower().replace('\n', ''), stop_words(), apply=clean_txt)
19         res1 = model.predict(handle_text)
20         print(res1[0][0].replace('__label__', ''))

predict.py

 1 import re
 2 from types import MethodType, FunctionType
 3 import jieba # 中文分词第三方库,需要自行安装 pip3 install jieba / 在pycharm中安装也可
 4
 5 # 文本清洗
 6 def clean_txt(raw):
 7     fil = re.compile(r"[^0-9a-zA-Z\u4e00-\u9fa5]+")
 8     return fil.sub(' ', raw)
 9
10 # 中文分词,去通用词,再连接成字符串
11 def seg(sentence, sw, apply=None):
12     if isinstance(apply, FunctionType) or isinstance(apply, MethodType):
13         sentence = apply(sentence)
14     return ' '.join([i for i in jieba.cut(sentence) if i.strip() and i not in sw])
15
16 # 停用词,stop_words.txt 需要下载
17 def stop_words():
18     with open('Data/stop_words.txt', 'r', encoding='utf-8') as swf:
19         return [line.strip() for line in swf]
20
21
22 # 对某个sentence进行处理:
23 # content = '上海天然橡胶期价周三再创年内新高,主力合约突破21000元/吨重要关口。'
24 # res = seg(content.lower().replace('\n', ''), stop_words(), apply=clean_txt)
25 # print(res)

preprocess.py

测试结果:

一个使用fasttext训练的新闻文本分类器/模型一个使用fasttext训练的新闻文本分类器/模型

根据人工判断进行比对,准确率大概在 18-19/20吧!


到这里,使用fastext训练一个新闻文本分类器,就结束了,其实自己的工作并不多,但是也学到了一些文本分类相关的东西,愿后来的你也能有所收获!

参考文档

[1] https://www.cnblogs.com/hyserendipity/p/11698606.html

[2] jieba库使用说明

[3] 利用Fast-Text进行中文文本分类[前期在用这里的训练集,虽然f1很高0.98,但实际使用效果并不好,不推荐]