在深度学习的图像识别领域中,我们经常使用卷积神经网络CNN来对图像进行特征提取,当我们使用TensorFlow搭建自己的CNN时,一般会使用TensorFlow中的卷积函数和池化函数来对图像进行卷积和池化操作,而这两种函数中都存在参数padding,该参数的设置很容易引起错误,所以在此总结下。

1.为什么要使用padding

在弄懂padding规则前得先了解拥有padding参数的函数,在TensorFlow中,主要使用tf.nn.conv2d()进行(二维数据)卷积操作,tf.nn.max_pool()、tf.nn.avg_pool来分别实现最大池化和平均池化,通过查阅官方文档我们知道其需要的参数如下:

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None,name=None)
tf.nn.max_pool_with_argmax(input, ksize, strides, padding, Targmax=None, name=None)
tf.nn.max_pool(value, ksize, strides, padding, name=None)

这三个函数中都含有padding参数,我们在使用它们的时候需要传入所需的值,padding的值为字符串,可选值为'SAME' 和 'VALID' ;

padding参数的作用是决定在进行卷积或池化操作时,是否对输入的图像矩阵边缘补0,'SAME' 为补零,'VALID' 则不补,其原因是因为在这些操作过程中过滤器可能不能将某个方向上的数据刚好处理完,如下所示:

当步长为5,卷积核尺寸为6×6时,当padding为VALID时,则可能造成数据丢失(如左图),当padding为SAME时,则对其进行补零(如右图),

2. padding公式

首先,定义变量:

输入图片的宽和高:i_w 和 i_h

输出特征图的宽和高:o_w 和 o_h

过滤器的宽和高:f_w 和 f_h

宽和高方向的步长:s_w 和 s_h

宽和高方向总的补零个数:pad_w 和 pad_h

顶部和底部的补零个数:pad_top 和 pad_bottom

左部和右部的补零个数:pad_left 和 pad_right

1.VALID模式

输出的宽和高为

o_w = (i_w - f_w + 1)/ s_w #(结果向上取整)
o_h = (i_h - f_h + 1)/ s_h #(结果向上取整)

2. SAME模式

输出的宽和高为

o_w = i_w / s_w#(结果向上取整)
o_h = i_h / s_h#(结果向上取整)

各个方向的补零个数为:max()为取较大值,

pad_h = max(( o_h -1 ) × s_h + f_h - i_h , 0)
pad_top = pad_h / 2 # 注意此处向下取整
pad_bottom = pad_h - pad_top
pad_w = max(( o_w -1 ) × s_w + f_w - i_w , 0)
pad_left = pad_w / 2 # 注意此处向下取整
pad_right = pad_w - pad_left

3.卷积padding的实战分析

接下来我们通过在TensorFlow中使用卷积和池化函数来分析padding参数在实际中的应用,代码如下:

# -*- coding: utf-8 -*-
import tensorflow as tf # 首先,模拟输入一个图像矩阵,大小为5*5
# 输入图像矩阵的shape为[批次大小,图像的高度,图像的宽度,图像的通道数]
input = tf.Variable(tf.constant(1.0, shape=[1, 5, 5, 1])) # 定义卷积核,大小为2*2,输入和输出都是单通道
# 卷积核的shape为[卷积核的高度,卷积核的宽度,图像通道数,卷积核的个数]
filter1 = tf.Variable(tf.constant([-1.0, 0, 0, -1], shape=[2, 2, 1, 1])) # 卷积操作 strides为[批次大小,高度方向的移动步长,宽度方向的移动步长,通道数]
# SAME
op1_conv_same = tf.nn.conv2d(input, filter1, strides=[1,2,2,1],padding='SAME')
# VALID
op2_conv_valid = tf.nn.conv2d(input, filter1, strides=[1,2,2,1],padding='VALID') init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
print("op1_conv_same:\n", sess.run(op1_conv_same))
print("op2_conv_valid:\n", sess.run(op2_conv_valid))

VALID模式的分析:

SAME模式分析:

o_w = i_w  / s_w = 5/2 = 3
o_h = i_h / s_h = 5/2 = 3 pad_w = max ( (o_w - 1 ) × s_w + f_w - i_w , 0 )
= max ( (3 - 1 ) × 2 + 2 - 5 , 0 ) = 1
pad_left = 1 / 2 =0
pad_right = 1 - 0 =0
# 同理
pad_top = 0
pad_bottom = 1

运行代码后的结果如下:

4.池化padding的实战分析

这里主要分析最大池化和平均池化两个函数,函数中padding参数设置和矩阵形状计算都与卷积一样,但需要注意的是:

1. 当padding='SAME',计算avg_pool时,每次的计算是除以图像被filter框出的非零元素的个数,而不是filter元素的个数,如下图,第一行第三列我们计算出的结果是除以2而非4,第三行第三列计算出的结果是除以1而非4;

2. 当计算全局池化时,即与图像矩阵形状相同的过滤器进行一次池化,此情况下无padding,即在边缘没有补0,我们直接除以整个矩阵的元素个数,而不是除以非零元素个数(注意与第一点进行区分)

池化函数的代码示例如下:

