YOLOv4代码学习笔记一

2023-05-16

YOLOV4代码学习笔记一

  • YOLOV4简介
  • CSPdarknet.py学习

本文是对另一个博主的 睿智的目标检测30——Pytorch搭建YoloV4目标检测平台代码的学习,由于我是cv新手,很多东西不懂,看了论文和代码后还有很多不太了解的地方,所以想把整个YOLOv4代码都做一下笔记,希望能够真正掌握YOLOv4。
大部分内容都是引用这个博主的文章和YOLOv4原论文的。下面就不一一解释了。


YOLOV4简介

由于本文主要目的是看懂代码,而不是对模型的理论学习。所以不做过多的原理分析。详细的可以查看原论文或中文的分析。

在这里插入图片描述
YOLOv4实际上和YOLOv3很像,是在YOLOv3做了很多修改后形成的模型。但是性能得到了很大的提升。看上图就知道了。

YOLOv3:
在这里插入图片描述
YOLOv4:在这里插入图片描述
上面的两张图分别是YOLOv3网络结构图和YOLOv4网络结构图。对比可知道,主要的变化是:

  1. 骨干网络从Darknet53变成了CSPDarknet53
    CSPNet如下图,将输入分成两块,一块做简单处理,另一块通过了很多残差快,最后进行堆叠处理。
    在这里插入图片描述

  2. 使用Mish激活函数(YOLOv3使用的是Relu)
    不多解释,Mish如下图。
    在这里插入图片描述

  3. 使用了SPPNet
    SPP结构参杂在对CSPdarknet53的最后一个特征层的卷积里,在对SPdarknet53的最后一个特征层进行三次DarknetConv2D_BN_Leaky卷积后,分别利用四个不同尺度的最大池化进行处理,最大池化的池化核大小分别为13x13、9x9、5x5、1x1(1x1即无处理)。

  4. 使用了PANet
    从PANet与FPN的区别在于下图的(b),有效特征层的提取不仅仅是骨干网络的最后几层及相应上采样的跳接,还将跳接后的特征层再做下采样,然后再把相同size的堆叠起来。(简单理解就是,本来是上采样然后堆叠,现在变成了上采样堆叠,然后再做一轮下采样,然后再堆叠。)
    在这里插入图片描述

CSPdarknet.py学习

这是原代码链接:https://github.com/bubbliiiing/yolov4-pytorch/blob/45ec8d1b655e27f10865fd277c111e2c1e0338bb/nets/CSPdarknet.py#L63

这个文件实现的是主干网络CSPdarknet53,总共定义了5个类和1个函数,下图是调用关系。
在这里插入图片描述

  • Mish:实现Mish激活函数。(这个没什么难理解的,不做过多分析)
#-------------------------------------------------#
#   MISH激活函数
#-------------------------------------------------#
class Mish(nn.Module):
    def __init__(self):
        super(Mish, self).__init__()

    def forward(self, x):
        return x * torch.tanh(F.softplus(x))
  • BasicConv:依次做了一次卷积,激活函数为Mish,通过设置padding使输出的h和w和输入一样
#---------------------------------------------------#
#   卷积块 -> 卷积 + 标准化 + 激活函数
#   Conv2d + BatchNormalization + Mish
#---------------------------------------------------#
class BasicConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1):
        super(BasicConv, self).__init__()

        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, kernel_size//2, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.activation = Mish()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.activation(x)
        return x
  • Resblock:这个是CSPdarknet53中的残差块基本单元。调用两次BasicConv做卷积,它的特点就是输出的通道数和输入一样
