• 目标检测Neck:FPN(Feature Pyramid Network)与PAN(附python代码)


    FPN和PAN都是用于解决在目标检测中特征金字塔网络(FPN)在多尺度检测任务上的不足的方法。下面分别详细介绍一下它们的原理和区别。

    0. 前言

    目标检测器的构成
    在这里插入图片描述

    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(v1、v2、v3),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

    1. FPN

    FPN全称Feature Pyramid Network,是由FAIR在2017年提出的一种处理多尺度问题的方法。FPN的主要思路是通过构建金字塔式的特征图来提取不同尺度下的目标特征,进而提高检测精度。

    在这里插入图片描述

    FPN的构建方式是从高分辨率的特征图开始向下采样,同时从低分辨率的特征图开始向上采样,将它们连接起来形成金字塔。在这个过程中,每一层特征图的信息都会与上下相邻层的特征图融合,这样可以使得高层特征图中的目标信息得以保留,同时低层特征图中的背景信息也可以被高层特征图所补充。经过这样的处理,FPN可以提高模型在多尺度检测任务上的精度,同时还可以在不影响检测速度的情况下提高检测速度。

    import collections
    import numpy as np
    
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    from torch.nn import init
    
    from core.config import cfg
    import utils.net as net_utils
    import modeling.ResNet as ResNet
    from modeling.generate_anchors import generate_anchors
    from modeling.generate_proposals import GenerateProposalsOp
    from modeling.collect_and_distribute_fpn_rpn_proposals import CollectAndDistributeFpnRpnProposalsOp
    import nn as mynn
    
    # Lowest and highest pyramid levels in the backbone network. For FPN, we assume
    # that all networks have 5 spatial reductions, each by a factor of 2. Level 1
    # would correspond to the input image, hence it does not make sense to use it.
    LOWEST_BACKBONE_LVL = 2   # E.g., "conv2"-like level
    HIGHEST_BACKBONE_LVL = 5  # E.g., "conv5"-like level
    
    
    # ---------------------------------------------------------------------------- #
    # FPN with ResNet
    # ---------------------------------------------------------------------------- #
    
    def fpn_ResNet50_conv5_body():
        return fpn(
            ResNet.ResNet50_conv5_body, fpn_level_info_ResNet50_conv5()
        )
    
    def fpn_ResNet50_conv5_body_bup():
        return fpn(
            ResNet.ResNet50_conv5_body, fpn_level_info_ResNet50_conv5(),
            panet_buttomup=True
        )
    
    
    def fpn_ResNet50_conv5_P2only_body():
        return fpn(
            ResNet.ResNet50_conv5_body,
            fpn_level_info_ResNet50_conv5(),
            P2only=True
        )
    
    
    def fpn_ResNet101_conv5_body():
        return fpn(
            ResNet.ResNet101_conv5_body, fpn_level_info_ResNet101_conv5()
        )
    
    
    def fpn_ResNet101_conv5_P2only_body():
        return fpn(
            ResNet.ResNet101_conv5_body,
            fpn_level_info_ResNet101_conv5(),
            P2only=True
        )
    
    
    def fpn_ResNet152_conv5_body():
        return fpn(
            ResNet.ResNet152_conv5_body, fpn_level_info_ResNet152_conv5()
        )
    
    
    def fpn_ResNet152_conv5_P2only_body():
        return fpn(
            ResNet.ResNet152_conv5_body,
            fpn_level_info_ResNet152_conv5(),
            P2only=True
        )
    
    
    # ---------------------------------------------------------------------------- #
    # Functions for bolting FPN onto a backbone architectures
    # ---------------------------------------------------------------------------- #
    class fpn(nn.Module):
        """Add FPN connections based on the model described in the FPN paper.
    
        fpn_output_blobs is in reversed order: e.g [fpn5, fpn4, fpn3, fpn2]
        similarly for fpn_level_info.dims: e.g [2048, 1024, 512, 256]
        similarly for spatial_scale: e.g [1/32, 1/16, 1/8, 1/4]
        """
        def __init__(self, conv_body_func, fpn_level_info, P2only=False, panet_buttomup=False):
            super().__init__()
            self.fpn_level_info = fpn_level_info
            self.P2only = P2only
            self.panet_buttomup = panet_buttomup
    
            self.dim_out = fpn_dim = cfg.FPN.DIM
            min_level, max_level = get_min_max_levels()
            self.num_backbone_stages = len(fpn_level_info.blobs) - (min_level - LOWEST_BACKBONE_LVL)
            fpn_dim_lateral = fpn_level_info.dims
            self.spatial_scale = []  # a list of scales for FPN outputs
    
            #
            # Step 1: recursively build down starting from the coarsest backbone level
            #
            # For the coarest backbone level: 1x1 conv only seeds recursion
            self.conv_top = nn.Conv2d(fpn_dim_lateral[0], fpn_dim, 1, 1, 0)
            if cfg.FPN.USE_GN:
                self.conv_top = nn.Sequential(
                    nn.Conv2d(fpn_dim_lateral[0], fpn_dim, 1, 1, 0, bias=False),
                    nn.GroupNorm(net_utils.get_group_gn(fpn_dim), fpn_dim,
                                 eps=cfg.GROUP_NORM.EPSILON)
                )
            else:
                self.conv_top = nn.Conv2d(fpn_dim_lateral[0], fpn_dim, 1, 1, 0)
            self.topdown_lateral_modules = nn.ModuleList()
            self.posthoc_modules = nn.ModuleList()
    
            # For other levels add top-down and lateral connections
            for i in range(self.num_backbone_stages - 1):
                self.topdown_lateral_modules.append(
                    topdown_lateral_module(fpn_dim, fpn_dim_lateral[i+1])
                )
    
            # Post-hoc scale-specific 3x3 convs
            for i in range(self.num_backbone_stages):
                if cfg.FPN.USE_GN:
                    self.posthoc_modules.append(nn.Sequential(
                        nn.Conv2d(fpn_dim, fpn_dim, 3, 1, 1, bias=False),
                        nn.GroupNorm(net_utils.get_group_gn(fpn_dim), fpn_dim,
                                     eps=cfg.GROUP_NORM.EPSILON)
                    ))
                else:
                    self.posthoc_modules.append(
                        nn.Conv2d(fpn_dim, fpn_dim, 3, 1, 1)
                    )
    
                self.spatial_scale.append(fpn_level_info.spatial_scales[i])
    
            # 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
  • 相关阅读:
    php实战案例记录(10)单引号和双引号的用法和区别
    干货 | Elasticsearch Java 客户端演进历史和选型指南
    Ps:选择主体
    软件测试报告模板(完整版)
    基于黏菌算法优化概率神经网络PNN的分类预测 - 附代码
    上架即封神!3.6k Star 的开源游戏模拟器,Delta 冲上 App Store 免费榜
    记录Linux系统中vim同时开多个窗口编辑文件
    如何使用SQL对数据进行分析和可视化
    Python、机器学习和量化开发环境
    【精讲】Es6 导入 import, 导出 export等多种操作
  • 原文地址:https://blog.csdn.net/JishuFengyang/article/details/133033659