基于BERT的多模型融合借鉴

本次介绍假新闻赛道一第一名的构建思路,大家一起学习下

任务描述

文本是新闻信息的主要载体,对新闻文本的研究有助于虚假新闻的有效识别。虚假新闻文本检测,具体任务为:给定一个新闻事件的文本,判定该事件属于真实新闻还是虚假新闻。该任务可抽象为NLP领域的文本分类任务,根据新闻文本内容,判定该新闻是真新闻还是假新闻。针对该任务,本文采用BERT-Finetune、BERT-CNN-Pooling、BERT-RCN-Pooling的多种结构进行融合,在输入上引入字词结合的形式,另外充分利用假新闻的关键词特征进行优化。在智源\&计算所-互联网虚假新闻检测挑战赛的假新闻文本识别这个评测任务上,该文提出的方法在最终的评测数据上达到F1为 0.92664的成绩。

模型介绍

模型结构

本文采用了多种模型,下以BERT-CNN-Pooling模型为例介绍,见下图。

该模型采用BERT模型提取出字向量(不Finetune),然后结合腾讯词向量,作为最终的词向量输入到1维卷积网络中。在池化过程中同时选择最大池化和平均池化,最后将其结果相加,接入一个Dense层中得到结果。

除了此模型外,本文还是用了BERT-Finetune、BERT-RCN-Pooling模型。

模型参数和融合细节

BERT模型可采用roeberta_zh_L-24_H-1024_A-16,其优点为准确率高,缺点为显存占用率较高。以BERT-Finetune为例,在训练工程中,batch_size选择为4,maxLen选择为164,epoch数选择为3,learning_rate为前两个epoch为1e-5,后一个为1e-6。

本文选择了10折交叉验证,每折中选择召回率较高的模型(一般为第二个epoch或第三个epoch训练出的模型)。另外,由于数据假新闻识别正确率较高,其召回率较低,因此在这10个模型进行融合时,可以将10个模型的直接结果相加,当其大于3认为是假新闻,小于3即为真新闻。

同理,在BERT-CNN-Pooling、BERT-RCN-Pooling模型中也采取以上的融合策略,在BERT-Finetune、BERT-CNN-Pooling、BERT-RCN-Pooling这3个模型间采用该策略(值改为1)。

在模型融合时发现,假新闻喜欢对部分人、地、名词、动词进行造谣。这些词的获取可通过对所有的假新闻和test集合,利用textrank4zh进行关键词获取,最后经过人工筛选,加入到模型融合的评判中,具体为当新闻的关键词含有这些词时,就有假新闻的倾向,此时评判值可以降低,利用这个关键词特征可以发现更多的假新闻,使得假新闻评判效果更好。

实验结果与分析

实验结果见下表,其中评判值即为判断真假新闻的临界值,BERT-RCN-Pooling、BERT-CNN-Pooling的实验结果基本与BERT_Finetune类似。

由表一可知:单模型在真假新闻判定的结果并不是很好,而将单模型进行10折交叉验证后准确率提升很大,说明10折交叉验证还是很有必要的。另外,融合BERT_Finetune+BERT-RCN-Pooling+BERT-CNN-Pooling这三个模型并加上关键词特征也会有不小的提升。

本文使用模型都较为基础,基本是通过交叉验证和模型融合提升测试集得分。在多模型融合上,测试了多种模型,最后处于效果和速度的考虑选择了这三种。

结论

本文介绍了小组参加智源\&计算所-互联网虚假新闻检测挑战赛假新闻文本识别评测的基本情况。本文采用BERT-Finetune、BERT-CNN-Pooling、BERT-RCN-Pooling的多种结构进行融合,在每一模型基础上进行10折交叉验证,然后利用假新闻的关键词特征进行优化,最终达到了不错的性能。

代码精华

字词向量结合

def remake(x,num):
    L = []
    for i,each in enumerate(num):
        L += [x[i]]*each
    return L
