摘要:文本分类是NLP应用领域中最常见也最重要的任务类型。本文简单定义了文本分类任务,说明了用文本分类形式解决问题的基本思路,讨论了数据集建设中的关键问题,并简要地介绍了文本分类算法,最后介绍了文本分类去工程化时的一些经验。
1. 引言
我在读研的时候,由于课题需要,开始接触自然语言处理——当时其实不知道啥是“自然语言处理”,只知道我需要“把微博文本分为两类”,即把微博文本分成按照情感极性分为“正面”和“负面”两类。分成两类之后干啥,我当时也不知道。每次整理文本算法时,想到读研阶段这种浑浑噩噩的状态时,我的脑海里会浮现一个字,那就是 “迟无嗯”。
什么是“整理文本分类算法”呢?就是基于目前掌握的一些方法或技术,重新做一次当年的情感分类任务,得到
![58485107b7636b723fcb49f2f1b6a8fd.png](https://i-blog.csdnimg.cn/blog_migrate/f1dae406fab064639c0d96345dda6200.png)
,然后和上一次的
![e5f5d771aabd37180175b85eab37da03.png](https://i-blog.csdnimg.cn/blog_migrate/018a40969b624039814f37d02cc11782.png)
比较一下,看看有没有进步。每次整理,我对文本分类任务都会有新的理解——孔子所说的的“温故而知新”,其实是一种学习方式。这篇博客的作用,就是把积累下来的经验和感受系统地整理一下,记录下来。目前为止,作为一个算法工程师,我的主要体会是,要想合理地完成一个文本分类任务,首先需要一定的方法论,其次需要懂一点算法,还需要一些经验。
本文的主要内容,就是我体会到的这3方面的东西:首先定义一下文本分类,介绍文本分类任务的几种经典场景;然后说说如何用文本分类方法解决实际问题;接着介绍数据科学类任务的重头戏,即数据集的建设;然后是数据科学类任务的核心,介绍了文本分类任务可以使用的几种算法;最后是工程化时需要注意的一些方面。
2. 一种解决问题的方式——文本分类
我们在做事情的时候,首先需要做的事情就是,确定待解决的问题。在职业生涯里,我们需要完成各种各样的任务,每一个任务都是由若干问题构成的。我们需要基于自己对问题和算法的了解,找到一种或者若干种可以合理地解决问题的方式。这里主要是介绍解决一类问题的过程,因此首先定义一下分类和文本分类,然后说一些文本分类任务相关的典型场景。
2.1. 分类与文本分类
分类就是人类出于某些需要、按照某些标准,将事物分为若干组的活动。分类可能是我们人类最喜欢做的事情之一。从操作的角度看,分类,就是把事物按照一定的规则分门别类。而文本分类,就是把文本按照一定的规则分门别类。“规则”可以由人来定,也可以用算法从有标签数据中自动归纳。一般来说,我们会首先考虑人为规定,如果不可行,就会考虑使用算法。
在我们的生活和工作中,很多事情可以转化为一个分类问题来解决,比如“今天要不要做眼保健操”、“这个方案好不好”等等可以转化为二分类问题。在自然语言处理领域也是这样,大量的任务可以用文本分类的方式来解决,比如垃圾文本识别、涉黄涉暴文本识别、意图识别、文本匹配、命名实体识别等——真的是很多任务。
2.2. 文本分类方法的应用场景
如表2-1,展示了若干可以用文本分类方法解决的问题。文本分类在搜索引擎、问答系统、会话系统等等重要的信息处理系统中应用非常广泛,可以说无处不在。
表2-1 几种可以用文本分类方法解决的问题
![b9b165c0363737a502f39eecb3640d33.png](https://i-blog.csdnimg.cn/blog_migrate/e2075b2632fa0b482facc001500f26d8.jpeg)
![88b18e43c5e62283c1e114b23e6b47dc.png](https://i-blog.csdnimg.cn/blog_migrate/4b529627831a9ac0dea5731404783801.jpeg)
3. 如何用分类的方式解决文本数据处理任务
本节的标题其实存在逻辑错误:不同场景里的文本数据处理任务千变万化,分类方法不一定能够解决问题。所以这里首先介绍如何判断一个任务是否可以用分类方法解决,然后说明如何将一个具体的任务转化为分类任务,并介绍一些可以用分类方法完成的文本数据处理任务。
总的来说,只要一个任务的输出值是离散值,或者可以转换为离散值,都可以用分类的方式来完成。而在确认一个任务可以用分类算法完成后,我们可以把业务问题转化为一个分类问题。
接下来,就需要确定研究对象的分类体系,即回答一个问题:研究对象需要分为哪些类别呢?一般来说,这个问题需要由提出任务的那个人回答,或者由他来指定一些人回答——当团队比较小的时候,算法工程师要挑起担子,把分类体系定下来。当分类体系确定之后,任务的输入(样本特征)和输出(类别标签)就呼之欲出了。表2-1所列的,是一些常见的,以文本分类形式解决的问题。
接下来可以开始建模了吗?
4. 数据集的建设
电影《天下无贼》里的黎叔提出过一个经典的问题,如图4-1。不管做哪一行,我们都要像黎叔一样,考虑一下这一行最重要的资源是什么,这样我们分配成本的时候就有了依据。那么,文本分类任务最重要的资源是什么呢?那就是知识的载体,数据(手动狗头)。
![59cce32407d96eeb1de13d701fe931ca.png](https://i-blog.csdnimg.cn/blog_migrate/9828cb70156ae95449d57331c4b26149.png)
文本分类需要用有监督模型来完成,因此需要人工对一些数据进行分类、形成一个有标签数据集来训练分类器。构建数据集的过程中,我们需要关注数据标注工具,以及数据的质量和数量。
4.1. 类别的定义与标注规则的制定
分类数据集的构建,应该从类别的定义开始。当然,这部分工作在前面定义分类问题的时候,就已经完成了。剩下需要关心的,就是如何标注数据。数据标注,不管是单练,还是团队作战,都要约定一套标注规则或者原则。我们可以约定一些类似《小学生守则》一样的规则,规定什么样的样本是“1类”、什么样的样本是“3类”。
4.2. 数据的质量
4.2.1. 影响数据质量的因素
数据科学类任务有个特点,训练数据的质量决定模型的上限。作为知识的载体,训练数据里会包含一定数量的错误。而模型在学习数据时,会把正确的和错误的知识都学到手——如果我们给模型喂(feed)的是高质量数据,那就有机会训练出一个高水平的模型,如果我们给模型喂的是低质量的数据,那么一定会训练出一个低水平的模型。
标注的过程中,会有很多因素会威胁数据标注的质量,包括:
(1)标注人员对标注规则的理解不准确。沟通是一个技术活,准确地传递和接受信息是很难做到的。这个环节需要迭代进行。
(2)随着时间的流逝,标注规则会在标注人员记忆中的逐渐消逝。可以通过定定期开会复习来缓解这种情况。
(3)在人机结合的标注环境中,人会被机器预先标注的结果误导。
(4)标注人员会在某些情况下工作能力会下降。比如,我在体力、脑力下降的情况下,对标注规则和文本数据的理解能力会降低,标注的质量也会下降。
(5)标注人员会在某些情况下会故意降低标注质量。假设我再标注500条数据就可以收工,然后吃一颗神木的旱地西瓜,如图4-2,那我就会有意地加快标注速度——“又快又好”是不可能的,工作质量肯定下降。
![4b14c46bddebdf9fd4aec5e0dd71c7db.png](https://i-blog.csdnimg.cn/blog_migrate/33917b9a1287da07e6cfc45b22a9da94.png)
看起来,数据标注工作需要对抗的不利因素非常多。我们该怎么办呢?
4.2.2. 保障数据质量的办法——管理
我们可以使用质量管理的思想和方法来帮助数据标注人员,进而保障数据质量。
数据质量检测是我们了解和控制数据标注情况的重要方法。假如有一双如图4-3的眼睛看着我,我是不敢做什么坏事的。同样的,如果知道有人会检查自己标注的数据,我会时刻抖擞精神、认真工作。在工作里,作为算法工程师,我有时候需要自己标注一些数据,尽量把模型训练的好一点——我知道,模型是要上线的,效果好不好大家一看就知道了,自欺欺人没有用。当然,规范一点的做法,是由若干利益无关,或者有动力追求高质量数据的人,对数据集进行抽检,并用准确率、召回率等指标度量数据集的质量。
![5b0f09936f8e81f5487bb9046ce5fb3b.png](https://i-blog.csdnimg.cn/blog_migrate/3df555b53e9c8937da9667466b5a3197.png)
在数据标注的过程中,针对理解偏差、记忆消逝、工作状态波动等可能的情况,可以设置一些制度,比如例会,尽量消除负面因素。
4.3. 工欲善其事
很久很久以前,我标注分类数据是在文本编辑器里,如图4-1。
![4d68deaeae58a73171338a7edb5a3abb.png](https://i-blog.csdnimg.cn/blog_migrate/1eb79e3ecf520e56a02a317f42d06736.png)
后来,我发现excel里的格子可以很好地将文本和标签分隔开,光标上下移动也方便。
再后来,我更懒了,想进一步降低数据标注环节的工作量,就花了一段时间调研了一下开源的文本数据标注工具,发现了一个叫doccano的东西。这个工具挺容易上手,部署难度也不大,可以在
https://github.com/doccano/doccanogithub.com找到。
4.4. 关于训练数据的数量
一般来说,我们会把数据集分为两部分:(1)训练集;(2)测试集。其中训练集用来做特征工程、构建分类模型,而测试集用来对模型的效果进行评测。在构建模型的过程中,我们经常需要对模型的结构进行调整,并观察不同结构的效果——因此我们又会把训练集分拆为两部分:(1)训练集;(2)验证集。这样一分拆,训练集里的数据可就不多了。
再加上现在大家比较推崇深度学习,干啥都要上深度学习,有标签数据集的规模需要足够大,才能让模型充分学习。
那么,标注多少数据算是足够了呢?比较稳妥的答案是:我们可以先标注一点试试看、不够再加。随着训练集的扩大,模型的效果会越来越好——当然,到一定阶段就不在明显上升了,这时候就可以停止标注数据集。注意,如果模型效果达标了,可以停止标注;如果时间或者金钱不够了,要及时停止标注。
4.5. 使用主动学习降低标注代价
不管加多少鸡腿,也不论标注工具有多酷炫,标注数据都是一件消耗体力、精力和时间的事情,我们需要想办法降低训练模型所需要的数据量。而主动学习(Active Learning, AL)是一种可以有效降低数据标注量的方法。AL的基本思想是,选择模型认为预测难度大(可以理解为空间中靠近分类界面的那些样本)的样本,由人工进行标注,然后用这些高难度样本训练模型、让模型快速获得较好的分类能力。
AL中,最关键的是“标注难度”的度量方式和计算方法。以逻辑回归分类器为例,在分类器对一个样本进行分类时,输出概率p越接近0.5,说明模型对本次判断越没有信心(此时相当于随机选一个类别)。那么,我们可以构造一个预测困难度的计算方法:
![8b779da8b6ed664ee5e7fbb269c6f226.png](https://i-blog.csdnimg.cn/blog_migrate/20c81dc49f4574f9dd22e244486b60c6.png)
当然,实际应用中的AL会稍微复杂一些,还需要考虑每次选择出来的样本的多样性等。除了AL,还有很多方法可以用来降低标注代价,不了解就不介绍了。
5. 文本分类算法
当然,数据中的知识需要我们用一定的方法提取出来——那就得靠文本分类任务的重要一环,算法了。
总的来说,文本分类任务的关键内容有两个:(1)文本表示;(2)分类算法。文本数据的最大的特点就是,它是一个字符串。字符串本身可以体现的信息比较少,而当它被切分开后,对人和机器来说,含义就丰富起来了。机器基于切分后的文本,将文本表示为包含了语义和信息了的数值(或数值向量), 就可以用分类算法进行文本分类了。
5.1文本表示
文本表示方法可以参考
李鹏宇:常见文本相似度计算方法简介zhuanlan.zhihu.com的1、3、4节。
5.2分类算法
NLP里使用的算法/模型,基本上可以分为3类:(1)规则;(2)统计和机器学习方法;(3)神经网络。它们支撑NLP度过了3个重要的阶段。
5.2.1规则
是的,规则是我们首先可以考虑的方法。假如说一眼就可以看出各类(或某一类)文本的特点,比如图4-1所示文本,那么直接上规则。
![76638475f2dd0effc5be33d3b9818e90.png](https://i-blog.csdnimg.cn/blog_migrate/0b92a4040818052455dd6961e4e6b97a.png)
5.2.2统计和机器学习方法
假如文本的模式比较复杂,人脑已经无法识别,那么我们需要机器的进一步帮助。我们可以使用统计或机器学习模型,自动地从文本数据中学习模式,然后自动地对文本进行分类。
统计和机器学习方法的特点是,对特征工程的依赖比较大。这是个双刃剑:当训练数据量比较小的时候,我们可以凭着对业务和数据的理解,为模型添加大量先验知识,让它站在我们的肩膀上;当然,这样做会消耗我们的时间和精力。
5.2.3神经网络
假如训练数据量比较大,我们还可以考虑使用神经网络来做文本分类。这里所说的“数据量大”可以是:(1)大量数据预训练得到的文本表示;(2)或者训练数据量大。常用的结构包括全连接层、softmax、CNN、RNN、LSTM、Transformer、GPT、BERT等等。
神经网络的突出优势是:
(1)结构灵活。可以基于常用结构方便地设计出各式各样的结构,以处理各式各样的任务。
(2)信息容量大。神经网络是众多机器学习模型中,效果上限最高的之一。据可靠消息,神经网络可以拟合任意复杂的函数。
(3)文本表示自动化。神经网络方法大部分情况下会采用词token的分布式表示作为输入特征——这种特征工程方法的泛化性比较强,不需要太多背景知识就可以得到比较好的特征。“万物皆可嵌入”这句口号还是有点道理的。
6. 工程化与算力
经过前面的努力,一个文本分类器终于出现了——我们的任务还没有结束,我们还需要将分类器工程化,即以一定的形式对外提供分类能力。一般来说,我们可以把分类器封装成api,就像pyltp这样的库一样;也可以基于flask这样的库,把分类器封装成一个restful服务。
我们还需要了解文本分类装置的性能。对工程师来说,一个产品一定要符合一系列的规格。在文本分类任务中,最后产出的模型必需满足一定的性能要求,即可以在一定的计算资源限制下、在一定的时间内完成训练或预测。换句话说,我们的文本分类系统需要在a个b处理器、c个d内存条、e个f型号显卡等的条件下,在g秒内完成对h个样本的类别预测(有些情况下,还需要在i秒内完成模型的训练)。相关的性能数据,可以用压力测试的方式获取。
分类装置的性能,主要由两个因素决定,即算力和算法复杂度。
调整算力,是一种比较通用的、用来调整系统性能的方式。我们需要通过测试了解系统对内存的消耗,以及单核可以达到的处理速度,并基于业务需求推测需要的计算资源,即内存大小、核心数、进程数等。
堆硬件比较容易,也比较贵,通常我们需要想办法,尽量在算法方面降低消耗。我们可以在模型复杂度、数据结构、缓存等等方面对分类系统进行优化。比如说,使用简单模型,或者使用知识蒸馏等方法减小参数规模;使用合适的数据结构存储数据,降低计算、查询等操作的资源消耗;把一些可以离线计算的数据提前计算好、缓存起来,需要使用的时候直接查询出来用;等等。
7. 结语
从这篇博客的篇幅分布和“手动狗头”,可以看出,在我看来,文本分类任务中各个环节的重要性排名是这样的:任务定义、数据集构建、模型构建都是不可忽视的一环。在唯物辩证法的指引下,我“系统地”分析了一下文本分类任务的各个环节:任务定义、数据集建设、算法任务定义糊里糊涂的情况下,这个任务将在各个环节充满不可控因素,最后的结局因此变得不可控,每一个参与者都将冒着较高的风险;前面提到过,数据是知识的载体,必需保质保量;而算法负责从数据中归纳知识,是任务的核心部分。这个观点也可以用我们常听说的 “短板理论”来解释:分类系统的任何一个环节没有做好,最后的分类效果都会受到影响。
在引言里,我说本文是“到目前为止”对我文本分类的看法,这是有缘由的。事物是不断发展的,我的看法也会不断发展,对文本分类的认识和理解还会变化。到一定阶段,还得复习一下文本分类相关内容。
注意:本文为李鹏宇(知乎个人主页https://www.zhihu.com/people/py-li-34)原创作品,受到著作权相关法规的保护。如需引用、转载,请注明来源信息:(1)作者名,即“李鹏宇”;(2)原始网页链接,即当前页面地址。如有疑问,可发邮件至我的邮箱:lipengyuer@126.com。