卷积神经网络CNN原理及实践

本文详细介绍了卷积神经网络(CNN)的基本概念及其在图像处理领域的应用。内容涵盖CNN的结构组成,如卷积层、池化层等,以及它们如何提取图像特征并进行分类。还介绍了使用TensorFlow实现CNN的具体方法。

卷积神经网络CNN

卷积神经网络(Convolutional Neural Network,CNN)是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。 它包括输入层,隐藏层,输出层,其中,隐藏层有包括卷积层(alternating convolutional layer)和池层(pooling layer)。卷积层用于提取特征,池化层也就是下采样,常见的有max_pooling和average_pooling.

CNN有三个特性

  1. 稀疏链接
  2. 参数共享 :
  3. 平移不变性

卷积层(convolutional layer)

自然图像有其固有特性,也就是说,图像的一部分的统计特性与其他部分是一样的。这也意味着我们在这一部分学习的特征也能用在另一部分上,所以对于这个图像上的所有位置,我们都能使用同样的学习特征。

更恰当的解释是,当从一个大尺寸图像中随机选取一小块,比如说 8x8 作为样本,并且从这个小块样本中学习到了一些特征,这时我们可以把从这个 8x8 样本中学习到的特征作为探测器,应用到这个图像的任意地方中去。特别是,我们可以用从 8x8 样本中所学习到的特征跟原本的大尺寸图像作卷积,从而对这个大尺寸图像上的任一位置获得一个不同特征的激活值。

在tensorflow中,tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)可以方便的实现卷积操作,其具体用法如下:

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, name=None)

除去name参数用以指定该操作的name,与方法有关的一共五个参数
第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一
第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维
第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4
第四个参数padding:string类型的量,只能是”SAME”,”VALID”其中之一,这个值决定了不同的卷积方式(后面会介绍)
第五个参数:use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true
结果返回一个Tensor,这个输出,就是我们常说的feature map
返回值: shape = [batch,out_high,out_width,out_channels]

用一个简单的例子来说明该函数的用法:
import tensorflow as tf

input = tf.Variable(tf.random_normal([1,5,5,5]))   
filter = tf.Variable(tf.random_normal([2,2,5,6]))                                                
op = tf.nn.conv2d(input, filter, strides=[1,2,2,1], padding="SAME")

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(op)
    print res.shape
>>>(1, 3, 3, 6)

在上面这个例子中,有一张[5*5*5]的输入,使用了6个[2*2]的卷积核去做卷积,至于参数strides可以理解为strides=[1,x_step,y_step,1]. x_step即每次向x轴方向的步长,y_step表示每次向y轴方向的步长。参数padding 可以为”SAME”,表示卷积核可以停留在图像边缘,缺失的地方用0代替,或者”VALID”表示卷积核只能在图像内部

import tensorflow as tf

input = tf.Variable(tf.random_normal([1,5,5,5]))   
filter = tf.Variable(tf.random_normal([2,2,5,6]))  

op = tf.nn.conv2d(input, filter, strides=[1,2,2,1], padding="VALID")

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    res = sess.run(op)
    print res.shape
>>>(1, 2, 2, 6)

同样的,有一张[5*5*5]的输入,使用了6个[2*2]的卷积核去做卷积,参数padding = “VALID”即卷积核在图像内部运动,从结果上看,输出结果形状的高度和宽度都变小了。

池化层(Pooling)

在通过卷积获得了特征 (features) 之后,下一步我们希望利用这些特征去做分类。理论上讲,人们可以用所有提取得到的特征去训练分类器,例如 softmax 分类器,但这样做面临计算量的挑战。
为了解决这个问题,首先回忆一下,我们之所以决定使用卷积后的特征是因为图像具有一种“静态性”的属性,这也就意味着在一个图像区域有用的特征极有可能在另一个区域同样适用。因此,为了描述大的图像,一个很自然的想法就是对不同位置的特征进行聚合统计,例如,人们可以计算图像一个区域上的某个特定特征的平均值 (或最大值)。这些概要统计特征不仅具有低得多的维度 (相比使用所有提取得到的特征),同时还会改善结果(不容易过拟合)。这种聚合的操作就叫做池化 (pooling),有时也称为平均池化或者最大池化 (取决于计算池化的方法)。
池化的平移不变性:如果人们选择图像中的连续范围作为池化区域,并且只是池化相同(重复)的隐藏单元产生的特征,那么,这些池化单元就具有平移不变性 (translation invariant)。这就意味着即使图像经历了一个小的平移之后,依然会产生相同的 (池化的) 特征
tensorflow自带的函数可以很方便的实现池化操作

tf.nn.max_pool(value, ksize, strides, padding, data_format=’NHWC’, name=None)

参数是四个,和卷积很类似:
第一个参数value:需要池化的输入,一般池化层接在卷积层后面,所以####输入通常是feature map,依然是[batch, height, width, channels]这样的shape
第二个参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1
第三个参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, x_step,y_step, 1]
第四个参数padding:和卷积类似,可以取’VALID’ 或者’SAME’
返回一个Tensor,类型不变,shape仍然是[batch, height, width, channels]这种形式

假设有这样一张图,双通道
第一个通道:
这里写图片描述
第二个通道:
这里写图片描述
用程序去做最大值池化:

import tensorflow as tf

image = tf.constant([
                    [[1.0,2.0,3.0,4.0],
                     [5.0,6.0,7.0,8.0],
                     [8.0,7.0,6.0,5.0],
                     [4.0,3.0,2.0,1.0]],
                    [[4.0,3.0,2.0,1.0],
                     [8.0,7.0,6.0,5.0],
                     [1.0,2.0,3.0,4.0],
                     [5.0,6.0,7.0,8.0]]
])

image = tf.reshape(image,[1,4,4,2])

pooling = tf.nn.max_pool(image, ksize=[1,2,2,1],strides=[1,1,1,1],padding="VALID")

with tf.Session() as sess:
    sess.run(pooling)
    print pooling.eval()
>>>[[[[ 8.  7.]
   [ 6.  6.]
   [ 7.  8.]]

  [[ 8.  7.]
   [ 8.  7.]
   [ 8.  7.]]

  [[ 4.  4.]
   [ 8.  7.]
   [ 8.  8.]]]]

最大值池化pooling之后的结果为
这里写图片描述
这里写图片描述

最后,对于使用CNN处理图像的一般流程是:

image –> Convolution –> Pooling –>Convolution –>Pooling –> Fully Connected –> Fully Connected –>Classifier

一个完整的CNN例子见:
https://github.com/Johnson0722/Tensorflow_demos/blob/master/simple_CNN.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值