words = [t for t in jieba.cut(text)]
temp = [len(t) for t in words]
x3 = [word2id[t] if t in vocabulary else 1 for t in words]
x3 = remake(x3, temp)
if len(x3) < maxlen - 2:
    x3 = [1] + x3 + [1] + [0] * (maxlen - len(x3) - 2)
else:
    x3 = [1] + x3[:maxlen - 2] + [1]

主要思路是把词向量映射到每个字上,如:中国,中国的词向量为a,那么体现在字上即为[a , a],若中国的字向量为[b , c], 相加后即为[a+b, a+c]。此处x3即为对称好的词向量,直接输入到Embedding层即可。

支持mask的最大池化

class MaskedGlobalMaxPool1D(keras.layers.Layer):
    def __init__(self, **kwargs):
        super(MaskedGlobalMaxPool1D, self).__init__(**kwargs)
        self.supports_masking = True

    def compute_mask(self, inputs, mask=None):
        return None

    def compute_output_shape(self, input_shape):
        return input_shape[:-2] + (input_shape[-1],)

    def call(self, inputs, mask=None):
        if mask is not None:
            mask = K.cast(mask, K.floatx())
            inputs -= K.expand_dims((1.0 - mask) * 1e6, axis=-1)
        return K.max(inputs, axis=-2)

支持mask的平均池化

class MaskedGlobalAveragePooling1D(keras.layers.Layer):

    def __init__(self, **kwargs):
        super(MaskedGlobalAveragePooling1D, self).__init__(**kwargs)
        self.supports_masking = True

    def compute_mask(self, inputs, mask=None):
        return None

    def compute_output_shape(self, input_shape):
        return input_shape[:-2] + (input_shape[-1],)

    def call(self, x, mask=None):
        if mask is not None:
            mask = K.repeat(mask, x.shape[-1])
            mask = tf.transpose(mask, [0, 2, 1])
            mask = K.cast(mask, K.floatx())
            x = x * mask
            return K.sum(x, axis=1) / K.sum(mask, axis=1)
        else:
            return K.mean(x, axis=1)

Bert Finetune

x1_in = Input(shape=(None,))
x2_in = Input(shape=(None,))
bert_model = load_trained_model_from_checkpoint(config_path, checkpoint_path)
for l in bert_model.layers:
    l.trainable = True
x = bert_model([x1_in, x2_in])
x = Lambda(lambda x: x[:, 0])(x)
x = Dropout(0.1)(x)
p = Dense(1, activation=‘sigmoid‘)(x)
model = Model([x1_in, x2_in], p)
model.compile(
        loss=‘binary_crossentropy‘,
        optimizer=Adam(1e-5),
        metrics=[‘accuracy‘]
    )

BERT+TextCNN

x1_in = Input(shape=(None,))
x2_in = Input(shape=(None,))
x3_in = Input(shape=(None,))
x1, x2,x3 = x1_in, x2_in,x3_in
x_mask = Lambda(lambda x: K.cast(K.greater(K.expand_dims(x, 2), 0), ‘float32‘))(x1)
bert_model = load_trained_model_from_checkpoint(config_path, checkpoint_path)
embedding1= Embedding(len(vocabulary) + 2, 200,weights=[embedding_index],mask_zero= True)
x3 = embedding1(x3)
embed_layer = bert_model([x1_in, x2_in])
embed_layer  = Concatenate()([embed_layer,x3])
x = MaskedConv1D(filters=256, kernel_size=3, padding=‘same‘, activation=‘relu‘)(embed_layer )
pool = MaskedGlobalMaxPool1D()(x)
ave = MaskedGlobalAveragePooling1D()(x)
x = Add()([pool,ave])
x = Dropout(0.1)(x)
x = Dense(32, activation = ‘relu‘)(x)
p = Dense(1, activation=‘sigmoid‘)(x)
model = Model([x1_in, x2_in,x3_in], p)
model.compile(
    loss=‘binary_crossentropy‘,
    optimizer=Adam(1e-3),
    metrics=[‘accuracy‘]
)

BERT + RNN + CNN

