前言

卷积反卷积在CNN中经常被用到,想要彻底搞懂并不是那么容易。本文主要分三个部分来讲解卷积和反卷积,分别包括概念工作过程代码示例,其中代码实践部分主结合TensorFlow框架来进行实践。给大家介绍一个卷积过程的可视化工具,这个项目是github上面的一个开源项目。

卷积和反卷积

卷积(Convolutional):卷积在图像处理领域被广泛的应用,像滤波边缘检测图片锐化等,都是通过不同的卷积核来实现的。在卷积神经网络中通过卷积操作可以提取图片中的特征,低层的卷积层可以提取到图片的一些边缘线条等特征,高层的卷积能够从低层的卷积层中学到更复杂的特征,从而实现到图片的分类和识别。
反卷积:反卷积也被称为转置卷积,反卷积其实就是卷积的逆过程。大家可能对于反卷积的认识有一个误区,以为通过反卷积就可以获取到经过卷积之前的图片,实际上通过反卷积操作并不能还原出卷积之前的图片,只能还原出卷积之前图片的尺寸。那么到底反卷积有什么作用呢?通过反卷积可以用来可视化卷积的过程,反卷积在GAN等领域中有着大量的应用。

工作过程

卷积


上图展示了一个卷积的过程,其中蓝色的图片(4*4)表示的是进行卷积的图片,阴影的图片(3*3)表示的是卷积核,绿色的图片(2*2)表示是进行卷积计算之后的图片。在卷积操作中有几个比较重要的参数,输入图片的尺寸、步长、卷积核的大小、输出图片的尺寸、填充大小
下面用一个图来详细介绍这些参数:

输入图片的尺寸:上图中的蓝色图片(55),表示的是需要进行卷积操作的图片,在后面的公式中有iii来表示输入图片的尺寸。
卷积核的大小:上图中的会移动阴影图片表示的是卷积核(4
4),通过不同参数不同大小的卷积核可以提取到图片的不同特征,后面用kkk表示卷积核的尺寸。
步长:是指卷积核移动的长度,通过上图可以发现卷积核水平方向移动的步长和垂直方向移动的步长是一样的都是1,后面用sss表示步长。
填充大小:是指在输入图片周围填充的圈数,通常都是用0来进行填充的,上图中蓝色图片周围两圈虚线的矩形表示的是填充的值,所以填充掉是2,后面用ppp来表示填充大小。
输出图片的尺寸:经过卷积操作之后获取到的图片的大小,上图的绿色图片(6*6),后面用o来表示。
如果已知i、k、p、si、k、p、si、k、p、s,可以求得ooo,计算公式如下:
o=i−k+2∗ps+1o=\frac{i-k+2*p}{s}+1 o=si−k+2∗p​+1

反卷积

上图展示一个反卷积的工作过程,乍看一下好像反卷积和卷积的工作过程差不多,主要的区别在于反卷积输出图片的尺寸会大于输入图片的尺寸,通过增加padding来实现这一操作,上图展示的是一个strides(步长)为1的反卷积。下面看一个strides不为1的反卷积

上图中的反卷积的stride为2,通过间隔插入padding来实现的。同样,可以根据反卷积的o、s、k、po、s、k、po、s、k、p参数来计算反卷积的输出iii,也就是卷积的输入。公式如下:i=(o−1)∗s+k−2∗pi=(o-1)*s+k-2*pi=(o−1)∗s+k−2∗p,其实就是根据上式推导出来的。

代码示例

为了便于大家理解卷积和反卷积工作过程,将会使用图示的方式来展示卷积和反卷积的工作过程,并利用tensorflow的卷积和反卷积函数来进行验证。

卷积

使用tensorflow来实现卷积的时候,主要利用tf.nn.conv2d函数来实现的,先介绍一下函数的参数
功能说明:通过4维的input和filter来计算2维卷积

  • input:4维的tensor,需要进行卷积的矩阵
  • filter:4维的tensor,卷积核的参数,需要和input具有相同的数据类型,[filter_height,filter_width,in_channels,out_channels],其中filter_height表示卷积核的高,filter_width表示卷积核的宽,in_channels表示需要进行卷积图片的通道数,out_channels卷积之后输出的通道数
  • strides:int类型的列表,设置卷积核滑动的步长
  • padding:填充类型有"SAME"和"VALID"两种模式,当步长为1时,padding为"SAME"可以保持输出与输入的尺寸具有相同的大小。
  • use_cudnn_on_gpu:使用cudnn来加速卷积,默认是True
  • data_format:输入数据的格式,有"NHWC"和"NCHW"两种模式,默认使用的是"NHWC",表示[batch,height,width,channels],"NCHW"数据格式[batch,channels,height,width]
  • dilations:一维的list,默认是[1,1,1,1],用来设置卷积核的扩展
  • name:操作的名称

