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

文章前瞻:
1.本论文作者Yoon Kim发表于2014年的EMNLP,TextCNN用来处理句子级分类任务。


2.本文的超参数设置: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,做了各种控制变量的实验对比,主要内容是TextCNN参数选择。


3.实验结果:在各个数据集上的验证结果表明,预先训练的向量是良好的、通用的“特征提取者”,并且可以跨数据集使用。从而预训练的词向量+动态调整效果更好。


4.这篇文章的成功不是网络结构的成功,而是通过引入已经训练好的词向量来在多个数据集上达到了超越benchmark的表现,进一步证明了构造更好的embedding,是提升NLP各项任务的关键能力。

1.文本分类大概介绍

1.1 文本分类

文本分类,指的是给定分类体系,将文本分类到某个或者某几个类别中。根据其目标类别的数量,文本分类涵盖了二分类、多分类、多标签分类等常见分类场景。

文本分类是计算机语言学的一个分支,同时也是自然语言处理中最基础的一个任务。涵盖了新闻主题分类、情感分类、关系分类、意图识别等等常见的自然语言处理场景。所以,开展文本分类相关的研究具有十分重要的理论意义和应用价值。


1.2 文本分类的发展历史

基于规则的文本分类 --> 基于特征的文本分类 --> 基于神经网络的文本分类。

(1)基于规则的文本分类:

基本思想:就是使用人工编写特定的规则来进行分类,一般情况下,当文本中含有特定的词语、短语或者模式时即将其判断为相应的类别,是最古老也最简单的一种分类方法。

大体流程:输入文本 --> 规则匹配 --> 输出类别

举例说明,如果一段话中出现了很好、很快就认为这段话是一个正面的评论:

“屏幕画质很好,为了省电可以调低画质,电量经用,充电那是真的快,一分钟一格,拍照三摄高清,系统运行很快感觉不到卡顿,的确是一款很好的手机,越用越喜欢,值得推荐!”

“挺失望的,拍照不错,屏幕不错。指纹也很灵敏很好,就是破玩意居然会卡。而且还会系统崩溃黑屏,吹的挺好。评论也好。网上宣传很好,就是用着不咋好。仁者见仁智者见智,真实评论,不吹不黑。”


(2)基于特征的文本分类

基本思想:通过人工设计和提取特征,例如:词法特征、句法特征等,使用机器学习模型来捕获句子中所蕴含的关键信息,从而来减少噪声词对最终结果的影响。

以向量空间模型为例:
1.使用词袋模型来表示每个词
2.使用词项作为特征项,使用词在文档中的TF-IDF值作为词的权重(特征权重)
3.使用加权求和得到文本表示
4.训练一个分类器(LR, SVM)进行文本分类

(3)基于神经网络的文本分类
基本思想:首先将输入的文本进行分词等一系列基础操作(中文需要分词),随后将句子中的单词转化为低维的词表示,使用编码器(如卷积神经网络、循环神经网络)得到句子表示,最终得到文本的目标类别。

大体流程:输入文本 --> 词表示 --> 编码器 --> 文本表示 --> 输出类别

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

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

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

注:TextCNN与image-CNN的差别:

最大的不同便是在输入数据的不同。图像是二维数据,图像的卷积核是从左到右,从上到下进行滑动来进行特征抽取。
自然语言是一维数据,虽然经过word-embedding生成了二维向量,但是对词向量只能做从上到下,做从左到右滑动来进行卷积没有意义;但我们为了理解方便,在后续的代码实现中还是使用Conv2d函数的。


2. 论文泛读

2.1 Abstract

我们报告了一系列基于预训练词向量训练的卷积神经网络 (CNN) 的实验,用于句子级分类任务。 我们证明,一个简单的 CNN 只需要很少的超参数调整和静态向量即可在多个基准测试中取得优异的结果 通过微调学习特定于任务的向量可以进一步提高性能。 我们还建议对架构进行简单的修改,以允许使用特定于任务的向量和静态向量。 本文讨论的 CNN 模型在 7 个任务中的 4 个上改进了现有技术,其中包括情感分析和问题分类。