x1_in = Input(shape=(None,))
x2_in = Input(shape=(None,))
x3_in = Input(shape=(None,))
x1, x2,x3 = x1_in, x2_in,x3_in
x_mask = Lambda(lambda x: K.cast(K.greater(K.expand_dims(x, 2), 0), ‘float32‘))(x1)
bert_model = load_trained_model_from_checkpoint(config_path, checkpoint_path)
embedding1= Embedding(len(vocabulary) + 2, 200,weights=[embedding_index],mask_zero= True)
x3 = embedding1(x3)
embed_layer = bert_model([x1_in, x2_in])
embed_layer  = Concatenate()([embed_layer,x3])
embed_layer = Bidirectional(LSTM(units=128,return_sequences=True))(embed_layer)
embed_layer = Bidirectional(LSTM(units=128,return_sequences=True))(embed_layer)
x = MaskedConv1D(filters=256, kernel_size=3, padding=‘same‘, activation=‘relu‘)(embed_layer )
pool = MaskedGlobalMaxPool1D()(x)
ave = MaskedGlobalAveragePooling1D()(x)
x = Add()([pool,ave])
x = Dropout(0.1)(x)
x = Dense(32, activation = ‘relu‘)(x)
p = Dense(1, activation=‘sigmoid‘)(x)
model = Model([x1_in, x2_in,x3_in], p)
model.compile(
    loss=‘binary_crossentropy‘,
    optimizer=Adam(1e-3),
    metrics=[‘accuracy‘]
)

10折交叉训练

for train,test in kfold.split(train_data_X,train_data_Y):
    model = getModel()
    t1,t2,t3,t4 = np.array(train_data_X)[train], np.array(train_data_X)[test],np.array(train_data_Y)[train],np.array(train_data_Y)[test]
    train_D = data_generator(t1.tolist(), t3.tolist())
    dev_D = data_generator(t2.tolist(), t4.tolist())
    evaluator = Evaluate()
    model.fit_generator(train_D.__iter__(),
                        steps_per_epoch=len(train_D),
                        epochs=3,
                        callbacks=[evaluator,lrate]
                        )
    del model
    K.clear_session()

关键词特征

def extract(L):
    return  [r.word for r in L]

tr4w = TextRank4Keyword()
result = []
for sentence in train:
    tr4w.analyze(text=text, lower=True, window=2)
    s =  extract(tr4w.get_keywords(10, word_min_len=1))
    result = result + s

c = Counter(result)
print(c.most_common(100))

找到词后从其中人工遴选,选出每类的词,另外,在test集合中也运行该代码,同时用jieba辅助分割词的类。

转载于:https://www.biendata.com/models/category/3529/L_notebook/

原文地址:https://www.cnblogs.com/demo-deng/p/12318439.html

时间: 2024-08-30 16:30:54

基于BERT的多模型融合借鉴的相关文章

CS231n 卷积神经网络与计算机视觉 7 神经网络训练技巧汇总 梯度检验 参数更新 超参数优化 模型融合 等

