• 【mmdetection代码解读 3.x版本】FPN层的解读


    1. forward函数

    def forward(self, inputs: Tuple[Tensor]) -> tuple:
    
    • 1

    在这里插入图片描述

    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)
    ]
    
    查输入特征 inputs 的数量是否等于定义的 self.in_channels 中的通道数
    构建特征金字塔网络中的侧边连接
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    在这里插入图片描述

    used_backbone_levels = len(laterals)
    for i in range(used_backbone_levels - 1, 0, -1):
        # In some cases, fixing `scale factor` (e.g. 2) is preferred, but
        #  it cannot co-exist with `size` in `F.interpolate`.
        if 'scale_factor' in self.upsample_cfg:
            # fix runtime error of "+=" inplace operation in PyTorch 1.10
            laterals[i - 1] = laterals[i - 1] + F.interpolate(
                laterals[i], **self.upsample_cfg)
        else:
            prev_shape = laterals[i - 1].shape[2:]
            laterals[i - 1] = laterals[i - 1] + F.interpolate(
                laterals[i], size=prev_shape, **self.upsample_cfg)
    
    取了实际用于 top-down 路径的侧边连接的数量
    循环,从最顶层的侧边连接开始向下构建 top-down 路径:
    	条件判断,检查是否设置了 'scale_factor'
    	根据上一层的尺寸,使用 F.interpolate 对下一层的侧边连接进行上采样,然后将两层的特征相加
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    outs = [
             self.fpn_convs[i](laterals[i]) for i in range(used_backbone_levels)
            ]
    
    通过对输入的侧边连接 laterals 进行卷积操作,生成用于网络输出的特征图 outs
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

     if self.num_outs > len(outs):
         # use max pool to get more levels on top of outputs
         # (e.g., Faster R-CNN, Mask R-CNN)
         if not self.add_extra_convs:
             for i in range(self.num_outs - used_backbone_levels):
                 outs.append(F.max_pool2d(outs[-1], 1, stride=2))
         # add conv layers on top of original feature maps (RetinaNet)
         else:
             if self.add_extra_convs == 'on_input':
                 extra_source = inputs[self.backbone_end_level - 1]
             elif self.add_extra_convs == 'on_lateral':
                 extra_source = laterals[-1]
             elif self.add_extra_convs == 'on_output':
                 extra_source = outs[-1]
             else:
                 raise NotImplementedError
             outs.append(self.fpn_convs[used_backbone_levels](extra_source))
             for i in range(used_backbone_levels + 1, self.num_outs):
                 if self.relu_before_extra_convs:
                     outs.append(self.fpn_convs[i](F.relu(outs[-1])))
                 else:
                     outs.append(self.fpn_convs[i](outs[-1]))
     return tuple(outs)
    
    检查是否需要在 outs 中添加额外的层级,以确保输出的特征图数量达到 self.num_outs
    如果 self.add_extra_convs 参数设置为 False:
    	使用最大池化来生成额外的输出层级,F.max_pool2d 用于对 outs 中的最后一层进行最大池化,将分辨率减半
    如果 self.add_extra_convs 参数设置为其他值:
    	根据 self.add_extra_convs 的设置,选择额外层级的输入来源
    	使用 self.fpn_convs 中的卷积层对额外层级的输入 extra_source 进行处理,生成一个额外的输出层级
    	如果仍然需要更多的输出层级,进行循环操作:
    		检查是否在额外卷积前应用了 ReLU 激活函数,如果是:
    			将 ReLU 激活函数应用于前一个输出层级 的特征图,并使用 self.fpn_convs[i] 中的卷积层进行处理
    		如果没有应用 ReLU:
    			将前一个输出层级 outs[-1] 直接送入 self.fpn_convs[i] 中的卷积层进行处理
    
    • 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

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述


    1.1 self.fpn_convs的构建

    self.lateral_convs = nn.ModuleList()
    self.fpn_convs = nn.ModuleList()
    
    for i in range(self.start_level, self.backbone_end_level):
        l_conv = ConvModule(
            in_channels[i],
            out_channels,
            1,
            conv_cfg=conv_cfg,
            norm_cfg=norm_cfg if not self.no_norm_on_lateral else None,
            act_cfg=act_cfg,
            inplace=False)
        fpn_conv = ConvModule(
            out_channels,
            out_channels,
            3,
            padding=1,
            conv_cfg=conv_cfg,
            norm_cfg=norm_cfg,
            act_cfg=act_cfg,
            inplace=False)
    
        self.lateral_convs.append(l_conv)
        self.fpn_convs.append(fpn_conv)
    
    创建了一个空的 PyTorch 模块列表,用于存储侧边连接的卷积层
    创建了另一个空的 PyTorch 模块列表,用于存储上采样卷积层
    通过循环,对从 self.start_level 到 self.backbone_end_level - 1:
    	l_conv 是一个 1x1 卷积层,用于对输入特征进行降维,将通道数从输入级别的 in_channels[i] 减少到 out_channels
    	fpn_conv 是一个 3x3 卷积层,用于对输入特征进行上采样
    	将侧边连接卷积层 l_conv 添加到 lateral_convs 模块列表中
    	将上采样卷积层 fpn_conv 添加到 fpn_convs 模块列表中
    
    • 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
    extra_levels = num_outs - self.backbone_end_level + self.start_level
    if self.add_extra_convs and extra_levels >= 1:
        for i in range(extra_levels):
            if i == 0 and self.add_extra_convs == 'on_input':
                in_channels = self.in_channels[self.backbone_end_level - 1]
            else:
                in_channels = out_channels
            extra_fpn_conv = ConvModule(
                in_channels,
                out_channels,
                3,
                stride=2,
                padding=1,
                conv_cfg=conv_cfg,
                norm_cfg=norm_cfg,
                act_cfg=act_cfg,
                inplace=False)
            self.fpn_convs.append(extra_fpn_conv)
    
    计算需要添加的额外级别数量
    检查是否需要添加额外级别并且是否有至少一个额外级别要添加:
    	循环遍历要添加的每个额外级别:
    		在第一个额外级别时,检查配置是否要将额外级别卷积添加到输入上:
    			将额外级别卷积添加到输入级别上
    		否则:
    			设置输入通道数等于输出通道数。这是因为额外级别的输入是上一个额外级别的输出
    			extra_fpn_conv 是一个额外级别的卷积层。它是一个 3x3 大小的卷积核,带有 2 的步长,用于将上一个级别的特征图上采样
    		将额外级别的卷积层添加到 fpn_convs 模块列表中
    
    • 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
  • 相关阅读:
    SpringCloud - Spring Cloud Alibaba 之 Seata分布式事务服务;TCC事务模式机制(二十三)
    还在用纸质表进行设备巡检?
    正则化函数表达是什么意思,一般是怎么用的
    zeus平台常见故障及排查方法
    如何做好一道数学题
    “创能源之新、享绿色未来” 数境“三星堆杯”能源装备智能化绿色化创新大赛启动...
    LabVIEW在安装了其它的NI软件之后崩溃了
    工厂是否需要单独的设备管理部门
    LyScript 内存扫描与查壳实现
    白蛋白纳米粒是一种较好的药物载体|白蛋白普萘洛尔人血清白蛋白HSA纳米粒|的帕西瑞肽牛血清白蛋白BSA纳米粒
  • 原文地址:https://blog.csdn.net/weixin_45935290/article/details/133806608