#---------------------------------------------------#
#   CSPdarknet的结构块的组成部分
#   内部堆叠的残差块
#---------------------------------------------------#
class Resblock(nn.Module):
    def __init__(self, channels, hidden_channels=None):
        super(Resblock, self).__init__()

        if hidden_channels is None:
            hidden_channels = channels

        self.block = nn.Sequential(
            BasicConv(channels, hidden_channels, 1),
            BasicConv(hidden_channels, channels, 3)
        )

    def forward(self, x):
        return x + self.block(x)
  • Resblock_body:这个就是CSPdarknet53中的残差块了。
    先看它的四个输入参数in_channels, out_channels, num_blocks, first。前面两个是输入输出通道数。看第三个num_blocks,这个指的是什么?
    看下图,这个CSPdarknet53的每个残差块是由多个残差单元Resblock组成的,具体多少个图片上已经标出来了。分别是1、2、8、8、4。
    在这里插入图片描述
    第四个参数first是因为第一个残差模块需要做一些不一样的操作,所以传入这个变量。不同在哪?
    其实是中间层的通道数的不同,第一个残差模块的CSPNet两个部分堆叠后,通道数是2倍out_channels,在做1x1卷积时,需要修改参数,使得通道数减半。但是后面的四个残差块的CSPNet两个部分堆叠后,通道数等于out_channels,1x1卷积通道数不变。
    之所以会有这个差异,是split_conv0和split_conv1的输出通道数在first中等于out_channels。不知为什么要这样处理,猜想是原码本身是这样的,所以博主也跟着这样。
    这个类的具体操作
    1 先做一次卷积使宽w高h为原来的一半(这个可以看上图,每一个块的宽高都是上一个块的一半)。
    2 然后是split_conv0和split_conv1,分别对应CSPNet中的part1和part2。实际就是调用BasicConv做一次卷积。
    3 接着是blocks_conv,对应CSPNet中part2之后的残差结构。将split_conv1作为输入,然后根据num_blocks调用resblock。
    4 最后是把split_conv0和blocks_conv堆叠起来再做一次卷积。
