YOLOV3 Pytorch版本代码解读

YOLOV3 Pytorch版本代码解读

代码与coco数据集关注wx公众号JokerTong回复yolov3即可获取
参考视频 YOLO系列算法


数据集准备与关键文件说明

使用经典的coco2014数据集,下载地址点击此处进入官网下载(也可以自行去网上搜索)
下载之后解压到项目对应的文件夹, 如下

下载的数据集imagelabel的版本需要一一对应
在这里插入图片描述
trainvalno5k.txt文件
在这里插入图片描述
5k.txt文件 : 验证集的数据的位置
在这里插入图片描述
PyTorch-YOLOv3\config\yolov3.cfg
网络配置文件
在这里插入图片描述

前提准备

代码大致流程

第一步: 加载配置参数
在这里插入图片描述
第二步: 构造模型
在这里插入图片描述
第三步: 读取数据
在这里插入图片描述

Tips: 以前在小数据集上进行训练的时候我们可以将数据集全部加载到内存中,但是由于coco数据集太大了, 内存放不下, 因此我们使用generator来提供数据, 在训练的过程中才读取数据, 根据模型的需要一个batch一个batch的为其提供数据
在这里插入图片描述

需要自行修改代码的部分

添加训练参数

--data_config config/coco.data  
--pretrained_weights weights/darknet53.conv.74

在这里插入图片描述
coco.data描述了训练数据集所需要的所有信息: 类别, 训练数据, 验证数据
在这里插入图片描述
pretrained_weights 迁移学习的思想, 加载一个预训练模型

修改数据集路径
在这里插入图片描述
在这里插入图片描述

项目代码解读

一 数据与标签的读取

109行打上断点, 观察数据的读取过程
在这里插入图片描述
点击Step Into My Code进入项目中的datasets.py文件, 可以看出, dataset通过getitem一张一张的读取图片
在这里插入图片描述
使用Image.open实际读取图片,统一通道为RGB,并且转换为tensor格式
在这里插入图片描述
使用padding的思想, 把原本的长方形图片padding为正方形
在这里插入图片描述
与读取图像类似, 读取对应的标签, 里面包括了类别, box的信息
在这里插入图片描述
这里要注意 图片的编号与标签的编号应该是对应的, 不然数据与标签不匹配训练结果啥也不是
在这里插入图片描述
读取label文件中的物体框信息
在这里插入图片描述

原始图像经过了padding处理, 因此标签中框的坐标也需要进行padding的操作, 最后转化为网络中需要的x,y,w,h格式
在这里插入图片描述
这一系列操作之后, 得到一个imgtarget, 后面会反复进行batch次, 然后返回模型一个batch的数据
在这里插入图片描述

二 模型构造

重新把断点打在66
在这里插入图片描述

进入models.py, init函数中根据之前的yolov3.cfg文件对网络整体架构进行定义, forward函数规定了网络前向传播的整个过程

在这里插入图片描述
加载配置文件的信息到self.module_defs变量中
在这里插入图片描述

self.hyperparams, self.module_list = create_modules(self.module_defs)  # 逐层定义好网络结构

调用create_modules来进行模型的构建
在这里插入图片描述
循环增加网络层

在这里插入图片描述

convolutional层的构建

注意这里的convolutional其实可能包括了卷积, BN, 以及Relu三种操作, 先将里面的参数信息读取出来

在这里插入图片描述
**根据参数信息 添加Conv2d 也就是卷积层 **在这里插入图片描述
如果有bn层以及激活函数, 将它们加入到网络结构当中
在这里插入图片描述
这里在控制台打印一下当前构造的modules, 其中包含了我们想要的三种层
在这里插入图片描述
也就是将之前构造完成的第一个模块加入到大的module_list当中, 并且记录下filters的输出个数
在这里插入图片描述

rout层与shortcut层的构建

这里只是创建了个空的层, 具体的操作执行在前向传播中
在这里插入图片描述
rout层主要起到拼接的作用, 起到了特征融合的作用
在这里插入图片描述

shortcut层主要是加法的作用(resnet的思想), 残差连接的功能已经很熟悉了, 这里就不介绍了
配置文件中的-3表示跟
在这里插入图片描述

yolo层的构建

YOLOV3中有三种YOLO层, 它们分别可以检测大中小三种物体

YOLOV3中有三种scale的先验框, 对应着这三种YOLO层, 感受野比较大的YOLO层对应使用大的先验框

这里通过anchor的编号获取实际先验框的大小

在这里插入图片描述
调用YOLOLayer来构建出YOLO层, 具体的前向传播在后面介绍
在这里插入图片描述

三 前向传播

在各个模型的forward处打上断点
首先进入的是Darknetforward
在这里插入图片描述
这里的卷积, 上采样, 和最大池化层的前向传播都非常简单, 根据pytorch内置的函数, 直接x = module(x)就可以了

            if module_def["type"] in ["convolutional", "upsample", "maxpool"]:
                x = module(x)
            elif module_def["type"] == "route":
                x = torch.cat([layer_outputs[int(layer_i)] for layer_i in module_def["layers"].split(",")], 1)
            elif module_def["type"] == "shortcut":
                layer_i = int(module_def["from"])
                x = layer_outputs[-1] + layer_outputs[layer_i]
  • route层的效果是按某个维度做拼接
  • shortcut层的效果是对两层做加法

最重要的是YOLO层

在这里插入图片描述
这里的img_dim可能有多种大小 但都能被32整除, 因为YOLOV3网络会随机的选择一个大小的图片进行训练

对于预测的维度进行调整, 4 * 3 * 15 * 15 * 85

  • 4 表示 batch_size
  • 3 表示 先验框的有三种
  • 15 * 15 为特征图的大小
  • 85 = 80 + 5 表示80个类别 与 x,y,w,h 与 置信度
    在这里插入图片描述
    取出其中的x,y,w,h,c与每个类别的预测值
    在这里插入图片描述
    通过相对位置得到对应的绝对位置
    在这里插入图片描述
    得到特征图(如当前为15*15)中各个坐标的实际位置
    在这里插入图片描述
    因为标签中的框是在原始图像中的, 所以output要把预测框也放大相应的倍数还原到原始图像中
    在这里插入图片描述

四 计算损失

通过build_targets函数将标签值进行转换, 转换成和预测值相同的格式, 这里可以点进去自己看一下build_targets的内容
在这里插入图片描述
计算loss

  • 对于x,y,w,h来说, 并不是所有的位置都要算一遍, 我们只计算有物体的位置处的损失, 所以这里用了obj_mask作为index
  • loss_conf_obj, loss_conf_noobj计算的是前景和背景的损失, 也就是当前位置是不是物体. 因为这里的预测值和真实值只有01, 所以使用bce_loss即可计算
    他们两个相加, 乘上相应的权重参数就得到了置信度损失loss_conf_noobj
  • loss_cls分类损失的原理也类似

最终将所有的损失相加就得到了总损失
在这里插入图片描述
这里附上一张损失函数的计算图像, 可以看出和代码中的一样, 很好理解
请添加图片描述
后面的操作基本上是通用的pytorch训练模式

猜你喜欢

转载自blog.csdn.net/Weary_PJ/article/details/128749270