1.问题背景
目前在做文本分类任务,按理说现在文本分类很成熟,基于bert进行分类基本就可以了。但是我这边任务有几个问题比较麻烦:
(1)样本本身并不保证完全正确。
(2)样本分类较多(50个类)而且分布极不均匀,有的几百,有的个位数。
问题(1)的话,找业务方帮忙梳理数据,还好解决。问题(2)就是小样本分类问题了。于是百度看下其他大手子怎么处理这种小样本分类问题。主要是借鉴美团技术团队发布的文章:美团获得小样本学习榜单FewCLUE第一!Prompt Learning+自训练实战 - 美团技术团队
文章里面提到的优化策略有模型结构优选、大规模预训练、样本增强、集成学习以及自训练等,讲道理,才疏学浅,有些我整不明白,就没有尝试。下面是我做的一些尝试。
2.方法尝试
先介绍下我的样本情况。我拿到手的样本是1800条左右(我是做了截取的,样本大于50的只取50,不到50的就是有多少取多少),然后训练集:验证集:测试集=7:1:2.模型准确率为83%。
样本增强
1.造数据
顾名思义,就是根据已有的验证过的数据,造相关的数据,这个就需要一点专业知识了。由于我有一点专业背景,所以就自己造了一批数据,造的原则就是地名啥的简单的替换(不太妥,但也没办法,不敢大改)。最后数据量大概我以50为基准上下稍微波动,最终数据量是2600左右。然后跑了下,模型准确率为89.62%。
2.利用现有数据做增强(这个处理稍显稚嫩,不如后面使用的Prompt Learning)
利用现有正样本,然后根据正样本造出其他负样本,转化为二分类。举个例子,比如输入的文本是"水中COD的测定",标签是"水监测",然后我会用剩下49个类造出49个负样本。输入的样本转化为"水中COD的测定->水监测",标签为1,剩下49个样本标签为0(比如"水中COD的测定->气监测",标签为0).这样就造了许多样本,然后训练。
这里有个问题,里面大部分标签是0,这样样本分布就很不均匀。当时我也想随机取几个类造负样本,但是效果很不理想,就用了全部类造样本。不过这个方法最后结果也不太理想,但是比随机取几个类做负样本好一点。
最终结果来看,不太好,模型效果下降。
3.样本相似度计算
类似于聚类。将训练集每个标签下的样本利用bert做词嵌入之后,求其均值,作为该标签的特征向量。将测试集的样本与不同标签的特征向量求余弦相似度,距离最近作为该样本标签。模型实际准确率51.22%。因为是多标签分类,标签反应比较敏感,可以通过阈值控制下提升。这部分优化我没做,因为起始就是51%,意义不大。
4.大规模预训练(推荐)
这个做法就是在预训练模型基础上,再用一批相关的数据继续做预训练。
这种对预训练模型继续做预训练的方法有融入领域知识的Domain-Adaptive Pretraining (DAPT)预训练方法和融入任务知识的Task-Adaptive Pretraining (TAPT)。DAPT是增加大量领域内无标签文本继续训练语言模型,之后再在指定任务的数据集上进行微调。TAPT指在预训练模型的基础上,增加数量较少但与任务直接相关的无标签语料进行预训练。
我这边目前暂用的TAPT,就是把相关数据集的文本作为语料,预训练语料为357KB,以bert-base-chinese为基础模型继续预训练。这个效果相较于之前有提升,模型准确率是91.32%,后来增加预训练语料规模到5M,模型又提升一个点。
5.Prompt Learning(推荐)
本质上是为了尽可能减小预训练目标与下游微调目标的差距。因为用的是Bert的MLM模型,而下游任务是分类,两者实际上是有差别的。所以为了保证上下游任务一致,调整模型输入,把分类任务转化为预测任务。另一种官方的说法是,BERT预训练时的MLM层的参数能利用上。而且,即使model没有进行fine tunning,这个model其实就会含有一定的准确率。具体做法如下:
假设样本是:我觉得这个电影不错,标签是正向。那么调整输入为:”我觉得这个电影不错,这是一条[MASK][MASK]评论“,label为”我觉得这个电影不错,这是一条积极评论“。这样把分类任务转化为预测任务。这里关键是模板的设计以及标签映射(比如{积极,消极}),具体参考上面提到的美团团队的文章。需要注意的是使用MLM模型时候,由于我们不是用默认的掩码模式,而是用自己定义的掩码模式,所以输入需要重写一下。
上面是最终版本,这里插播一下我的试错,可能也有用:
因为我的标签比较多,我当时是把多个标签{A,B,C...}映射到另一个标签列表{a,b,c...}(A我这里只是个代号,实际上是xxxxx类,我偷懒这里就用A代替了;a同理,不过a表示两个字的词),映射的标签列表里面每个标签都是两个字组成(与输入的两个[MASK]对应),当时只考虑这些标签不重复即可,后来发现效果不行,预测出的标签有时候前言不搭后语。后面改变了策略,想用一个标签来代替,标签映射为{A,B,..Z,a,b,..z},但是我用的是不区分大小写的模型,结果惨不忍睹。后来就把标签按照模板写进样本,然后标签映射为{正确,错误}来处理。
我训练了25轮,效果有提升,推荐。
Embedding增强
Embedding增强,就是不再对输入进行操作,转而在Embedding层面进行操作,可以通过对Embedding增加扰动或者插值等方式提升模型的鲁棒性。
我本来打算用Manifold,具体做法是随机选择层数k,对该层的特征表示进行Mixup插值。普通的Mixup的插值发生在输出层Embedding部分,而Manifold Mixup相当于把这一系列插值操作加入到语言模型内部的Transformers结构的随机某层中。
实际上我目前只用了mixup,模型效果有下降。
最近事情比较多,等有空再弄,待续。。。