TensorFlow提供的卷积函数padding只有"SAME""VALID"两种模式,所以输出矩阵的尺寸大小与之前的公式有所不同,下面介绍这两种模式下输出矩阵尺寸的计算公式:
padding为SAME时:ceil(i/s)ceil(i/s)ceil(i/s),其中iii表示输入矩阵的大小,s表示卷积核的步长,ceil函数表示向上取整。下图展示是一个padding为SAME的卷积,卷积开始的时候保证卷积核的中心位于输入矩阵角的顶点位置

padding为VALID时:ceil((i−k+1)/s)ceil((i-k+1)/s)ceil((i−k+1)/s),kkk表示卷积核的尺寸。下图展示的是一个padding为VALID的卷积过程,卷积核始终都是位于输入矩阵内进行移动

    x1 = tf.constant(1.0, shape=[1,4,4,3])x2 = tf.constant(1.0,shape=[1,6,6,3])kernel = tf.constant(1.0,shape=[3,3,3,1])y1_1 = tf.nn.conv2d(x1,kernel,strides=[1,2,2,1],padding="SAME")y1_2 = tf.nn.conv2d(x1,kernel,strides=[1,2,2,1],padding="VALID")y2_1 = tf.nn.conv2d(x2,kernel,strides=[1,2,2,1],padding="SAME")y2_2 = tf.nn.conv2d(x2,kernel,strides=[1,2,2,1],padding="VALID")sess = tf.InteractiveSession()tf.global_variables_initializer()x1,y1_1,y1_2,x2,y2_1,y2_2 = sess.run([x1,y1_1,y1_2,x2,y2_1,y2_2])print(x1.shape)         #(1, 4, 4, 3)print(y1_1.shape)       #(1, 2, 2, 1)print(y1_2.shape)       #(1, 1, 1, 1)print(x2.shape)         #(1, 6, 6, 3)print(y2_1.shape)       #(1, 3, 3, 1)print(y2_2.shape)       #(1, 2, 2, 1)

下面看一个卷积的计算例子

    x1 = tf.constant([i*0.1 for i in range(16)],shape=[1,4,4,1],dtype=tf.float32)kernel = tf.ones(shape=[3,3,1,1],dtype=tf.float32)conv1 = tf.nn.conv2d(x1,kernel,strides=[1,1,1,1],padding="VALID")sess = tf.InteractiveSession()tf.global_variables_initializer()conv1 = sess.run(conv1)print(conv1)



将卷积核与输入矩阵对应的位置进行乘加计算即可,对于多维输入矩阵和多维卷积核的卷积计算,将卷积后的结果进行堆叠,作为最终卷积的输出结果。

反卷积

tensorflow提供了tf.nn.conv2d_transpose函数来计算反卷积
功能说明:计算反卷积(转置卷积)

  • value:4维的tensor,float类型,需要进行反卷积的矩阵
  • filter:卷积核,参数格式[height,width,output_channels,in_channels],这里需要注意output_channels和in_channels的顺序
  • output_shape:一维的Tensor,设置反卷积输出矩阵的shape
  • strides:反卷积的步长
  • padding:"SAME"和"VALID"两种模式
  • data_format:和之前卷积参数一样
  • name:操作的名称
if __name__ == "__main__":x1 = tf.constant([4.5,5.4,8.1,9.0],shape=[1,2,2,1],dtype=tf.float32)dev_con1 = tf.ones(shape=[3,3,1,1],dtype=tf.float32)y1 = tf.nn.conv2d_transpose(x1,dev_con1,output_shape=[1,4,4,1],strides=[1,1,1,1],padding="VALID")sess = tf.InteractiveSession()tf.global_variables_initializer()y1,x1 = sess.run([y1,x1])print(y1)print(x1)


需要注意的是,通过反卷积并不能还原卷积之前的矩阵,只能从大小上进行还原,反卷积的本质还是卷积,只是在进行卷积之前,会进行一个自动的padding补0,从而使得输出的矩阵与指定输出矩阵的shape相同。框架本身,会根据你设定的反卷积值来计算输入矩阵的尺寸,如果shape不符合,则会报错。
错误提示:InvalidArgumentError (see above for traceback): Conv2DSlowBackpropInput,这时候需要检查反卷积的参数与输入矩阵之间的shape是否符合。计算规则可以根据padding为SAME还是VALID来计算输入和输出矩阵的shape是否相符合。如上例中,根据反卷积的参数来计算输入矩阵的shape:因为padding是VALID模式,所以我们套用ceil((i−k+1)/s)=ceil((4−3+1)/1)=2ceil((i-k+1)/s)=ceil((4-3+1)/1)=2ceil((i−k+1)/s)=ceil((4−3+1)/1)=2,而输入矩阵x1的shape刚好是2*2,所以符合。
上面介绍的反卷积的stride是1,接下来看一个stride不为1的例子

    x1 = tf.constant([4.5,5.4,8.1,9.0],shape=[1,2,2,1],dtype=tf.float32)dev_con1 = tf.ones(shape=[3,3,1,1],dtype=tf.float32)y1 = tf.nn.conv2d_transpose(x1,dev_con1,output_shape=[1,6,6,1],strides=[1,2,2,1],padding="VALID")sess = tf.InteractiveSession()tf.global_variables_initializer()y1,x1 = sess.run([y1,x1])print(x1)print(y1)


