【实例分割|Detectron2】在主干网络 ResNet50 中添加 SE 注意力模块

本文档介绍了如何在Detectron2中添加SE模块,并展示了在ResNetBlockBase类中实现SELayer的代码。同时,由于Mask2Former使用Detectron2的ResNet,所以在Detectron2中添加SE模块后,Mask2Former也会受到影响。添加SE模块旨在提升模型的特征学习能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 Detectron2 中使用 SE 模块

直接在 detectron2/detectron2/modeling/backbone/resnet.py 中添加 SELayer ,若想自己新建一个文件,重新写模型类,这样 fpn.py 等文件中的 build_resnet_backbone 等函数均要修改,担心自己漏了,所以直接在原文件上添加了。

其中 SENet-Pytorch 的代码参考 https://github.com/moskomule/senet.pytorch/blob/master/senet

__all__ = [
    "SELayer",
    "ResNetBlockBase",
    "BasicBlock",
    "BottleneckBlock",
    "DeformBottleneckBlock",
    "BasicStem",
    "ResNet",
    "make_stage",
    "build_resnet_backbone",
]

class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)
        print(f"shape: {y.shape}")
        y = self.fc(y).view(b, c, 1, 1)
        return x * y.expand_as(x)

class BottleneckBlock(CNNBlockBase):
    """
    The standard bottleneck residual block used by ResNet-50, 101 and 152
    defined in :paper:`ResNet`.  It contains 3 conv layers with kernels
    1x1, 3x3, 1x1, and a projection shortcut if needed.
    """

    def __init__(
        self,
        in_channels,
        out_channels,
        *,
        bottleneck_channels,
        stride=1,
        num_groups=1,
        norm="BN",
        stride_in_1x1=False,
        dilation=1,
    ):
        """
        Args:
            bottleneck_channels (int): number of output channels for the 3x3
                "bottleneck" conv layers.
            num_groups (int): number of groups for the 3x3 conv layer.
            norm (str or callable): normalization for all conv layers.
                See :func:`layers.get_norm` for supported format.
            stride_in_1x1 (bool): when stride>1, whether to put stride in the
                first 1x1 convolution or the bottleneck 3x3 convolution.
            dilation (int): the dilation rate of the 3x3 conv layer.
        """
        super().__init__(in_channels, out_channels, stride)

        if in_channels != out_channels:
            self.shortcut = Conv2d(
                in_channels,
                out_channels,
                kernel_size=1,
                stride=stride,
                bias=False,
                norm=get_norm(norm, out_channels),
            )
        else:
            self.shortcut = None

        # The original MSRA ResNet models have stride in the first 1x1 conv
        # The subsequent fb.torch.resnet and Caffe2 ResNe[X]t implementations have
        # stride in the 3x3 conv
        stride_1x1, stride_3x3 = (stride, 1) if stride_in_1x1 else (1, stride)

        self.conv1 = Conv2d(
            in_channels,
            bottleneck_channels,
            kernel_size=1,
            stride=stride_1x1,
            bias=False,
            norm=get_norm(norm, bottleneck_channels),
        )

        self.conv2 = Conv2d(
            bottleneck_channels,
            bottleneck_channels,
            kernel_size=3,
            stride=stride_3x3,
            padding=1 * dilation,
            bias=False,
            groups=num_groups,
            dilation=dilation,
            norm=get_norm(norm, bottleneck_channels),
        )

        self.conv3 = Conv2d(
            bottleneck_channels,
            out_channels,
            kernel_size=1,
            bias=False,
            norm=get_norm(norm, out_channels),
        )

        for layer in [self.conv1, self.conv2, self.conv3, self.shortcut]:
            if layer is not None:  # shortcut can be None
                weight_init.c2_msra_fill(layer)
        
        self.se = SELayer(bottleneck_channels * 4, 16)

        # Zero-initialize the last normalization in each residual branch,
        # so that at the beginning, the residual branch starts with zeros,
        # and each residual block behaves like an identity.
        # See Sec 5.1 in "Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour":
        # "For BN layers, the learnable scaling coefficient γ is initialized
        # to be 1, except for each residual block's last BN
        # where γ is initialized to be 0."

        # nn.init.constant_(self.conv3.norm.weight, 0)
        # TODO this somehow hurts performance when training GN models from scratch.
        # Add it as an option when we need to use this code to train a backbone.

    def forward(self, x):
        out = self.conv1(x)
        out = F.relu_(out)

        out = self.conv2(out)
        out = F.relu_(out)

        out = self.conv3(out)
        out = self.se(out) # 添加了 SELayer

        if self.shortcut is not None:
            shortcut = self.shortcut(x)
        else:
            shortcut = x

        out += shortcut
        out = F.relu_(out)
        return out

