tf.nn.conv2d在tensorflow中做什么?

我在这里查看关于tf.nn.conv2d文档。 但我无法理解它做了什么或试图达到什么目的。 它在文档上说,

#1:将滤波器平坦化为具有形状的2-D矩阵

[filter_height * filter_width * in_channels, output_channels]

那现在做了什么? 那是单元乘法还是纯矩阵乘法? 我也无法理解文档中提到的其他两点。 我在下面写了他们:

#2:从输入张量中提取图像块以形成虚拟的形状张量

[batch, out_height, out_width, filter_height * filter_width * in_channels]

#3:对于每个补丁,右乘过滤器矩阵和图像补丁矢量。

如果任何人都可以给出一个例子,一段代码(非常有帮助),并且解释那里发生了什么,以及为什么操作是这样的,那将会非常有帮助。

我试过编码一小部分并打印出操作的形状。 不过,我不明白。

我尝试了这样的事情:

op = tf.shape(tf.nn.conv2d(tf.random_normal([1,10,10,10]), 
              tf.random_normal([2,10,10,10]), 
              strides=[1, 2, 2, 1], padding='SAME'))

with tf.Session() as sess:
    result = sess.run(op)
    print(result)

我理解卷积神经网络的一些零碎。 我在这里研究他们。 但是张量流的实现并不是我所期望的。 所以它提出了这个问题。

编辑 :所以,我实现了一个简单得多的代码。 但我无法弄清楚发生了什么事。 我的意思是结果如何。 如果有人能告诉我什么过程产生这个输出,那将是非常有帮助的。

input = tf.Variable(tf.random_normal([1,2,2,1]))
filter = tf.Variable(tf.random_normal([1,1,1,1]))

op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
init = tf.initialize_all_variables()
with tf.Session() as sess:
    sess.run(init)

    print("input")
    print(input.eval())
    print("filter")
    print(filter.eval())
    print("result")
    result = sess.run(op)
    print(result)

产量

input
[[[[ 1.60314465]
   [-0.55022103]]

  [[ 0.00595062]
   [-0.69889867]]]]
filter
[[[[-0.59594476]]]]
result
[[[[-0.95538563]
   [ 0.32790133]]

  [[-0.00354624]
   [ 0.41650501]]]]

二维卷积的计算方法与计算一维卷积的方法相似:将内核滑过输入,计算单元乘法并对其进行求和。 但是不是你的内核/输入是一个数组,这里它们是矩阵。


在最基本的例子中,没有填充和stride = 1。 假设你的inputkernel是:

当你的内核,你会收到以下输出: ,其计算方式如下:

  • 14 = 4 * 1 + 3 * 0 + 1 * 1 + 2 * 2 + 1 * 1 + 0 * 0 + 1 * 0 + 2 * 0 + 4 * 1
  • 6 = 3 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 0 * 1 + 1 * 0 + 2 * 0 + 4 * 0 + 1 * 1
  • 6 = 2 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 2 * 1 + 4 * 0 + 3 * 0 + 1 * 0 + 0 * 1
  • 12 = 1 * 1 + 0 * 0 + 1 * 1 + 2 * 2 + 4 * 1 + 1 * 0 + 1 * 0 + 0 * 0 + 2 * 1
  • TF的conv2d函数批量计算卷积并使用稍微不同的格式。 对于输入,它是[batch, in_height, in_width, in_channels]内核,它是[filter_height, filter_width, in_channels, out_channels] 。 所以我们需要以正确的格式提供数据:

    import tensorflow as tf
    k = tf.constant([
        [1, 0, 1],
        [2, 1, 0],
        [0, 0, 1]
    ], dtype=tf.float32, name='k')
    i = tf.constant([
        [4, 3, 1, 0],
        [2, 1, 0, 1],
        [1, 2, 4, 1],
        [3, 1, 0, 2]
    ], dtype=tf.float32, name='i')
    kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
    image  = tf.reshape(i, [1, 4, 4, 1], name='image')
    

    之后,卷积计算如下:

    res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "VALID"))
    # VALID means no padding
    with tf.Session() as sess:
       print sess.run(res)
    

    并且将等于我们手工计算的那个。


    有关填充/跨度的示例,请看看这里。


    好吧,我认为这是解释这一切的最简单方法。


    你的例子是1个图像,大小为2x2,带有1个通道。 您有1个过滤器,大小为1x1,1个通道(大小为高x宽x通道x过滤器数量)。

    对于这种简单情况,生成的2x2,1通道图像(大小为1x2x2x1,图像数量x高x宽xx通道)是将滤镜值与图像的每个像素相乘的结果。


    现在让我们尝试更多渠道:

    input = tf.Variable(tf.random_normal([1,3,3,5]))
    filter = tf.Variable(tf.random_normal([1,1,5,1]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')
    

    这里的3x3图像和1x1滤镜各有5个通道。 得到的图像将是3x3,具有1个通道(大小为1x3x3x1),其中每个像素的值是滤波器通道与输入图像中相应像素的点积。


    现在使用3x3滤镜

    input = tf.Variable(tf.random_normal([1,3,3,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,1]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')
    

    在这里,我们得到一个1x1的图像,1通道(大小1x1x1x1)。 该值是9元素和5元素点积的和。 但是你可以称它为一个45元素的点积。


    现在有了更大的图像

    input = tf.Variable(tf.random_normal([1,5,5,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,1]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID')
    

    输出是3x3 1通道图像(尺寸1x3x3x1)。 这些值中的每一个都是9个5元素点积的和。

    每个输出都是通过将滤波器置于输入图像的9个中心像素中的一个中心上进行的,这样就不会出现任何滤波器。 下面的x s代表每个输出像素的滤波器中心。

    .....
    .xxx.
    .xxx.
    .xxx.
    .....
    

    现在用“SAME”填充:

    input = tf.Variable(tf.random_normal([1,5,5,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,1]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
    

    这提供了一个5x5输出图像(尺寸1x5x5x1)。 这是通过将过滤器置于图像上的每个位置来完成的。

    滤镜伸出图像边缘的任何5元素点产品都会得到零值。

    所以角落只有4,5元点产品的总和。


    现在有多个过滤器。

    input = tf.Variable(tf.random_normal([1,5,5,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,7]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
    

    这仍然提供5x5输出图像,但有7个通道(尺寸为1x5x5x7)。 每个通道由集合中的其中一个过滤器生成。


    现在步伐2,2:

    input = tf.Variable(tf.random_normal([1,5,5,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,7]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')
    

    现在结果仍然有7个频道,但只有3x3(尺寸1x3x3x7)。

    这是因为滤镜不是在图像上的每个点上居中对齐,而是以图像上的每个其他点为中心,采用宽度为2的步长(步幅)。下面的x表示每个输出像素的滤镜中心,在输入图像上。

    x.x.x
    .....
    x.x.x
    .....
    x.x.x
    

    当然,输入的第一个维度是图像的数量,因此您可以将其应用于一批10张图像,例如:

    input = tf.Variable(tf.random_normal([10,5,5,5]))
    filter = tf.Variable(tf.random_normal([3,3,5,7]))
    
    op = tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')
    

    这对每个图像独立执行相同的操作,结果为10张图像(尺寸为10x3x3x7)


    为了增加其他答案,你应该考虑参数

    filter = tf.Variable(tf.random_normal([3,3,5,7]))
    

    作为对应于每个过滤器中的通道数量的“5”。 每个滤镜都是一个3d立方体,深度为5.您的滤镜深度必须与您输入图像的深度相对应。 最后一个参数7应该被认为是批次中的过滤器数量。 忘记这是4D,而是想象你有一套或一批7个过滤器。 你所做的是创建7个尺寸为(3,3,5)的滤镜立方体。

    由于卷积变为逐点乘法,因此在傅里叶域中可视化显得容易得多。 对于尺寸(100,100,3)的输入图像,可以将滤镜尺寸改写为

    filter = tf.Variable(tf.random_normal([100,100,3,7]))
    

    为了获得7个输出特征图中的一个,我们简单地执行滤镜立方体与图像立方体的逐点相乘,然后我们将结果在通道/深度维度上(这里是3)相加,折叠成2d (100,100)功能地图。 对每个滤镜立方体进行此操作,并获得7个2D特征地图。

    链接地址: http://www.djcxy.com/p/32095.html

    上一篇: What does tf.nn.conv2d do in tensorflow?

    下一篇: Storing TensorFlow network weights in Python multi