《Convolutional Neural Networks for Sentence Classification》速读

文本分类任务中可以利用CNN来提取句子中类似 n-gram 的关键信息。

TextCNN的详细过程原理图见下:

keras 代码:

 1 def convs_block(data, convs=[3, 3, 4, 5, 5, 7, 7], f=256):
 2     pools = []
 3     for c in convs:
 4         conv = Activation(activation="relu")(BatchNormalization()(
 5             Conv1D(filters=f, kernel_size=c, padding="valid")(data)))
 6         pool = GlobalMaxPool1D()(conv)
 7         pools.append(pool)
 8     return concatenate(pools)
 9
10
11 def rnn_v1(seq_length, embed_weight, pretrain=False):
12
13     main_input = Input(shape=(seq_length,), dtype=‘float64‘)
14
15     in_dim, out_dim = embed_weight.shape
16     embedding = Embedding(input_dim=in_dim, weights=[
17         embed_weight], output_dim=out_dim, trainable=False)
18     content = Activation(activation="relu")(
19         BatchNormalization()((TimeDistributed(Dense(256))(embedding(main_input)))))
20     content = Bidirectional(GRU(256))(content)
21     content = Dropout(0.3)(content)
22     fc = Activation(activation="relu")(
23         BatchNormalization()(Dense(256)(content)))
24     main_output = Dense(3,
25                         activation=‘softmax‘)(fc)
26
27     model = Model(inputs=main_input, outputs=main_output)
28     model.compile(optimizer=‘adam‘,
29                   loss=‘categorical_crossentropy‘,
30                   metrics=[‘accuracy‘])
31     model.summary()
32     return model

说明如下:

  • 输入层

如图所示,,假设句子有 n 个词,vector的维数为 k ,那么这个矩阵就是 n×k 的。

这个矩阵的类型可以是静态的(static),也可以是动态的(non static)。静态就是word vector是固定不变的,而动态则是在模型训练过程中,word vector也当做是可优化的参数,通常把反向误差传播导致word vector中值发生变化的这一过程称为Fine tune

对于未登录词的vector,可以用0或者随机小的正数来填充。

  • 第一层卷积层

输入层通过卷积操作得到若干个Feature Map,卷积窗口的大小为 m*k ,其中 m表示n_gram中的n,通过卷积将得到F个列数为1的Feature Map,F表示卷积核的个数。

  • 池化层

接下来的池化层,文中用了一种称为Max-over-time Pooling的方法。这种方法就是简单地从之前一维的Feature Map中提出最大的值,文中解释最大值代表着最重要的信号。

最终池化层的输出为各个Feature Map的最大值,即一个一维的向量。polling之后得到的是1*F的一维向量。

  • 全连接 + Softmax层

池化层的一维向量的输出通过全连接的方式,连接一个Softmax层。

最终实现时,我们可以在倒数第二层的全连接部分上使用Dropout技术,即对全连接层上的权值参数给予L2正则化的限制。这样做的好处是防止隐藏层单元自适应(或者对称),从而减轻过拟合的程度。

实验部分

1. 数据

实验用到的数据集如下(具体的名称和来源可以参考论文):

2. 模型训练和调参

  • 修正线性单元(Rectified linear units)
  • 滤波器的h大小:3,4,5;对应的Feature Map的数量为100;
  • Dropout率为0.5,L2正则化限制权值大小不超过3;
  • mini-batch的大小为50;

这些参数的选择都是基于SST-2 dev数据集,通过网格搜索方法(Grid Search)得到的最优参数。另外,训练过程中采用随机梯度下降方法,基于shuffled mini-batches之上的,使用了Adadelta update rule(Zeiler, 2012)。

3. 预训练的Word Vector

这里的word vector使用的是公开的数据,即连续词袋模型(COW)在Google News上的训练结果。未登录次的vector值是随机初始化的。

4. 实验结果

实验结果如下图:

