《Convolutional Neural Network for Sentence Classification》论文阅读笔记

文章前瞻:

  1. 阅读本论文,你将需要学习掌握自然语言处理:预训练中的词嵌入n-gram、word2vec(题外话,当然后面还有FastText、GloVe和当前非常火的来自Transformer中的双向编码器表示BERT)
  1. 学习了解掌握到CNN在文本领域的首次应用。TextCNN用来处理句子级分类任务。所以你要读懂论文中给的Model。
  1. 超参数设置:dropout=0.5,filter_size=(3,4,5),feature_map=100,mini-bacth size=50。更多的参数设置可以看这篇论文:A Sensivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classfication,专门做了各种控制变量的实验对比。
  1. 实验结果:在各个数据集上的验证结果表明,预先训练的向量是良好的、通用的"特征提取者",并且可以跨数据集使用。从而预训练的词向量+动态调整效果更好。
  1. TextCNN的成功不是网络结构的成功,而是通过引入已经训练好的词向量来在多个数据集上达到了超越benchmark的表现,进一步证明了构造更好的embedding,是提升NLP各项任务的关键能力。

1.文本分类大概介绍

对于文本分类问题,常见的方法无非就是抽取文本的特征,比如使用doc2evc或者LDA模型将文本转换成一个固定维度的特征向量,然后在基于抽取的特征训练一个分类器。然而研究证明,TextCNN在文本分类问题上有着更加卓越的表现。

TextCNN对文本浅层特征的抽取能力很强 ,在短文本领域如搜索、对话领域专注于意图分类时效果很好,应用广泛,且速度快,一般是首选。对长文本领域,TextCNN主要靠filter窗口抽取特征,在长距离建模方面能力受限,且对语序不敏感。

TextCNN使用预先训练好的词向量作embedding layer。对于数据集里的所有词,因为每个词都可以表征成一个向量,因此我们可以得到一个嵌入矩阵MM,MM里的每一行都是词向量。这个MM可以是静态的,也就是固定不变。也可以是非静态的,也就是可以根据反向传播更新。

在Convolutional Neural Networks for Sentence Classfication文章中给出了几种模型,其实这里都是针对Embedding layer做的变化。本篇论文是使用卷积神经网络处理句子级别的文本分类,并在多个数据集上取得很好的效果。

TextCNN与image-CNN的差别:

最大的不同便是在输入数据的不同;

图像是二维数据,图像的卷积核是从左到右,从上到下进行滑动来进行特征抽取;

自然语言是一维数据,虽然经过word-embedding生成了二维向量,但是对词向量只能做从上到下,做从左到右滑动来进行卷积没有意义;

文本卷积宽度是固定的,就是embedding的维度。

2.Model

2.1 模型总览

我们将model看成一个黑盒,那么它的输入是:n个词w1、w2、w3、...,输出:label,预测的类别。下图便是论文中给出的模型结构:

我们用一个整体流程图来表示上图模型结构的步骤,则如下图:

