yolov4_u5版复现—1. 网络基本架构

yolov4_u5版复现

写在前面
本复现的主要目的为:1)总结知识点,提升实战能力。2)提供一份可读性更强的yolov4_u5版代码(源代码很强,但是很难看懂)

  1. 网络基本架构(yolov4_l)
    在这里插入图片描述
    1). Conv
def autopad(kernel, padding=None):
    # Pad to 'same'
    if padding is None:
        padding = kernel // 2 if isinstance(kernel, int) else [x // 2 for x in kernel]
    return padding


class Conv(nn.Module):
    # Standard convolution
    def __init__(self, channel_in, channel_out, kernel=1, stride=1, padding=0, groups=1):
        super(Conv, self).__init__()
        self.conv = nn.Conv2d(channel_in, channel_out, kernel, stride, autopad(kernel), groups=groups,bias=False)
        self.bn = nn.BatchNorm2d(channel_out)
        self.activation = MishCuda()

    def forward(self, x):
        x = self.activation(self.bn(self.conv(x)))
        return x

    def set_mish(self, mishcuda=True):
        # Sets mish function as mish_cuda (for training) or Mish (for export).
        self.activation = MishCuda() if mishcuda else Mish()

a). padding大小一般设定为核大小的一半, 使用autopad,
b). set_mish确保在训练阶段使用mish_cuda加速,当export为onnx或其他部署格式时需要使用普通的mish,onnx等不支持mish_cuda (ps:自己加的)
c). bias=False, 卷积之后,如果要接BN操作,最好是不设置偏置,因为不起作用,而且占显卡内存。原理参考https://blog.csdn.net/u013289254/article/details/98785869
d). BN算法像卷积层,池化层、激活层一样也输入一层。BN层添加在激活函数前,对输入激活函数的输入进行归一化。这样解决了输入数据发生偏移和增大的影响.原理参考:https://blog.csdn.net/qq_37100442/article/details/81776191
)

2). Bottleneck
原理参考https://blog.csdn.net/guoyueyang/article/details/89247459
即res uint
1X1fliter分别用于降低和升高特征维度,主要目的是为了减少参数的数量,从而减少计算量,如下图所示,c_hidden通道数远小于c_in和c_out,减少了参数量

class Bottleneck(nn.Module):
    # bottleneck, when shortcut=True, it means res unit
    def __init__(self, channel_in, channel_out, shortcut=True, expansion=0.5):
        super(Bottleneck, self).__init__()
        channel_hidden = int(channel_out * expansion)
        self.cv1 = Conv(channel_in, channel_hidden, 1, 1)
        self.cv2 = Conv(channel_hidden, channel_out, 3, 1)
        self.add = shortcut and channel_in == channel_out

    def forward(self, x):
        x = x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
        return x

    def set_mish(self, mishcuda=True):
        # Sets mish function as mish_cuda (for training) or Mish (for export).
        self.cv1.set_mish(mishcuda)
        self.cv2.set_mish(mishcuda)

3). BottleneckCSP

class BottleneckCSP(nn.Module):
    def __init__(self, channel_in, channel_out, n=1, shortcut=True, expansion=0.5):
        super(BottleneckCSP, self).__init__()
        channel_hidden = int(channel_out * expansion)
        self.cv1 = Conv(channel_in, channel_hidden, 1, 1)
        self.bottleneck_n = nn.Sequential(*[Bottleneck(channel_hidden, channel_hidden, shortcut, expansion=1)
                                            for _ in range(n)])
        self.cv2 = nn.Conv2d(channel_in, channel_hidden, 1, 1, bias=False)
        self.cv3 = nn.Conv2d(channel_hidden, channel_hidden, 1, 1, bias=False)
        self.bn = nn.BatchNorm2d(2*channel_hidden)
        self.activation = MishCuda()
        self.cv4 = Conv(2*channel_hidden, channel_out, 1, 1)

    def forward(self, x):
        y1 = self.cv3(self.bottleneck_n(self.cv1(x)))
        y2 = self.cv2(x)
        # y1.shape: torch.Size([bs, channel_number, H, W])
        x = self.cv4(self.activation(self.bn(torch.cat((y1, y2), dim=1))))
        return x

    def set_mish(self, mishcuda=True):
        # Sets mish function as mish_cuda (for training) or Mish (for export).
        self.cv1.set_mish(mishcuda)
        for bottlenect in self.bottleneck_n:
            bottlenect.set_mish(mishcuda)
        self.activation = MishCuda() if mishcuda else Mish()
        self.cv4.set_mish(mishcuda)

