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。 假设你的input
和kernel
是:
当你的内核,你会收到以下输出: ,其计算方式如下:
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