剧本角色情感分析赛后总结


比赛链接
本次我与抖音大佬共同组队参加了剧本角色情感识别的比赛,成绩为二十多名的水平,这个成绩距离前排大佬还有一定的差距,因此我们需要进行一定的反思总结。

模型的搭建

第一个遇到的问题是模型的搭建问题,起初我们的想法是采用常规的分类做法,搭6个网络层,对于每一个网络层使用交叉熵损失函数进行模型训练,但是在这个比赛上这种方式指标并不佳。原因在于本次比赛采用了均方根误差的方式来计算评分,所以使用mse作为损失函数效果较好。
模型的评测指标这里也提醒我们,在打比赛的过程之中一定要采用更加贴合评测指标的损失函数进行训练。
修改了模型结构之后,我们选用nezha后面接上一个(768,6)的线性层进行回归计算,效果有明显的提升。
在比赛的过程中,我们还实验过其他结构,比如多个线性层加上dropout

class ClassificationModel(nn.Module):
    def __init__(self,model,config,n_labels):
        super(ClassificationModel,self).__init__()
        #self.embedding = nn.Embedding(30522,768)
        self.model = model
        self.fc1 = nn.Linear(config.embedding_size,128)
        self.activation = F.relu
        self.dropout = nn.Dropout(0.2)
        #self.activation = F.tanh
        self.fc2 = nn.Linear(128,n_labels)
        
    def forward(self,input_ids,segment_ids,input_mask):
        #outputs = self.embedding(input_ids)
        output = self.model(input_ids)
        #[64,128,768]
        output = self.dropout(output)
        output = output[:,0]
        output = self.fc1(output)
        output = self.activation(output)
        output = self.dropout(output)
        output = self.fc2(output)
        return output

整体效果与(768,6)线性层效果差不多,另外使用这种结构训练之后进行融合模型结果也没有明显的上升。

整数与浮点数提交之争

对于mse损失函数,有一个必要的特性,就是当你的值越远离增加标签的时候,每远离一步就会放大误差,这里举一个例子来说明
如果真实标签为1的时候,假设标签距离都为0.1
1.本身预测为0.9,放缩为1
减小误差 ( 1 − 0.9 ) 2 − ( 1 − 1 ) 2 = 0.01 (1-0.9)^2 - (1-1)^2 = 0.01 (10.9)2(11)2=0.01
2.本身预测为1.9,放缩为2
增大误差 ( 2 − 1 ) 2 − ( 1.9 − 1 ) 2 = 1 − 0.81 = 0.19 (2-1)^2-(1.9-1)^2 =1-0.81 = 0.19 (21)2(1.91)2=10.81=0.19
可以看出来情形2比情形1放大了19倍
这也就是我们为什么选择浮点数提交的原因
有些标签计算的可能有向正确标签的趋势,但是由于模型学习能力所限未能够达到正确的标签,此时如果选择整数提交的话,可能这一部分数据过大会拉大误差,因此这里我们选择浮点数进行提交

上下文的选择以及主语的加入

如果想要模型学习充分,必须加入所有的特征。
首先我们必须加入主语部分,因为同一句可能包含不同的主语。
其次我们需要加入上下文部分,因为上下文的情感同样也可能影响当前的情感。
对于上文加入,我们有以下几种策略:
1.加入上文不同角色的5句话(可以是n句话,大致4~6句最佳)
2.加入上文同一角色的多句话(可以是n句话,也可以全加)
实验的过程中发现策略1效果更好,猜测可能是由于方案2中的加入多句话有的时候距离较远,可能影响模型对于情感的判断。
同时跨幕在实验中发现结果会下降,说明上一幕的情感并不会影响到本幕的情感。

验证集和测试集的划分问题

验证集和测试集的划分有两种方式:一种是按照不同的情感来进行划分,另外一种是不同的剧本来进行划分。官方的baseline推荐的是按照剧本进行划分,这里我们尝试了两种方案,发现两种方案线上线下都有较大的差距,相对来讲按照剧本划分可能更好一些,因为按照标签划分前面有一些句子可能在模型中训练过了。

多折模型训练及模型融合的方法