在 Mask2Former 中使用 SE 模块

Mask2Former 调用的是 Detectron2 中 ResNet ,所以在 Detectron2 中添加 SE 模块后,在 Mask2Former 中也会有改动。要注意的是当本地存在多个 Detectron2 项目文件夹时,需要在虚拟环境安装过的 Detectron2 中进行修改。

<think>好的,我需要解决用户的问题:如何在ResNet50中嵌入CBAM注意力机制并生成对应的网络模型图。首先,我得回忆一下ResNet50的基本结构和CBAM模块的工作原理。 ResNet50由多个残差块组成,每个残差块通常包含多个卷积层。CBAM(Convolutional Block Attention Module)包括通道注意力和空间注意力两个部分。根据引用[2]中的描述,CBAM可以无缝集成到CNN架构中,特别是在ResNet的ResBlock里。图3可能展示了这种集成方式,但用户无法直接查看图片,所以需要文字描述。 接下来,我需要确定在哪里插入CBAM模块。通常在残差块的卷积操作之后,激活函数之前加入CBAM。例如,在ResNet的Bottleneck结构中,三个卷积层之后可以插入CBAM模块。这样,注意力机制可以调整特征图的通道和空间信息,增强重要特征。 然后,关于生成网络模型结构图,用户可能需要使用工具如TensorBoard、Netron或在线绘图工具绘制。需要指导用户如何修改ResNet50的代码,添加CBAM模块,并生成结构图。引用[3]提供的GitHub和博文可能有具体的代码实现,可以建议用户参考。 还需要考虑代码示例。根据引用[1],用户可能需要将CBAM添加到YOLO中的示例,但这里需要针对ResNet50。可能需要展示如何在PyTorch或TensorFlow中修改ResNet的残差块,插入CBAM模块。 最后,生成相关问题,帮助用户深入理解,例如性能影响、与其他注意力机制的比较等。确保回答符合用户的要求,结构清晰,步骤明确,并正确引用提供的资料。</think>### 在ResNet50中嵌入CBAM注意力机制的步骤 #### 1. **理解CBAM模块结构** CBAM包含两个子模块: - **通道注意力(Channel Attention Module)**:通过全局平均池化和最大池化生成通道权重,公式为: $$ M_c(F) = \sigma(MLP(AvgPool(F)) + MLP(MaxPool(F))) $$ - **空间注意力(Spatial Attention Module)**:通过通道维度的池化和卷积生成空间权重,公式为: $$ M_s(F) = \sigma(f^{7×7}([AvgPool(F); MaxPool(F)])) $$ #### 2. **修改ResNet50残差块** 在ResNet50的Bottleneck结构中,将CBAM插入卷积层与激活函数之间: ``` 原始Bottleneck: Conv1x1 → Conv3x3 → Conv1x1 → ReLU 修改后Bottleneck: Conv1x1 → Conv3x3 → CBAM → Conv1x1 → CBAM → ReLU ``` (具体插入位置可根据任务需求调整[^2]) #### 3. **代码实现示例(PyTorch)** ```python class CBAM(nn.Module): # 通道注意力和空间注意力实现(代码参考引用[3]) class Bottleneck(nn.Module): def __init__(self, inplanes, planes, stride=1): super().__init__() self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, planes*4, 1, bias=False) self.bn3 = nn.BatchNorm2d(planes*4) self.cbam = CBAM(planes*4) # 在最后一个卷积后添加CBAM self.relu = nn.ReLU(inplace=True) def forward(self, x): identity = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) out = self.cbam(out) # 应用CBAM out += identity out = self.relu(out) return out ``` #### 4. **生成网络结构图的方法** - **使用可视化工具**: - TensorBoard的`add_graph()`函数 - Netron模型可视化工具(https://netron.app/) - 手动绘制(示例结构): ``` Input │ ├─Conv7x7 + BN + ReLU ├─MaxPool ├─Layer1(含3个带CBAM的Bottleneck) ├─Layer2(含4个带CBAM的Bottleneck) ├─Layer3(含6个带CBAM的Bottleneck) ├─Layer4(含3个带CBAM的Bottleneck) ├─AvgPool └─FC Layer ``` #### 5. **实验验证** - 通过消融实验验证CBAM有效性(如分类准确率提升1-2%) - 可视化注意力权重观察特征聚焦区域
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇宙爆肝锦标赛冠军

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

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

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

打赏作者

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

抵扣说明:

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

余额充值