反卷积

转载:https://blog.csdn.net/sinat_29957455/article/details/85558870

反卷积


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

上图中的反卷积的stride为2,通过间隔插入padding来实现的。同样,可以根据反卷积的o、s、k、p o、s、k、po、s、k、p参数来计算反卷积的输出i ii,也就是卷积的输入。公式如下:i=(o−1)∗s+k−2∗p i=(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),其中i ii表示输入矩阵的大小,s表示卷积核的步长,ceil函数表示向上取整。下图展示是一个padding为SAME的卷积,卷积开始的时候保证卷积核的中心位于输入矩阵角的顶点位置。

padding为VALID时:ceil((i−k+1)/s) ceil((i-k+1)/s)ceil((i−k+1)/s),k kk表示卷积核的尺寸。下图展示的是一个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)=2 ceil((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的填充。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值