需要注意的是,在进行反卷积的时候设置的stride并不是指反卷积在进行卷积时候卷积核的移动步长,而是被卷积矩阵填充的padding,仔细观察红色框内可以发现之前输入矩阵之间有一行和一列0的填充

彻底搞懂CNN中的卷积和反卷积相关推荐

  1. cnn stride and padding_彻底搞懂CNN中的卷积和反卷积

    前言 卷积和反卷积在CNN中经常被用到,想要彻底搞懂并不是那么容易.本文主要分三个部分来讲解卷积和反卷积,分别包括概念.工作过程.代码示例,其中代码实践部分主结合TensorFlow框架来进行实践.给 ...

  2. 彻底搞懂 JS 中 this 机制

    彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 this 是什么 this 的四种绑定规 ...

  3. 15个示例让你搞懂Linux中的cd命令

    15个示例让你搞懂Linux中的cd命令 在Linux中,cd(更改目录)命令是新手和系统管理员最重要且使用最广泛的命令之一.对于没有头绪的管理员来说,cd是导航到其他目录以检查日志,执行程序/应用程 ...

  4. java 自旋锁_搞懂Java中的自旋锁

    轻松搞懂Java中的自旋锁 前言 在之前的文章<一文彻底搞懂面试中常问的各种"锁">中介绍了Java中的各种"锁",可能对于不是很了解这些概念的同学 ...

  5. 分分搞懂c#中的委托

    分分搞懂c#中的委托: 不说废话,不来虚的概念,不管代码是否有意义,看我的优化之路,你会理解委托了: 源代码1 public class test{//我们不管代码是否有意义,我们直接看代码重构和一步 ...

  6. 一文搞懂Qt中的颜色渐变(QGradient Class)

    一文搞懂Qt中的颜色渐变(QGradient Class) 1, 快速开始! Qt中与颜色渐变有关的类是QGradient 其中它又有三个子类:QLinearGradient.QRadialGradi ...

  7. 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    帮你彻底搞懂JS中的prototype.__proto__与constructor(图解) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文 ...

  8. 这一篇彻底搞懂JS中的prototype、__proto__与constructor真的很好

    文章目录 1. 前言 2. _ _ proto _ _ 属性 3. prototype属性 4. constructor属性 5. 总结 提示:不要排斥,静下心来,认真读完,你就搞懂了!(可以先看一下 ...

  9. (转)帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    文章目录 1. 前言 2. _ _ proto _ _ 属性 3. prototype属性 4. constructor属性 5. 总结 提示:不要排斥,静下心来,认真读完,你就搞懂了!(可以先看一下 ...

  10. 彻底搞懂javascript中的replace函数

    javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...

最新文章

  1. cannot be found on object of type xx.CacheExpressionRootObject
  2. java 远程修改linux服务器文件_linux服务器之间复制文件
  3. python关键词大全_Python 批量获取Baidu关键词的排名并入库
  4. CentOS7 如何关闭防火墙
  5. 【Java】Java对象序列化I/O体系总结
  6. CentOS配置本地YUM源
  7. 【响应式编程的思维艺术】 (4)从打飞机游戏理解并发与流的融合
  8. 【Siddhi】Siddhi 入门案例
  9. Linux IO控制命令生成
  10. Android之WindowManager+OpenGL+EGL绘制(十七)
  11. hdu4906:3-idiots【FFT】
  12. [环境搭建]-Web Api搭建到IIS服务器后PUT请求返回HTTP Error 405.0 - Method Not Allowed 解决方法
  13. MMKV_Android数据持久化方案调研-MMKV SP REALM ROOM WCDB...
  14. 计算机统计分析spss试卷,《SPSS计算机统计分析方法》习题A卷.doc
  15. android屏幕尺寸像素详解
  16. 内存数据库fastdb的使用研究报告
  17. MIPI 打怪升级之DSI篇
  18. Codeforces 1010D Mars rover
  19. odoo11在win10环境搭建
  20. 算法入门刷题笔记 Day2 K - Coat of Anticubism L - Five-In-a-Row M - Island Puzzl......

热门文章

  1. 6 errors and 0 warnings potentially fixable with the`--fix` option
  2. 80psi等于多少kpa_PSI和KPa如何转换
  3. 2021边缘保研经历(整个大三),川大 - 浙大软院
  4. windows 2003 directx 3D加速 开启
  5. 如何禁用Citrix Receiver硬件加速功能
  6. Python列表解析式
  7. Hello December
  8. 音视频编辑软件哪个好
  9. C# 清除cookies
  10. 九、springboot+ idea + gradle使用jib打docker镜像