# -*- coding: utf-8 -*-
import tensorflow as tf # 首先,模拟输入一个特征图,大小为5*5
# 输入图像矩阵的shape为[批次大小,图像的高度,图像的宽度,图像的通道数]
input = tf.Variable(tf.constant(1.0, shape=[1, 5, 5, 1])) # 最大池化操作 strides为[批次大小,高度方向的移动步长,宽度方向的移动步长,通道数]
# ksize为[1, 池化窗口的高,池化窗口的宽度,1]
# SAME
op1_max_pooling_same = tf.nn.max_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='SAME')
# VALID
op2_max_pooling_valid = tf.nn.max_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='VALID') # 平均池化
op3_avg_pooling_same = tf.nn.avg_pool(input, [1,2,2,1], strides=[1,2,2,1],padding='SAME')
# 全局池化,filter是一个与输入矩阵一样大的过滤器
op4_global_pooling_same = tf.nn.avg_pool(input, [1,5,5,1], strides=[1,5,5,1],padding='SAME') init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
print("op1_max_pooling_same:\n", sess.run(op1_max_pooling_same))
print("op2_max_pooling_valid:\n", sess.run(op2_max_pooling_valid))
print("op3_max_pooling_same:\n", sess.run(op3_avg_pooling_same))
print("op4_global_pooling_same:\n", sess.run(op4_global_pooling_same))

运行结果如下:

 

5.总结

在搭建CNN时,我们输入的图像矩阵在网络中需要经过多层卷积和池化操作,在这个过程中,feature map的形状会不断变化,如果不清楚padding参数引起的这些变化,程序在运行过程中会发生错误,当然在实际写代码时,可以将每一层feature map的形状打印出来,了解每一层Tensor的变化。

转载请注明出处:https://www.cnblogs.com/White-xzx/p/9497029.html

【TensorFlow】一文弄懂CNN中的padding参数的更多相关文章

  1. 一文弄懂神经网络中的反向传播法——BackPropagation【转】

    本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法——BackPropagation   最近在看深度学习 ...

  2. 基于TensorFlow理解CNN中的padding参数

    1 TensorFlow中用到padding的地方 在TensorFlow中用到padding的地方主要有tf.nn.conv2d(),tf.nn.max_pool(),tf.nn.avg_pool( ...

  3. [转] 一文弄懂神经网络中的反向传播法——BackPropagation

    在看CNN和RNN的相关算法TF实现,总感觉有些细枝末节理解不到位,浮在表面.那么就一点点扣细节吧. 这个作者讲方向传播也是没谁了,666- 原文地址:https://www.cnblogs.com/ ...

  4. 一文弄懂神经网络中的反向传播法——BackPropagation

    最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...

  5. 一文弄懂神经网络中的反向传播法(Backpropagation algorithm)

    最近在看深度学习的东西,一开始看的吴恩达的UFLDL教程,有中文版就直接看了,后来发现有些地方总是不是很明确,又去看英文版,然后又找了些资料看,才发现,中文版的译者在翻译的时候会对省略的公式推导过程进 ...

  6. 彻底弄懂AngularJS中的transclusion

    点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...

  7. 一文弄懂-Netty核心功能及线程模型

    目录 一. Netty是什么? 二. Netty 的使用场景 三. Netty通讯示例 1. Netty的maven依赖 2. 服务端代码 3. 客户端代码 四. Netty线程模型 五. Netty ...

  8. 一文弄懂-《Scalable IO In Java》

    目录 一. <Scalable IO In Java> 是什么? 二. IO架构的演变历程 1. Classic Service Designs 经典服务模型 2. Event-drive ...

  9. 一文弄懂-BIO,NIO,AIO

    目录 一文弄懂-BIO,NIO,AIO 1. BIO: 同步阻塞IO模型 2. NIO: 同步非阻塞IO模型(多路复用) 3.Epoll函数详解 4.Redis线程模型 5. AIO: 异步非阻塞IO ...

随机推荐

  1. servlet与tomcat的关系

    1.4   Tomcat简介 学习Servlet技术,首先需要有一个Servlet运行环境,也就是需要有一个Servlet容器,本书采用的是Tomcat. Tomcat是一个免费的开放源代码的Serv ...

  2. python---图表的使用

    一:使用预览 二:插件使用来源 Highcharts(本次使用) ECharts 三:插件的使用 HighCharts的简单上手 (一)后台传递数据 getHchart方法获取用户数据(用户名,数据列 ...

  3. python---堡垒机开发

    一:堡垒机需求分析 注意: 虽然我们在中间使用防火墙服务器对流量进行拦截和转发也可以起到过滤作用,但是我们无法去获取到完整,正确的操作记录.因为无论是客户端还是服务器端(管理员可能会去修改记录,而且可 ...

  4. vuejs2.0 vue实例的生命周期

    每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer).编译模版.挂载实例到 DOM ,然后在数据变化时更新 DOM .下图展示的就是一个v ...

  5. noi题库(noi.openjudge.cn) 1.13编程基础之综合应用 T12 分数求和

    12:分数求和 描述 输入n个分数并对他们求和,并用最简形式表示.所谓最简形式是指:分子分母的最大公约数为1:若最终结果的分母为1,则直接用整数表示. 如:5/6.10/3均是最简形式,而3/6需要化 ...

  6. Python入门系列教程(二)字符串

    字符串 1.字符串输出 name = 'xiaoming' print("姓名:%s"%name) 2.字符串输入 userName = raw_input('请输入用户名:') ...

  7. 视差滚动(Parallax Scrolling)的一点小心得

    下面内容来源于我知乎的这个答案:http://www.zhihu.com/question/20990029/answer/21436067 假期有空,整理到博客园这边,并做了一些语境的调整. ——— ...

  8. Java后台获取前端utf-8格式&nbsp;空格,使用trim()消除不了的解决办法

    byte bytes[] = {(byte) 0xC2,(byte) 0xA0}; String UTFSpace = new String(bytes,"utf-8"); htm ...

  9. 天梯赛 L2-013. (并查集) 红色警报

    题目链接 题目描述 战争中保持各个城市间的连通性非常重要.本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报.注意:若该国本来就不完全连通,是分裂的k个区域 ...

  10. HDU 1074 Doing Homework (dp+状态压缩)

    题目链接 Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot ...