首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >tf.nn.conv2d在tensorflow中做什么?

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

Stack Overflow用户
提问于 2016-01-06 02:51:57
回答 7查看 86.5K关注 0票数 145

我在看tensorflow关于tf.nn.conv2d here的文档。但我不明白它是做什么的,也不明白它试图实现什么。文件上写着,

#1 :将过滤器展平为具有形状的2-D矩阵

[filter_height * filter_width * in_channels, output_channels]

那么这是做什么呢?这是基于元素的乘法,还是仅仅是纯矩阵乘法?我也不能理解文档中提到的另外两点。我把它们写在下面:

2:从输入张量中提取图像块以形成形状的虚拟张量[batch, out_height, out_width, filter_height * filter_width * in_channels].3:对于每个块,右乘滤波器矩阵和图像块向量。

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

我试着编写了一小部分代码,并打印出了操作的形状。不过,我还是不明白。

我尝试了这样的东西:

代码语言:javascript
复制
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)

我了解一些零碎的卷积神经网络。我研究了一下here。但tensorflow上的实现并不是我所期望的。因此,它提出了一个问题。

编辑:所以,我实现了一个简单得多的代码。但我搞不懂到底发生了什么。我的意思是结果是这样的。如果有人能告诉我是什么过程产生了这个输出,那将是非常有帮助的。

代码语言:javascript
复制
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)

输出

代码语言:javascript
复制
input
[[[[ 1.60314465]
   [-0.55022103]]

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

  [[-0.00354624]
   [ 0.41650501]]]]
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2017-05-22 08:59:24

2D卷积的计算方式与计算1D convolution的方式类似:将内核滑动到输入上,计算逐个元素的乘法并求和。但是,这里的内核/输入不是数组,而是矩阵。

在最基本的例子中,没有填充和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]。因此,我们需要以正确的格式提供数据:

代码语言:javascript
复制
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')

然后,使用以下命令计算卷积:

代码语言:javascript
复制
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)

并且将等同于我们手工计算的结果。

为了examples with padding/strides, take a look here

票数 71
EN

Stack Overflow用户

发布于 2016-01-10 03:45:16

好的,我想这大概是最简单的解释方式了。

您的示例是1张图像,大小为2x2,具有1个通道。您有一个大小为1x1的滤镜和一个通道(大小为高度x宽度x通道x滤镜数量)。

对于这个简单的例子,得到的2x2,1通道图像(大小为1x2x2x1,图像数量x高x宽x通道)是滤镜值乘以图像的每个像素的结果。

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

代码语言:javascript
复制
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个通道。生成的图像将是具有1个通道的3x3 (大小为1x3x3x1),其中每个像素的值是滤镜通道与输入图像中相应像素的点积。

现在使用3x3过滤器

代码语言:javascript
复制
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元点积。

现在有一个更大的图像

代码语言:javascript
复制
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表示每个输出像素的滤波器中心。

代码语言:javascript
复制
.....
.xxx.
.xxx.
.xxx.
.....

现在使用“相同”填充:

代码语言:javascript
复制
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个元素点积的和。

现在有了多个过滤器。

代码语言:javascript
复制
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:

代码语言:javascript
复制
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表示输入图像上每个输出像素的滤镜中心。

代码语言:javascript
复制
x.x.x
.....
x.x.x
.....
x.x.x

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

代码语言:javascript
复制
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)

票数 161
EN

Stack Overflow用户

发布于 2017-07-13 19:35:32

为了补充其他答案,您应该考虑

代码语言:javascript
复制
filter = tf.Variable(tf.random_normal([3,3,5,7]))

因为'5‘对应于每个滤波器中的通道数。每个滤镜都是一个3d立方体,深度为5。滤镜深度必须与输入图像的深度相对应。最后一个参数7应该被认为是批处理中过滤器的数量。忘了这是4D吧,想象一下你有一组或一批7个过滤器。您要做的是创建7个具有维度(3,3,5)的筛选多维数据集。

由于卷积变成了逐点乘法,因此在傅立叶域中更容易可视化。对于尺寸为(100,100,3)的输入图像,可以将滤波器尺寸重写为

代码语言:javascript
复制
filter = tf.Variable(tf.random_normal([100,100,3,7]))

为了获得7个输出特征图中的一个,我们只需将滤波器立方体与图像立方体按点相乘,然后将结果在通道/深度维度(此处为3)上求和,折叠为2d (100,100)特征图。对每个过滤器立方体执行此操作,您将获得7个2D特征图。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34619177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档