文本分类真的简单吗?——公众健康问句分类测评比赛小记

        去年九月份我随项目组一起参加了中华医学会医学信息学分会主办的医学数据挖掘算法评测大赛,原本是抱着拿一部分医疗文本数据的心态区参加比赛的,最后取得了比较好的成绩,而且洛基在比赛中也学到了很多,本来去年就想把比赛里学到的东西记录在博客中,却因为种种原因搁置了。仔细一想,自己的博客也很久没有经营,最近在看对比学习的文章时候突然想到自己以前也写过一篇关于对比学习的“论文读后感”,遂翻看博客观赏旧作,感叹写博客是一个将输入转化为输出的过程,确实能帮助自己在这个过程中学到很多东西,并且是对自己的知识体系的一个梳理和记录,值得时常温习,温故知新。

        回到正题——简单介绍一下这个任务,公众健康问句分类任务,主要是针对给出的与健康有关的中文问句,对问句的主题进行分类(共5000训练样本,3000测试样本,包含 6 个大类:A 诊断、B 治疗、C 解剖学/生理学、D 流行病学、E 健康生活方式、F 择医)。其中一个中文健康可以被归为多个主题类别,因此该任务是一个多标签分类的问题,评测指标是在6个类别上计算的F1 score。报名参赛的一共有400个队伍,共500人,最终取得了初赛第3,决赛第6的成绩(决赛成绩是取初赛成绩和决赛答辩成绩的平均分,也就是说初赛成绩不错,决赛阶段答辩的不理想导致名次跌了两名=。=)。

        这个任务的主要难点有以下几点:①多标签分类,这类问题的解决方案通常是建立多个二分类器,所以需要对不同类别的数据单独分析;②比赛允许采用外部数据进行训练,其他队伍中有一些成员具有医学背景,能够获取到更多优质的医疗类数据,而我们团队因为以前没有做过医疗领域的任务,所以并没有可靠的外部数据;③样本不平衡问题,数据集包含6 个大类,其中有两个类别的样本极不平衡,并且C类的训练集中正样本只有1个,只用模型来判断会导致recall等于0,严重影响F1 score。

        当时因为比赛时间比较紧,所以我们只针对③样本不平衡问题进行了一些尝试和探索。样本不平衡其实是一个真实落地场景下常见的问题,它的解决方案多种多样,而且需要不断试错,并没有哪种方法能一劳永逸解决样本不平衡问题,需要不断积累经验,所以以后如果有新的方法洛基也会记录下来。在这里洛基就把之前尝试的、以及现在学习到的一些关于样本不平衡问题的应对方案,记录如下。

1.过采样/欠采样:①欠采样通常适合样本总数较多但是分布不平衡的情况,尤其适合需要严格控制样本量级的应用场景;简单欠采样的缺点是会损失大量样本,对模型是一种损失,而之前洛基在一篇公众号文章上看到了“迭代预分类欠采样”——假设一共有k个(少量)正样本,大量负样本,首先采样k个负样本,与正样本组成训练集,训练一个分类器,然后去对剩余的负样本做预测,在预测错误的样本(不放回)采样k个样本,再加入原来的训练集,继续训练一个分类器,再对剩余的负样本进行分类...迭代执行这个过程,直到所有负样本被正确分类。“迭代预分类欠采样”的好处是,优点是在控制样本规模的情况下,充分利用了负样本中差异性较大、有代表意义的样本。②再说过采样,在没有严格控制样本量级的情况下可以缓解样本不平衡问题。

2.简单样本增强:①EDA如词汇替换、随机删除、词序替换、随机插入等经典方法,EDA是通过给文本注入噪声等方式获取相似样本,从而扩充训练集,优点是做法简单、快捷,通过nlpaug、textattack等库可以轻松完成,缺点是没有给样本引入新的知识。  ②回译方法也是一个常用的样本增强手段,通过将中文文本翻译成A语种,再翻译成B语种,最后翻译回中文,可以实现样本的线性增长,值得一提的是,回译方法的本质也可归为最近比较火的一个概念——迁移学习,本质上是把翻译模型学习到的多语种的语法、语义、句法等知识转移到了新生成样本上,给旧的样本注入了新的知识,因此回译生成样本的质量取决于翻译模型的好坏,洛基认为,这既是回译的优点,也是它的局限,优点在于我们或许可以借助强大的翻译模型(例如谷歌翻译)生成具备更丰富表达的样本,局限在于在特定领域任务上由于数据分布差异,翻译模型效果很容易受到影响。

3.基于预训练的样本增强:在简单样本增强中我们通过翻译模型将语法等知识迁移到样本中获得新的训练样本,同样的思路,我们也可以将bert等预训练模型的知识迁移到我们的样本中。基于这个想法,就有了基于生成式预训练模型的样本增强,比如在分类场景下,微调一个输入数据是“[CLS]标签[sep]样本”的gpt2模型(有条件可以上gpt3),然后根据标签和几个初始词让模型生成对应的样本;或者在相似句判断任务中,用相似的文本微调一个SimBert,然后通过SimBert生成相似的文本。

