博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CNNs for Text Classification
阅读量:6191 次
发布时间:2019-06-21

本文共 4612 字,大约阅读时间需要 15 分钟。

研究问题

关于Convlutional Neural Networks(CNNs)在自然语言处理领域的应用。

这一次的研究主要是针对文本分类这一个问题所展开。

研究方法

  1. 了解卷积神经网络。
  2. 阅读paper,深入理解CNN在NLP中的模型细节。
  3. 类比CNN在CV中的应用,总结两者异同。
  4. 代码实现

附加:

类比信号与系统,理解卷积的真正意义,体会信号系统与图像处理中卷积模型所起的不同作用。

拟采用的方法

CNNs的定义

卷积神经网络本质上是由多个卷积层,经过激活函数后产生输出的网络。可以将其大致划分为输入层,卷积层,池化层,全连接层和输出层。

卷积层

其中卷积层的工作,是通过定义一系列卷积核,依次扫过图像中的每个区域,产生一个新的特征矩阵的过程。因此,卷积核在训练完成后,更像是一个特征过滤器,在扫过图像的过程中,忽略掉与特征不相符的部分,而将符合这种特征的部分放大化(通常是分配一个较大的权重)。

池化层

池化层通常会紧跟在卷积层之后,对卷积层所产生的特征矩阵进行子采样(可能是去平均值,或者取最大值),最终得到一个固定大小的矩阵。

池化层主要的作用有两方面。

第一,固定大小。经由卷积层产生的特征矩阵通常是大小不定的,所以我们无法将它直接投入到全连接层进行后续工作,而池化层在这里起到了“连接器”的作用,它将一个不定大小的矩阵转化成了固定大小的矩阵,随时可以喂食到后续神经网络。

第二,信息提取。池化层在降低输出维度的同时,保留了原始特征矩阵总最显著的信息,并不会因为维度的降低而导致信息的丢失。

全连接层

所谓全连接是指,本层所有的神经元都与下一层的神经元相连。因为相对简单,这里也不再赘述。

总结

通过观察下图我们可以发现,一个CNNs会由多个卷积层,多个池化层,经由全连接层产生输出。

全连接层起到的作用很容易理解,通常也只是分类,回归等任务。那么介于原始图像,和分类网络之间的卷积层和池化层究竟起了什么作用?

我认为,它们两层合起来可以用“特征提取层”来概括,也就是说,卷积层和池化层其实是一个特征抽取,数据加工的过程,将原始的图像经过一系列的处理,加工,才能产生易于分类的数据类型,然后进行分类工作。

CNNs在NLP中的模型

类比CNNs在图像处理中的应用,NLP中的模型实际上是将一个句子以图的概念理解。

initialize

在初始化特征矩阵时,句子中的每一个单词的word embeddings作为矩阵的一行,得到一个n*k的矩阵,其中n是句子中的单词数,k是词嵌入模型的维度,也可以是one-hot模型,但是考虑到样本的稀疏度,一般会采用低维的词嵌入模型。

filter

在CV中,一般我们的卷积核filters会扫过图像的局部像素,但在NLP中,通常会只改变filters的长度,而宽度始终等于词嵌入维度k,也就是说,filter的最小单位一整行,一个完整的word。而通常情况下,会使用一个长度为2~5的filter,这是因为实际情况中,很少会出现5个词以上的长组合短语。

pooling

CV中的池化操作通常会产生一个n * m的特征矩阵,但在NLP中,产生的特征矩阵会是一个n * 1的矩阵。

产生这种不同的原因是因为,在图像中,传递信息的是一个像素块,而在自然语言处理中,传递信息的是一个word,图像本身就是二维的,所以需要用二维去传递信息,但是对于词而言,第二个维度k实际上是词嵌入的维度,并不会传递有关于这个句子的信息。

channel

CV处理中,我们会遇到RGB图分为R,G,B三个channel分析的情况。在NLP中,似乎看上去一个channel就足够来做分析。

但是在原始paper中提到,NLP中的CNNs模型也可以有多个通道,一般是staticfine-tuned

static通道在backpropagation的过程中是静态的,保持不变的,但是fine-tuned通道会随着训练发生变化。

除了这两个通道之外,我们也可以增加另外的通道,比如改变句子的语言,或者将句子替换成其他同义句等等。

实验

实验部分用tensorflow实现了CNN-rand模型,数据集采用原paper中的MR数据集,这是一个关于电影评价的数据集,数据集将评价分为了positive和negetive两个部分。

由于这个数据集本身较小,而且没有dev,因此抽取了其中的10%作为dev。

Embedding Layer

第一部分是embedding layer,将一个词映射成低维word embedding。这里没有采用google的word2vec是因为这个模型本身较为简单,而且笔记本算力有限,所以自己构建了一个简单的embedding layer。

