# 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个特征层,但是没有用到
发表回复