其中,前四个模型是上文中所提出的基本模型的各个变种:

  • CNN-rand: 所有的word vector都是随机初始化的,可以训练的参数。
  • CNN-static: Google的Word2Vector工具(CBOW模型)得到的结果,不可训练;
  • CNN-non-static: Google的Word2Vector工具(CBOW模型)得到的结果,但是会在训练过程中被Fine tuned
  • CNN-multichannel: CNN-static和CNN-non-static的混合版本,即两种类型的输入;

5. 结论

  • CNN-static较与CNN-rand好,说明pre-training的word vector确实有较大的提升作用(因为pre-training的word vector显然利用了更大规模的文本数据信息);
  • CNN-non-static较于CNN-static大部分要好,说明适当的Fine tune也是有利的,是因为使得vectors更加贴近于具体的任务
  • CNN-multichannel较于CNN-single在小规模的数据集上有更好的表现,实际上CNN-multichannel体现了一种折中思想,即既不希望Fine tuned的vector距离原始值太远,但同时保留其一定的变化空间。

值得注意的是,static的vector和non-static的相比,有一些有意思的现象如下表格:

  • 原始的word2vector训练结果中,bad对应的最相近词为good,原因是这两个词在句法上的使用是极其类似的(可以简单替换,不会出现语句毛病);而在non-static的版本中,bad对应的最相近词为terrible,这是因为在Fune tune的过程中,vector的值发生改变从而更加贴切数据集(是一个情感分类的数据集),所以在情感表达的角度这两个词会更加接近;
  • 句子中的!最接近一些表达形式较为激进的词汇,如lush等;而,则接近于一些连接词,这和我们的主观感受也是相符的。

Kim Y的这个模型很简单,但是却有着很好的性能。后续Denny用TensorFlow实现了这个模型的简单版本,可参考这篇博文;以及Ye Zhang等人对这个模型进行了大量的实验,并给出了调参的建议,可参考这篇论文

下面总结一下Ye Zhang等人基于Kim Y的模型做了大量的调参实验之后的结论:

  • 由于模型训练过程中的随机性因素,如随机初始化的权重参数,mini-batch,随机梯度下降优化算法等,造成模型在数据集上的结果有一定的浮动,如准确率(accuracy)能达到1.5%的浮动,而AUC则有3.4%的浮动;
  • 词向量是使用word2vec还是GloVe,对实验结果有一定的影响,具体哪个更好依赖于任务本身;
  • Filter的大小对模型性能有较大的影响,并且Filter的参数应该是可以更新的;
  • Feature Map的数量也有一定影响,但是需要兼顾模型的训练效率;
  • 1-max pooling的方式已经足够好了,相比于其他的pooling方式而言;
  • 正则化的作用微乎其微。

Ye Zhang等人给予模型调参者的建议如下:

  • 使用non-static版本的word2vec或者GloVe要比单纯的one-hot representation取得的效果好得多;
  • 为了找到最优的过滤器(Filter)大小,可以使用线性搜索的方法。通常过滤器的大小范围在1-10之间,当然对于长句,使用更大的过滤器也是有必要的;
  • Feature Map的数量在100-600之间;
  • 可以尽量多尝试激活函数,实验发现ReLUtanh两种激活函数表现较佳;
  • 使用简单的1-max pooling就已经足够了,可以没必要设置太复杂的pooling方式;
  • 当发现增加Feature Map的数量使得模型的性能下降时,可以考虑增大正则的力度,如调高dropout的概率;
  • 为了检验模型的性能水平,多次反复的交叉验证是必要的,这可以确保模型的高性能并不是偶然。

论文附录中还附上了各种调参结果,感兴趣的可以前往阅读之。

TextCNN详细过程:第一层是图中最左边的7乘5的句子矩阵,每行是词向量,维度=5,这个可以类比为图像中的原始像素点了。然后经过有 filter_size=(2,3,4) 的一维卷积层,每个filter_size 有两个输出 channel。第三层是一个1-max pooling层,这样不同长度句子经过pooling层之后都能变成定长的表示了,最后接一层全连接的 softmax 层,输出每个类别的概率。

