目录
前言
此前,我尝试了使用BERT-FC模型去做文本分类,遇到了以下几个问题,这里再回顾一下:
(1)模型泛化能力不足
训练集准确率达到97%以上,但测试集的分类准率均值在80%左右浮动,最好的一次达到了83.8%,但也很难再有提升。
(2)分类效果不平衡
样本面临不平衡分类问题,在对训练集进行简单随机过采样的预处理的前提下,仍未解决该问题。测试集上使用最优模型进行预测的结果是:两个小类上的F1值刚过50%,两个较大类上的F1值达到90%。
本文从模型结构的角度进行优化。在寻找适用模型的过程中,看到这样一篇推文:《用深度学习(CNN RNN Attention)解决大规模文本分类问题 - 综述和实践》 ,作者根据自己的经验提出:文本分类的最佳实践,是先从textCNN开始训练出一个较好的模型,再以此为基础尝试改进模型。因此,本文尝试采用BERT-textCNN进行实验。
1 textCNN架构分析
2014年,Yoon Kim在《Convolutional Neural Networks for Sentence Classification》1一文中提出了textCNN,其在一系列基线模型中证明了:① 通过预训练静态词向量和参数微调,简单的CNN可以在句子级别的分类任务中取得较好的学习效果;② 预训练的向量是良好的“通用”特征提取器,可以跨数据集使用。许多博主都对textCNN进行了详细的解析,但是为了加深自己的理解,还是以自己的方式再梳理一下思路。
1.1 textCNN架构
图1为论文中提供的textCNN模型架构示例,包括 输入层、卷积层、池化层、全连接层四个基本结构:
(1)输入层
以输入一个样本为例:假设输入是一个句子,共包括
n
n
n 个单词,每个单词可以通过word2vec等模型表示为一个
k
k
k 维的向量,则,一个句子被表示为一个
n
×
k
n \times k
n×k 的二维矩阵,即,textCNN的输入。
(2)卷积层
卷积层,主要通过设置若干滤波器 ( f i l t e r ) (filter) (filter)对输入层进行卷积操作,即计算(对应元素相乘之和+偏置),以提取文本特征。
例如,一个尺寸为 h × k h\times k h×k 的滤波器在非全零填充的情况下,以 1 1 1 为步长滑动,每次滑动都进行卷积操作,结果将形成长度为 n − h + 1 n-h+1 n−h+1 的文本特征 c i , i ∈ [ 1 , n − h + 1 ] c_{i, i\in [1,n-h+1]} ci,i∈[1,n−h+1],相当于提取一个句子中的 h − g r a m h-gram h−gram 特征。
在图3中,设置了两种类型的滤波器:
① 尺寸为 2 × k 2\times k 2×k 的滤波器(红框),将形成长度为 8 8 8 的一维文本特征 c 1 i , i ∈ [ 1 , 7 ] c_{1i , i\in [1,7]} c1i,i∈[1,7]。
② 尺寸为 3 × k 3\times k 3×k 的滤波器(黄框),将形成长度为 7 7 7 的一维文本特征 c 2 i , i ∈ [ 1 , 7 ] c_{2i , i\in [1,7]} c2i,i∈[1,7]。
(3)池化层
池化层,主要对卷积操作后形成的每一个文本特征 c i c_{i} ci进行最大池化操作,即计算 m a x { c i } max\{c_i\} max{ci},以提取最重要的特征。
原文提到,这一处理能够应对可变的句子长度。这是因为,池化层所得的特征长度取决于我们事先设定好的滤波器的总数(注意不是种类数),而非句子中可变化的单词总数(它只决定一个文本特征的长度,无论有多长,池化仅提取其中的最大值)。
例如,图3中共包括 2 2 2种滤波器,每种滤波器的个数均为 2 2 2,则滤波器总数为 4 4 4,则卷积后操作后得到 4 4 4个文本特征: c 1 i c_{1i} c1i, c 1 i ′ c_{1i}^{'} c1i′, c 2 i c_{2i} c2i, c 2 i ′ c_{2i}^{'} c2i′。分别对上述 4 4 4个文本特征进行池化操作,并将结果拼接,如图4所示,得到的池化层是长度为 4 4 4的一维向量 c − = ( c − 1 , c − 2 , c − 3 , c − 4 ) = ( m a x { c 1 i } , m a x { c 1 i ′ } , m a x { c 1 i } , m a x { c 1 i ′ } ) \overset{-}c=(\overset{-}c_1,\overset{-}c_2,\overset{-}c_3,\overset{-}c_4)=(max\{c_{1i}\},max\{c_{1i}^{'}\},max\{c_{1i}\},max\{c_{1i}^{'}\}) c−=(c−1,c−2,c−3,c−4)=(max{c1i},max{c1i′},max{c1i},max{c1i′})。
(4)全连接层
全连接层,首先,对池化层的神经元以某一概率进行dropout,以缓解过拟合;其次,经过一层带有softmax激活函数的神经元,即输出层,以便输出这句话属于各个类别的概率分布。
ps:
- 由于使用了dropout,训练时,前向传播和梯度的反向传播仅通过未被mask的神经元;测试时,不进行dropout,即,使用全部神经元进行前向传播。
- 若模型需要完成 m m m分类任务,则输出层的神经元个数为 m m m。图5中的输出层只包括 2 2 2个神经元,可见是二分类任务。
- 在每次梯度下降后,如果全连接层中的权重矩阵 w w w的 L 2 L_2 L2范数高于阈值s,原文还会对 w w w进行重新缩放。
- 原文为了防止小数据集上的过拟合,提出了双通道的概念,即其中一个通道的参数不做更新,另一个通道正常更新,从而避免学习向量不会过于偏离原始值。但可能需要规范调参规则,例如,仅在可更新参数的部分增加不可被更新的通道。
1.2 textCNN实践
textCNN提出后,也有许多论文应用了这一架构进行文本分类。为了更好地将textCNN应用于本领域的文本分类任务,我在CNKI阅读了一些相关论文,并记录了其对textCNN的应用(表1)。
作者 | 训练集 | 文本预处理 | 预训练词向量 | 卷积层 | 池化层 | 全连接层 | 优化器 | 效果 |
---|---|---|---|---|---|---|---|---|
Yoon Kim 1 | 公开数据集 | — | 谷歌新闻预训练word2vec (dim=300,sg=‘CBOW’) 不存在于word2vec的单词向量被随机初始化 | h = 3,4,5;每种滤波器100个 | max | dropout(0.5) | Adadelta | —— |
杨林2 | —— | BERT (句子长度:250;字向量维度:768) | h=2,3,4;activation=‘relu’;每种滤波器256个 | max | dropout(0.1) | lr=1e-5 | 基线模型 BERT_test_acc=0.90(epoch=5); 提出模型 BERT-textCNN(LP)_test_acc=0.90(epoch=5) | |
范昊3 | train:144000;test:36000 | 去除标点符号、特殊符号 | BERT (句子长度:64;字向量维度:768) | h=3,4,5;activation=‘relu’;padding=‘same’;输出维度=200 | max;h=2;步长=2 | 先接BILSTM再过softmax | lr=1e-5 | 基线模型 BERT-textCNN_test_acc=0.85(epoch=32);提出模型BERT-textCNN-BILSTM_test_acc=0.92(epoch=7) |
- 在 范昊3的论文中,为了让模型学习到文本上下文的信息,做出了如下处理:①textCNN中对卷积层使用全零填充;②textCNN中在池化层让窗口以步长为2进行滑动;③在textCNN后接入BiLSTM学习单词间的长依赖关系。
- 在沈自强4的论文中,通过textRank或TF-IDF的方式提取了政策文本中的关键词,与政策标题拼接,再输入BERT模型(bert-base-chinese)进行训练,准确率达到94%,在各个类别上的分类效果最低也有90%。
总结:
阅读几篇论文后,发现BERT+textCNN与BERT+FC相比并没有多大程度的改进,并且相比textCNN,将BERT与BILSTM进行结合的改进效果更显著,这可能是因为BILSTM有助于学习单词间的远距离依赖关系,而textCNN只擅长提取n-gram的单词特征。在我所需要完成的任务中,分类标签与单词间的长依赖关系有关。因此,在后续的模型改进中,我可能会朝着BERT+textCNN、BERT+BILSTM、BERT+textCNN+BILSTM的方向进行进一步实验,本文仍以实现BERT+textCNN这一基线模型为目的。
1.3 textCNN的调优
对模型的优化十分重要,在跑出一代baseline的基础上,要通过重点分析badcase找出预测错误的原因,包括与特征有关的原因、与模型参数有关的原因等等,从而对症下药,并做好试验记录。附以下参考链接:
2 本领域应用:BERT+textCNN实践
2.1 研究思路
(1)文本预处理
- 1. 去除英文、数字、标点符号、特殊符号
- 2. 去除停用词
- 3. 提取关键词(基于类别改进的TF-IDF 或 textrank)
- 4. 划分训练集(80%)和测试集(20%)
(2)输入层
使用bert-base-Chinese预训练模型对每一句话中的每一个字编码字向量,用[SEP]分割两种视图的文本,最终一句话将被表示为
406
×
768
406\times768
406×768 的二维矩阵。其中,406为一条文档的最长字符数(少于406的用padding补齐,多于406的仅截取前406个字符);768为字向量的维度,该数值已由bert模型决定。batchsize=64。
(3)卷积层
考虑设置三种卷积核,每种卷积核200个,总共600个卷积核,均以1为步长滑动,不使用全零填充,卷积操作后过BN层(批标准化)、过relu激活函数。三种卷积核的尺寸如下:
- h=2, dim=768
- h=3, dim=768
- h=4, dim=768
由此,相当于提取二元、三元、四元的单词信息,最终得到600个文本特征,其中,有200个为长度为511的一维文本特征(卷积核1)、200个为长度为510的一维文本特征(卷积核2)、200个为长度为509的一维文本特征(卷积核3)。
参数量:
2
×
768
+
3
×
768
+
4
×
768
+
3
+
B
N
层
=
2\times768+3\times768+4\times768+3+BN层=
2×768+3×768+4×768+3+BN层=
(4)池化层
考虑最大池化,分别以1、2为步长进行实验。最终得到长度为600的一维向量。
(5)全连接层
全连接层包含一个隐藏层、一个输出层:
- 隐藏层:神经元个数为64,采用dropout(0.5)
- 输出层:神经元个数为4,因为是四分类任务
参数量: 600 × 64 + 1 + 64 × 4 = 600\times64+1+64\times4= 600×64+1+64×4=
2.2 代码实现
(1)文本预处理
代码:
# (1) 构造文本
def convert(title, ab):
title = title.replace(' ','')
if isinstance(ab, str):
ab = ab.replace(' ','')
return title + ab
else:
return title
data['文本'] = data[['题名_分词','摘要_分词']].apply(lambda x: convert(x['题名_分词'], x['摘要_分词']), axis=1)
dataset = data[['题名', '摘要', '文本', '分类','学科']]
dataset = dataset.sample(frac=1.0) # 把数据集打乱
dataset.to_excel('./bert_dataset_all_shuffle.xlsx')
# (2) 计算最长文本
maxlen = 0
def maxlength(text):
global maxlen
if len(text) > maxlen:
maxlen = len(text)
dataset['文本'].apply(lambda x: maxlength(x))
print('最长文本:', maxlen)
# (3) 切分训练集和测试集
from sklearn.model_selection import train_test_split
train_x, test_x, train_y, test_y = train_test_split(dataset[['文本']], dataset[['分类']], test_size=0.2, stratify=dataset[['分类']], random_state=0)
print('\n train_x:', train_x.iloc[:1,:], train_x.shape)
print('\ntrain_y:', train_y.iloc[:1,:], train_y.shape, '\n',train_y.value_counts())
print('\ntest_x:', test_x.iloc[:1,:], test_x.shape)
print('\ntest_y:', test_y.iloc[:1,:], test_y.shape, '\n',test_y.value_counts())
# (4) 不做过采样
train_x['分类'] = train_y['分类']
test_x['分类'] = test_y['分类']
train_x.to_csv('./bert_dataset_train_nosample.csv')
test_x.to_csv('./bert_dataset_test_nosample.csv')
train_x.shape, test_x.shape
数据预览:
最长文本: 406
train_x: 文本
612 资本逻辑生产逻辑马克思主义欧洲一体化理论解释学界欧洲一体化理论解释局限于超国家分析路径西方马... (906, 1)
train_y: 分类
612 2 (906, 1)
分类
2 637
3 136
0 83
1 50
dtype: int64
test_x: 文本
525 比较政治学现实需求学科道路现实政治实践理论学者自觉推动比较政治研究呈现出自主探索态势学者比较... (227, 1)
test_y: 分类
525 2 (227, 1)
分类
2 160
3 34
0 21
1 12
dtype: int64
(2)输入层(嵌入层)
2.3 训练结果与模型评估
2.4 结果分析
占个坑
Kim Y . Convolutional Neural Networks for Sentence Classification[J]. Eprint Arxiv, 2014. ↩︎ ↩︎
杨林,黄晓硕,王嘉阳等.基于BERT-TextCNN的临床试验疾病亚型识别研究[J].数据分析与知识发现,2022,6(04):69-81. ↩︎
范昊,何灏.融合上下文特征和BERT词嵌入的新闻标题分类研究[J].情报科学,2022,40(06):90-97.DOI:10.13833/j.issn.1007-7634.2022.06.012. ↩︎ ↩︎
沈自强,李晔,丁青艳等.基于BERT模型的科技政策文本分类研究[J].数字图书馆论坛,2022,No.212(01):10-16. ↩︎