4.伪标签的样本增强:利用训练好的模型给无标签的数据进行预测,把预测置信度高的样本(比如二分类任务中预测某类概率大于0.95)取出来打上伪标签,然后得到一个增强样本池,然后每次在样本池中采样一部分样本纳入训练集,假如最后在测试集上效果有提升,则将这部分伪标签数据与训练集合并,迭代进行新一轮采样、预测、合并。

5.模型层面缓解样本不平衡:①损失函数的修改,比如类别加权loss,想法很直观,根据正负样本比例去调整正负样本的loss权重,其实这一点和过采样、欠采样的思路是异曲同工的,洛基的观点是,它们都认为单个正样本和单个负样本对模型参数有相同的贡献,所以根据样本比例去修改正负样本的loss权重就等价于平衡正负样本数量了。Focal loss是一种改进版的loss,它除了考虑类别比例之外,还考虑了样本的难易程度,即样本预测的概率越接近真实的标签,则loss会呈指数级缩小,当正样本被预测为1、或负样本被预测为0时,该样本loss会变成0(这里不对公式进行展开,以后有机会再写一篇文章专门探讨)。这里洛基又想提的是,focal loss就和迭代预分类负采样的思路也有相似的地方,迭代预分类负采样只会把预分类错误的样本纳入训练集,而分类正确的样本不会被纳入训练集,是在寻找更难以判断的样本,而focal loss也倾向于给予难以判断的样本更大的权重——追本溯源,有些方法的思想都是相通的~ ②分类阈值调整,比如二分类上对于正负类别判定的阈值是0.5,可以考虑调整阈值来适应比例失衡的训练样本,比如负样本比较多,正样本概率阈值调小一些或许能增加召回率,那么可以设定分类器输出为正的概率大于0.4就判定为正。

        在这次比赛中,我们总共尝试的就是过采样,EDA,回译,(针对测试集的)伪标签,Focal loss,分类阈值调整等方法,考虑到数据集本身数量少,并没有采用欠采样,而由于时间关系也没有微调一个生成式预训练模型做数据增强(a pity)。从最后的效果来看,伪标签,Focal loss对于效果有一定提升;回译并没有收到理想效果(可能因为使用的是有道翻译而不是Google?)。

        以上几种方法有一个共同缺点就是不能解决语料空间扩展的问题,只能帮助模型在当前语料空间学得更好,比如针对医疗领域的样本进行增强,并不能获得法律领域的样本。所以在样本极度缺乏,上述方法皆收效甚微时,不妨直接动手标注数据吧=。=

        回到比赛上。参考其他的比赛top方案,nlp打比赛的过程通常都可以分为四个阶段:数据分析和预处理;技术选型;开展实验与模型调优;模型融合。下面根据这四个阶段简要介绍我们的做法。

1.数据分析和预处理

        洛基认为,不管是什么任务,数据的重要性都是大于模型的。于是先对文本进行初步清洗,用正则匹配去除一些URL字符和长串数字;对字母并没有执行删除,因为考虑到有些字母包含了与样本类别有关的信息,如CT,B超;停用词与标点没有去除。

        观察并统计文本长度分布,发现超过95%的样本字数小于512,想到可以用bert模型,文本字数集中在100-200之间,如果要用bert可以把文本长度设为512,短补齐长截断。这里进行截断的时候需要考虑保留重要分类特征,当时我们观察数据的时候的时候发现患者的问句通常在第一句或者最后一句,而这类问句往往包含了潜在类别信息,所以进行截断时候要保留句首和句尾,然后再从中间截断,尝试过从第二句截断和从倒数第二句截断,效果相差不大。

        数据增强,这部分在前面已经介绍。

        关键词提取,对所有样本(包括增强样本)进行分词,然后计算每个单词的tf-idf,把每个样本的tf-idf最高的前几个词作为关键词,拼接到文本前面,作为关键词特征。

2.技术选型

        对于分类任务,text CNN是一个不错的基线模型,它搭建快,训练效率高,而且效果通常还不错,所以这个模型理所当然要加入我们的实验中。接着因为以前搭建过各种文本分类模型,包括text RNN,text RCNN,所以将它们一起考虑了。传统的模型在比赛中往往能发挥很大作用,首先传统模型可以作为baseline,通过对比来发现其他模型是否搭建正确,比如我们采用bert模型做分类任务,结果效果还比不上text CNN,那么可以说明bert模型代码出了问题;其次,在模型融合阶段,用差异较大的模型进行融合效果要好于用差异较小的模型进行融合,通常这种差异一般体现在数据层面和模型结构层面,k折交叉验证是利用数据层面的差异进行融合,而传统模型和bert等前沿模型进行融合,则属于后者。

        如今预训练模型大行其道,各种预训练方法层出不穷,确实是让研究者有些“乱花渐欲迷人眼”了。不过去年的九月份,当时比较好的预训练模型是Roberta,它通过使用了比原始bert更多的数据集、删去了NSP预训练任务、寻找到一个优于原始bert的超参配置、将固定mask改为每个epoch执行的mask操作是相互独立的等待一系列操作对bert进行了优化,获得了更优秀的模型性能,所以当时除了原始bert,我们也将Roberta纳入了我们的实验。出于时间关系的考虑,其他预训练模型并没有尝试,不过今年已经有参数量更大、预训练数据更多、效果更优异的模型了,在此不得不感叹行业发展速度之快。

