目标检测 - Neck的设计 PAN(Path Aggregation Network)

目标检测 - Neck的设计 PAN(Path Aggregation Network)

flyfish

目标检测器的构成

在这里插入图片描述

1. Input:Image,Patches,ImagePyramid

2. Backbones:VGG16,ResNet(ResNet-18、ResNet-34、ResNet-50、ResNet-101、ResNet-152),SpineNet,EfficientNet-B0/B7,CSPResNeXt50,CSPDarknet53,MobileNet(v1v2v3),ShuffleNet(v1、v2) ,GhostNet

3. Neck
  Additional blocks:SPP,ASPP,RFB,SAM
  Path-aggregation blocks:FPN,PAN,NAS-FPN,Fully-connectedFPN,BiFPN,ASFF,SFAM

4. Heads
  Dense Prediction(one-stage)
    RPN,SSD,YOLO,RetinaNet(anchorbased)
    CornerNet,CenterNet,MatrixNet,FCOS(FCOSv1、FCOSv2),ATSS,PAA(anchorfree)
  SparsePrediction(two-stage)
    FasterR-CNN,R-FCN,MaskR-CNN(anchorbased)
    RepPoints(anchorfree)

Neck部分的设计是多种多样的

在这里插入图片描述
(a) FPN
(b) PANet
(c) NAS-FPN
(d) BiFPN

其中PANet就是本文说的
这里说明Neck-》Path-aggregation blocks-》PAN(Path Aggregation Network)
论文作者实现的代码
https://github.com/ShuLiu1993/PANet
在这里插入图片描述

看图
(a) FPN backbone
(b) Bottom-up path augmentation
(c) Adaptive feature pooling
(d) Box branch
(e) Fully-connected fusion
p5 -> p2是从上向下(Top-down),N2 -> N5是(Bottom-up)
原作者把backbone与FPN合并称为FPN backbone。而在实际写代码中,从上向下和从下向上这两条路径合并称为FAN
如下图
在这里插入图片描述
如何是轻量级模型则会只留下几层例如
在这里插入图片描述

PAN简单理解就是FPN多了一条Bottom-up path augmentation
FPN是从上向下,PAN包含了从上向下和从下向上的路径。

原版

PAN的原作者作者也是按照上图写代码将新增的模块直接加入到FPN代码中,区分是否使用GroupNorm
PANet/lib/modeling/FPN.py

# add for panet buttom-up path
if self.panet_buttomup:
    self.panet_buttomup_conv1_modules = nn.ModuleList()
    self.panet_buttomup_conv2_modules = nn.ModuleList()
    for i in range(self.num_backbone_stages - 1):
        if cfg.FPN.USE_GN:
            self.panet_buttomup_conv1_modules.append(nn.Sequential(
                nn.Conv2d(fpn_dim, fpn_dim, 3, 2, 1, bias=True),
                nn.GroupNorm(net_utils.get_group_gn(fpn_dim), fpn_dim,
                            eps=cfg.GROUP_NORM.EPSILON),
                nn.ReLU(inplace=True)
            ))
            self.panet_buttomup_conv2_modules.append(nn.Sequential(
                nn.Conv2d(fpn_dim, fpn_dim, 3, 1, 1, bias=True),
                nn.GroupNorm(net_utils.get_group_gn(fpn_dim), fpn_dim,
                            eps=cfg.GROUP_NORM.EPSILON),
                nn.ReLU(inplace=True)
            ))
        else:
            self.panet_buttomup_conv1_modules.append(
                nn.Conv2d(fpn_dim, fpn_dim, 3, 2, 1)
            )
            self.panet_buttomup_conv2_modules.append(
                nn.Conv2d(fpn_dim, fpn_dim, 3, 1, 1)
            )

torch.cat例子

>>> x = torch.randn(2, 3)
>>> x
tensor([[ 0.6580, -1.0969, -0.4614],
        [-0.1034, -0.5790,  0.1497]])
>>> torch.cat((x, x, x), 0)
tensor([[ 0.6580, -1.0969, -0.4614],
        [-0.1034, -0.5790,  0.1497],
        [ 0.6580, -1.0969, -0.4614],
        [-0.1034, -0.5790,  0.1497],
        [ 0.6580, -1.0969, -0.4614],
        [-0.1034, -0.5790,  0.1497]])
>>> torch.cat((x, x, x), 1)
tensor([[ 0.6580, -1.0969, -0.4614,  0.6580, -1.0969, -0.4614,  0.6580,
         -1.0969, -0.4614],
        [-0.1034, -0.5790,  0.1497, -0.1034, -0.5790,  0.1497, -0.1034,
         -0.5790,  0.1497]])

mmdetection中yolo_neck版本

mmdetection中的yolo_neck是采样之后带cat运算
路径是mmdetection/mmdet/models/necks

def forward(self, feats):
    assert len(feats) == self.num_scales

    # processed from bottom (high-lvl) to top (low-lvl)
    outs = []
    out = self.detect1(feats[-1])
    outs.append(out)

    for i, x in enumerate(reversed(feats[:-1])):
        conv = getattr(self, f'conv{i+1}')
        tmp = conv(out)

        # Cat with low-lvl feats
        tmp = F.interpolate(tmp, scale_factor=2)
        tmp = torch.cat((tmp, x), 1)

        detect = getattr(self, f'detect{i+2}')
        out = detect(tmp)
        outs.append(out)

    return tuple(outs)

nanodet版本

nanodet的作者的PAN没有卷积,使用interpolate进行上采样和下采样。按照top-down和bottom-up做的加法运算

def forward(self, inputs):
    """Forward function."""
    assert len(inputs) == len(self.in_channels)

    # build laterals
    laterals = [
        lateral_conv(inputs[i + self.start_level])
        for i, lateral_conv in enumerate(self.lateral_convs)
    ]

    # build top-down path
    used_backbone_levels = len(laterals)
    for i in range(used_backbone_levels - 1, 0, -1):
        prev_shape = laterals[i - 1].shape[2:]
        laterals[i - 1] += F.interpolate(
            laterals[i], size=prev_shape, mode='bilinear')

    # build outputs
    # part 1: from original levels
    inter_outs = [
        laterals[i] for i in range(used_backbone_levels)
    ]

    # part 2: add bottom-up path
    for i in range(0, used_backbone_levels - 1):
        prev_shape = inter_outs[i + 1].shape[2:]
        inter_outs[i + 1] += F.interpolate(inter_outs[i], size=prev_shape, mode='bilinear')

    outs = []
    outs.append(inter_outs[0])
    outs.extend([
        inter_outs[i] for i in range(1, used_backbone_levels)
    ])
    return tuple(outs)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西笑生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值