Tensorflow Conv2D和MaxPool2D原理

原创文章,转载请注明: 转载自慢慢的回味

本文链接地址: Tensorflow Conv2D和MaxPool2D原理

卷积神经网络(CNN)是指在所有网络中,至少优一层使用了卷积运算运算的神经网络,因此命名为卷积神经网络。
那么什么是卷积呢?如果需要卷积一个二位图片,首先定义一个卷积核(kernel),即权重矩阵,它能表面每一次卷积那个方向的值更重要,然后逐步在二维输入数据上“扫描卷积”。当卷积核“滑动”的同时进行卷积:计算权重矩阵和扫描所得的数据矩阵的乘积,求和后得到一个像素输出。
步长(Stride)为每次卷积核移动格数,填充(Padding)为是否对元素数据进行边缘填充。当不填充的时候,即Tensorflow中的VALID选项,卷积后的数据会比输入数据小,而加入合适的填充后,即Tensorflow中的SAME选项,卷积后的数据可以保持和输入数据大小一致。如下图所示:

那么什么是池化呢?池化也称为欠采样或下采样。主要用于特征降维,在保持旋转、平移、伸缩等不变性的前提下,压缩数据和参数的数量,减小过拟合,同时提高模型的容错性。常用的有按均值池化(mean-pooling):更大地保留图像背景信息,按最大值池化(max-pooling):更多的保留纹理信息。如下图所示,池化大大压缩了数据:

原理

以下面的测试程序来讨论Conv2D(卷积)和MaxPool2D(池化)的具体实现原理:
首先定义一个具有1张图,大小为6X6,通道为1个,即输入数据img的shape为[1,6,6,1]。
然后定义过滤器filter,NHWC格式,即批次,高,宽,通道格式,和输入数据是同一个格式。
下图为不同的卷积核对同一图片处理的结果:

测试程序

如下程序和图片示例,一个 3X3 的filter(卷积核的特征是提取图片从左上到右下的特征)在 6X6 的图片上,按照步长 1X1 从左往右,从上往下计算蒙版区域输出结果。
卷积计算:
图例1的卷积计算为:1*1 + 0*-1 + 0*-1 + 0*-1 + 1*1 + 0*-1 + 0*-1 + 0*-1 + 1*1 = 3
图例2的卷积计算为:1*1 + 0*-1 + 0*-1 + 0*-1 + 1*1 + 1*-1 + 0*-1 + 0*-1 + 0*1 = 1


池化计算:
图例3,4,5,6分别取区域内的最大值做池化运算(提取图片的纹理特征而不是背景)。

由此,从原来的 6X6 矩阵变成了 2X2 矩阵。
fitler1是一个filter的情况,输出:

******************** op2 ********************
tf.Tensor(
[[[[3.]
   [0.]]
 
  [[3.]
   [1.]]]], shape=(1, 2, 2, 1), dtype=float32)

filter3是2个filter的情况,输出:

******************** op4 ********************
tf.Tensor(
[[[[ 3. -1.]
   [ 0.  1.]]
 
  [[ 3.  0.]
   [ 1.  3.]]]], shape=(1, 2, 2, 2), dtype=float32)

下面为整个程序代码:

from __future__ import division, print_function, absolute_import
 
import tensorflow as tf
 
img = tf.reshape( [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
                    0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
                    0.0, 0.0, 1.0, 1.0, 0.0, 0.0,
                    1.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                    0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
                    0.0, 0.0, 1.0, 0.0, 1.0, 0.0], [1,6,6,1] )
filter1 = tf.reshape( [  1.0, -1.0, -1.0,
                        -1.0,  1.0, -1.0,
                        -1.0, -1.0,  1.0], [3,3,1,1] )
filter2 = tf.reshape( [ -1.0,  1.0, -1.0,
                        -1.0,  1.0, -1.0,
                        -1.0,  1.0, -1.0], [3,3,1,1] )
