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

我正在看这里关于tf.nn.conv2d的tensorflow的文档。 但是我不明白它做了什么或试图达到什么目的。 它在文档上说,

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

[filter_height * filter_width * in_channels, output_channels]

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

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

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

#3:对于每个修补程序,右乘filtermatrix和图像修补程序向量。

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

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

我尝试了这样的事情:

 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) 

我了解卷积neural network的一些零件。 我在这里研究他们。 但是张量stream的实现并不是我所期望的。 所以它提出了这个问题。

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

 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]]]] 

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


你的例子是1个图像,大小为2×2,带有1个通道。 您有1个filter,大小为1×1,1个通道(大小为高x宽x通道xfilter数量)。

对于这种简单情况,生成的2×2,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') 

这里的3×3图像和1×1滤镜都有5个通道。 得到的图像将是3×3的1通道(尺寸1x3x3x1),其中每个像素的值是滤波器通道与input图像中相应像素的点积。


现在有一个3×3的filter

 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') 

在这里,我们得到一个1×1的图像,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') 

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

每个输出都是通过将滤波器集中在input图像的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') 

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

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

所以angular落只是4,5元点积的总和。


现在有多个filter。

 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') 

这仍然给出一个5×5的输出图像,但有7个通道(尺寸1x5x5x7)。 每个通道由集合中的一个filter生成。


现在步伐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个频道,但只有3×3(尺寸1x3x3x7)。

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

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

当然,input的第一个维度是图像的数量,因此您可以将其应用于一批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张图像的堆叠(尺寸10×3×3×7)

二维卷积的计算方法与计算一维卷积的方法类似:将内核滑过input,计算单元乘法并将其相加。 但是,而不是你的内核/input是一个数组,在这里他们是matrix。


在最基本的例子中,没有填充和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]它是[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) 

而且相当于我们手工计算的那个。


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

我试图实施conv2d(为我的学习)。 那么我写到:

 def conv(ix, w): # filter shape: [filter_height, filter_width, in_channels, out_channels] # flatten filters filter_height = int(w.shape[0]) filter_width = int(w.shape[1]) in_channels = int(w.shape[2]) out_channels = int(w.shape[3]) ix_height = int(ix.shape[1]) ix_width = int(ix.shape[2]) ix_channels = int(ix.shape[3]) filter_shape = [filter_height, filter_width, in_channels, out_channels] flat_w = tf.reshape(w, [filter_height * filter_width * in_channels, out_channels]) patches = tf.extract_image_patches( ix, ksizes=[1, filter_height, filter_width, 1], strides=[1, 1, 1, 1], rates=[1, 1, 1, 1], padding='SAME' ) patches_reshaped = tf.reshape(patches, [-1, ix_height, ix_width, filter_height * filter_width * ix_channels]) feature_maps = [] for i in range(out_channels): feature_map = tf.reduce_sum(tf.multiply(flat_w[:, i], patches_reshaped), axis=3, keep_dims=True) feature_maps.append(feature_map) features = tf.concat(feature_maps, axis=3) return features 

希望我做得很好。 检查了MNIST,结果非常接近(但是这个实现比较慢)。 我希望这可以帮助你。

只是添加到其他答案,你应该想到的参数

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

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

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

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

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