前面几章已经介绍了神经网络的结构.数据初始化.激活函数.损失函数等问题,现在我们该讨论如何让神经网络模型进行学习了. 1 梯度检验 权重的更新梯度是否正确决定着函数是否想着正确的方向迭代,在UFLDL中我们提到过,计算时梯度公式如果计算错误是不容被察觉的,我们需要比较分析法得到梯度与数值法得到的梯度是否相似,下面是一些技巧: 1.1 centered formula 高等数学中我们知道导数的近似公式: df(x)dx=f(x+h)?f(x)h 以及下面的centered formula: df(

基于RBAC权限管理模型学习

在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限.这就极大地简化了权限的管理. 在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色.角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收. 角色与角色的关系可以建立起来以囊括更广泛的客观情况. BAC支持三个著名的安全原则:最小权限原则,责任分离原则和数据抽象原则. (1)最小权限原则之所以被RBAC所支持,是因

多模型融合推荐算法

常见的多模型融合算法 多模型融合算法可以比单一模型算法有极为明显的效果提升.但是怎样进行有效的融合,充分发挥各个算法的长处?这里总结一些常见的融合方法: 1. 线性加权融合法 线性加权是最简单易用的融合算法,工程实现非常方便,只需要汇总单一模型的结果,然后按不同算法赋予不同的权重,将多个推荐算法的结果进行加权,即可得到结果: 是给用户(user)推荐商品(item)的得分, 是算法K的权重,是算法k得到的用户(user)对商品item的推荐得分.这种融合方式实现简单,但效果较差.因为线性加权的参

Gluon炼丹(Kaggle 120种狗分类,迁移学习加双模型融合)

http://www.cnblogs.com/fiercex/p/7927804.html fiercex 路漫漫其修远兮,吾将上下而求索 Gluon炼丹(Kaggle 120种狗分类,迁移学习加双模型融合) 这是在kaggle上的一个练习比赛,使用的是ImageNet数据集的子集.注意,mxnet版本要高于0.12.1b2017112.下载数据集. train.zip test.zip labels然后解压在data文件夹下 1. 数据 1.1 整理数据 将解压后的数据整理成Gluon能够读取

模型融合

一.Voting 模型融合其实也没有想象的那么高大上,从最简单的Voting说起,这也可以说是一种模型融合.假设对于一个二分类问题,有3个基础模型,那么就采取投票制的方法,投票多者确定为最终的分类. 二.Averaging 对于回归问题,一个简单直接的思路是取平均.稍稍改进的方法是进行加权平均.权值可以用排序的方法确定,举个例子,比如A.B.C三种基本模型,模型效果进行排名,假设排名分别是1,2,3,那么给这三个模型赋予的权值分别是3/6.2/6.1/6这两种方法看似简单,其实后面的高级算法也可

谈谈模型融合之一 —— 集成学习与 AdaBoost

前言 前面的文章中介绍了决策树以及其它一些算法,但是,会发现,有时候使用使用这些算法并不能达到特别好的效果.于是乎就有了集成学习(Ensemble Learning),通过构建多个学习器一起结合来完成具体的学习任务.这篇文章将介绍集成学习,以及其中的一种算法 AdaBoost. 集成学习 首先先来介绍下什么是集成学习: 构建多个学习器一起结合来完成具体的学习任务,常可获得比单一学习器显著优越的泛化性能,对"弱学习器" 尤为明显(三个臭皮匠,顶个诸葛亮) 也称为Multi-Classif

谈谈模型融合之二 —— 随机森林

前言 上篇文章介绍了集成学习的相关概念以及基于 Boosting的 AdaBoost,这篇文章将介绍基于模型融合的另一种方式 Bagging 的算法,随机森林(Random Forest).(上篇公式敲的太累了这篇就来个简单的缓解缓解) 随机森林 算法思想 我们先来看看这个算法的名字,可以拆分开为两部分,随机和森林.森林我们很容易可以想到,就是有很多棵树,即由多颗决策树组成.那么随机指的是什么呢?这里我们来看看 Bagging 的思想了. 首先先说说自助采样(Bootstrap Sanpling

word2vec 中的数学原理详解(四)基于 Hierarchical Softmax 的模型

  word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包,它简单.高效,因此引起了很多人的关注.由于 word2vec 的作者 Tomas Mikolov 在两篇相关的论文 [3,4] 中并没有谈及太多算法细节,因而在一定程度上增加了这个工具包的神秘感.一些按捺不住的人于是选择了通过解剖源代码的方式来一窥究竟,出于好奇,我也成为了他们中的一员.读完代码后,觉得收获颇多,整理成文,给有需要的朋友参考. 相关链接 (一)目录和前言 (二)预备知

基于SOA的编程模型

1.webservice是SOA架构的一种实现 ====================================================================================================== Spring-WS编程模型: 面向契约的开发:xml--对象(而不是对象---xml) 编程模型: 1.定义消息契约xml(数据契约+操作契约) 2.生成xsd 3.编写消息端点 4.配置序列化OXM 5.生成wsdl-操作契约 ========