YOLO物体检测-系列教程5:YOLOV3项目实战2之 darknet模型构造、前向传播计算方式

news/2024/7/10 23:57:36 标签: YOLO, 图像处理, 物体检测, 深度学习, cnn

🎈🎈🎈YOLO 系列教程 总目录

上篇内容:

YOLOV3项目实战1之 整体介绍与数据处理

YOLOV3提出论文:《Yolov3: An incremental improvement》

4、模型创建函数

模型创建函数 位置:项目 / utils / models.py / def create_modules

def create_modules(module_defs):
    hyperparams = module_defs.pop(0)
    output_filters = [int(hyperparams["channels"])]
    module_list = nn.ModuleList()
    for module_i, module_def in enumerate(module_defs):
        modules = nn.Sequential()
        if module_def["type"] == "convolutional":(暂时省略)
        elif module_def["type"] == "maxpool":(暂时省略)
        elif module_def["type"] == "upsample":(暂时省略)
        elif module_def["type"] == "route":(暂时省略)
        elif module_def["type"] == "shortcut":(暂时省略)
        elif module_def["type"] == "yolo":(暂时省略)
        module_list.append(modules)
        output_filters.append(filters)
    return hyperparams, module_list
  1. 模型创建函数,读进来配置文件module_defs
  2. 从 module_defs 列表中移除第一个元素,并将其存储在 hyperparams 变量中。这个元素通常包含了一些超参数(例如,输入通道数和其他配置信息),它们用于定义网络的输入和全局参数
  3. 创建了一个名为 output_filters 的列表,其中包含一个整数,表示模型的输出通道数
  4. 创建了一个空的 PyTorch ModuleList 对象,用于存储神经网络的各个模块
  5. 迭代 module_defs 列表,逐个处理模块的定义,module_i 是当前迭代的模块索引,module_def 包含了当前模块的配置信息,例如模块的类型、参数等
  6. 在每次迭代中,创建了一个空的 PyTorch Sequential 容器,用于存储当前模块中的层次。
  7. 接下来是6个多向if语判断句,分别为:
    1. 处理卷积层的情况
    2. 最大池化层
    3. 上采样层
    4. 路由层
    5. 快捷连接层
    6. YOLO
  8. module_list.append(modules)这一行代码将当前处理的模块的层次结构 modules 添加到神经网络模型的 module_list 中。module_list 是一个 PyTorch ModuleList 对象,它用于存储神经网络的各个模块(例如卷积层、池化层、激活函数等)
  9. output_filters.append(filters):这一行代码将当前处理的模块的输出通道数 filters 添加到 output_filters 列表中。output_filters 用于跟踪每个模块的输出通道数,以便在构建下一个模块时确定输入通道数。

5、卷积层的处理

4中介绍了模型创建函数,但是if判断语句中没有给出内容,在5介绍一下卷积层是如何处理的

if module_def["type"] == "convolutional":
    bn = int(module_def["batch_normalize"])
    filters = int(module_def["filters"])
    kernel_size = int(module_def["size"])
    pad = (kernel_size - 1) // 2
    modules.add_module(
        f"conv_{module_i}",
        nn.Conv2d(
            in_channels=output_filters[-1],
            out_channels=filters,
            kernel_size=kernel_size,
            stride=int(module_def["stride"]),
            padding=pad,
            bias=not bn,
        ),
    )
    if bn:
        modules.add_module(f"batch_norm_{module_i}", nn.BatchNorm2d(filters, momentum=0.9, eps=1e-5))
    if module_def["activation"] == "leaky":
        modules.add_module(f"leaky_{module_i}", nn.LeakyReLU(0.1))
  1. 检查当前type值为convolutional,即卷积层:在配置文件中,每个模块开头都有一个中括号括起来的部分,这个是一个type值。
  2. 解析是否应该使用批归一化的信息,将其转换为整数值。如果 batch_normalize 为1,表示应该使用批归一化,否则为0,表示不使用。
  3. 解析卷积层的输出通道数(即卷积核数量)
  4. 解析卷积核的大小。
  5. 计算卷积层的填充大小,以确保输出的特征图尺寸与输入一致。
  6. 使用 PyTorch 的 nn.Conv2d 创建卷积层并添加到 modules 容器中:
    1. 输入通道数等于上一层的输出通道数
    2. 输出通道数等于当前卷积层的配置中指定的通道数
    3. 卷积核大小
    4. 卷积层的步幅
    5. 填充大小
    6. 是否使用偏置项。如果使用批归一化 (bn 为1),则不使用偏置项
  7. 如果 bn 为真(即应该使用批归一化),则添加批归一化层到 modules 容器中:nn.BatchNorm2d(filters, momentum=0.9, eps=1e-5):创建批归一化层,其中 filters 表示通道数,momentum 和 eps 是批归一化的超参数。
  8. 如果当前卷积层的激活函数为 “leaky”,则添加 Leaky ReLU 激活函数层到 modules 容器中:nn.LeakyReLU(0.1):创建 Leaky ReLU 激活函数层,参数 0.1 是斜率,控制着负数部分的输出

6、最大池化层的处理