2.2 Introduction

近年来深度学习模型在计算机视觉(Krizhevsky et al., 2012)和语音识别(Graves et al., 2013)方面取得了显着的成果。 在自然语言处理中,深度学习方法的大部分工作都涉及通过神经语言模型学习词向量表示(Bengio et al., 2003; Yih et al., 2011; Mikolov et al., 2013)并在 学习用于分类的词向量(Collobert et al., 2011)。 单词向量,其中单词通过隐藏层从稀疏的 1-of-V 编码(这里 V 是词汇量)投影到较低维度的向量空间上,本质上是在单词的维度中对单词的语义特征进行编码的特征提取器。 在这种密集表示中,语义上接近的单词在低维向量空间中同样接近(欧几里德距离或余弦距离)。

上面这一段简单介绍了深度学习的发展和词向量的发展,以及介绍了词向量。

卷积神经网络 (CNN) 利用具有应用于局部特征的卷积滤波器的层(LeCun 等人,1998)。 CNN 模型最初是为计算机视觉而发明的,后来被证明对 NLP 有效,并在语义解析(Yih 等人,2014)、搜索查询检索(Shen 等人,2014)、句子建模(Kalchbrenner)方面取得了优异的结果。 等人,2014),以及其他传统的 NLP 任务(Collobert 等人,2011)。

CNN发展以及在NLP中的应用。

在目前的工作中,我们训练了一个简单的 CNN,在从无监督神经语言模型获得的词向量之上有一层卷积 这些载体由 Mikolov 等人训练。 (2013) 基于 1000 亿个 Google 新闻单词,并且是公开可用的。我们最初保持单词向量静态,只学习模型的其他参数。 尽管对超参数进行了很少的调整,但这个简单的模型在多个基准上取得了优异的结果,这表明预训练的向量是可用于各种分类任务的“通用”特征提取器通过微调学习特定于任务的向量可以带来进一步的改进 最后,我们描述了对架构的简单修改,以允许通过具有多个通道来使用预训练向量和特定于任务的向量。

我们干了啥。

我们的工作在哲学上与 Razavian 等人相似。 (2014)表明,对于图像分类,从预训练的深度学习模型获得的特征提取器在各种任务上都表现良好,包括与训练特征提取器的原始任务非常不同的任务。



3.Model

3.1 模型总览

我们将model看成一个黑盒,那么它的输入是:长度为n的一个句子,有n个词w1、w2、w3、…,输出:label,预测的类别。

我们先不看原论文给的model结构,而是先看论文A Sensivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classfication给出的model结构图如下图,个人觉得这篇论文给出的model结构图更容易理解,所以看下面的结构图就好了。后面我的代码复现也是基于下面这个model结构图。

在这里插入图片描述
然后我大概说一下上图的这个流程吧。最左边是词向量矩阵embedding,然后经过卷积,这里的卷积核大小有2、3、4,每个大小的卷积核有两个通道,得到len(region_sizes) * 2feature map。然后对每个feauture map做最大池化操作接着再拼接起来,最后再经过全连接层。

如果有不了解卷积的同学,可以先看一下这篇blog,写的非常详细卷积过程详细解析

后面在模型详解部分我也还会推荐一篇写的非常不错的卷积介绍的blog。



3.2 模型详解

3.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初始化方法。

后面代码实现的时候,为了容易理解,降低复杂度,不会考虑这些太细节的东西。我写代码是为了更好的理解Model结构。

b.使用预训练的词向量文件初始化词向量矩阵
本质上,词向量矩阵的作用是实现文本的向量表征,因此,如何用更合适的向量表示文本,逐渐成为了一个热门研究方向。

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

具体命令是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。

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

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

3.2.2 卷积层

如果对卷积不太理解的话,推荐先看一下这个文章理解NLP中的卷积神经网络

在此Model中,用三个不同的卷积核大小(h, k),h=2,3,4,分别与上面所说的词向量矩阵做卷积操作。哦对了,这儿的卷积是不会左右移动只会上下移动的,为什么呢?你想啊,左右移动不就截不出一个单词的完整向量表示了吗?那就是打乱了单词词序,破坏了单词语义。在后面的DPCNN论文中,是采用了后者的方法的即保留词序。

