CCF BDCI新闻情感分类初赛A榜4/2735,复赛1%题解报告

写在前面

本文将带来CCF BDCI新闻情感分类的题解报告,该方案在初赛A榜获得了4/2735,复赛成绩1%。希望可以给大家提供一些思路,互相交流学习

比赛代码已经开源在
https://github.com/linhaow/TextClassify

赛题说明
比赛的链接在这里:
https://www.datafountain.cn/competitions/350


比赛的内容是互联网的新闻情感分析。给定新闻标题和新闻的内容,然后需要我们设计一个方案对新闻的情感进行分类,判断新闻是消极的,积极的还是中立的。
训练数据集的字段如下:
id:新闻的唯一标识。
title:新闻的题目。
content:新闻的内容。
label:情感分类的标签。

数据分析

一个好的数据分析可以给比赛带来很大的提升。所以数据分析的过程不能忽视。对训练数据集分析后,可以发现训练集有如下一些特征。

(1)训练数据集中 0标签
的数据量比较少,只有几百。

(2)训练集中 1和2的标签
比较平衡,都是几千,相差不大。

(3)此外新闻的 文章内容
很长
,很多有上千个字。

(4)相比于新闻内容, 新闻标题较短
,很少有上百字的标题。

针对上述特征,可以看出标签中存在一定的数据不均衡,此外如何处理过长的文章内容也是一个核心任务。对于常用的bert模型,只能接收512个token,所以需要一个能处理过千字的文章内容的方法。
baseline
我刚参加比赛的时候初赛已经过去了一段时间了,当时有一个郭大开源的baseline,我的baseline是基于这个开源baseline修改的。baseline的结构图如下:


整个模型由两个部分组成。
(1)第一部分是最下方的split_num个bert模型(这里可以使用bert全家桶中的任意一个),现在基本文本分类比赛的前排都是bert模型。毕竟bert模型在预训练的时候就加入了很多比赛外的数据。所以相对来说效果也不会太差。

为了同时利用标题和文章内容信息,
在bert模型的
输入端。
我选用了
两个sentence加[SEP]做为模型的输入,其中sentence1是该新闻的标题,而sentence2则是该新闻的内容的一部分。为了让新闻内容可以覆盖到整篇文章,我首先将文章分成split_num段,然后在每一段选择maxlen的长度,分别做为split_num个bert模型的sentence2的输入。

举个例子,如果下面的长方形代表的是一个文章的内容,而split_num是3,则三颗五角星的地方是三个bert的sentence2的输入。sentence1均是文章标题。


(2)第二部分是上方的biGRU模块。该模块将bert对文章理解的不同部分串起来,最后给出综合考虑的分类输出。在这种RNN结构中, 双向
的效果往往比单向更好,所以使用了双向的GRU。
上述结构有如下的优点:
(1)减少了显存的使用,经过split后你可以在同样显存下处理更长的长度。
(2)另一个就是解决了长度上千的句子塞进bert的问题。上文bert模型处我使用的是中文的roberta-large模型。

提升模型

使用完上述baseline,并且调参后成绩就可以达到100名左右了。接下来就是如何提升模型的效果了。
(1)首先我发现郭大最初的代码好像有bug,当gru的层数大于1的时候维度不对。于是我查看源代码后把它fix了,然后在gru中加了几层layers,调整参数后,名次就到了前50了,大概线上是81.6左右。
具体的代码在pytorch_transformers文件夹中的modeling_bert.py第976行,修改后的代码如下:

self.gru.append(nn.GRU(config.hidden_sizeif i==0else config.lstm_hidden_size*2, config.lstm_hidden_size,num_layers=1,bidirectional=True,batch_first=True).cuda() )

这里增加layers的层数是为了让BiGRU更好地学习一篇长文章的不同部分。一层layer明显是 欠拟合
的,实际上实验结果也证明这里layers增大后成绩上去了不少。
(2)我尝试去清洗数据,除去一些url,img之类的数据,发现成绩不但没有提升,还有下降(其实这一点早就有心理准备了)。
因为在bert的使用中去除停用词等经常不能带来性能的提升。毕竟bert在预训练时使用的就是完成的带有噪声的文本信息,所以去停用词,清洗数据等不一定能带来效果的提升。