elif module_def["type"] == "maxpool":
    kernel_size = int(module_def["size"])
    stride = int(module_def["stride"])
    if kernel_size == 2 and stride == 1:
        modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1)))
    maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2))
    modules.add_module(f"maxpool_{module_i}", maxpool)
  1. elif module_def["type"] == "maxpool"::这个条件语句检查当前模块是否为最大池化层
  2. kernel_size = int(module_def["size"]):解析模块配置中的池化核大小,将其转换为整数
  3. stride = int(module_def["stride"]):解析模块配置中的池化层步幅,将其转换为整数
  4. if kernel_size == 2 and stride == 1::这一行代码检查是否满足一个特定条件,即池化核大小为2且步幅为1。如果满足这个条件,就执行下面的操作
    • modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1))):这里添加了一个用于调试的零填充层。具体来说,它使用 nn.ZeroPad2d 在输入图像的底部和右侧各添加一列零填充。这个填充的目的可能是为了处理特定情况下的池化层,以确保输出大小与输入大小一致。这个步骤通常是为了处理某些特殊情况而添加的
  5. 创建最大池化层并添加到 modules 容器中:
    • maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2)):创建最大池化层,其中包括池化核大小、步幅和填充大小的配置
    • modules.add_module(f"maxpool_{module_i}", maxpool):将最大池化层添加到 modules 容器中,命名为 maxpool_{module_i},其中 module_i 是当前模块的索引

通过上述操作,当前最大池化层的配置被解析,并相应地创建了相应的 PyTorch 模块,这些模块将在神经网络模型中用于后续的前向传播计算。最大池化层用于减小特征图的尺寸,以帮助网络提取更高级别的特征。

7、上采样层的处理

8、快捷连接层的处理

9、yolo层的处理

10、读取配置文件

配置文件:项目位置\PyTorch-YOLOv3\config\yolov3.cfg
部分参数展示:

batch=16
subdivisions=1
width=416

[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky

上面主要是一些训练参数,紧接着都是卷积的参数
模型文件:项目位置\PyTorch-YOLOv3\models.py
我们的主体模型在darknet.类中,是model.py文件中的一个类,实际上就是darknet53

在PyTorch深度学习框架中,用类来定义模型,类的构造函数用来定义模型的参数,forward函数用来定义前向传播计算方法

class Darknet(nn.Module):
    def __init__(self, config_path, img_size=416):
        super(Darknet, self).__init__()
        self.module_defs = parse_model_config(config_path)
        self.hyperparams, self.module_list = create_modules(self.module_defs)
        self.yolo_layers = [layer[0] for layer in self.module_list if hasattr(layer[0], "metrics")]
        self.img_size = img_size
        self.seen = 0
        self.header_info = np.array([0, 0, 0, self.seen, 0], dtype=np.int32)
  1. parse_model_config方法读取配置文件
  2. 创建模型

这个构造函数,在读取参数的同时也定义了大部分的网络结构


http://www.niftyadmin.cn/n/5029144.html

相关文章

用python代码写中秋电影动画送对象

好,中秋节快到了,那我们就写个代码送对象吧! 目录 基础代码 添加月兔和月饼 加上颜色 添加动作 添加兔子动作 成品 基础代码 直接上print时间复杂度杠杠的: import timedef send_mid_autumn_movie_to_girlfriend():pri…

使用Python编写一个多线程的12306抢票程序

国庆长假即将到来,大家纷纷计划着自己的旅行行程。然而,对于很多人来说,抢购火车票人们成了一个令人头疼的问题。12306网站的服务器经常因为流量高而崩溃,导致抢票变得越来越严重异常困难。 首先,让我们来了解一下1230…

中老年美文视频祝福打卡流量主小程序开发

一款针对中老年朋友开发的祝福打卡小程序。 爷爷奶奶、爸爸妈妈都非常喜欢的小程序,支持卡片祝福、视频祝福、美文祝福,而且可以搭配每日打卡、万年历等多种工具模块,提高小程序适用率。一键转发到好友和群可以提高小程序的传播度&#xff0…

前端mounted的使用

今天完成了一个前端的需求,将前端页面的固定值换成从后端查询的值,后端的接口已经写好,主要是前端的编写。 1.新建一个js文件 import request from /utils/request; export function getMusic() {return request({method: POST,url: /music…

CPU的三级缓存

CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多。高速缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多&#…

肖sir__mysql之三表__008

mysql之三表 create table student( stu_no int, stu_name varchar(10), sex char(1), age int(3), edit varchar(20) ) DEFAULT charsetutf8; insert into student values (1,‘wang’,‘男’,21,‘hello’), (2,‘小明’,‘女’,22,‘haha2’), (3,‘hu’,‘女’,23,‘haha3…

图片拖动验证效果(源码)

JS案例图片拖动验证 🌟效果展示 🌟前置知识 CSS sprite 精灵图 🌟 代码实现 页面搭建 距离计算 逻辑部分 随机生成背景图片 计算拖动图块和空缺图块的位置 绑定事件 🌟写在最后 🌟效果展示 🌟…

RK3588 添加I2C模拟芯片CH423

一.简介 有时候会遇到IO不够用的情况,例如说驱动LED灯,那么有没有什么便宜的,容易买到的芯片?我这次就考虑使用WCH的CH423S,这是一个比较新的IO扩展芯片。 二.硬件原理图 使用gpio来模拟IIC,飞线处理&…