特征:这里的特征就是词向量,有静态(static)和非静态(non-static)方式。static方式采用比如word2vec预训练的词向量,训练过程不更新词向量,实质上属于迁移学习了,特别是数据量比较小的情况下,采用静态的词向量往往效果不错。non-static则是在训练过程中更新词向量。推荐的方式是 non-static 中的 fine-tunning方式,它是以预训练(pre-train)的word2vec向量初始化词向量,训练过程中调整词向量,能加速收敛,当然如果有充足的训练数据和资源,直接随机初始化词向量效果也是可以的。

通道(Channels):图像中可以利用 (R, G, B) 作为不同channel,而文本的输入的channel通常是不同方式的embedding方式(比如 word2vec或Glove),实践中也有利用静态词向量和fine-tunning词向量作为不同channel的做法。

一维卷积(conv-1d):图像是二维数据,经过词向量表达的文本为一维数据,因此在TextCNN卷积用的是一维卷积。一维卷积带来的问题是需要设计通过不同 filter_size 的 filter 获取不同宽度的视野。

Pooling层:利用CNN解决文本分类问题的文章还是很多的,比如这篇 A Convolutional Neural Network for Modelling Sentences 最有意思的输入是在 pooling 改成 (dynamic) k-max pooling ,pooling阶段保留 k 个最大的信息,保留了全局的序列信息。比如在情感分析场景,举个例子:

            “ 我觉得这个地方景色还不错,但是人也实在太多了 ”

虽然前半部分体现情感是正向的,全局文本表达的是偏负面的情感,利用 k-max pooling能够很好捕捉这类信息。

原文地址:https://www.cnblogs.com/zle1992/p/9093102.html

时间: 2024-10-21 14:27:04

《Convolutional Neural Networks for Sentence Classification》速读的相关文章

速读《深入理解计算机系统(第三版)》总结

速读<深入理解计算机系统(第三版)>总结 第一章 计算机系统漫游 读完第一章的心情实在难以述说,在此写下这一章自己的一点学习经历及感想 仔细读完了这本书的第一章的内容,之前零零散散的学过一些计算机系统知识,也接触过编程,但是对于这两者并没有什么太多的思考,它们底层是什么联系也不太了解.当我读完这一章的内容时,我的内心是非常激动的,解除了很多之前学习中所残留下来的困惑,虽说是残留,但十分致命,令我一直处于一知半解的状态,我第一次的深刻觉得计算机是一个如此紧密的工具,我跟着作者的思路,从给出计算机

速读《深入理解计算机系统》

本周速读了<深入理解计算机系统>这本书,这本书从程序员的角度介绍了计算机系统的内在运作,展示了一些本质概念是如何实际的影响应用程序的正确性.性能和实用性的.收获如下: 1.关于进程和线程 进程是操作系统对运行程序的一种抽象,是指计算机中已运行的程序,是系统进行资源分配和调度的基本单位,是操作系统结构的基础. 线程有时被称为轻量级进程,是操作系统能够进行运算调度的最小单位.线程是进程中的一个实体,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥

2018-2019-1 20189221 书籍速读 第 1 周

2018-2019-1 20189221 书籍速读 第 1 周 <深入理解计算机系统> 第 1 章: 怎样理解Amdahl定律? 第 2 章: 如何让代码可以正常的运行在任意字长的机器上,怎样进行不同机器之间的代码移植? 第 3 章: C++和Java的编译器是怎样映射产生机器级程序? 第 4 章: 流水线型的处理器怎样进行基本的异常处理? 第 5 章: 乱序处理器操作具体是怎样? 第 6 章: 结合机要密码方面的知识,德国恢复已经过多次硬件删除的磁盘数据的原理会是怎样的? 第 7章: 怎样高

【转】《深入理解计算机系统》C程序中常见的内存操作有关的典型编程错误

原文地址:http://blog.csdn.net/slvher/article/details/9150597 对C/C++程序员来说,内存管理是个不小的挑战,绝对值得慎之又慎,否则让由上万行代码构成的模块跑起来后才出现内存崩溃,是很让人痛苦的.因为崩溃的位置在时间和空间上,通常是在距真正的错误源一段距离之后才表现出来.前几天线上模块因堆内存写越界1个字节引起各种诡异崩溃,定位问题过程中的折腾仍历历在目,今天读到<深入理解计算机系统>第9章-虚拟存储器,发现书中总结了C程序中常见的内存操作有