DPCNN作者argue前者做法更容易造成过拟合,后者的性能却跟前者差不多。

在这里插入图片描述

从直观上理解,TextCNN通过利用多个不同size的kernel来提取句子中的关键信息(类似于多窗口大小的n-gram),从而能够更好地捕捉局部相关性


3.2.3 池化层

池化采用的是最大池化,在经过卷积操作之后,对得到的结果取最大特征值进行降维采样。最大池化操作我就不说了,如果有不明白的同学可以百度一下。

max-pool这个想法也是为了每个特征图能够捕获最重要的特征,这种池化方案自然能够处理可变的句子长度。

在另一篇论文A Convolutional Neural Network for Modelling Sentences里就是对池化层做了改进,它不是1-max-pooling,而是k-max-pooling。有关这篇论文的内容可以看我下一篇博客(准备写了)。



3.3 论文中的model

下图便是论文中给出的model。

在这里插入图片描述

原文中是这样描述的:在其中一种模型变体中,我们尝试使用两个词向量“通道”——一个在整个训练过程中保持静态,另一个通过反向传播进行微调(第 3.2 节)。 在多通道架构中,如图 1 所示 ,每个滤波器应用于两个通道,并将结果相加以计算公式 (2) 中的 Ci。 该模型在其他方面等效于单通道架构。
在这里插入图片描述
上面的公式就是在做我们前面介绍的卷积操作。



4.数据集和实验设置

4.1 数据集

在这里插入图片描述
MR:电影评论,每条评论一句话。 分类涉及检测正面/负面评论。

SST-1:斯坦福情绪树库——MR 的扩展,但提供了训练/开发/测试分割和细粒度标签(非常积极、积极、中立、消极、非常消极),由 Socher 等人重新标记。 (2013)

SST-2:与 SST-1 相同,但删除了中立评论并添加了二进制标签。

Subj:主观性数据集,其中的任务是将句子分类为主观或客观。

TREC:TREC 问题数据集——任务涉及将问题分为 6 种问题类型(问题是否涉及人物、位置、数字信息等)

CR:各种产品(相机、MP3 等)的客户评论。 任务是预测正面/负面评论(Hu and Liu,2004)。

MPQA:MPQA 数据集的意见极性检测子任务(Wiebe 等人,2005)


4.2 超参数设置

超参数
滑动窗口大小h3,4,5
dropout rate0.5
L23
mini-batch size50

4.3 预训练的词向量

在没有大型监督训练集的情况下,使用从无监督神经语言模型获得的词向量来初始化词向量是一种提高性能的流行方法(Collobert et al., 2011; Socher et al., 2011; Iyyer et al., 2014) 。

我们使用公开可用的 word2vec 向量,这些向量是根据 Google 新闻中的 1000 亿个单词进行训练的。 这些向量的维数为 300,并使用连续词袋架构进行训练(Mikolov 等人,2013)。 预训练单词集中不存在的单词被随机初始化。


4.4 论文中四个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 搭两个通道来做。


学累了吧,学累了就看张图歇一会吧

在这里插入图片描述

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有坏的影响。


5.结果讨论

在这里插入图片描述
从结果来看,CNN-non-static在各个数据集上表现都良好,说明使用预训练的词向量+微调效果更好,证明了构造更好的embedding是提升NLP各项任务的关键能力。



6.总结

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



7.代码复现

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

我先在前面贴出数据变化的过程。如果你在看代码的过程中有不理解的情况,可以回过头来看看。遇到不理解的代码也可以问文心一言。

x, y = next(iter(train_loader))  # 获取一组数据用来检验

embedding = nn.Embedding(vocab_size, embedding_dim)
print("embedding_weight:", embedding.weight)

conv_list = []
filter_sizes = [2, 3]
for conv_size in filter_sizes:
    conv_list.append(nn.Conv2d(1, 2, (conv_size, embedding_dim)))
conv_model = nn.ModuleList(conv_list)

x = embedding(x)
print("embedding(x):", x, "shape:", x.shape)

