YOLOv5算法改进(13)— 替换主干网络之PP-LCNet

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第1张图片

前言:Hello大家好,我是小哥谈。PP-LCNet是一个由百度团队针对Intel-CPU端加速而设计的轻量高性能网络。它是一种基于MKLDNN加速策略的轻量级卷积神经网络,适用于多任务,并具有提高模型准确率的方法。与之前预测速度相近的模型相比,PP-LCNet具有更高的准确性。此外,对于计算机视觉的下游任务(如目标检测、语义分割等),该模型的效果也很好。 PP-LCNet还采用了H-Swish激活函数,这是一种优化的激活函数,可以提高性能而几乎不增加预测时间。 

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第2张图片 前期回顾:

              YOLOv5算法改进(1)— 如何去改进YOLOv5算法

              YOLOv5算法改进(2)— 添加SE注意力机制

              YOLOv5算法改进(3)— 添加CBAM注意力机制

              YOLOv5算法改进(4)— 添加CA注意力机制

              YOLOv5算法改进(5)— 添加ECA注意力机制

              YOLOv5算法改进(6)— 添加SOCA注意力机制

              YOLOv5算法改进(7)— 添加SimAM注意力机制

              YOLOv5算法改进(8)— 替换主干网络之MobileNetV3

              YOLOv5算法改进(9)— 替换主干网络之ShuffleNetV2

              YOLOv5算法改进(10)— 替换主干网络之GhostNet

              YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2

              YOLOv5算法改进(12)— 替换主干网络之Swin Transformer

             目录

1.论文

2.PP-LCNet网络架构及原理

3.YOLOv5结合PP-LCNet

步骤1:在common.py中添加PP-LCNet模块

步骤2:在yolo.py文件中加入类名

步骤3:创建自定义yaml文件

步骤4:验证是否加入成功

步骤5:修改train.py中的'--cfg'默认参数

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第3张图片

1.论文

PP-LCNet是百度团队结合Intel-CPU端侧推理特性而设计的轻量高性能网络,所提方案在图像分类任务上取得了比ShuffleNetV2MobileNetV2MobileNetV3以及GhostNet更优的延迟-精度均衡。论文提出了一种基于MKLDNN加速的轻量CPU模型PP-LCNet,它在多个任务上改善了轻量型模型的性能

如下图所示,在图像分类任务方面,所提PP-LCNet在推理延迟-精度均衡方面大幅优于ShuffleNetV2、MobileNetV2、MobileNetV3以及GhostNet。

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第4张图片

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第5张图片

论文试验结果:

不同尺度的PP-LCNet在ImageNet上的精度和延迟如下表所示:

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第6张图片

 和其它轻量模型的对比如下表所示:

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第7张图片

说明:♨️♨️♨️

本文提出一个能够在 CPU 上训练的深度学习网络模型,文章和算法都很简单,很容易复现。

文章总结起来就 4 点

(1)使用 H-Swish (替代传统的 ReLU);

(2)SE 模块放在最后一层,并使用大尺度卷积核;

(3)大尺度卷积核放在最后几层;

(4)在最后的 global average pooling 后增加更大尺寸的 1 × 1 卷积层。

论文题目:《PP-LCNet: A Lightweight CPU Convolutional Neural Network》

论文地址:  https://arxiv.org/abs/2109.15099

代码实现:  GitHub - ngnquan/PP-LCNet: PyTorch implementation of PP-LCNet


2.PP-LCNet网络架构及原理

PP-LCNet网络结构整体如下图所示:

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第8张图片

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第9张图片

(1)模块

使用了类似 MobileNetV1 中的深度可分离卷积作为基础,通过堆叠模块构建了一个类似 MobileNetV1 的BaseNet,然后组合BaseNet与某些现有技术构建了一种更强力网络PP-LCNet。

结构图如下,左图是卷积+标准化+激活函数,右图是PP-LCNet中的基础模块,源代码中是先卷积+SE模块+卷积。

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第10张图片

(2)激活函数的使用

自从卷积神经网络使用了 ReLU 激活函数后,网络性能得到了大幅度的提升,近些年 ReLU 激活函数的变体也相继出现,如 Leaky-ReLU、P-ReLU、ELU 等。2017 年,谷歌大脑团队通过搜索的方式得到了 swish 激活函数,该激活函数在轻量级网络上表现优异,在 2019 年,MobileNetV3 的作者将该激活函数进一步优化为 H-Swish,该激活函数去除了指数运算、速度更快、网络精度几乎不受影响,也经过很多实验发现该激活函数在轻量级网络上有优异的表现。所以在 PP-LCNet 中,选用了该激活函数

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第11张图片

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第12张图片

(3)SE 模块

SE模块使用了激活函数ReLU和H-sigmoid。

(4)合适的位置添加更大的卷积核