with tf.device('/cpu:0'), tf.name_scope("embedding"):    self.W = tf.Variable(        tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0),        name="W")    self.embedded_chars = tf.nn.embedding_lookup(self.W, self.input_x)    self.embedded_chars_expanded = tf.expand_dims(self.embedded_chars, -1)复制代码

W是一个随机均匀分布,维度为vocab_size * embedding_size的初始化矩阵。

tf.nn.embedding_lookup方法创建了一个词嵌入矩阵,它的维度和W一致,返回的类型为[None, sequence_length, embedding_size]

tf.expand_dims(self.embedded_chars, -1)在返回值的最后一个维度插入1,变成[None, sequence_length, embedding_size, 1],这里的1代表的通道数,在后续con2d卷积方法中会使用。

Convolution and Max-Pooling Layer

卷积和池化模型的建立。

因为是CNN-rand模型,所以通道数为1,且采用窄卷积的方式进行卷积操作。

pooled_outputs = []        for i, filter_size in enumerate(filter_sizes):            with tf.name_scope("conv-maxpool-%s" % filter_size):                # Convolution Layer                filter_shape = [filter_size, embedding_size, 1, num_filters]                W = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.1), name="W")                b = tf.Variable(tf.constant(0.1, shape=[num_filters]), name="b")                conv = tf.nn.conv2d(                    self.embedded_chars_expanded,                    W,                    strides=[1, 1, 1, 1],                    padding="VALID",                    name="conv")                # Apply nonlinearity                h = tf.nn.relu(tf.nn.bias_add(conv, b), name="relu")                # Max-pooling                pooled = tf.nn.max_pool(                    h,                    ksize=[1, sequence_length - filter_size + 1, 1, 1],                    strides=[1, 1, 1, 1],                    padding='VALID',                    name="pool")                pooled_outputs.append(pooled)        # Combine all the pooled features        num_filters_total = num_filters * len(filter_sizes)        self.h_pool = tf.concat(pooled_outputs, 3)        self.h_pool_flat = tf.reshape(self.h_pool, [-1, num_filters_total])复制代码

这里的filter_size = "3,4,5",是采用长度分别为3,4,5的三种filter对词嵌入矩阵进行卷积。

W是卷积核,用截断正态分布进行初始化。b是偏置数,h为卷积输出经过激活函数以后的结果。

tf.nn.conv2d中的stridespadding参数,分别表示步长和卷积方式。'VALID'是窄卷积,产生的输出类型为[1, sequence_length - filter_size +1, 1, 1]

卷积结果经过一个ReLU激活后,放入池化层。

池化层是一个Max-pooling,会将卷积输出的n * 1的矩阵中取出一个最大值。然后将同一个filter的Max-pooling结果连接起来,最终得到的类型为[filter_num, 1]

最后将所有filter的结果相连,得到最终经过Convolution和Pooling的矩阵。

讨论

和原paper中给的76%比较接近,误差产生的原因可能在于我没有采用交叉验证,数据集较小的情况下可能发生过拟合的情况。

通过这一次课题研究,我试图去寻找CV和NLP在使用CNNs时的共性,我个人认为,他们都是通过特征的部分提取去创造特征来进行最终的分类训练。

但是在CV中,卷积核最终的训练形态比较容易理解,应该是一个图像的局部特征,比如一个圆,一个三角形,或是一条线等等。但在NLP中,却很难去定义卷积核最终到底产生了什么特性,它提取出来的特征到底是什么,这一点是我做完这一次研究后所困扰的。

总体而言,CNNs在NLP中的应用是将文本以图像的表示形式进行处理,虽然可能在一些方面的概念比较模糊,但卷积操作的速度,也使得CNNs模型在文本分类这一方向取得了不小的进步。

转载地址:http://strda.baihongyu.com/

你可能感兴趣的文章
演示针对LVM分区的管理
查看>>
MVC模式下如何实现RegisterStartupScript等功能
查看>>
Ubuntu 无法mount解决办法
查看>>
CSS一些最佳实践
查看>>
8.Kubernetes Service(服务)
查看>>
Creating A Second Instance of the IPS Repository Server With SMF
查看>>
iOS开发库的族“.NET研究”谱介绍
查看>>
图解DevExpress RichEditControl富文本的使用,附源码及官方API
查看>>
ubuntu 学习笔记
查看>>
BNU 34986 Football on Table
查看>>
三级联动---城市地区选择
查看>>
闪回flashback#ocp试验#
查看>>
webpack插件html-webpack-plugin
查看>>
软件设计的复杂度
查看>>
无法从使用方法中推导出方法... 的类型实參,请尝试显式指定类型实參
查看>>
axios学习笔记
查看>>
Git各种错误操作撤销的方法
查看>>
剖析 Laravel 计划任务--避免重复
查看>>
公司框架遇到的问题
查看>>
详解 Discuz 的 PHP经典加密解密函数 authcode
查看>>