# 升维
x = x.unsqueeze(1)
print(x.shape)
conv_result_list = []
for conv in conv_model:
    conv_out = conv(x)
    print("conv(x):", conv_out, "shape:", conv_out.shape)
    conv_out = conv_out.squeeze(3)
    print(conv_out.shape)
    conv_out = F.relu(conv_out)
    print("relu(x):", conv_out)
    max_conv_out = F.max_pool1d(conv_out, conv_out.size(2)).squeeze(2)
    print("max_pool(x):", max_conv_out, "shape:", max_conv_out.shape)
    conv_result_list.append(max_conv_out)
# 拼接起来
concat_out = torch.cat(conv_result_list, dim=1)
print("concat_out:", concat_out)
linear = nn.Linear(2 * len(filter_sizes), 2)
model_out = linear(concat_out)
print("model_out:", model_out)

在这里插入图片描述在这里插入图片描述

7.1 导入必要的包

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader

import numpy as np

7.2 预处理数据

def get_text():
    sentence_list = [
        "i love you",
        "he loves me",
        "she likes baseball",
        "i hate you",
        "sorry for that",
        "it is awful",
        "this is terrible"
    ]
    sentence_label = [1, 1, 1, 0, 0, 0, 0]
    return sentence_list, sentence_label

sentence_list, sentence_label = get_text()
word_list = " ".join(sentence_list).split()
vocab = list(set(word_list))
word_to_index = {w: i for i, w in enumerate(vocab)}
vocab_size = len(vocab)

batch_size = 1
embedding_dim = 4

7.3 封装自己的数据集

class TextCNNDataset(Dataset):
    
    def __init__(self, text_list, text_label):
        super(TextCNNDataset, self).__init__()
        self.text_list = text_list
        self.text_label = text_label
        self.train_data = self.generate_train_data(text_list)
        
    def __getitem__(self, idx):
        inputs = self.train_data[idx]
        label = self.text_label[idx]
        return inputs, label
    
    def __len__(self):
        return len(self.train_data)
        
    def generate_train_data(self, text_list):
        inputs = []
        for text in text_list:
            inputs.append([word_to_index[n] for n in text.split(" ")])
        return np.array(inputs)
    
dataset = TextCNNDataset(sentence_list, sentence_label)
train_loader = DataLoader(dataset, batch_size=batch_size)

7.4 搭建model