通过实验总结了一些更大的卷积核在不同位置的作用,类似 SE 模块的位置,更大的卷积核在网络的中后部作用更明显,所以在网络的后部会使用很多5x5的卷积核。

(5)GAP 后使用更大的 1x1 卷积层

在 GoogLeNet 之后,GAP(Global-Average-Pooling)后往往直接接分类层,但是在轻量级网络中,这样会导致 GAP 后提取的特征没有得到进一步的融合和加工。如果在此后使用一个更大的 1x1 卷积层(等同于 FC 层),GAP 后的特征便不会直接经过分类层,而是先进行了融合,并将融合的特征进行分类。这样可以在不影响模型推理速度的同时大大提升准确率。


3.YOLOv5结合PP-LCNet

步骤1:在common.py中添加PP-LCNet模块

将下面PP-LCNet模块的代码复制粘贴到common.py文件的末尾。

class SeBlock(nn.Module):
    def __init__(self, in_channel, reduction=4):
        super().__init__()
        self.Squeeze = nn.AdaptiveAvgPool2d(1)

        self.Excitation = nn.Sequential()
        self.Excitation.add_module('FC1', nn.Conv2d(in_channel, in_channel // reduction, kernel_size=1))  # 1*1卷积与此效果相同
        self.Excitation.add_module('ReLU', nn.ReLU())
        self.Excitation.add_module('FC2', nn.Conv2d(in_channel // reduction, in_channel, kernel_size=1))
        self.Excitation.add_module('Sigmoid', nn.Sigmoid())

    def forward(self, x):
        y = self.Squeeze(x)
        ouput = self.Excitation(y)
        return x * (ouput.expand_as(x))
 
 
class DepthSepConv(nn.Module):
    def __init__(self, inp, oup, dw_size, stride, use_se):
        super(DepthSepConv, self).__init__()
        self.stride = stride
        self.inp = inp
        self.oup = oup
        self.dw_size = dw_size
        self.dw_sp = nn.Sequential(
            nn.Conv2d(self.inp, self.inp, kernel_size=self.dw_size, stride=self.stride, padding=(dw_size - 1) // 2, groups=self.inp, bias=False),
            nn.BatchNorm2d(self.inp),
            nn.Hardswish(),

            SeBlock(self.inp, reduction=16) if use_se else nn.Sequential(),

            nn.Conv2d(self.inp, self.oup, kernel_size=1, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(self.oup),
            nn.Hardswish())

    def forward(self, x):
        y = self.dw_sp(x)
        return y

步骤2:在yolo.py文件中加入类名

首先在yolo.py文件中找到 parse_model函数这一行,加入DepthSepConv

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第13张图片

步骤3:创建自定义yaml文件

models文件夹中复制yolov5s.yaml,粘贴并重命名为yolov5s_PPLCNet.yaml

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第14张图片

然后根据PP-LCNet的网络架构来修改配置文件。

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第15张图片

yaml文件修改后的完整代码如下:

# YOLOv5  by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

#  PP-LCNet backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [16, 3, 2, 1]],              # 0-P1/2  ch_out, kernel, stride, padding
   [-1, 1, DepthSepConv, [32, 3, 1, False]],  # 1

   [-1, 1, DepthSepConv, [64, 3, 2, False]],  # 2-P2/4
   [-1, 1, DepthSepConv, [64, 3, 1, False]],  # 3

   [-1, 1, DepthSepConv, [128, 3, 2, False]], # 4-P3/8
   [-1, 1, DepthSepConv, [128, 3, 1, False]], # 5

   [-1, 1, DepthSepConv, [256, 3, 2, False]], # 6-P4/16
   [-1, 5, DepthSepConv, [256, 5, 1, False]], # 7

   [-1, 1, DepthSepConv, [512, 5, 2, True]],  # 8-P5/32
   [-1, 1, DepthSepConv, [512, 5, 1, True]],  # 9
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [256, 1, 1]], # 10
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 7], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [256, False]],  # 13

   [-1, 1, Conv, [128, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [128, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [128, 3, 2]],
   [[-1, 14], 1, Concat, [1]], # cat head P4
   [-1, 3, C3, [256, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [512, False]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

步骤4:验证是否加入成功

yolo.py文件里,配置我们刚才自定义的yolov5s_PPLCNet.yaml

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第16张图片

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第17张图片

然后运行yolo.py,得到结果。

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第18张图片

这样就算添加成功了。  

步骤5:修改train.py中的'--cfg'默认参数

train.py文件中找到 parse_opt函数,然后将第二行 '--cfg的default改为 'models/yolov5s_PPLCNet.yaml ',然后就可以开始进行训练了。 

YOLOv5算法改进(13)— 替换主干网络之PP-LCNet_第19张图片


你可能感兴趣的:(YOLOv5:从入门到实战,YOLO,目标检测,人工智能,计算机视觉,深度学习,机器学习,神经网络)