《深入理解计算机系统》第六周学习笔记

第四章 处理器体系结构 (一)知识点总结 一.Y86指令集体系结构 1.Y86处理器状态类似于IA32,有8个程序寄存器: %eax.%ecx.%edx.%ebx.%esi.%edi.%esp.%ebp.处理器的每个程序寄存器存储一个字.%esp被入栈.出栈.调用和返回指令作为栈指针. 2.3个一位的条件吗:ZF.SF.OF,它们保存最近的算术或逻辑指令所造成影响的有关信息.程序计数器PC存放当前正在执行指令的地址. 3.程序状态的最后一个部分是状态码stat,它表明程序执行的总体状态 4.Y8

深入理解计算机系统(4.2)---硬件的魅力

引言 这个系列已经很久没更新了,记得上一篇博文已经是三月份了,实在是抱歉.最近业余时间没有以前充裕了,因此更新一篇博文已经变成了一种奢侈.记得以前刚开始写的时候,最多的时候LZ一天写过3篇博文,现在想想,往事如梦. 好了,好不容易写一次,就不多说废话了,本文主要介绍一下硬件以及HCL语言的内容. 从疑问开始 首先,在介绍本文的内容之前,我们先来思考一个看似简单,却实际比较“高深”的问题.众所周知,计算机归根结底是在和0.1打交道,那么到底0和1是如何被计算机记住的呢? 怎么样,这个问题是不是有点

深入理解计算机系统(1.1)------Hello World 是如何运行的

上一篇序章我谈了谈 程序员为啥要懂底层计算机结构 ,有人赞同也有人反对,但是这并不影响 LZ 对深入理解计算机系统研究的热情.这篇博客以案例驱动的模式,通过跟踪一个简单 Hello World 程序的生命周期开始系统的学习,包括它被程序员创建,到在系统上运行,输出简单的消息,然后终止.LZ 将沿着这个程序的声明周期,先简要的介绍一些逐步出现的关键概念.专业术语以及组成部分.后面将会详细展开. 1.计算机系统 我们知道计算机系统是由硬件和软件组成的.它们共同工作来运行应用程序.虽然系统的实现方式随

《深入理解计算机系统》读书笔记第七章——链接

<深入理解计算机系统>第七章 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 链接的时机 编译时,也就是在源代码被翻译成机器代码时 加载时,也就是在程序被加载器加载到存储器并执行时. 运行时,由应用程序执行. 在现代系统中,链接是由链接器自动执行的. 7.1 编译器驱动程序 编译系统提供编译驱动程序——调用语言预处理器.编译器.汇编器和链接器. (1)运行C预处理器:源程序main.c->ASCII码中间文件main.i (2)

《深入理解计算机系统》第二章习题2_66

最近打算把<深入理解计算机系统>再读一遍,说实话这本书读多少遍都不嫌多,每读一遍都会有收获.这次决心把书中的习题整个过一遍,并把其中我认为比较典型的.有意思的写城博文记录一下,恩,这就是这篇博文的由来.恳请各路大神拍砖. 一. 问题描述(鉴于我这不忍直视的翻译水平,我就直接贴书中的问题描述了): Generate mask indicating leftmost 1 in x. Assume w = 32. For example 0xFF00 -> 0x8000, and 0x6600

计算机编程基础之深入理解计算机系统1

目录 概述——<深入理解计算机系统> 计算机系统漫游 信息的表示和处理 概述——<深入理解计算机系统> Computer Systems A Programmers Perspective  英文名 计算机系统漫游 本章简介 当系统上执行hello程序时,系统发生了什么以及为什么会这样 信息就是位+上下文 源程序(或者源文件) hello.c,实际上是由值0和1组成的位(bit)序列,8个位被组织成一组,成为字节.每个字节表示程序中某个文本字符,大部分的现代系统都使用ASCII标准