class TextCNN(nn.Module):
    
    def __init__(self, vocab_size, embedding_dim=4, output_dim=2, out_channels=2, filter_sizes=(2, 3)):
        super(TextCNN, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        conv_list = []
        for conv_size in filter_sizes:
            conv_list.append(nn.Conv2d(1, out_channels, (conv_size, embedding_dim)))
        self.conv_model = nn.ModuleList(conv_list)
        self.linear = nn.Linear(out_channels * len(filter_sizes), output_dim)
        
    def forward(self, x):
        x = self.embedding(x)
        x = x.unsqueeze(1)
        conv_result_list = []
        for conv in self.conv_model:
            conv_out = conv(x)
            conv_out = conv_out.squeeze(3)
            conv_out = F.relu(conv_out)
            max_conv_out = F.max_pool1d(conv_out, conv_out.size(2)).squeeze(2)
            conv_result_list.append(max_conv_out)
        concat_out = torch.cat(conv_result_list, dim=1)
        model_out = self.linear(concat_out)
        return model_out

7.5 训练

# 训练
model = TextCNN(vocab_size)
optimizer = torch.optim.Adam(model.parameters(), lr = 0.001)
criterion = nn.CrossEntropyLoss()

for epoch in range(1000):
    for batch_x, batch_y in train_loader:
        pred = model(batch_x)
        loss = criterion(pred, batch_y)
        if (epoch + 1) % 1000 == 0:
            print('Epoch:', '%04d' % (epoch + 1), 'loss =', '{:.6f}'.format(loss))

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

7.6 测试

# Test
test_text = 'i love me'
tests = [[word_to_index[n] for n in test_text.split()]]
test_batch = torch.LongTensor(tests)
# Predict
model = model.eval()
predict = model(test_batch).data.max(1, keepdim=True)[1]
if predict[0][0] == 0:
    print(test_text,"is Bad Mean...")
else:
    print(test_text,"is Good Mean!!")

7.7 运行结果

在这里插入图片描述

题外话,上面的代码还是有很多地方可以优化的,读者有兴趣且有精力的话可以尝试一下。比如我这儿故意设置语料库里面的句子长度是不一样的,如果不一样,是不是要写一个函数处理一下(设置一个固定长度,多的切除,少的补零),一些细节比如dropoutL2范数约束也没有去实现等等。

这篇论文的阅读笔记就到这儿了,拜拜咯~如果对你有帮助,麻烦点赞收藏拜托拜托,谢谢。



8. 参考资料

主要参考博客:TextCNN

如果你想完整的复现论文,上面的这篇blog可以的。

  • 42
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 卷积神经网络 (Convolutional Neural Networks, CNN) 是一种常用于文本分类的深度学习模型。它通过卷积和池化层来提取文本中的特征,并使用全连接层来进行分类CNN 的一个优点是能够处理变长的输入,并且不需要对文本进行预处理。 ### 回答2: 卷积神经网络是一种深度学习方法,用于对文本进行分类。在训练过程中,这种网络可以自动学习输入数据的特征表示。卷积神经网络中的卷积层可以识别输入中的局部模式,这些局部模式组合起来形成更高级别的特征,最终帮助分类器确定类别。对于文本分类问题,卷积神经网络的输入是文本的词嵌入向量,可以从先验知识中自动学习特征。 在一些文本分类任务中,卷积神经网络已经取得了很好的表现。文本分类任务通常被分为两种类型:二元分类和多分类。二元分类任务是指将数据分为两类,例如垃圾邮件和非垃圾邮件。多类分类任务是指将数据分为多类,例如新闻分类。在这两种任务中,卷积神经网络都能够进行有效的分类。 对于二元分类任务,卷积神经网络可以使用一个输出节点,并使用 sigmoid 激活函数将输入映射到 0 到 1 之间的概率。对于多分类任务,卷积神经网络可以使用多个输出节点,每个节点对应一个类别,并使用 softmax 激活函数将输入映射到 0 到 1 之间,并且所有输出节点的和为 1。 要训练卷积神经网络进行文本分类,需要对模型进行三个主要的训练步骤。首先,需要构建词嵌入矩阵,该矩阵将文本中的每个词都映射到一个向量。然后,需要将文本数据转换为卷积神经网络所需的格式。最后,需要对模型进行训练,并根据测试数据进行评估。 总之,卷积神经网络已经被证明是一种强大的工具,可以用于文本分类等任务。在处理文本数据时,卷积神经网络可以自动学习输入数据的特征表示,并使用这些特征来确定文本的类别。 ### 回答3: 卷积神经网络(CNN)是一种深度学习模型,它在图像识别、计算机视觉和自然语言处理中表现出色。最近几年,CNN 在句子分类中也获得了很大的成功。 CNN 句子分类模型的输入是一个序列,输出是类别标签。与传统的 RNN 模型不同之处在于,CNN 可以使每个神经元只能捕获一个固定大小的区域的特征,从而加快模型的训练和降低了模型的复杂度。 CNN 句子分类模型的基本架构包括词嵌入层、卷积层、池化层和全连接层。词嵌入层将输入的文本转化为向量表示。卷积层通过滑动窗口对输入的序列进行卷积操作,提取出局部特征。池化层在每个滑动窗口上提取出一个最大值或平均值,进一步降低维度。最后,全连接层将提取出的特征传递到输出层进行分类CNN 句子分类模型的优点在于它可以处理不定长的文本序列,并在仅有少量特征的情况下表现出色。但是,CNN 模型的缺点在于不善于处理长期依赖关系,例如情感分析中的Irony识别。为了解决这个问题,可以引入 RNN 或 Transformer 等模型。 总的来说,CNN 模型为句子分类问题提供了一个简单有效的解决方案。在实践中,需要根据具体的任务选择合适的模型结构和参数设置,才能取得最佳效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值