最近在作一些意图识别方面的工做,因此尝试一下用 fasttext 作一个文本分类器,学习记录以下。java
首先,咱们使用 fasttext 的目的是什么?是文本分类,即对一个词语,给出它所属于的类别。python
文本分类的目标是将文档(如电子邮件,博文,短信,产品评论等)分为一个或多个类别。 这些类别能够是根据评论分数,垃圾邮件与非垃圾邮件来划分,或者文档的编写语言。 现在,构建这种分类器的主要方法是机器学习,即从样本中学习分类规则。 为了构建这样的分类器,咱们须要标注数据,它由文档及其相应的类别(也称为标签或标注)组成。git
什么是 fasttext 呢?github
FastText 是 Facebook 开源的一款快速文本分类器,提供简单而高效的文本分类和表征学习的方法,精度接近深度模型可是速度更快。shell
原理这部分要跳过了,由于网上的原理文章特别多,若是各位感兴趣的话能够移步 google 搜索或者文末相关文章。我在那里放了几个连接。微信
至于本文,首先网上的原理文章讲的广泛都不错。其次我对原理的了解程度彻底不能让我在这里清楚的写出来,毕竟我只是个可怜的工程师。实现它,干上线才是个人宿命。markdown
首先要理解,fasttext 只是一个工具包,怎么使用它,用什么方式来实现它都是可选的。这里我选择的是使用命令行来训练模型,以后用 java 语言提供在线服务。固然你能够选择使用各类语言来进行训练和服务,由于有多种语言的 fasttext 包。机器学习
咱们能够直接下载正式发布的某个版本,工具
wget https://github.com/facebookresearch/fastText/archive/v0.1.0.zip
unzip v0.1.0.zip
复制代码
我我的更加推荐直接 clone 它在 github 上的项目,即执行:oop
git clone git@github.com:facebookresearch/fastText.git
复制代码
以后进入他的目录,执行 make
便可。
安装完毕以后,能够直接执行不带任何参数的命令,能够获取相关的帮助手册。
官网的教程是使用 传送门 的一部分数据进行训练,这固然能够,可是我以为你们可能更想看一些中文的训练样本。
首先给你们介绍一下训练样本的格式。以下:
__label__name 呼 延 十
__label__name 张 伟
__label__city 北京
__label__city 西安
复制代码
文本文件的每一行都包含一条训练样本,其后是相应的文档。 全部标签都以 label 前缀开始,这就是 fastText 如何识别标签或单词是什么。 而后对模型进行训练,以预测给定文档的标签。
注意,当你生成你的样本以后,须要区分开训练集和测试集,通常状况下咱们使用训练:测试=8:2
的比例。
我我的的训练样本中,包含城市名 (area), 人名 (name), 以及其余一些标签。训练样本 4 千万条,测试样本 1 千万条。基本上使用已经肯定的一些词典生成。为了提高效果,样本尽量准确,且数量尽可能多一些。
执行下面的命令,而后你会看到相似于下面的输出,等待运行完成(其中 input 是你的训练数据,output 是你输出的模型文件名称):
./fasttext supervised -input data.train -output model_name
Read 0M words
Number of words: 14598
Number of labels: 734
Progress: 100.0% words/sec/thread: 75109 lr: 0.000000 loss: 5.708354 eta: 0h0m
复制代码
训练完成以后,你能够这样运行你的测试集来查看一些关键指标:
其中 test 以后紧接着是你的模型文件以及测试数据集。下面的指标是精确率和召回率。这个在后面解释。
./fasttext test model_name.bin data.test
N 3000
P@5 0.0668
R@5 0.146
Number of examples: 3000
复制代码
为了直观的测试一些常见 case 的结果,咱们能够运行命令,交互式的进行一些测试。个人一些测试以下: .
首先这是对精确度和召回率的定义。
精确度是由 fastText 所预测标签中正确标签的数量。 召回率是全部真实标签中被成功预测出的标签数量。 咱们举一个例子来讲明这一点:
Why not put knives in the dishwasher?
在 Stack Exchange 上,这句话标有三个标签:equipment,cleaning 和 knives。 模型预测出的标签前五名能够经过如下方式得到:
>> ./fasttext predict model_cooking.bin - 5
前五名是 food-safety, baking, equipment, substitutions and bread.
所以,模型预测的五个标签中有一个是正确的,精确度为 0.20。 在三个真实标签中,只有 equipment 标签被该模型预测出,召回率为 0.33。
复制代码
毫无疑问,不论咱们的目的是否是识别多个标签,这两个数值咱们都要尽可能高一些。
优化样本
咱们的样本是程序生成的,这样理论上来讲不能保证正确,最好是人工标注,固然人工标注千万级别的数据比较难,那么咱们至少应该对样本进行一些基本的清理,好比单字去掉,符号去掉,统一小写等等操做。只要是与你的分类无关的数据理论上都应该去掉。
更多的迭代和更好的学习速率
简而言之,就是一些运行参数的变化,咱们让程序训练更多轮,且更优的学习速率,加上这两个参数-lr 1.0 -epoch 25
, 固然你能够根据实际状况进行不断的调整及测试。
使用 n-gram
这是一个额外提升,在刚才的模型中,训练的时候是没有加上n-gram
特征的,也就是没有考虑词序的因素。这里能够 简单了解 n-gram.
这是最终执行的训练命令:
./fasttext supervised -input data.train -output ft_model -epoch 25 -lr 1.0 -wordNgrams 2 -bucket 200000 -dim 50 -loss hs
复制代码
这是我在个人测试集上的精确率和召回率:
N 10997060
P@1 0.985
R@1 0.985
复制代码
通过以上几个简单的步骤,识别准确度已经到了 98.5%, 这实际上是一个不错的效果了,由于我目前没有肯定是否使用这个方案来进行实际应用,因此到了 98.5%以后也没有继续进行优化了,若是后续有优化,我会来更新这篇文章。将所用到的优化方法记录下来。
首先咱们在 pom 文件中引入:
<dependency>
<groupId>com.github.vinhkhuc</groupId>
<artifactId>jfasttext</artifactId>
<version>0.4</version>
</dependency>
复制代码
而后简单的写一下就行了:
import com.github.jfasttext.JFastText;
/** * Created by pfliu on 2019/11/17. */
public class FastTextDemo {
public static void main(String [] args){
JFastText jt = new JFastText();
jt.loadModel("/tmp/ft_model_5.bin");
String ret = jt.predict("呼 延 十");
System.out.println(ret);
}
}
复制代码
python 代码,更加简单了:
固然记得先安装一下:pip3 install fasttext
.
完。
以上皆为我的所思所得,若有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文连接。
更多学习笔记见我的博客或关注微信公众号 < 呼延十 >------>呼延十