池化和卷积操作在输入张量上滑动一个“窗口”。以tf.nn.conv2d
为例:如果输入张量有四个维度:[batch, height, width, channels]
,那么卷积在height, width
维度上的二维窗口上运算。
strides
决定了窗口在每个维度上移动的距离。一般用法将第一个(批次)和最后一个(深度)步长设置为1。
我们来看一个非常具体的例子:对一个 32x32 的灰度输入图像进行 2D 卷积运算。这里使用灰度图是因为它的深度等于 1,这使得问题简单化。假设该图像长这样:
00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...
让我们在单个示例上运行一个2x2的卷积窗口(批量大小=1)。我们将给卷积一个8的输出通道深度。
卷积的输入具有shape=[1, 32, 32, 1]
。
如果您使用strides=[1,1,1,1]
和padding=SAME
指定,则滤波器的输出将为[1, 32, 32, 8]。
滤波器将首先为以下内容创建输出:
F(00 01
10 11)
然后是:
F(01 02
11 12)
等等。然后它将移动到第二行,计算:
F(10, 11
20, 21)
然后
F(11, 12
21, 22)
如果您指定步长为[1, 2, 2, 1],它将不会使用重叠的窗口。它将计算:F(00, 01
10, 11)
然后
F(02, 03
12, 13)
对于池化操作,步幅的操作方式类似。
问题2:为什么卷积神经网络使用步幅 [1,x,y,1]?
第一个1表示批处理大小:通常不希望跳过批处理中的示例,否则就不应该在第一次包含它们。 :)
最后一个1是卷积的深度:出于相同的原因,通常不希望跳过输入。
Conv2d运算符更加通用,因此您可以创建沿其他维度滑动窗口的卷积,但这不是卷积神经网络的典型用途。 典型用途是在空间上使用它们。
为什么要重塑成-1 -1是一个占位符,表示“根据需要调整以匹配完整张量所需的大小”。 这是使代码独立于输入批处理大小的一种方法,因此可以更改管道而不必在代码的各个位置调整批处理大小。