Press "Enter" to skip to content

卷积神经网络识别负面评论 我们先来看看CNN的架构传统的DNN(即Deep neural network,泛指一般的深…

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

我们先来看看CNN的架构

 

传统的DNN(即Deep neural network,泛指一般的深度学习网路)最大问题在于它会忽略资料的形状。例如,输入影像的资料时,该data通常包含了水平、垂直、color channel等三维信息,但传统DNN的输入处理必须是平面的、也就是为一维的。比如使用DNN来分类MNIST手写数字集吗?其图像信息是水平28 pixels、垂直28 pixels、color channel=1,即(1, 28, 28)的形状,但输入DNN时,所有dataset必须转为一维的dataset。

 

因此,若去除了这些特征,就代表失去了一些重要的空间信息,像不同影像但类似的空间可能有着相似的像素值、图像位置不同就会产生完全不同的数据表达、RGB不同的channel之间也可能具有某些关连性、而远近不同的像素彼此也应具有不同的关联性,而这些特征只有在三维中才能保留下来。

 

如下图,假如有圆形是1,没有圆形是0,那幺圆形的位置不同就会产生完全不同的数据表达。但是从视觉的角度来看,图像的内容(本质)并没有发生变化,只是位置发生了变化。

 

所以当我们移动图像中的物体,用传统的方式的得出来的参数会差异很大!这是不符合图像处理的要求的。

 

而 CNN 解决了这个问题,他用类似视觉的方式保留了图像的特征,当图像做翻转,旋转或者变换位置时,它也能有效的识别出来是类似的图像

因此,Deep learning中的CNN较传统的DNN多了Convolutional(卷积)及池化(Pooling) 两层layer,用以维持形状特征并且避免参数大幅增加。在加入此两层后,我们所看到的架构就如下图,分别有两层的卷积和池化层,以及一个全连结层(即传统的DNN),最后再使用Softmax activation function来输出分类结果。

先来看卷积层

 

如果使用传统的深度学习网络(例如全连接层)来识别图像,那幺原本是二维的图片就必须先打散成一维,然后再将每个像素视为一个特征值丢入DNN架构进行分析,因此这些输入的像素已经丢失了原有的空间排列信息。然而CNN的Convolution layer的目的就是在保留图像的空间排列并取得局部图像作为输入特征。

 

Convolution原理是透过一个指定尺寸的window,由上而下依序滑动取得图像中各局部特征作为下一层的输入,这个sliding window在CNN中称为称为Convolution kernel。这个滑动视窗的方法是不是很熟悉?的确,Convolution kernel其实不是新技术,它在我们之前的影像处理技术中经常应用到,例如Opencv的模糊化、边缘或轮廓侦测…等都是透过kernel window来进行,只是CNN利用此方式来取得图像中各局部的区域加总计算后,透过ReLU activation function输出为特征值再提供给下一层使用。

 

下面用较简单的二进制的黑白图片为例说明。假设我们有一张5×5黑白图片(其维度为5x5x1),使用3×3的kernel window进行卷积(该kernel维度为3x3x1)

在这卷积的过程中,如果二进制的黑白图片中有一个形状与该kernel所表示的形状类似(即kernel中大于0的格子),就会产生激励效果,两者相乘的乘积会变成更大或更小的数。如下图所示,kernel由左至右由上而下滑动会得到9组图形

接下来,再经过ReLU函数处理,将小于0的值输出为0,大于0则直接输出,此结果即为所谓的feature map,此feature map上的每一点皆可视为原图形中该区域的特征并传递给下一层,CNN的卷积层就是专注在取得图形的这些局部特征

由于范例中kernel是逐步移动一格,因此我们称其stride步长为一(这个值是定义CNN时的hyperparameter之一),如果我们把stride加大,那幺涵盖的特征会比较少,但速度较快,得出的feature map更小。此外,在上例中,会发现最后得到的feature map比起原图要小,此种情况称为valid padding,如果我们希望输出的是与原图同等大小的图形,那幺就需要在原图周围补上0(如下图所示),此种于周围补零的方式则称为zero-padding。 zero-padding除了可维持输出图形大小不变之外,也有抑制图像边缘的效果,因为一般情况下我们认为图像的中间部分比起周围更重要

通过上方的步骤我们发现,卷积层会依据指定的kernel大小及stride,取图像各区域的特征值再与kernel各点的权重相乘计算最后得到feature map,此map会传给下游的池化层。所以在多个卷积层中,图像通过kernel提取后的特征再传递给下一层,因此越上层的卷积层会对更小的特征起反应,而kernel的weight值会在反向传播时逐次依loss值用ReLU activate function进行梯度修正。

 

然而如果我们输入的是三层的RGB图像而非单层的呢?或是想要使用多个kernel来取得不同的特征,那幺就需要在同一卷积层中定义多个kernel,此时kernel的数量就代表其kernel的维度。当kernel维度越大,代表使用的kernel种类愈多提取的图像特征也就越多,图像识别的能力也就更好。以下图为例,该input image使用了三种kernels输出三个feature maps。

因此,卷积层有三个超参数对我们在定义layer时相当重要,分别是:

 

Depth:即输入图像的layer数(dimension)

 

Stride:即kernel每次移动的格数

 

zero-padding:外围补0的大小

 

接下来看Pooling layer

 

Pooling layer称为池化层,它的功能很单一,就是将输入的图片尺寸缩小(大部份为缩小一半)以减少每张feature map维度并保留重要的特征,其好处有:

 

减少后续layer需要参数,加快系统运作的效率。

 

具有抗干扰的作用:图像中某些像素在邻近区域有微小偏移或差异时,对Pooling layer的输出影响不大,结果仍是不变的。

 

减少过度拟合over-fitting的情况。

 

与卷积层相同,池化层会使用kernel来取出各区域的值并运算,但最后的输出并不通过Activate function(卷积层使用的function是ReLU)。另外,池化层用来缩小图像尺寸的作法主要有三种:最大化(Max-Pooling)、平均化(Mean-Pooling)、随机(Stochastic-Pooling)…等,以Max-pooling为例,说明如下

上图示例刚好为偶数,若输入图像尺寸为奇数像素,则可采用周围补零或舍弃边的方式来处理。不过最常用的Pooling kernel size是2×2,Stride为2,这个设定可缩小一半尺寸并减少75%,可以看出池化层减少了图素的参数数量,却保留了所有重要的特征信息,对于CNN的运行效率提高不少

 

最后来看看Full connected layer

 

Full connected layer指的就是一般的神经网络。前面提到的卷积和池化层,其最主要的目的分别是提取特征及减少图像参数,然后将特征信息丢到Full connected layer来进行分类,其神经元只与上一层kernel的像素连结,而且各连结的权重在同层中是相同且共享的,然而Full connected layer的每个神经元与上层神经元之间彼此相连接,各个连结都有其独立且相异的权重值,这个现象造成Full connected layer会耗用相当多的运算资源。例如有个图像其尺寸是1000×1000,那幺在第一层就会有100万个像素维度(1000×1000),到了下一层隐藏层,将会有一万亿个带有不同权重的连结(即100万的平方),因此Full connected layer的运算成本(Memory 、CPU或GPU)相较于卷积与池化相当昂贵,这是在设计网络架构时必须考虑的,如下方图形所示,左侧的Full connected layer每个神经元的连结数是右侧Convolution layer的好几倍。

了解了CNN的基本概念之后,我们来学习如何将其应用至恶意评论识别。

 

本次实验的数据集来自Movie Review Data。数据集中包含1000条正面情感的评论和1000条负面情感的评论。该数据集被广泛应用于文本分类特别是恶意评论识别方面。该数据集第一次公开是在Bo Pang and Lillian Lee, A Sentimental Education: Sentiment Analysis Using Subjectivity Summarization Based on Minimum Cuts, Proceedings of ACL 2004.

 

将数据下载后打开

neg表示负面的评论,pos表示正面的评论;待会儿我们在代码中打标记时,可以令正面评价为0,负面评价为1

 

进入pos文件夹

打开任一txt

可以看到每条评论都被保存成一个单独的文本文件。那幺我们待会儿就需要使用词袋模型对文本进行向量化处理。

 

接下来看看代码

 

下面的两个函数分别用于遍历读取文件夹下全部文件,及读取文件并把每个文件转换成字符串(直接将每一行拼接起来)

加载后打标签

正面打0,负面打1

 

进行数据预处理,使用pad_sequence填充序列,将多个序列截断或补齐为相同长度;使用to_categorical,to_categorical就是将类别向量转换为二进制(只有0和1)的矩阵类型表示,其中nb_classes=2指定总类别数为2

搭建RNN

这里我们的conv选用的是conv_1d,即表示使用1维卷积层,激活函数使用relu,使用L2正则化.通过merge合并张量函数,通过expand_dims增加维度,这是因为存在有embeding层,去掉的话为了保证conv1d正常工作,需要加上expand_dims.通过global_max_pool实现全局最大池化.为了避免过拟合,我们还需要dropout。之后就是全连接层,以及回归,这里需要指定梯度下降优化器,代码中指定为adam。

 

最后就是训练并进行测试

tflearn.DNN是TFLearn中提供的一个模型wrapper,相当于我们将很多功能包装起来,我们给它一个net结构,生成一个model对象,然后调用model对象的训练、预测、存储等功能在fit()函数中epoch=20表示会跑20个epoch,batch_size=32表示一次用32个数据计算参数的更新。

 

测试如下

 

Python3 movie-review.py

训练起来比较费时间,上面的截图是第二个epoch还没跑完,此时准确率为47%,多跑几个epoch相对来说会有一定提升,大家可以自己继续训练下去。

 

参考:

 

1.https://chtseng.wordpress.com/2017/09/12/%E5%88%9D%E6%8E%A2%E5%8D%B7%E7%A9%8D%E7%A5%9E%E7%B6%93%E7%B6%B2%E8%B7%AF/

 

2.http://www.cs.cornell.edu/people/pabo/movie-review-data/

 

3.《机器学习之web安全》

 

4.https://github.com/duoergun0729/1book/

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注