在论文A Sensivity Analysis of (and Practitioners' Guide to)Convolutional Neural Networks for Sentence Classification给出的model结构图如下图,个人觉得这篇论文给出的model结构图更容易理解,所以看下面的结构图就好了。

2.2 模型详解

我们再细化,将论文中给出的模型结构的流程维度给在下面:

这上面的这个流程维度图一定是个伟大的图,接下来我们就针对这个流程维度图一步一步来解析TextCNN这个model。

2.2.1 Embedding层

最左边的(n, k)矩阵就是输入层(Embedding层)输入层的作用就是将输入文本切词后,通过词向量文件及词向量矩阵,将文本向量化,支持后续进行卷积池化等操作。具体来说,分为以下几步:

step1:文本切词

通过jieba分词等工具,将输入文本切分为若干个词。例如"今天晚上吃什么呢",分词后变为["今天", "晚上", "吃", "什么", "呢"]。

除了文本输入时,需要进行切词,接下来要介绍的词向量,在构建词向量文件时,也需要进行切词操作。

step2:词向量矩阵初始化

先简要介绍下词向量文件及词向量矩阵。词向量文件的表现形式,是以离线配置文件的形式存在的,通常是json文件,代码中加载后以dict形式存在,如{"的":1, "是": 2 ...}(word_to_index)。词向量文件的作用是,在对输入文本进行切词后,需要获取每个词的向量表征,则先通过词向量文件获取词对应的索引,再通过索引在词向量矩阵中获取词的向量表征。

这时在理解词向量矩阵,就简单多了,词向量矩阵的作用,是用于获取输入文本的向量表征,说的通俗点,就是用向量将文本表现出来,以用于模型中的数值计算(例如后续的卷积、池化等操作)。词向量矩阵的每一行,是某个词对应的向量,也就是说,我们通过词向量文件中的索引,可以在词向量矩阵中获取词的向量表征。再简单介绍下词向量矩阵及词向量文件生成的两种方式。

a.随机初始化词向量矩阵

这种方式很容易理解,就是使用self.embedding = torch.nn.Embedding(vocab_size, embedding_dim)命令直接随机生成个初始化的词向量矩阵,此时的向量值符合正态分布N(0,1)。

这里的vocab_size是指词向量矩阵能表征的词的个数,这个数值即是词向量文件中词的数量加1(加1的原因是,如果某个词在词向量文件中不存在,则获取不到索引,也就无法在词向量矩阵中获取对应的向量,这时我们默认这个词的索引为0,即将词向量的第一行作为这个词的向量表征。使用预训练的词向量文件时,这个方法同样适用。)

embedding_dim是指表征每个词时,向量的维度(可自定义) 。对于随机初始化词向量矩阵的方式,词向量文件的生成方式一般是将当前所有的文本数据(包括训练数据、验证数据、测试数据)进行切词,再对所有词进行聚合统计,保留词的数量大于某个阈值(比如3)的词,并进行索引编号(编号从1开始,0作为上面提到的不在词向量文件中的其他词的索引),进而生成词向量文件。

顺便提一句,词向量矩阵的初始化方式也有很多种,比如Xavier、Kaiming初始化方法。

b.使用预训练的词向量文件初始化词向量矩阵

本质上,词向量矩阵的作用是实现文本的向量表征,因此,如何用更合适的向量表示文本,逐渐成为了一个热门研究方向。

预训练的词向量文件便是其中的一个研究成果,如通过word2vecglove等预训练模型生成的词向量文件,通过大量的训练数据,来生成词的向量表征。以word2vec为例,训练后生成的词向量文件是以离线配置文件的形式存在,可通过gensim工具包进行加载。

具体命令是:

python 复制代码
wvmodel = gensim.models.KeyedVectors.load_word2vec_format(word2vec_file, binary=False, encoding='utf-8', unicode_errors='ignore')

加载后,可通过wvmodel.key_to_index获取词向量文件(要对词向量文件中的词索引进行重新编号,原索引从0开始,调整为从1开始,0作为不在词向量文件中的词的索引)。

通过wvmodel.get_vector("xxx")获取词向量文件中每个词对应的向量,将词向量文件中所有词对应的向量聚合在一起后(聚合的方式是,每个词的向量表征,按照词的索引,填充在词向量矩阵对应的位置),生成预训练词向量矩阵weight。

再通过

python 复制代码
self.embedding = torch.nn.Embedding.from_pretrained(weight, freeze=False)

完成词向量矩阵的初始化,参数freeze的作用,是指明训练时是否更新词向量矩阵的权重值,True为不更新,默认为True,等同于self.embedding.weight.requires_grad = False

step3:输入文本向量化

经过上述两步,输入文本已经完成分词,且词向量矩阵也完成初始化,这时便可对输入文本进行向量化操作,总结下,会根据文本切词后,每个词在词向量文件中的索引,确定这个词在词向量矩阵中的位置,从而获取这个词的向量表征,最终组合出输入文本的向量表征,即输入文本对应的向量矩阵,这个矩阵的列数和词向量矩阵的列数一致,行数不固定了,依赖于文本切词后词的数量。

也就是上面的流程维度图得到的最左边的(n, k)矩阵。

2.2.2 卷积层

如果对卷积不太理解的话,推荐先看一下这个文章理解NLP中的卷积神经网络(CNN)_cnn nlp-CSDN博客

在此Model中,用三个不同的卷积核大小(h, k),h=2,3,4,分别与上面所说的词向量矩阵做卷积操作。

从直观上理解,TextCNN通过利用多个不同size的kernel来提取句子中的关键信息(类似于多窗口大小的n-gram),从而能够更好地捕捉局部相关性。TextCNN只能在输入文本上纵向滑动,因为每个单词的embedding长度固定,不能截断。filter的宽度要与输入向量一致,不同的filter高度不一样。

2.2.3 池化层

池化采用的是最大池化,在经过卷积操作之后,对得到的结果取最大特征值进行降维采样。

3.数据集和实验设置

数据集就不说了,可以看看论文,这里没什么需要理解的点。

3.1 超参数设置

滑动窗口为3,4,5;dropout rate为0.5,L2为3,mini-batch size为50。

OK,我们接下来就是关于A Sensivity Analysis of (and Practitioners' Guide to) Convolutional Neural Networks for Sentence Classfication论文里关于超参数的实验结论。

(1)Static or None-static

通常来说,使用预训练词向量比随机初始化的效果要好。然而,使用预训练词向量初始化后,是否应该进行微调?这篇论文在多个数据集做了如下图所示的对照实验。

从实验结果可以看出,在上述所有数据集中,采取微调策略的效果比固定词向量的效果要好。

(2)Baseline Configuration

这篇论文的baseline参数设置如下:

之后的对照试验都是在baseline设置上进行对比分析。在分析某个超参数时,只对该参数进行改变,其余保持不变。论文在预训练词向量、filter窗口、filter个数、激活函数、池化策略、以及正则化策略方面做对照实验,并给出了相关建议。

(3)Effect of input word vectors:

建议:

无法确定用哪种预训练词向量更好,不同的任务结果不同,应该对于你当前的任务进行实验

论文还使用one-hot编码作为句子表示,但是实验结果不理想,这应该是因为句子的长度较短,无法在高维空间提供足够的信息。当然,如果训练语料非常充分,从头开始学习embedding可能确实更好。Semi-supervised convolutional neural networks for text categorizattion via region embedding论文提供了一种半监督方法。

(4)Effect of filter region size

每次使用一种类型的filter进行实验,得到上图结果,表明filter的窗口大小设置在1到10之间是一个比较合理的选择。

之后论文对多种类型的filter同时使用进行了对比实验,Table5表明在MR数据上,(7,7,7,7)的设置结果最好,而Table6表明在TREC数据集上,(2,3,4,5)设置最好。MR数据集的最好的多类型窗口大小(7,7,7,7)的均值为7,而TREC数据集的最好的多类型窗口大小(2,3,4,5)的均值为3.5,这与单类型的对比实验结果保持一致。因此有如下建议:

First perform a coarse line-search over a single filter region size to find the 'best' size for the dataset under consideration

and then explore the combination of several region sizes nearby this single best size, including combining both different region sizes and copies of the optimal sizes.

(5)Effect of number of feature maps for each filter region size

确定了filter窗口大小,还需要确定对每种类型的filter的个数,实验结果如上图。总结如下经验:

a.每种窗口类型的filter对应的"最好"的filter个数(feature map数量)取决于具体数据集;

b.但是,可以看出,党feature map数量超过600时,performance提高有限,甚至会损害performance,这可能是过多的feature map数量导致过拟合了;

c.在实践中,100到600是一个比较合理的搜索空间。

(6)Effect of activation function

Sigmoid、Cube、and tanh,cube相较于上表中的激活函数,表现很糟糕,因此没有显示在表中。

tanh比sigmoid好,这可能是由于tanh具有zero centering property(过原点),如下图:

与sigmoid相比,ReLU具有非饱和形式的优点,并能够加速SGD的收敛。

对于某些数据集,线性变换(Iden,即不使用非线性激活函数)足够捕获词嵌入与输出标签之间的相关性。(但是如果有多个隐藏层,相较于非线性激活函数,Iden就不太适合了,因为完全用现行激活函数,即使有多个隐藏层,组合后整个模型还是线性的,表达能力可能不足,无法捕获足够信息)

因此,建议首先考虑ReLU和tanh,也可以尝试Iden。

(7)Effect of pooling strategy

对于句子分类任务,1-max pooling往往比其他池化策略要好;

这可能是因为上下文的具体位置对于预测label可能并不是很重要,而句子某个具体的n-gram(1-max-pooling后filter提取出来的特征)可能更可以刻画整个句子的某些含义,对于预测label更有意义。

(8)Effect of regularization

a.0.1到0.5之间的非零dropout rates能够提高一些performance(尽管提升幅度很小),具体的最佳设置取决于数据集;

b.对L2范数加上一个约束往往不会提高performance(除了Opi数据集);

c.当feature map的数量大于100时,可能 导致过拟合,影响performance,而dropout将减轻这种影响;

d.在卷积层上进行dropout帮助很小,而且较大的dropout rate对performance有坏的影响。

3.2 预训练单词向量

word2vec,向量的维度为3,使用CBOW结构进行训练。不存在于预先训练的单词被随机初始化。

3.3 论文中四个model的不同

CNN-rand (单channel), 设计好 embedding_size 这个 Hyperparameter 后, 对不同单词的向量作随机初始化, 后续BP的时候作调整.

CNN-static(单channel), 拿 pre-trained vectors from word2vec, FastText or GloVe 直接用, 训练过程中不再调整词向量.

CNN-non-static(单channel), pre-trained vectors + fine tuning , 即拿word2vec训练好的词向量初始化, 训练过程中再对它们微调.

CNN-multiple channel(多channels), 类比于图像中的RGB通道, 这里也可以用 static 与 non-static 搭两个通道来做

4.结果讨论

5.总结

TextCNN用来做短文本分类效果很好。但是细粒度不够,也就是在在池化层取最大池化层,可能会忽略掉一些信息。所以在DCNN中提到了动态k-max-pooling以及2017年的DPCNN。

6.代码复现

读到这儿,我相信你对这篇论文有了一定的认识和理解,但是这是理论层面上的,如果让你用PyTorch去写出来可以吗?这一块的内容就是用PyTorch实现TextCNN的文本分类。通过代码复现过程进一步加深对这篇论文的理解。读者尤其要注意,在真正实践中,数据的维度是怎么样的?又是怎么样变化的?

自己手搓的代码还是有点问题的,等代码完善了再贴上来。

相关推荐
qq_153214526427 分钟前
【2020工业图像异常检测文献】SPADE
图像处理·深度学习·神经网络·目标检测·机器学习·计算机视觉·视觉检测
985小水博一枚呀9 小时前
【深度学习|可视化】如何以图形化的方式展示神经网络的结构、训练过程、模型的中间状态或模型决策的结果??
人工智能·python·深度学习·神经网络·机器学习·计算机视觉·cnn
Hiweir ·12 小时前
机器翻译之创建Seq2Seq的编码器、解码器
人工智能·pytorch·python·rnn·深度学习·算法·lstm
菜♕卷12 小时前
深度学习-03 Pytorch
人工智能·pytorch·深度学习
你的陈某某12 小时前
【变化检测】基于ChangeStar建筑物(LEVIR-CD)变化检测实战及ONNX推理
深度学习·变化检测
哦豁灬14 小时前
NCNN 学习(2)-Mat
深度学习·学习·ncnn
十有久诚15 小时前
E2VPT: An Effective and Efficient Approach for Visual Prompt Tuning
人工智能·深度学习·提示学习·视觉语言模型
王豫翔16 小时前
OpenAl o1论文:Let’s Verify Step by Step 快速解读
人工智能·深度学习·机器学习·chatgpt
qq_4350707816 小时前
python乱炖6——sum(),指定维度进行求和
pytorch·python·深度学习
L107320348217 小时前
深度学习笔记17_TensorFlow实现咖啡豆识别
笔记·深度学习·tensorflow