# yolo3
**Repository Path**: hellozahn/yolo3
## Basic Information
- **Project Name**: yolo3
- **Description**: 使用yolo3实现目标检测
- **Primary Language**: Unknown
- **License**: GPL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2024-03-07
- **Last Updated**: 2024-11-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# YOLO3实现目标检测
> 注意:保存权重的.pt文件太大,无法上传,需手动修改参数文件相关路径后,在net文件夹创建weights文件保存权重
## 项目实现步骤
1. 准备数据集
2. 自定义数据集
3. 构建网络模型
4. 训练模型
5. 推理预测
6. 计算评价指标
## 1-准备数据集
1. 按帧数读取视频保存图片 video2frame.py
2. 使用labelimg标注工具对图片进行标注
3. 统一图片大小为 416x416,并把标签等信息写成.xml文件 conver_point.py
4. 读取缩放后的标签图片,转为左上角右下角坐标信息 voc2yolo_v3.py
## 2-自定义数据集
1. 准备数据集
- 使用标注工具(labelimg)给图片标注标签,转换为YOLO可用的格式
- 标签框信息:类别 + 中心点坐标 + 宽高
- cls, cx, cy, w, h
2. 准备锚框
- 自定义锚框,3类检测目标各3种锚框,共9种锚框
- 获取锚框宽高 anchor_w, anchor_h,用于tw, th的制作
3. 标签形状更换
- C H W --> H W C
- 如:使用13x13,四分类
- 13, 13, 27 --> (情况1) 13, 13, 3, 9 (情况2) 3, 13, 13, 9
4. 填值(one-hot编码)
- tx, ty, tw, th, one-hot
- tx = 坐标x偏移量
- ty = 坐标y偏移量
- tw = torch.log(gt_w / anchor_w)
- th = torch.log(gt_h / anchor_h)
## 3-构建网络模型
### 网络结构
1. 主干网络 backbone
- 卷积层 CBL
- Conv
- BN
- LeakReLu
- 残差单元 ResUnit
- 下采样 DownSample
2. neck
- 卷积集合 ConvolutionSet
- 卷积层 CBL
- 上采样 UpSample
- 拼接操作 torch.cat
3. head
- 卷积层 CBL
- 全卷积预测
- 类别 x 锚框
- ( 1 + 4 + 4 ) x 3
### 实现结构
1. module.py
- 卷积层 CBL
- 残差单元 ResUnit
- 下采样 DownSample
- 上采样 UpSample
- 卷积集合 ConvolutionSet
2. data.yaml
- 保存主干网络结构的参数:通道数、残差块数量
3. darknet53.py
- 实现主干网络结构,输出out_13x13, out_26x26, out_52x52
4. yolov3.py
- 初始化主干网络,实现neck、head网络结构,输出detect_13_out, detect_26_out, detect_52_out
## 4-训练模型
### 分析
1. 准备数据dataset
2. 初始化网络模型
3. 损失函数
- 目标检测
- 正样本
- 置信度:二分类交叉熵
- 坐标:均方差损失
- 类别:交叉熵损失
- 负样本
- 置信度:二分类交叉熵
4. 优化器
### 核心功能
1. train
- 网络模型开启训练
- 遍历数据加载器获得三种特征大小标签值、图片张量,并切换设备
- 图片张量传入网络获得三种预期输出
- 三种标签值、对应预期输出值和正负样本因子传入loss_fn,计算获得对应损失,并求和获得模型损失
- 优化器进行梯度清零
- 模型损失反向传播
- 优化器进行梯度更新
- 累加模型损失计算平均损失
- 保存模型权重
2. loss_fn
- 预期输出值更换通道 N 27 H W --> N H W 27 --> N H W 3 9
- 获取位置索引值
- 正样本数据位置 `target[..., 0] > 0`
- 负样本数据位置 `target[..., 0] == 0`
- 计算损失
- 正样本:置信度 坐标 类别
- 负样本:置信度
- 索引获取
- 0 置信度
- 1:5 坐标
- 5: 类别
- 正负样本乘上对应规模因子的累加和
## 5-推理预测
### 分析
1. 网络初始化,加载权重参数 net
2. 输入数据预处理(归一化) img_norm
3. 前向传播获得输出,输出数据形状是 N C H W --> N 3(锚框数量 anchor_num) 9 H W
4. 根据给定的阈值 thresh 获取符合阈值要求目标的索引
- `idx = torch.where([:, :, 0, :, :] > thresh`
- `N: idx[0]`
- `anchor_num = idx[1]`
- `H(rows): idx[2]`
- `W(cols): idx[3]`
5. 解码中心点坐标 cx cy
- `cx_idx = 2`
- `cy_idx = 1`
- `tx = [:, :, 1, :, :]`
- `ty = [:, :, 2, :, :]`
- `tw = [:, :, 3, :, :]`
- `th = [:, :, 4, :, :]`
- `cx = (cx_idx + tx) * 32`
- `cy = (cy_idx + ty) * 32`
- `pred_w = exp(tw) * anchor_w`
- `pred_h = exp(th) * anchor_h`
### 核心功能
1. decode
- 预期输出值更换通道 N 27 H W --> N H W 27 --> N H W 3 9
- 获取检测框的坐标索引 锚框数量
- 获取检测框的标签信息 `[[conf, tx, ty, tw, th, cls], ...]`
- 方式1:`label = pred_out[idx[0], idx[1], idx[2], idx[3], :]`
- 方式2:`label = pred_out[idx]`
- 计算检测框的中心坐标 宽高
- 规模因子 = 原图大小 / 特征大小
- 获取当前特征对应的三种锚框
- 获取索引对应的锚框的宽高
- 坐标转换:中心点坐标+宽高 --> 左上角坐标+右下角坐标
- torch.stack 整合坐标 `[conf, x_min, y_min, x_max, y_max, cls]`
2. bbox_iou
- 计算标签框和输出框的交并比
3. nms
- 模型输出的框,按置信度排序
- 置信度最高的,作为当前类别最优的框 `max_conf_box = detect_boxes[0]`
- 剩余的框 `detect_boxes[1:]` 和当前最优框 `max_conf_box` 计算IOU `获取 iou_val`
- 和给定阈值(超参数)作比较 `iou_idx = iou_val < thresh`
- `detect_boxes[1:][iou_idx]` 则为保留的框
4. forward
- 图像预处理
- 图片转为张量
- 扩张维度,表示批次
- 图片张量传给网络获得检测输出
- 对检测输出进行解码 decode,获得检测框信息
- 拼接大中小目标框信息并返回
5. run
- 传入图片进行前向传播,获得预测框信息
- 根据不同类别,遍历框信息,进行NMS,获得各类别最优框
- 不同类别绘制不同颜色的检测框,并标注类别名
- 保存框的置信度和坐标信息,以便计算mAP
## 6-计算评价指标
1. Github上下载一个mAP源码(如:`https://github.com/Cartucho/mAP.git`)
2. 手动创建计算mAP的输入数据文件夹
- input
- detection-results:模型输出数据集
- ground-truth:标签数据集
- images-optional:原图缩放后的数据集

- data/VOC2007/YOLOv3_JPEGImages数据拷贝到images-optional
- data/VOC2007/Annotations数据拷贝到ground-truth
3. 运行convert_gt_xml.py,把`.xml`文件转为`.txt`文件
- 其中`.txt`文件保存的是图片标签框的类别名+坐标信息`cls_name xmin ymin xmax ymax`

4. detector.py取消142-146行代码的注释,运行代码后,detection-results文件夹会保存模型输出框的`.txt`文件
- 其中`.txt`文件保存的是图片标签框的类别名+置信度+坐标信息`cls_name conf xmin ymin xmax ymax`


5. 运行map.py会自动生成output文件,弹出mAP图