#--------------------------------------------------------------------#
#   CSPdarknet的结构块
#   首先利用ZeroPadding2D和一个步长为2x2的卷积块进行高和宽的压缩
#   然后建立一个大的残差边shortconv、这个大残差边绕过了很多的残差结构
#   主干部分会对num_blocks进行循环,循环内部是残差结构。
#   对于整个CSPdarknet的结构块,就是一个大残差块+内部多个小残差块
#--------------------------------------------------------------------#
class Resblock_body(nn.Module):
    def __init__(self, in_channels, out_channels, num_blocks, first):
        super(Resblock_body, self).__init__()
        #----------------------------------------------------------------#
        #   利用一个步长为2x2的卷积块进行高和宽的压缩
        #----------------------------------------------------------------#
        self.downsample_conv = BasicConv(in_channels, out_channels, 3, stride=2)

        if first:
            #--------------------------------------------------------------------------#
            #   然后建立一个大的残差边self.split_conv0、这个大残差边绕过了很多的残差结构
            #--------------------------------------------------------------------------#
            self.split_conv0 = BasicConv(out_channels, out_channels, 1)

            #----------------------------------------------------------------#
            #   主干部分会对num_blocks进行循环,循环内部是残差结构。
            #----------------------------------------------------------------#
            self.split_conv1 = BasicConv(out_channels, out_channels, 1)
            self.blocks_conv = nn.Sequential(
                Resblock(channels=out_channels, hidden_channels=out_channels//2),
                BasicConv(out_channels, out_channels, 1)
            )

            self.concat_conv = BasicConv(out_channels*2, out_channels, 1)
        else:
            #--------------------------------------------------------------------------#
            #   然后建立一个大的残差边self.split_conv0、这个大残差边绕过了很多的残差结构
            #--------------------------------------------------------------------------#
            self.split_conv0 = BasicConv(out_channels, out_channels//2, 1)

            #----------------------------------------------------------------#
            #   主干部分会对num_blocks进行循环,循环内部是残差结构。
            #----------------------------------------------------------------#
            self.split_conv1 = BasicConv(out_channels, out_channels//2, 1)
            self.blocks_conv = nn.Sequential(
                *[Resblock(out_channels//2) for _ in range(num_blocks)],
                BasicConv(out_channels//2, out_channels//2, 1)
            )

            self.concat_conv = BasicConv(out_channels, out_channels, 1)

    def forward(self, x):
        x = self.downsample_conv(x)

        x0 = self.split_conv0(x)

        x1 = self.split_conv1(x)
        x1 = self.blocks_conv(x1)

        #------------------------------------#
        #   将大残差边再堆叠回来
        #------------------------------------#
        x = torch.cat([x1, x0], dim=1)
        #------------------------------------#
        #   最后对通道数进行整合
        #------------------------------------#
        x = self.concat_conv(x)

        return x

  • CSPDarkNet:这个是CSPdarknet53主体。搭建出CSPdarknet53。没有什么不好理解的地方,不解释了。
#---------------------------------------------------#
#   CSPdarknet53 的主体部分
#   输入为一张416x416x3的图片
#   输出为三个有效特征层
#---------------------------------------------------#
class CSPDarkNet(nn.Module):
    def __init__(self, layers):
        super(CSPDarkNet, self).__init__()
        self.inplanes = 32
        # 416,416,3 -> 416,416,32
        self.conv1 = BasicConv(3, self.inplanes, kernel_size=3, stride=1)
        self.feature_channels = [64, 128, 256, 512, 1024]

        self.stages = nn.ModuleList([
            # 416,416,32 -> 208,208,64
            Resblock_body(self.inplanes, self.feature_channels[0], layers[0], first=True),
            # 208,208,64 -> 104,104,128
            Resblock_body(self.feature_channels[0], self.feature_channels[1], layers[1], first=False),
            # 104,104,128 -> 52,52,256
            Resblock_body(self.feature_channels[1], self.feature_channels[2], layers[2], first=False),
            # 52,52,256 -> 26,26,512
            Resblock_body(self.feature_channels[2], self.feature_channels[3], layers[3], first=False),
            # 26,26,512 -> 13,13,1024
            Resblock_body(self.feature_channels[3], self.feature_channels[4], layers[4], first=False)
        ])

        self.num_features = 1
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()


    def forward(self, x):
        x = self.conv1(x)

        x = self.stages[0](x)
        x = self.stages[1](x)
        out3 = self.stages[2](x)
        out4 = self.stages[3](out3)
        out5 = self.stages[4](out4)

        return out3, out4, out5

  • darknet53:这个可以看做是CSPDarkNet的封装函数吧,if语句是用来载入参数权重的。
def darknet53(pretrained, **kwargs):
    model = CSPDarkNet([1, 2, 8, 8, 4])
    if pretrained:
        if isinstance(pretrained, str):
            model.load_state_dict(torch.load(pretrained))
        else:
            raise Exception("darknet request a pretrained path. got [{}]".format(pretrained))
    return model

参考文献:

  • 睿智的目标检测30——Pytorch搭建YoloV4目标检测平台
  • TensorFlow2深度学习实战(十四):目标检测算法 YOLOv4 解析
  • YOLOv4: Optimal Speed and Accuracy of Object Detection
  • Batch Normalization原理与实战
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

YOLOv4代码学习笔记一 的相关文章

  • Windows10下编译opencv以及yolov4、yolov4_cpp_dll.dll

    编译的安装顺序是 xff0c CUDA 43 CUDNN xff08 安装包与压缩包不要删除 xff0c 不要删除 xff0c 不要删除 xff0c 防止踩坑的后备 xff09 然后是VisualStdio xff0c 其次是OPENCV
  • DeepStream 部署 RTSP + scaled-yolov4 (tensorrtx)

    DeepStream应用程序将深度神经网络和其他复杂的处理任务引入到流处理管道中 xff0c 以实现对视频和其他传感器数据的近实时分析 从这些传感器中提取有意义的见解为提高运营效率和安全性创造了机会 例如 xff0c 摄像头是当前使用最多的
  • YOLOv4-pytorch训练自己的数据集

    YOLOv4 pytorch训练自己的数据集 YOLOv4 pytorch介绍环境配置运行环境安装依赖包 准备工作Git clone YOLOv4准备数据集下载PascalVOC MSCOCO 2017数据集准备自己的数据集 下载权重文件
  • c++调用yolov4模型进行目标检测-使用opencv4.4.0

    前言 最近刚出的opencv4 4 0也支持了yolov4 xff0c 便尝试用opencv调用yolov4进行检测 xff0c 做个记录 当然 xff0c yolov3 yolov4 tiny等也能调用 xff0c 只需修改加载的cfg和
  • YOLOv4代码学习笔记一

    YOLOV4代码学习笔记一 YOLOV4简介CSPdarknet py学习 本文是对另一个博主的 睿智的目标检测30 Pytorch搭建YoloV4目标检测平台代码的学习 xff0c 由于我是cv新手 xff0c 很多东西不懂 xff0c
  • YOLOv4:ubuntu18下使用darknet训练自己的模型

    首先 xff0c 如果使用GPU xff0c 确认你电脑的有关环境是否符合以下要求 xff1a CMake gt 61 3 12CUDA gt 61 10 0OpenCV gt 61 2 4cuDNN gt 61 7 0GPU with C
  • yolov4-tiny使用jetson nano进行目标检测+tensorrt+CSI+USB摄像头检测

    软硬件版本 Jetson Nano 4G ubuntu 18 04 JP 4 5 1 CUDA 10 2 TensorRT 7 1 3 0 Python 3 6 一 下载源码 git clone https github com Alexe
  • PyTorch版YOLOv4训练自己的数据集---基于Google Colab

    colab简介 Google Colaboratory是谷歌开放的一款研究工具 xff0c 主要用于机器学习的开发和研究 工具优势 xff1a Google Colab最大的好处是给广大的AI开发者提供了免费的GPU使用 你可以在上面轻松地
  • YOLOv4剪枝【附代码】

    本项目只是负责把框架搭建起来 xff0c 没有进行重训练的微调或者去研究应该剪哪里比较好 xff0c 需要自己去研究 YOLOv4代码参考 xff1a Pytorch 搭建自己的YoloV4目标检测平台 xff08 Bubbliiiing
  • YOLOv4从配置环境到跑通代码的小白教程

    一直以来都只是看论文和网上的一些纯文字的讲解 xff0c 但从来没有实操过 xff0c 非常想自己跑一下代码 xff0c 看一下算法的整个实现过程 xff0c 于是就有了这次尝试 系统环境介绍 windows 10 NVIDIA GeFor
  • 无人机目标检测:使用YOLOv4在VisDrone数据集上进行目标检测任务

    在本篇博客中 我们将探讨如何使用YOLOv4在VisDrone数据集上进行无人机目标检测任务 目标检测是计算机视觉中的一个重要任务 可以用于自动驾驶汽车 无人机监测和视频分析等多种应用 YOLOv4是一种实时目标检测算法 以其速度和准确性而
  • 【YOLOv4】详细讲解全过程

    目录 1 YoloV4核心基础内容 1 1 网络结构可视化 1 2 网络结构图 1 3 核心基础内容 1 3 1 输入端创新 xff08 1 xff09 Mosaic数据增强 1 3 2 BackBone创新 xff08 1 xff09 C
  • Jetson Nano( 五) TensorRT yolov4 yolov4-tiny yolov5 实测

    TensorRT yolov4 yolov4 tiny yolov5 长期更新 文章目录 TensorRT yolov4 yolov4 tiny yolov5 长期更新软硬件环境参考大佬项目简要流程注意要点操作流程记录遇坑推理速度记录 软硬
  • DeepSOCIAL:基于YOLOv4的人群距离监测!集检测、跟踪以及逆透视映射一体的系统!...

    点击下方 AI算法与图像处理 xff0c 一起进步 xff01 重磅干货 xff0c 第一时间送达 论文 xff1a https doi org 10 3390 app10217514 代码 xff1a https github com D
  • Darknet YoloV4编译+训练(避免踩坑)

    AlexAB darknet yolov4编译 43 训练 时间间隔好几天今天来更新一下yolov4的训练 训练篇 在训练之前需要对大佬的源码进行编译本本机编译 xff0c 编译过程可查看下述链接 xff1a https blog csdn
  • c++ 调用yolov3-yolov4

    ifdef WIN32 define OPENCV define GPU endif include lt iostream gt include lt windows h gt include 34 yolo v2 class hpp 3
  • c++封装yolov4进行目标检测

    yolo4是用c 43 43 写的 xff0c 在工程中的部署特别方便 之前项目中使用yolov4 xff0c 取得了不错的效果 在这里记录一下 使用官方接口调用 xff0c 我们首先得编译darknet动态库 xff0c 下载yolov4
  • 睿智的目标检测29——Keras搭建YoloV4目标检测平台

    睿智的目标检测29 Keras搭建YoloV4目标检测平台 学习前言 什么是YOLOV4 代码下载 YOLOV4改进的部分 不完全 YOLOV4结构解析 1 主干特征提取网络Backbone 2 特征金字塔 3 YoloHead利用获得到的
  • [yolov4]yolov4.weights

    版本 https github com AlexeyAB darknet 权重链接 yolov4 weights https 72k us file 26468910 439532813 提取密码 446792 yolov4 conv 13
  • yolov4训练自己的数据模型

    看了下yolov4的作者给的操作说明 链接如下 https github com AlexeyAB darknet how to compile on linux using make 有兴趣的可以去看看 总结起来 跟yolov3的操作方式

随机推荐