(3)我尝试了不同的split_num和maxlen,发现在roberta模型中,split_num越大的时候效果越好(我在7,8左右时效果最好),这是因为更大的split_num可以让模型更好地获取长句子的信息,更多的split_num可以让模型 捕捉的
密度
更高
,从而对长篇章的把握更加准群。给一个极端的例子,如果你的 split_num
比较小,maxlen也比较小,刚好把文章先抑后扬的抑的部分全捕捉了,那准确性肯定会下降。

与此同时也需要增加
weigt_dec
ay去防
止过拟合。通过这个方法线上就可以到81.7了


(4)使用多折交叉验证,多折交叉验证的效果会明显好于单折。 多折交叉和融合往往都能带来一定的稳定性和性能的提升。不过多折也

会增加 训练的时长
,所以往往在先调参确定好模型后再进行多折交叉。通过这个方法,线上就可以到达81.8了,

当时已经在a榜前15了。

(5)使用roberta-wwm-ext模型,
roberta-wwm-ext是一个基于全词遮罩(Whole Word Masking)技术的预训练模型。
 
简单来说,原有基于WordPiece的分词方式会把一个完整的词切分成若干个子词,在生成训练样本时,这些被分开的子词会随机被mask。
在全词Mask中,如果一个完整的词的部分WordPiece子词被mask,则同属该词的其他部分也会被mask,即全词Mask。
这个模型在复赛的a榜上效果比较好。这个应该是初赛和复赛训练数据集分布情况不同导致的。不过多样化的模型对于模型融合是很有帮助的。repo的链接如下:

https://github.com/ymcui/Chinese-BERT-wwm
(6)All data训练,在之前的训练中会使用一部分作为验证集,但是当你确定了所有超参数后你就可以尝试把所以数据拿过来盲跑,这样训练数据会多一点,不过缺点是拿不到本地的开发集测试结果。
模型融合

在得到两个模型的多个不同split_num,maxlen值后,就可以对模型的结果进行融合了,在融合中我使用的是分类问题中常用 投票法

总的来说就是用不同的模型输出结果进行投票,哪个结果的票多就选择哪个结果,如果票数一样,有0 label就选0,没有的话就选单模最好的模型。这里选0是因为之前的0样本在训练的时候比较少。
对于候选融合结果的选择我们采用的方法如下:


首先我们计算不同输出文件之间的相关性,然后选择相关性最小的几个输出结果,在相关性和得分上需要对不同的输出结果进行一个trade off。即最好的情况就是几个得分较高的模型相关性比较低。相关系数可以使用pandas中的 corr()计算。

接着对选出的几个模型进行融合即可得到最后的输出,投票融合结果的代码框架如下:

import pandas as pd

import numpy as np

submits =['0.818.csv','0.816.csv']

#需要融合的文件放submits中

files = []

data = []

for f in submits:

    if 'csv' in f:

        files.append(f)

        data.append(pd.read_csv(f).values)

print(len(files))


weight = [2,1] #融合的权重 result = np.zeros([len(data[0]), 3])
for i in range(len(data)): for j in range(len(data[0])): if data[i][j][1] == 0: result[j][0] += weight[i] elif data[i][j][1] == 1: result[j][1] += weight[i] elif data[i][j][1] == 2: result[j][2] += weight[i]
np.argmax(result, axis = 1) submit = pd.read_csv('submit_example.csv') submit['label'] = np.argmax(result, axis = 1) submit.to_csv('result.csv',index=None)

总结

其实比赛中还有很多方法可以尝试,不过中间有点事耽误了很多时间所以就尝试了两个模型,有点可惜,文章中有很多地方都还是可以调整的,比如融合方法等,大家有空可以继续探究。

本文转载在公众号:

纸鱼AI,作者:
linhw


推荐阅读


Transformer详解《attention is all your need》论文笔记

深度学习笔记系列(一):导数,梯度与方向导数


BERT源码分析PART I


BERT源码分析PART II


BERT源码分析PART III


站在BERT肩膀上的NLP新秀们(PART I)


站在BERT肩膀上的NLP新秀们(PART II)


站在BERT肩膀上的NLP新秀们(PART III)


Nvidia League Player:来呀比到天荒地老

关于AINLP
AINLP 是一个有趣有AI的自然语言处理社区,专注于 AI、NLP、机器学习、深度学习、推荐算法等相关技术的分享,主题包括文本摘要、智能问答、聊天机器人、机器翻译、自动生成、知识图谱、预训练模型、推荐系统、计算广告、招聘信息、求职经验分享等,欢迎关注!加技术交流群请添加AINLP君微信(id:AINLP2),备注工作/研究方向+加群目的。