--neozng1@hnu.edu.cn
笔者已经为nanodet增加了非常详细的注释,代码请戳此仓库:nanodet_detail_notes: detail every detail about nanodet 。
此仓库会跟着文章推送的节奏持续更新!
目录
1. Backbone
作为一个着眼于边缘平台部署,尤其是针对CPU型设备的网络,NanoDet之前自然选择的是使用深度可分离卷积的轻量骨干网络。
这里我们主要介绍默认的Backbone:GhostNet,这是一个由华为提出的轻量骨干网络,关于GhostNet的详解请戳:占位符。此模块提供了预训练权重下载,并将结构封装成了一个类。
ghostnet.py这个文件被放在仓库中的nanodet/model/backbone下。
1.0. _make_divisible()
# _make_divisible()是一个用于取整的函数,确保ghost module的输入输出都可以被组卷积数整除
# 这是因为nn.Conv2d中要求groups参数必须能被输入输出整除,具体请参考深度可分离卷积相关的资料
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
It can be seen here:
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v:
new_v += divisor
return new_v
1.1. SqueezeExcite
class SqueezeExcite(nn.Module):
def __init__(
self,
in_chs,
se_ratio=0.25,
reduced_base_chs=None,
activation="ReLU",
gate_fn=hard_sigmoid,
divisor=4,
**_
):
super(SqueezeExcite, self).__init__()
self.gate_fn = gate_fn
reduced_chs = _make_divisible((reduced_base_chs or in_chs) * se_ratio, divisor)
# channel-wise的全局平均池化
self.avg_pool = nn.AdaptiveAvgPool2d(1)
# 1x1卷积,得到一个维度更小的一维向量
self.conv_reduce = nn.Conv2d(in_chs, reduced_chs, 1, bias=True)
# 送入激活层
self.act1 = act_layers(activation)
# 再加上一个1x1 conv,使得输出长度还原回通道数
self.conv_expand = nn.Conv2d(reduced_chs, in_chs, 1, bias=True)
def forward(self, x):
x_se = self.avg_pool(x)
x_se = self.conv_reduce(x_se)
x_se = self.act1(x_se)
x_se = self.conv_expand(x_se)
# 用刚得到的权重乘以原输入
x = x * self.gate_fn(x_se)

本文详细介绍了NanoDet中使用的GhostNet backbone,涉及make_divisible函数、SqueezeExcite模块、ConvBnAct、GhostModule和GhostBottleneck的设计。通过这些模块,作者展示了如何构建适用于边缘设备的高效网络结构。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