3.开展实验与模型调优:

        预训练模型尝试了bert-base,roberta-base,中文医学预训练bert,具体做法是利用bert对文本的所有单词进行编码,然后把单词编码执行一个pooling操作得到整个句子的表征,接着把句子输入分类层,尝试过第一层transformer和最后一层transformer得到的字向量累加再取均值,效果没有提升;最后发现单模型对比中Roberta效果最好;在对预训练模型进行fine-tune时,注意要避免weight decay(参数正则化)对偏置的影响,因为在过拟合发生时往往是权重w过大导致的,因为w过大,输入数据产生微小变化时,输出才会有很大差异,而偏置b对于所有输入都是一视同仁的,如果w很小,就算b很大,输入数据的微小变化也不会使得最终的输出产生大的改变,所以实际调参时通常会避免对偏置的正则。之前洛基也看到别人的代码里,对于Layer Norm层和Batch Norm层的参数也是不进行正则话化,据说会引起Layer Norm层的失效,特此记录。

        分类模型尝试过text CNN,text RNN,RCNN,最后发现textCNN效果最好;在对text CNN调参时发现卷积核尺寸采用20,30,40三种较大的尺寸效果比较好,尝试过小的size,效果不如大的size,可能与长文本中特征通常是较长的segment有关,长文本的分类通常因为文中出现了一些与类别有关的句子、关键词,所以不需要考虑文本的整体语义,只考虑局部语义就能将句子进行正确地分类。

        分类层尝试过sigmoid和softmax两种方式,当时发现softmax效果比较好,对于这个结果洛基比较差异,以前认为softmax做二分类的效果应该是和sigmoid等价的。后来查阅资料,看到有讨论说这是pytorch框架的问题,pytorch中sigmoid和softmax在反向传播中存在一些细微差异,这种差异最终体现在效果上了,具体原因以后再深入探究。

        损失函数尝试过交叉熵,focal loss,focal loss对于模型效果有提升。

        对text CNN、text RNN等传统模型的embedding层添加对抗扰动,考虑到添加embedding扰动会影响模型训练速度,所以并没有给bert模型尝试这种trick。实验证明embedding添加对抗扰动能略微提升模型效果,这也是一种防止过拟合的方法,它的思想可以解释为:在输入上执行梯度上升,在参数上执行梯度下降,从而让模型对于输入的细微变化不敏感,增强模型的鲁棒性与泛化性。典型的embedding对抗扰动方法有FGSM和FGM,其中FGSM是使输入沿着梯度方向往损失函数极大值走,而FGM在FGSM的基础上增加了一步对具体梯度的scale,相当于归一化,保证数值的稳定。对于前述介绍其实还是没有给大家一个关于对抗扰动更立体的认知,洛基在这里从直觉上猜想embedding层添加对抗扰动能够work的原因不管是word2vec还是glove等词向量,在生成词向量时候都是考虑了词与上下文关系的,这也许会导致一些含义相反、上下文语境相似的单词,在embedding空间中距离也相近,比如good和bad,我们可以说you are a good boy,也可以说you are a bad boy,而如果用CBOW训练一个word2vec,那么这种情况下学到的good和bad的词向量应该是接近的,然而它们的含义却大相径庭;对抗扰动考虑到了这种情况,设想在添加扰动之后模型把输入的good识别成了bad从而导致情感分类模型loss急剧增大,就会迫使embedding层修改对于这类单词的映射规则,使得这类单词在语义空间中的距离增大,从而优化embedding的表达能力

        其他trick:对于模型优化方法,关于提前终止,fix embedding,Layer Norm,bridge network等的trick,往往是八仙过海、各显神通,由于时间太久也忘记了很多trick的具体细节,这部分以后有机会想单独做一个总结。总之需要不断学习,在实践中积累经验。

4.模型融合

集成相关性低的模型能够提升模型的纠错能力,所以当时我们小组在做任务的时候,初步的规划就是组内成员各自搭建模型,最后把成员各自的模型进行一个集成,将预测的结果进行融合。于是最终模型融合是对Bert,Roberta,医疗Bert,text CNN,text RNN,RCNN进行融合,每个单模型先通过5折交叉验证训练5个模型,然后把这些模型一起融合。(很暴力,但比赛就是这样,崇尚暴力美学)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值