YOLOX-PAFPN

# YOLOPAFPN全称是YOLOv3的PANet的FPN版本,PANet是YOLOv3的PANet版本,FPN是YOLOv3的FPN版本
# PANet全称是Pyramid Attention Network,是YOLOv3的PANet版本,FPN是YOLOv3的FPN版本
class YOLOPAFPN(nn.Module):
    """
    YOLOv3 model. Darknet 53 is the default backbone of this model.
    """
    def __init__(
        self,
        depth=1.0,          # 深度, 1.0, 0.5, 0.33
        width=1.0,          # 宽度, 1.0, 0.5, 0.33
        in_features=("dark3", "dark4", "dark5"), # backbone输出的特征层, 3个
        in_channels=[256, 512, 1024],            # backbone输出的特征层通道数, 3个
        depthwise=False,                         # 是否使用深度可分离卷积
        act="silu",                              # 激活函数
    ):
        super().__init__()
        self.backbone = CSPDarknet(depth, width, depthwise=depthwise, act=act)
        # backbone使用CSPDarknet, 3个特征层,CSPDarknet输出的特征层通道数为256, 512, 1024
        # CSP表示Cross Stage Partial,即跨阶段部分,是YOLOv3的改进版本
        # 与Darknet53相比,CSPDarknet53的主要改进是在每个stage中增加了一个CSP模块
        # CSP模块的主要作用是增加了一个残差连接,使得模型的深度更深,同时也增加了模型的感受野
        self.in_features = in_features
        self.in_channels = in_channels
        Conv = DWConv if depthwise else BaseConv

        self.upsample = nn.Upsample(scale_factor=2, mode="nearest")
        # 上采样, scale_factor=2, mode="nearest"表示上采样2倍, 且使用最近邻插值
        self.lateral_conv0 = BaseConv(
            int(in_channels[2] * width), int(in_channels[1] * width), 1, 1, act=act
            # lateral_conv0的输入通道数为1024, 输出通道数为512, 卷积核大小为1, 步长为1, 激活函数为act
            # Q: 如何形象地了解lateral
            # A: lateral表示侧面的,即侧面的卷积层
            # lateral_conv0的作用是将输入的特征图的通道数从1024降低到512,将特征图的尺寸从W*H降低到W/2*H/2
        )
        self.C3_p4 = CSPLayer(
            int(2 * in_channels[1] * width),
            int(in_channels[1] * width),
            round(3 * depth),
            False,
            depthwise=depthwise,
            act=act,
        )  # cat
        # C3_p4的输入通道数为1024, 输出通道数为512, 卷积核大小为3, 步长为1, 激活函数为act
        # C3表示3个卷积层, p4表示PANet的第4个特征层
        # PANet的作用是将输入的特征图的尺寸从W*H降低到W/2*H/2,它的输入通道数为512, 输出通道数为512,目的是为了与bottom-up的第3个特征层进行融合

        self.reduce_conv1 = BaseConv(
            int(in_channels[1] * width), int(in_channels[0] * width), 1, 1, act=act
        )
        # reduce_conv1作用是将输入的特征图的通道数从512降低到256
        self.C3_p3 = CSPLayer( # C3表示3个卷积层, p3表示PANet的第3个特征层
            int(2 * in_channels[0] * width),
            int(in_channels[0] * width),
            round(3 * depth),
            False,
            depthwise=depthwise,
            act=act,
        )
        
        # bottom-up conv
        self.bu_conv2 = Conv(
            int(in_channels[0] * width), int(in_channels[0] * width), 3, 2, act=act
        )
        # bu_conv2表示bottom-up的第2个卷积层, 输入通道数为256, 输出通道数为256, 卷积核大小为3, 步长为2, 激活函数为act
        # bottom-up的作用是将输入的特征图的尺寸从W*H降低到W/2*H/2,它的输入通道数为256, 输出通道数为256,目的是为了与PANet的第3个特征层进行融合
        self.C3_n3 = CSPLayer(          # C3_n3表示3个卷积层, n3表示bottom-up的第3个特征层
            int(2 * in_channels[0] * width),
            int(in_channels[1] * width),
            round(3 * depth),
            False,
            depthwise=depthwise,
            act=act,
        )
        # C3_n3表示3个卷积层, n3表示bottom-up的第3个特征层

        # bottom-up conv
        self.bu_conv1 = Conv(           # bu_conv1表示bottom-up的第1个卷积层
            int(in_channels[1] * width), int(in_channels[1] * width), 3, 2, act=act
        )
        self.C3_n4 = CSPLayer(          # C3_n4表示3个卷积层, n4表示bottom-up的第4个特征层
            int(2 * in_channels[1] * width),
            int(in_channels[2] * width),
            round(3 * depth),
            False,
            depthwise=depthwise,
            act=act,
        )

    def forward(self, input):
        """
        Args:
            inputs: input images.

        Returns:
            Tuple[Tensor]: FPN feature.
        """

        #  backbone
        out_features = self.backbone(input)
        features = [out_features[f] for f in self.in_features]
        [x2, x1, x0] = features
        # x2表示CSPDarknet53的第3个特征层, x1表示CSPDarknet53的第2个特征层, x0表示CSPDarknet53的第1个特征层
        # x2(256, 128, 128), x1(512, 64, 64), x0(1024, 32, 32)
        # Q: 不应该是深度越深, 特征图的尺寸越小吗
        # A: 这里的特征图尺寸是指特征图的宽和高, 而不是深度, 深度是指特征图的通道数

        fpn_out0 = self.lateral_conv0(x0)       # 1024->512/32 其中32表示下采样倍数
                                                # 1x1卷积核, stride=1, 激活函数为act              
        f_out0 = self.upsample(fpn_out0)        # 512/16       其中16表示下采样倍数

        f_out0 = torch.cat([f_out0, x1], 1)     # 512->1024/16
        f_out0 = self.C3_p4(f_out0)             # 1024->512/16

        fpn_out1 = self.reduce_conv1(f_out0)    # 512->256/16
        f_out1 = self.upsample(fpn_out1)        # 256/8
        f_out1 = torch.cat([f_out1, x2], 1)     # 256->512/8
        pan_out2 = self.C3_p3(f_out1)           # 512->256/8

        p_out1 = self.bu_conv2(pan_out2)            # 256->256/16
        p_out1 = torch.cat([p_out1, fpn_out1], 1)   # 256->512/16
        pan_out1 = self.C3_n3(p_out1)               # 512->512/16

        p_out0 = self.bu_conv1(pan_out1)            # 512->512/32
        p_out0 = torch.cat([p_out0, fpn_out0], 1)   # 512->1024/32
        pan_out0 = self.C3_n4(p_out0)  # 1024->1024/32

        outputs = (pan_out2, pan_out1, pan_out0)
        return outputs
