轻量级网络整理及其在Yolov5上的实现

我的学习路线依旧是
在这里插入图片描述
以及一些比较新的轻量级网络
华为唯一真神涵盖了大量backbone

1.PP-LCNet

实战:PP-LCNet-YoloV5

整体block架构:

NET_CONFIG = {
    "blocks2":
    # k, in_c, out_c, s, use_se
            [[3, 16, 32, 1, False]],
    "blocks3": [[3, 32, 64, 2, False], [3, 64, 64, 1, False]],
    "blocks4": [[3, 64, 128, 2, False], [3, 128, 128, 1, False]],
    "blocks5": [[3, 128, 256, 2, False], [5, 256, 256, 1, False],
                [5, 256, 256, 1, False], [5, 256, 256, 1, False],
                [5, 256, 256, 1, False], [5, 256, 256, 1, False]],
    "blocks6": [[5, 256, 512, 2, True], [5, 512, 512, 1, True]]
}

在这里插入图片描述
block的对应关系如上图红圈,其他代码都挺规整的

我也在我自己的数据集上进行了MobileNetv3+yolov5,PP-LCNet+yolov5,效果确实会好一点!

2.MobileNet(v2)

MobileNet(v2),MobileNet(v3)的代码看这里!!!博主也得很好我就不细写了
在这里插入图片描述

1.代码理解疑难点
1)在每个bottleneck(由一个或者多个倒残差结构组成)结构中规定的s指的是第1层倒残差结构的步距

 stride = s if i == 0 else 1  
 # s只规定block中第1层倒残差结构的步距,其它层的步距都为1

2)初始化

 # weight initialization,初始化权重
        for m in self.modules():
            if isinstance(m, nn.Conv2d):  
            # 如果是卷积层,对权重进行凯明初始化
                nn.init.kaiming_normal_(m.weight, mode='fan_out')
                if m.bias is not None:  
                # 如果有bias,将偏置设置为0
                    nn.init.zeros_(m.bias)
            elif isinstance(m, nn.BatchNorm2d):  
            # 如果子模块是BN层
                nn.init.ones_(m.weight)  # 将方差设置为1
                nn.init.zeros_(m.bias)  # 将均值设置为0
            elif isinstance(m, nn.Linear):  # 如果子模块是全连接层
 # normal为正态分布函数,将权重调整为均值为0,方差为0.01的正态分布
                nn.init.normal_(m.weight, 0, 0.01) 
                nn.init.zeros_(m.bias)  # 将偏置设置为0

MobileNet(v3)

MobileNet(v2),MobileNet(v3)的代码看这里!!!博主也得很好我就不细写了

bneck_conf = partial(InvertedResidualConfig, width_multi=width_multi)  # 给InvertedResidualConfig传入默认超参数α=1

functools.partial(func[,*args][, **kwargs])接受一个函数作为参数,后面可传入参数供传入函数调用

self.use_res_connect = (cnf.stride == 1 and cnf.input_c == cnf.out_c)

不管是v2还是v3使用shortcut的条件都相同!!!
①步长为1
②input/output channel相同

 layers.append(ConvBNActivation(cnf.expanded_c,  # 无论是否使用SE模块,最后一层卷积的input_c都等于DW卷积后的output_c
                                       cnf.out_c,  # 输出特征矩阵的channel为配置文件中给定的#out
                                       kernel_size=1,
                                       norm_layer=norm_layer,
                                       activation_layer=nn.Identity)) 
					 # 最后1层卷积的激活函数为线性激活,即没有做任何处理

nn.Identity:不区分参数的占位符标识运算符。

在这里插入图片描述
对于最后的分类器的代码:

self.classifier = nn.Sequential(nn.Linear(lastconv_output_c, last_channel),
                                        # 输入c等于上面计算所得,输出last_channel为初始化中传入参数
                                        nn.Hardswish(inplace=True),  # 使用HS激活函数
                                        nn.Dropout(p=0.2, inplace=True),
                                        nn.Linear(last_channel, num_classes))  # 输入节点个数为上1个FC层输出的节点个数,输出节点个数为分类类别个数

图片中看上去是conv操作为什么代码用的是Linear?
其实很简单:在pooling操作之后,可以理解成将通道转化成(11通道数)的特征图像,使用1*1的卷积实际就是对其进行映射

在这里插入图片描述
花了一个不太正式的图大概长这样

GhostNet

看啥都不如看作者自己的解析强!!

作者遵循MobileNetV3的基本体系结构的优势,然后使用Ghost bottleneck替换MobileNetV3中的bottleneck

在这里插入图片描述
作为整个架构中使用最多的模块GhostModule代码如下:

class GhostModule(nn.Module):
    def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
        super(GhostModule, self).__init__()
        self.oup = oup
        init_channels = math.ceil(oup / ratio)
        new_channels = init_channels*(ratio-1)

        self.primary_conv = nn.Sequential(
            nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
            nn.BatchNorm2d(init_channels),
            nn.ReLU(inplace=True) if relu else nn.Sequential(),
        )

        self.cheap_operation = nn.Sequential(
            nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
            nn.BatchNorm2d(new_channels),
            nn.ReLU(inplace=True) if relu else nn.Sequential(),
        )

    def forward(self, x):
        x1 = self.primary_conv(x)
        x2 = self.cheap_operation(x1)
        out = torch.cat([x1,x2], dim=1)
        return out[:,:self.oup,:,:]#只返回需要的通道数

cheap_operation为什么使用过conv来实现的?

G-Ghost RegNet 新升级的Ghost

在这里插入图片描述

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值