作者 | Erez Posner
来源 | Medium
编辑 | 代码医生团队
早在三月份,就开放了实施“具有池化或跨越层的CNN的快速密集特征提取”,虽然未广为人知,但2017年BMVC发表的论文提供了一种高效优雅的解决方案,可以避免在使用时避免计算冗余基于补丁的卷积神经网络。因此在这篇文章中,将解释该模型的工作原理,并展示如何在实际应用程序中使用它。
将介绍两件事:第一,概述了名为“具有池化或跨越层的CNN的快速密集特征提取”的方法。其次,如何在现有训练有素的补丁网络上使用此方法来加快推理时间。
什么是基于补丁的方法?有什么问题?
基于补丁的CNN通常应用于图像的单个补丁,其中每个补丁被单独分类。当尝试在图像中相邻的重叠补丁上多次执行相同的CNN时,通常会使用此方法。这包括基于任务的特征提取,如相机校准,补丁匹配,光流估计和立体匹配。此外基于补丁的应用程序不被视为特征提取,如滑动窗口对象检测或识别。
在所有这种基于补丁的任务中,在相邻CNN的计算之间可能存在大量冗余。例如下图:
在左侧,可以看到简单的1维CNN。从底部开始,每个像素仅对输出层中的一个结果起作用而没有任何冗余。相反在右边,如果这个CNN在一个图像以创建特征中的每个像素位置执行时,许多中间层的结果网络无故之间共享。
节点中的数字表示节点共享的频率。红色连接显示红色节点的共享方式。以步幅2汇集输出分辨率。因此需要两个池化层:原始层(蓝色)和一个移动一个像素(绿色)以避免输出分辨率减半。
快速密集特征提取
这种方法的主要思想是,不是为图像中的每个补丁分别执行基于补丁的CNN Cp(对训练补丁P进行训练),让在输入中的所有补丁P(x,y)上有效地执行它。
为了保持一致性,定义具有宽度Iw和高度Ih的输入图像I,可以定义具有宽度Pw的补丁P(x,y)和以每个像素位置(x,y)为中心的高度Ph ,x∈0 ...输入图像I中的Iw -1,y∈0... Ih -1 。输出向量O(x,y)= CP(P(x,y))是属于(Ih,Iw,k)维输出矩阵O的k通道向量,其包含在所有图像块上执行的Cp的结果P(x,y)。
为此可以创建一个直接从I计算O的网络CI,同时避免在每个图像补丁上独立执行Cp时发生的冗余。Cp和CI之间的架构差异如下图所示。此处,要素提取器中的所有池化层都将替换为多池层
Cp(左)和CI(右)的架构
值得一提的是,CI将给出与在图像I的每个补丁上独立执行网络Cp相同的结果。但是CI运行速度要快得多,因为它避免了重叠补丁之间的冗余。
当处理层的类型时从Cp到CI的必要步骤:主要是普通层(没有汇集或跨越)和异常层(包括池或跨越)。
1.普通图层
没有跨步或汇集,Cp和CI的层是相同的,即
这是因为它们的输出不依赖于输入的空间位置,而只取决于输入值本身。
2.异常层(包括汇集或跨越)
与普通层相比,必须明确处理跨步和合并层。下图显示了汇集的主要问题:第一个补丁P(x,y)需要与第二个补丁P(x + 1,y)(绿色)不同的2 x 2汇集(蓝色),因此不能共享汇集输出。
但是补丁P(x + 2,y)可以再次使用原始池(蓝色)。P(x,y)和P(x + 2,y)的重叠位置提供相同的结果,因此可以共享(亮黄色)。
这个例子的概括是s 是池/步幅大小,u和v是整数,P(x,y)和P(x + su,y + sv)补丁仍然共享由共享的像素的汇集输出两个补丁。
在不同的图像位置(红色)修补P. 使用蓝色的补丁和使用绿色池的补丁之间的共享是不可能的
这将创建所有一起S×S具有不同的池的情况下独立于所述输入来计算“我们的池层,其中的I”是用于输入图像1-第i层。由于s×s汇聚层将输出大小减小到Iw / s ,Ih / s(输入大小为Iw ,Ih),很明显需要s×s这样的输出来获得空间大小Iw的输出O,Ih。
不同池输出被堆叠在一个额外的输出尺寸记为中号。记录为通道的所有不同池化输出现在将被后续层视为独立样本(类似于批量维度)。
上面的动画给出了关于如何完成过程的更好的直觉,每个通道最终执行池化以在M 中堆叠。
3.没有变形
使用一个多池层,得到一个输出W,其尺寸为W =(M = s×s,Ih / s,Iw / s,k),要将其取消到最终输出O =(Ih,Iw, k)。未扭曲程序背后的直觉在下图中可视化,用于2×2汇集。在这里,所有的渠道应该得到交织在一起,产生最终的输出Ø。
在左边, 2×2 = 4输出图像来自2×2多次充电,右边是最终的非扭曲输出O.
直接不变形是复杂的,特别是有几个池层。这可能是以前的工作避免汇集图层的原因。但是,如果观察尺寸空间中的问题,只需转置和重塑操作就可以轻松解决。大多数深度学习框架都支持这些操作作为层。
实验
作者提出了基准测试结果,比较了改进的网络CI和在图像的所有补丁上运行的基于补丁的CNN Cp。实验在GeForce GTX TITAN X上进行。
从下表中可以看出,Cp的执行时间与图像像素大致成比例(如预期)。另一方面,CI几乎不需要更多时间来拍摄更大的图像。另一方面,CI的内存消耗几乎呈线性增长。如果没有足够的可用内存,则可以将输入图像拆分为多个部分,并且可以单独处理每个部分。
检查加速列清楚地表明CI执行速度更快,尤其是在较大的图像上。
CI和 Cp的速度基准
加速基于补丁的CNN
在这里将解释如何使用“具有池化或跨越层的CNN快速密集特征提取”的实现来加速任何基于补丁的CNN。
项目结构很简单,有两个实现:pytorch和tensforflow,每个包含以下内容:
1.实施改进的网络 -CI
为了使用自己的预先训练的网络,需要执行补丁:
self.conv1 = list(base_net.modules())[change_this_index]
2.在改进的网络上运行示例代码
现在应该sample_code.py确保项目正常工作。该测试生成一个大小的随机输入图像I,imH X imW并在Cp和CI上对其进行评估。
该脚本继续并评估CNN输出之间的差异并执行速度基准测试。Cp有两种操作模式
可能的参数 - sample_code.py有可以调整的初始参数,如图像高度,图像宽度,贴片宽度,贴片高度等...
3.应该期待看到什么?
脚本输出以下内容:
预期的详细信息应如下所示:
Total time for C_P: 0.017114248275756836 sec
------------------------------------------------------------
Averaged time for C_I per Patch without warm up: 0.0010887398617342114 sec
------- Comparison between a base_net over all patches output and slim_net -------
aggregated difference percentage = 0.0000000000 %
maximal abs difference = 0.0000000000 at index i=0,j=0
------------------------------------------------------------
已经大大提升了网络。就在这个例子中,将运行时间提高了~10。
结论
源代码GitHub存储库。
https://github.com/erezposner/Fast_Dense_Feature_Extraction