这就提供了一个思路:为了用一个相等的卷积层替换一个全连接层,只要将过滤器的尺寸设置成层输入的尺寸,并使用数量与全连接层中的神经元数量相同的过滤器。我们会在 Alexnet(fc6)的第一个全连接层中展示这个过程:相关层的 DIGITS 可视化见图 8。你能见到 fc6 从 pool5 中接收了它的输入,同时输入的形状是一个 256-channel 6×6 的图像。此外,fc6 上的激活是一个长度为 4096 的向量,这意味着 fc6 有 4096 个输出神经元。也就是说,如果我想用一个相等卷积层替换 fc6,我要做的就是将这个过滤器的大小设为 6×6,将输出特征图的数量设置为 4096。一个小小的题外话,你认为这一层有多少个可训练的参数?对于每个过滤器,感受野中每个数字都有一个偏项(bias term)加上一个权重。这个感受野的深度为 256,大小为 6×6,因此每一个过滤器都有 256×6×6+1=9217 个参数。因为有 4096 个过滤器,所以这一层的参数总数为 37752832。那正是 DIGITS 认为 fc6 会有的参数数量。 在实际中,取代该层很简单。如果你使用 Caffe,只需要用表 1 右边的定义取代左边的定义就行。
表 1:左:fc6 定义,右:对等的带有大小为 6 的核函数的 conv6,因为向 fc6 输入的是 6×6 的图像块。 了解了这些之后,你可以继续将所有的完全连接层转换成相应的卷积层。注意,不要用 DIGITS 计算这些层的输入的形状;你可以手动计算。听上去很有趣,但我保证要在 VGG-16 中做完所有的 16 层你会失去耐心,而且还没有暂存器来暂存记录。此外,作为一个深度学习爱好者,你应该适应让机器来为你干活。所以,就让 DIGITS 帮你做这些吧。 由此产生的 FCN 有与基础卷积神经网络数量相同的可学习的参数以及相同的表现和计算复杂性。由于输入相同,输出也就相同。你或许会惊讶:为什么这么麻烦滴转换模型?好吧,「卷积化」基础 CNN 引进了大量的灵活性。模型不再被限制在一个固定的输入尺寸(Alexnet 中是 224×224 个像素)上运行。它能像滑动 window 一样扫描整个输入来处理更大的图像,并且无需为整个输入单独输出一个概率分布,而是每 224×224 个 window 生成一个概率分布。网络输出的是一个带有 KxHxW 形状的张量,其中 K 是类别的数量,H 是垂直轴上滑动 window 的数量,W 是水平轴上滑动 window 的数量。 关于计算效率的一个提示:理论上你可以通过重复选择图像块并将它们馈送到 CNN 进行处理来实现 sliding window。但在实际中,计算效率会非常低:在你递增移动 window 时,只有一小部分新像素可被发现。如今,每个图像块都需要完全被 CNN 处理,即使在相邻图像块之间有很大的重叠。因此你可能要多次处理每个像素。在 FCN 中,因为这些计算都在网络内发生,只有小量的运算需要执行,因此处理速度有了量级增加。 总而言之,这给我们带来了新的里程碑:为分类网络增加了两个空间维度。在下一章节中,我讲演示如何进一步精调模型。 图像分割 FCN 在前面的章节中展示了如何设计一个预测每个 window 的一个类概率分布的 FCN。明显的是,在扫描输入图像时,window 的数量由输入图像的大小、window 的大小和 window 之间使用的 step 的大小所决定。理想上,一个图像分割模型将为图像中的每个像素产生一个概率分布。但在实际中如何做到这些?这里我会再次利用来自 FCN 论文的一个方法。 当输入图像连续穿过「卷积的」Alexnet 的各个层时,输入中的像素数据被有效的压缩为一系列粗糙的、更高层次的特征表征。在图像分割中,这么做的目的是插入这些粗糙特征来为输入中的每个像素重建出好的分类。事实证明使用解卷积(deconvolutional)层能很好的做到这些。这些层进行与卷积相反的逆运算:给定卷积输出和 filter 定义的情况下,一个解卷积层能够发现会生成这种输出的输入数据。记住在处理输入时,卷积层(或池化层)中的 stride 决定了 window 滑动的距离,因此它也是输出如何下采样的一种测量。相反,在解卷积层中的 stride 是输出如何上采样的一种度量。把 stride 选择为 4,输出就更大了 4 倍! 下一个问题是:在模型中,我如何决定上采样多少最后卷积层的激活函数,从而获得与输入图像同样大小的输出?我需要检查每一层,并谨慎的记下它的换算系数(scaling factor)。一旦我检查了所有层,只需要把所有换算系数相乘就行。让我们看一下 Alexnet 中的第一个卷积层: (责任编辑:本港台直播) |