4). BottleneckCSP2

class BottlneckCSP2(nn.Module):
    def __init__(self, channel_in, channel_out, n=1, shortcut=True, expansion=0.5):
        super(BottlneckCSP2, self).__init__()
        channel_hidden = int(channel_out)
        self.cv1 = Conv(channel_in, channel_hidden, 1, 1)
        self.bottleneck_n = nn.Sequential(*[Bottleneck(channel_hidden, channel_hidden, shortcut, expansion=1)
                                            for _ in range(n)])
        self.cv2 = nn.Conv2d(channel_hidden, channel_hidden, 1, 1, bias=False)
        self.bn = nn.BatchNorm2d(2*channel_hidden)
        self.activation = MishCuda()
        self.cv3 = Conv(2*channel_hidden, channel_out, 1, 1)

    def forward(self, x):
        x1 = self.cv1(x)
        y1 = self.bottleneck_n(x1)
        y2 = self.cv2(x1)
        x = self.cv3(self.activation(self.bn(torch.cat((y1, y2), dim=1))))
        return x

    def set_mish(self,mishcuda):
        # Sets mish function as mish_cuda (for training) or Mish (for export).
        self.cv1.set_mish(mishcuda)
        for bottlenect in self.bottleneck_n:
            bottlenect.set_mish(mishcuda)
        self.activation = MishCuda() if mishcuda else Mish()
        self.cv3.set_mish(mishcuda)

5). SPPCSP

class SPPCSP(nn.Module):
    def __init__(self, channel_in, channel_out, n=1, expansion=0.5, k=(5, 9, 13)):
        super(SPPCSP, self).__init__()
        channel_hidden = int(2 * channel_out * expansion)
        self.cv1 = Conv(channel_in, channel_hidden, 1, 1)
        self.cv2 = nn.Conv2d(channel_in, channel_hidden, 1, 1, bias=False)
        self.cv3 = Conv(channel_hidden, channel_hidden, 3, 1)
        self.cv4 = Conv(channel_hidden, channel_hidden, 1, 1)
        self.spp = nn.ModuleList([nn.MaxPool2d(k_i, 1, autopad(k_i)) for k_i in k])
        self.cv5 = Conv(4*channel_hidden, channel_hidden, 1, 1)
        self.cv6 = Conv(channel_hidden, channel_hidden, 3, 1)
        self.bn = nn.BatchNorm2d(2*channel_hidden)
        self.activation = MishCuda()
        self.cv7 = Conv(2*channel_hidden, channel_out, 1, 1)

    def forward(self, x):
        x1 = self.cv4(self.cv3(self.cv1(x)))
        y1 = self.cv6(self.cv5(torch.cat([x1] + [m(x1) for m in self.spp], dim=1)))
        y2 = self.cv2(x)
        x = self.cv7(self.activation(self.bn(torch.cat((y1, y2), dim=1))))
        return x

    def set_mish(self,mishcuda):
        # Sets mish function as mish_cuda (for training) or Mish (for export).
        self.cv1.set_mish(mishcuda)
        self.cv3.set_mish(mishcuda)
        self.cv4.set_mish(mishcuda)
        self.cv5.set_mish(mishcuda)
        self.cv6.set_mish(mishcuda)
        self.cv7.set_mish(mishcuda)
        self.activation = MishCuda() if mishcuda else Mish()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值