zoukankan      html  css  js  c++  java
  • 【Tensorflow】tf.nn.atrous_conv2d如何实现空洞卷积?膨胀卷积

    介绍
    关于空洞卷积的理论可以查看以下链接,这里我们不详细讲理论:

    1.Long J, Shelhamer E, Darrell T, et al. Fully convolutional networks for semantic segmentation[C]. Computer Vision and Pattern Recognition, 2015.

    2.Yu, Fisher, and Vladlen Koltun. “Multi-scale context aggregation by dilated convolutions.” arXiv preprint arXiv:1511.07122 (2015).

    3.如何理解空洞卷积(dilated convolution)?

    其实用一句话概括就是,在不用pooling的情况下扩大感受野(pooling层会导致信息损失)

    为了阅读方便再贴一些相关链接:

    【TensorFlow】tf.nn.conv2d是怎样实现卷积的?

    【TensorFlow】tf.nn.conv2d_transpose是怎样实现反卷积的?

    惯例先展示函数:

    tf.nn.atrous_conv2d(value,filters,rate,padding,name=None)
    1
    除去name参数用以指定该操作的name,与方法有关的一共四个参数:

    value:
    指需要做卷积的输入图像,要求是一个4维Tensor,具有[batch, height, width, channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数]

    filters:
    相当于CNN中的卷积核,要求是一个4维Tensor,具有[filter_height, filter_width, channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],同理这里第三维channels,就是参数value的第四维

    rate:
    要求是一个int型的正数,正常的卷积操作应该会有stride(即卷积核的滑动步长),但是空洞卷积是没有stride参数的,这一点尤其要注意。取而代之,它使用了新的rate参数,那么rate参数有什么用呢?它定义为我们在输入图像上卷积时的采样间隔,你可以理解为卷积核当中穿插了(rate-1)数量的“0”,把原来的卷积核插出了很多“洞洞”,这样做卷积时就相当于对原图像的采样间隔变大了。具体怎么插得,可以看后面更加详细的描述。此时我们很容易得出rate=1时,就没有0插入,此时这个函数就变成了普通卷积。

    padding:
    string类型的量,只能是”SAME”,”VALID”其中之一,这个值决定了不同边缘填充方式。

    ok,完了,到这就没有参数了,或许有的小伙伴会问那“stride”参数呢。其实这个函数已经默认了stride=1,也就是滑动步长无法改变,固定为1。

    结果返回一个Tensor,填充方式为“VALID”时,返回[batch,height-2*(filter_width-1),width-2*(filter_height-1),out_channels]的Tensor,填充方式为“SAME”时,返回[batch, height, width, out_channels]的Tensor,这个结果怎么得出来的?先不急,我们通过一段程序形象的演示一下空洞卷积。

    实验
    首先创建一张2通道图

    img = tf.constant(value=[[[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]]]],dtype=tf.float32)
    img = tf.concat(values=[img,img],axis=3)
    1
    2
    然后用一个3*3卷积核去做卷积

    filter = tf.constant(value=1, shape=[3,3,2,5], dtype=tf.float32)
    out_img = tf.nn.atrous_conv2d(value=img, filters=filter, rate=1)
    1
    2
    建立好了img和filter,就可以做卷积了

    out_img = tf.nn.conv2d(input=img, filter=filter, strides=[1,1,1,1], padding='VALID')
    1
    输出5个channel,我们设置rate=1,此时空洞卷积可以看做普通的卷积,分别在SAME和VALID模式下输出如下:

    ok,调整rate=2,继续运行程序

    out_img = tf.nn.atrous_conv2d(value=img, filters=filter, rate=2, padding='SAME')
    1
    查看输出结果

    [[[[ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]
    [ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]]

    [[ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]
    [ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]]

    [[ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]
    [ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]]

    [[ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]
    [ 16. 16. 16. 16. 16.]
    [ 24. 24. 24. 24. 24.]]]]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    这个结果怎么出来的呢?再用一张图


    这里我们看到rate=2时,通过穿插“0”,卷积核由3*3膨胀到了5*5。再看看“VALID”模式下,会发生什么?

    直接报错了。因为卷积核的大小已经超过了原图大小

    好了,看到这里相信大家对于空洞卷积有了基本的了解了。那么,填充方式为“VALID”时,返回[batch,height-2*(filter_width-1),width-2*(filter_height-1),out_channels]的Tensor,这个结果,相信大家就可以证明了。

    代码清单
    import tensorflow as tf


    img = tf.constant(value=[[[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]]]],dtype=tf.float32)
    img = tf.concat(values=[img,img],axis=3)
    filter = tf.constant(value=1, shape=[3,3,2,5], dtype=tf.float32)
    out_img1 = tf.nn.atrous_conv2d(value=img, filters=filter, rate=1, padding='SAME')
    out_img2 = tf.nn.atrous_conv2d(value=img, filters=filter, rate=1, padding='VALID')
    out_img3 = tf.nn.atrous_conv2d(value=img, filters=filter, rate=2, padding='SAME')

    #error
    #out_img4 = tf.nn.atrous_conv2d(value=img, filters=filter, rate=2, padding='VALID')

    with tf.Session() as sess:
    print 'rate=1, SAME mode result:'
    print(sess.run(out_img1))

    print 'rate=1, VALID mode result:'
    print(sess.run(out_img2))

    print 'rate=2, SAME mode result:'
    print(sess.run(out_img3))

    # error
    #print 'rate=2, VALID mode result:'
    #print(sess.run(out_img4))
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    TensorFlow实现卷积、反卷积和空洞卷积
    阅读数 1532

    TensorFlow实现卷积、反卷积和空洞卷积TensorFlow已经实现了卷积(tf.nn.conv2d卷积函数),反卷积(tf.nn.conv2d_transpose反卷积函数)以及空洞卷积(tf...
    博文
    来自: pan_jinquan的博客


    wsdgh: Nice, but `height - [filter_width + (filter_width - 1) * (rate - 1)] + 1` make more sense, when `padding=VALID`.
    import tensorflow as tf
    import numpy as np

    kernel_height = 3
    kernel_width = kernel_height

    img_height = 9
    img_width = img_height
    rate = 2
    padding = 'VALID'
    sz_same = img_height
    sz_valid = img_height - ((kernel_height - 1)*(rate - 1) + kernel_height) + 1

    img = np.random.randn(1, img_height, img_width, 3)
    kernel = np.random.randn(kernel_height, kernel_width, 3, 1)

    imgT = tf.constant(img)
    kernelT = tf.constant(kernel)

    imgO1 = tf.nn.atrous_conv2d(imgT, kernel, rate=rate, padding=padding)
    print(imgO1.shape)
    print(sz_same if padding.upper() == 'SAME' else sz_valid)
    # (1, 5, 5, 1)
    # 5

    ---------------------
    作者:xf__mao
    来源:CSDN
    原文:https://blog.csdn.net/mao_xiao_feng/article/details/78003730
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    php js表单登陆验证
    jQuery Ajax 简单的实现跨域请求
    常见http代码错误原因及处理
    使用git做服务器端代码的部署
    mysql之消息队列
    MySQL触发器使用详解
    mysql之触发器before和after的区别
    mysql之触发器trigger
    手把手教你使用Git
    xcode: {} 花括号缩进一个空格
  • 原文地址:https://www.cnblogs.com/jfdwd/p/11184384.html
Copyright © 2011-2022 走看看