# YOLO_PANet的数据结构:
# 1. backbone: CSPDarknet53输出的3个特征层,分别是x2, x1, x0,256/8, 512/16, 1024/32
# 2. lateral_conv0: 1x1卷积核, stride=1, 激活函数为act,将CSPDarknet53的第1个特征层x0的通道数从1024变为512,512/32
# 3. upsample: 上采样层, 将输入的特征图的尺寸从W*H变为2W*2H,它的输入通道数为512, 输出通道数为512,目的是为了与PANet的第4个特征层进行融合,512/16
# 4. C3_p4: 3个卷积层, p4表示PANet的第4个特征层,512/16
# 5. reduce_conv1: 1x1卷积核, stride=1, 激活函数为act 
# 6. C3_p3: 3个卷积层, p3表示PANet的第3个特征层
# 7. bu_conv2: 3x3卷积核, stride=2, 激活函数为act
# 8. C3_n3: 3个卷积层, n3表示bottom-up的第3个特征层
# 9. bu_conv1: 3x3卷积核, stride=2, 激活函数为act
# 10. C3_n4: 3个卷积层, n4表示bottom-up的第4个特征层
# Q: n3 n4是什么意思,有n1 n2吗
# A: n3 n4表示bottom-up的第3个和第4个特征层, n1 n2表示top-down的第1个和第2个特征层
# Q: p3 p4是什么意思,有p1 p2吗,在哪里用到了
# A: p3 p4表示PANet的第3个和第4个特征层, p1 p2表示PANet的第1个和第2个特征层,但是没有用到

已发布

分类

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注