# 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:原图缩放后的数据集
![img.png](img.png) - 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`
![img_3.png](img_3.png) 4. detector.py取消142-146行代码的注释,运行代码后,detection-results文件夹会保存模型输出框的`.txt`文件 - 其中`.txt`文件保存的是图片标签框的类别名+置信度+坐标信息`cls_name conf xmin ymin xmax ymax`
![img_1.png](img_1.png)
![img_2.png](img_2.png) 5. 运行map.py会自动生成output文件,弹出mAP图
![img_4.png](img_4.png)
![img_5.png](img_5.png)