通过实验,我们选择按照剧本划分多折,每一折选择3个剧本,总共为10折的过程,模型融合采用平均融合的方式,单折多模可以提升到0.707x的水平。
模型融合的时候应该选择分数相近的模型进行融合,才能有效的提升分数。针对mse一般采用平均融合的方法
之所以可以采用平均的模型融合方法,这里通过举例说明一下:
由于两个模型预测结果分数相近,假设第一个模型对于标签1的距离为0.75,对于标签2的距离为0.25,第二个模型对于标签1的距离为0.25,对于标签2的距离为0.75,则这两个模型的mse均为 1 2 ∗ ( 0.7 5 2 + 0.2 5 2 ) \frac{1}{2}*(0.75^2+0.25^2) 21(0.752+0.252),而融合之后两个标签的距离均为0.5, m s e = 1 2 ∗ ( 0. 5 2 + 0. 5 2 ) < 1 2 ∗ ( 0.7 5 2 + 0.2 5 2 ) mse = \frac{1}{2}*(0.5^2+0.5^2) < \frac{1}{2}*(0.75^2+0.25^2) mse=21(0.52+0.52)<21(0.752+0.252)
因此如果分数接近的两个模型融合,很有可能能够提升分数

融合提升的要点

融合模型的过程中最主要的是选择不同路径的分数相近的模型(根据上面分析可得)。
在实验中我们发现,如果选择变化不大的模型进行融合,融合到一定程度分数增长缓慢,因此要选择不同的分数相近的模型进行融合,多尝试不同的模型比如nezha、roberta、electra,同时多尝试不同的方法,比如更换主语,加入不同的上文等。
此外模型还可以采用多模型加入一个线性层进行融合的过程,这种方法由于代码有点复杂就没有尝试,不过有其他小伙伴尝试了,发现线下很猛线上很拉跨,猜想这里本质上还是由于不同剧本的预测难度不同,标签分布不同,导致一个模型预测线下剧本效果还行的情况下线上不一定能提升。

预训练操作

这里预训练的时候我只加入了本文和上一句话下一句话,总共三句话。感觉这里超出maxlen的部分还可以做得更精细一点,通过句子的部分进行分割。

对抗训练

这里我们实验了fgm对抗训练的过程,由于时间有限未能实验不同的epsilon参数以及pgd对抗的过程。
实验的过程中发现,可能原先未使用对抗训练的种子不再适用于对抗训练的种子(分数波动较大),也就是说选择好相应的epsilon参数之后,还需要一定的时间重新调整种子。

种子的固定

为了保证实验的可重复性,我们需要进行种子的固定。
在实验的过程中,我们发现,tensorflow即使固定了种子,同样代码跑两遍也会出现差异,也就是tensorflow无法做到可复现性。pytorch固定了种子之后,可以保证代码的可复现性。但是即使pytorch固定了种子之后,不同的gpu,不同的系统,不同的nvidia、cuda、cudnn版本都有可能造成不同的结果,因为这些都可能导致随机数计算的方法不同,进而导致最后的结果不同,因此深度学习要想完全完整的复现代码效果,基本上是不可能的。
同样我们也发现,相同的策略在不同的模型,体系,gpu下可能效果不一样,比如之前大佬提供的融合最后两层模型的方法在我们的模型体系之下并不能起到涨分的效果,因此要想提分还是要多实验不同的trick,找寻到能够提升自己模型的trick,别人的trick只能作为自己的备选。

修改代码的注意事项

每次如果变换数据处理的时候,需要修改三个地方:train_dataset,test_dataset以及maxlen,如果修改训练部分的内容还需要修改训练部分

增强数据

由于标签3的数据预测的不好,这里我们尝试着加入一些标签3的数据增强模型训练标签3的能力,但是实验完成之后发现效果并不好,因为增加标签3的数据会改变标签的分布,模型预测标签0、1的能力明显下降。(也有可能加少量的数据有帮助,但是始终没有调节出那个比例)

更换主语

融合模型的过程中可以尝试着更换主语,主要有以下两种方法
1.将本句的角色统一成中文主语,其他内容保持不变
2.将所有的角色随机更换成Vocab中的其他内容
本文尝试了方法1,并与其他的模型进行融合,效果有显著的提升

一些可能有效没时间尝试的方法以及一些在我们的体系下没有用但是在别人的体系下可能有用的方法

simcse、rdropout
transformer最后两层连接接线性层输出
使用sigmoid先将概率映射到0~1,计算标签的时候再乘上相应比例系数(或者将标签/3映射到0~3的区间)
加入洪泛法flooding进行训练

参考大佬的解题策略,总结一下自己没想到的解题步骤

暂时留空

本赛题应该的正确路线

搭建模型->单模多折->尝试预训练和多种模型->尝试simcse、rdropout、对抗、sigmoid激活、flooding、加入不同的上文等策略->模型融合->拿钱

总结

这个比赛与常规的分类比赛有着一定的特殊性
1.不同本预测难度不一样
2.使用mse作为损失函数
3.特征更多,比如上文,本文中的角色
因此有一定的特殊性,但是本质上又属于一个文本分类问题,因此又有一些文本分类可以尝试的策略,希望以后再遇到类似的问题,能够处理的更加合理。

猜你喜欢

转载自blog.csdn.net/znevegiveup1/article/details/121434921