print(img)
print(filter1)
print(filter2)
op1 = tf.nn.conv2d(img, filter1, strides=[1, 1, 1, 1], padding='VALID')  
 
print('*' * 20 + ' op1 ' + '*' * 20)
print(op1)
 
op2 = tf.nn.max_pool2d(input=op1, ksize=[2,2], strides=[2,2], padding='VALID')
print('*' * 20 + ' op2 ' + '*' * 20)
print(op2)
 
filter3 = tf.reshape( [  1.0,-1.0,  -1.0,1.0,  -1.0,-1.0,
                        -1.0,-1.0,   1.0,1.0,  -1.0,-1.0,
                        -1.0,-1.0,  -1.0,1.0,   1.0,-1.0], [3,3,1,2] )
op3 = tf.nn.conv2d(img, filter3, strides=[1, 1, 1, 1], padding='VALID')  
 
print('*' * 20 + ' op3 ' + '*' * 20)
print(op3)
 
op4 = tf.nn.max_pool2d(input=op3, ksize=[2,2], strides=[2,2], padding='VALID')
print('*' * 20 + ' op4 ' + '*' * 20)
print(op4)

程序输出为:

tf.Tensor(
[[[[1.]
   [0.]
   [0.]
   [0.]
   [0.]
   [1.]]

  [[0.]
   [1.]
   [0.]
   [0.]
   [1.]
   [0.]]

  [[0.]
   [0.]
   [1.]
   [1.]
   [0.]
   [0.]]

  [[1.]
   [0.]
   [0.]
   [0.]
   [1.]
   [0.]]

  [[0.]
   [1.]
   [0.]
   [0.]
   [1.]
   [0.]]

  [[0.]
   [0.]
   [1.]
   [0.]
   [1.]
   [0.]]]], shape=(1, 6, 6, 1), dtype=float32)
tf.Tensor(
[[[[ 1.]]

  [[-1.]]

  [[-1.]]]


 [[[-1.]]

  [[ 1.]]

  [[-1.]]]


 [[[-1.]]

  [[-1.]]

  [[ 1.]]]], shape=(3, 3, 1, 1), dtype=float32)
tf.Tensor(
[[[[-1.]]

  [[ 1.]]

  [[-1.]]]


 [[[-1.]]

  [[ 1.]]

  [[-1.]]]


 [[[-1.]]

  [[ 1.]]

  [[-1.]]]], shape=(3, 3, 1, 1), dtype=float32)
******************** op1 ********************
tf.Tensor(
[[[[ 3.]
   [-1.]
   [-3.]
   [-1.]]

  [[-3.]
   [ 1.]
   [ 0.]
   [-3.]]

  [[-3.]
   [-3.]
   [ 0.]
   [ 1.]]

  [[ 3.]
   [-2.]
   [-2.]
   [-1.]]]], shape=(1, 4, 4, 1), dtype=float32)
******************** op2 ********************
tf.Tensor(
[[[[3.]
   [0.]]

  [[3.]
   [1.]]]], shape=(1, 2, 2, 1), dtype=float32)
******************** op3 ********************
tf.Tensor(
[[[[ 3. -1.]
   [-1. -1.]
   [-3. -1.]
   [-1. -1.]]

  [[-3. -1.]
   [ 1. -1.]
   [ 0. -2.]
   [-3.  1.]]

  [[-3. -1.]
   [-3. -1.]
   [ 0. -2.]
   [ 1.  1.]]

  [[ 3. -1.]
   [-2.  0.]
   [-2. -4.]
   [-1.  3.]]]], shape=(1, 4, 4, 2), dtype=float32)
******************** op4 ********************
tf.Tensor(
[[[[ 3. -1.]
   [ 0.  1.]]

  [[ 3.  0.]
   [ 1.  3.]]]], shape=(1, 2, 2, 2), dtype=float32)

本作品采用知识共享署名 4.0 国际许可协议进行许可。

发表回复