首发:AIWalker
1567737711899
本文是英特尔中国投于ICCV2019的一篇关于Backbone的论文。MobileNet,一种在精度与效率方面具有顶级性能的CNN架构,已被广泛应用于诸多资源受限的视觉应用中。作者提出一种新颖的架构单元HBO用于提升轻量型(少于40MFlops层面) MobileNet的性能。
不用于已有瓶颈层设计方案(探索组卷积特征通道间信息的依赖型),HBO通过联合跨空间与通道维编码特征依赖型改进瓶颈层的表达能力同时保留相似的复杂度。它包含两个相互成分:空间维度的收缩扩张与通道围堵的扩张收缩。这两个蒸饺维度上互依赖变换组合提升的所提模块的表达能力与泛化能力,保证了有限资源下的性能提升。
通过采用HBO替换MobileNetV2中的瓶颈层构建了HBONet,在ImageNet分类(+6.6%)、VOC目标检测(+6.3%)、以及Market-1501行人重识别(+5.0%)等任务上验证了所提方法的性能。
Abstract
有鉴于现有轻量型网络(含MobileNet系列、ShuffleNet系列)在不高于40MFLOPs时的低性能,作者基于MobileNetV2设计一种新颖的瓶颈层以提升其性能。
ShuffleNet、MobileNet主要是从特征通道间变换角度入手,而忽视了探索其其正交维(空间维)。作者从通道维与空间维两个层面设计一种新颖的瓶颈层HBO以提升其表达能力。在每个HBO模块内,空间维收缩用于降低输入尺度,后接通道扩张收缩补偿空间维降低的副作用,最后街上空间维扩张以保证输出具有原始输入相同的空间分辨率。
总而言之,该文主要有以下几点贡献:
- 提出一种新颖的瓶颈层模块HBO;
- 采用HBO替换MobileNetV2中的瓶颈层构建HBONet取得了性能的极大提升(不高于40MFLOPs维度);
- 所提HBONet在300MFLOPs层面超过了其他轻量型架构,取得了73.1%的分类精度。
Methond
1567740154933
上图给出了作者所提HBO的架构图。按照处理流程,简单分析如下:
- 空间维收缩操作采用了stride=s的深度卷积/下采样以降低空间分辨率;
- 空间维扩张操作采用了stride=s的转置卷积/上采样以提升空间分辨率;
- 通道维扩张操作采用了PWConv以提升通道维度;
- 通道收缩采用了采用了PWConv以降低通道维度。
下图给出了采用HBO构建的模块,整体网络架构如与MobileNetV2类似,这里不再展示。
Experiments
作者在多个应用领域验证了所提方法的有效性,这里仅列出ImageNet分类领域的对比分析。在训练过程中,采用SGD优化器,动量因子为0.9,wd=4e-5,batchSize=256,学习率0.05以Consine形式下降到接近0.下图给出了HBONet与MobileNetV2以及其他SOTA轻量型网络的的性能对比。
Conclusion
作者提出一种紧致的瓶颈层HBO以提升轻量型网络(比如不高于40MFLOPs)的性能。HBO以双边对称架构同时考虑空间维与通道维的信息依赖关系。最后作者在分类、检测以及行人重识别等应用中验证了所提模块的优异性能。
参考代码
# 这里仅列出HBO的核心代码,更详细见作者代码。
class HBO(nn.Module):
def __init__(self, inc, outc, ratio):
super().__init__()
sc = [nn.Conv2d(inc,inc,5,2,2,groups=inc,bias=False),
nn.BatchNorm2d(inc)]
ce = [nn.Conv2d(inc,inc*ratio, 1, 1, bias=False),
nn.BatchNorm2d(inc*ratio),
nn.ReLU6()]
dw = [nn.Conv2d(inc*ratio,inc*ratio,3,1,1,
groups=inc*ratio, bias=False),
nn.BatchNorm2d(inc*ratio)]
cc = [nn.Conv2d(inc*ratio,outc//2,1,1,bias=False),
nn.BatchNorm2d(outc//2)]
se = [nn.Upsample(scale_factor=2)]
fu = [nn.Conv2d(outc//2, outc//2,5,1,2,goups=outc//2,
bias=False),
nn.BatchNorm2d(out//2)]
self.sc = nn.Sequential(*sc)
self.se = nn.Sequential(*se)
self.ce = nn.Sequential(*ce)
self.cc = nn.Sequential(*cc)
self.dw = nn.Sequential(*dw)
self.fu = nn.Sequential(*fu)
def forward(self, x):
res = self.se(self.cc(self.dw(self.ce(self.sc(x)))))
right = self.fu(res + x[:,:(outc//2),:,:])
left = x[:,-(outc-outc//2):,:,:]
return torch.cat([left, right], dim=1)
推荐阅读:
本文章著作权归作者所有,任何形式的转载都请注明出处。更多动态滤波,图像质量,超分辨相关请关注我的专栏深度学习从入门到精通。