当前位置: 首页 > news >正文

【YOLO V3】目标检测 Darknet 训练自定义模型

【YOLO V3】目标检测 Darknet 训练自定义模型

  • 前言
  • 整体思路
  • 环境检查与依赖配置
  • 克隆 YOLOv3 Darknet 并编译
    • Clone Darknet 项目文件
    • 修改 Makefile 文件
    • 修改模型保存频率
    • 项目编译
  • 准备数据集
  • 配置训练文件
    • 数据集:`datasets` (自制)
    • 权重文件 `yolov3-tiny.weights` (下载)
    • 预训练卷积层权重文件:`yolov3-tiny.conv.15` (下载)
    • 标签索引文件 `classes.names` (自制)
    • 数据集配置文件 `mydata.data` (自制)
    • 模型配置文件:`yolov3-tiny.cfg` (修改)
      • 第一处修改
      • 第二处修改
      • 第三处修改
    • 预先准备文件夹
  • 模型训练
  • 导出训练结果

前言

对于初学者而言,学习 YOLO 并实现目标检测时,并不需要深入理解底层原理。本篇文章的重点是如何快速上手 YOLOv3,使用 Darknet 源码训练自定义模型,并实现目标检测。

PS:本文适用于已有 YOLOv5 基础的读者,你可以参考【YOLO V5】目标检测 WSL2 AutoDL VScode SSH学习 YOLOv5。由于 YOLOv5 的 PyTorch 训练方式与 YOLOv3 的 Darknet 训练方法存在相似之处,两者是互通的,这将有助于你更快理解和上手 YOLOv3。

我的环境:
WSL2 Ubuntu 20.04 YOLOv3 Darknet

关联文章:

  • 【YOLO V5】目标检测 WSL2 AutoDL VScode SSH
  • 【YOLO】X-Anylabeling 数据集标注
  • 【YOLO】X-AnyLabeling 半自动标注

参考资料:

  • Darknet框架2:YOLOV3-使用Darknet训练检测自定义模型+COCO数据集!
  • YOLOV3 - 使用 Darknet 训练检测模型

整体思路

环境检查与依赖配置—克隆 YOLOv3 Darknet 并编译—准备数据集—配置训练文件—模型训练—导出训练结果

  1. 环境检查与依赖配置:确保 OpenCV 版本为 2.x 或 3.x,避免使用 OpenCV 4.x,因为 Darknet C 框架当前不兼容 OpenCV 4.x。
  2. 克隆 YOLOv3 Darknet 并编译:从官方源码仓库克隆 Darknet,修改 Makefile 以适配环境,修改模型保存频率。
  3. 准备数据集:确保数据集符合 YOLOv3 Darknet 训练要求,即采用 YOLO 格式(.txt 标签文件与对应的图片)。
  4. 配置训练文件:准备以下关键配置文件:.weights(预训练权重)classes.names(类别标签索引) mydata.data(数据集配置) .cfg(模型结构参数) .conv.x(预训练特征提取层权重)
    【对应于 YOLOv5 的 .ptclasses.txt(YOLOv5 实际上不使用)、mydata.yamlyolov5s.yaml
  5. 模型训练:基于 Darknet 框架启动训练过程,优化模型权重。
  6. 导出训练结果:生成最终的 .weights 权重文件,供后续部署与推理使用。

环境检查与依赖配置

在此步骤中,需确保 OpenCV 版本为 2.x 或 3.x,因 Darknet 训练不兼容 OpenCV 4.x。若当前 OpenCV 版本不符合要求,请参考相关资料进行降级或在虚拟环境中安装较低版本。

克隆 YOLOv3 Darknet 并编译

Clone Darknet 项目文件

git clone https://github.com/pjreddie/darknet
cd darknet

修改 Makefile 文件

修改 Makefile 时,重点关注前几行的配置,通常只需调整前五行及 ARCH 参数,其余部分会由 Makefile 自动处理。若编译时报错,再根据具体错误信息进行调整。

# 编译选项开关(根据自身需求修改)
GPU=1    # 是否启用 GPU 支持 (1:启用, 0:禁用)
CUDNN=1  # 是否启用 CUDNN 加速库 (1:启用, 0:禁用)
OPENCV=1 # 是否启用 OpenCV 支持 (1:启用, 0:禁用)
OPENMP=0 # 是否启用 OpenMP 并行计算 (1:启用, 0:禁用)
DEBUG=0  # 是否启用调试模式 (1:启用, 0:禁用)

# NVIDIA GPU 架构设置
# compute_XX 表示虚拟架构版本,sm_XX 表示实际架构版本
# 支持多个不同的 GPU 架构版本编译
# 支持的 GPU 架构配置包括:
# Kepler, Maxwell, Turing, Ampere 和 Ada Lovelace
ARCH= -gencode arch=compute_30,code=sm_30 \
      -gencode arch=compute_35,code=sm_35 \
      -gencode arch=compute_50,code=[sm_50,compute_50] \
      -gencode arch=compute_52,code=[sm_52,compute_52] \
      -gencode arch=compute_75,code=[sm_75,compute_75] \
      -gencode arch=compute_86,code=[sm_86,compute_86] \
      -gencode arch=compute_89,code=[sm_89,compute_89]
# compute_30/35: Kepler
# compute_50/52: Maxwell
# compute_75: Turing (RTX 2080 Ti)
# compute_86: Ampere (RTX 3090/3060)
# compute_89: Ada Lovelace (RTX 4090)

# 如果明确知道自己的 GPU 架构,可以取消下面的注释并指定
# ARCH= -gencode arch=compute_52,code=compute_52

VPATH=./src/:./examples
SLIB=libdarknet.so
ALIB=libdarknet.a
EXEC=darknet
OBJDIR=./obj/

CC=gcc
CPP=g++
NVCC=nvcc 
AR=ar
ARFLAGS=rcs
OPTS=-Ofast
LDFLAGS= -lm -pthread 
COMMON= -Iinclude/ -Isrc/
CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC


# OpenCV 相关配置
# 当 OPENCV=1 时启用以下配置
ifeq ($(OPENCV), 1) 
COMMON+= -DOPENCV    # 添加 OpenCV 宏定义
CFLAGS+= -DOPENCV    # 编译标志添加 OpenCV 支持
LDFLAGS+= `pkg-config --libs opencv` -lstdc++    # 链接 OpenCV 库和 C++ 标准库
COMMON+= `pkg-config --cflags opencv`            # 添加 OpenCV 头文件路径
# 下面两行是 OpenCV4 的配置,如果使用 OpenCV4 则取消注释
# LDFLAGS+= `pkg-config --libs opencv4` -lstdc++
# COMMON+= `pkg-config --cflags opencv4` 
endif

# CUDA 相关配置
# 当 GPU=1 时启用以下配置
ifeq ($(GPU), 1) 
COMMON+= -DGPU -I/usr/local/cuda/include/    # 添加 CUDA 宏定义和头文件路径
CFLAGS+= -DGPU                               # 编译标志添加 GPU 支持
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand    # 链接 CUDA 相关库
endif

# CUDNN 相关配置
# 当 CUDNN=1 时启用以下配置
ifeq ($(CUDNN), 1) 
COMMON+= -DCUDNN     # 添加 CUDNN 宏定义
CFLAGS+= -DCUDNN     # 编译标志添加 CUDNN 支持
LDFLAGS+= -lcudnn    # 链接 CUDNN 库
endif

修改模型保存频率

进入 darknet/examples/detector.c 文件,找到第 138 行的以下代码:

        if(i%10000==0 || (i < 1000 && i%100 == 0)){
#ifdef GPU

将其修改为:

if(i%1000==0){
#ifdef GPU

项目编译

make -j$(nproc)

make -j$(nproc) 通过并行使用所有 CPU 核心加速编译,提高编译效率。

准备数据集

准备数据集时,可参考:

  • 【YOLO】X-Anylabeling 数据集标注
  • 【YOLO】X-AnyLabeling 半自动标注。

【YOLO】X-Anylabeling 数据集标注 中写的的标签导出为 YOLO 格式,无需额外转换。该文章提供的数据集拆分脚本会自动生成 train.txt、test.txt 和 val.txt 文件,完全符合 Darknet YOLO 训练的要求。

所需的数据集结构应如下所示:
在这里插入图片描述
在 train.txt 文件中,每行应包含一个训练图像的路径,如下所示:
在这里插入图片描述

如果训练时的路径与导出时不一致,可以使用 VSCode 的搜索与替换功能,将文件内所有路径前缀更改为实际路径。
在这里插入图片描述

配置训练文件

本文以 YOLOv3-tiny 模型为例,首先需要准备以下训练文件:

  • 数据集: datasets 数据集文件夹
  • 权重文件yolov3-tiny.weights
  • 预训练卷积层权重文件yolov3-tiny.conv.15
  • 标签索引文件classes.names
  • 数据集配置文件mydata.data
  • 模型配置文件yolov3-tiny.cfg
  1. 建议将这些文件统一放入一个文件夹中进行管理,例如命名为 abaaba 文件夹,这样便于上传到服务器并组织好所有预先准备的训练和配置文件。

  2. 我习惯于将工程文件夹、预先准备的训练文件和数据集压缩后,直接通过 VSCode 的 SSH 功能上传到服务器。这样比使用 wget 更为高效,避免了传输速率慢的问题。

文件下载地址:

  • yolov3-tiny.weights
  • yolov3-tiny.conv.15

数据集:datasets (自制)

根据前文提到的两篇文章的操作步骤,准备好自制的数据集,并将其存放到自定义的文件夹中即可,例如 abaaba 文件夹。

权重文件 yolov3-tiny.weights (下载)

该 yolov3-tiny.weights 权重文件可以直接下载,并存放到自定义的文件夹中,例如 abaaba 文件夹。

预训练卷积层权重文件:yolov3-tiny.conv.15 (下载)

该yolov3-tiny.conv.15文件可以直接下载,并存放到自定义的文件夹中,例如 abaaba 文件夹。

标签索引文件 classes.names (自制)

标签索引文件的名称可以自定义,但文件后缀必须为 .names
该文件中的每一行对应一个类别名称,并且类别顺序必须与标注时的顺序一致因为 YOLO 标签使用从 0 到 n 的数字索引来对应不同类别,所以类别顺序必须严格保持一致。

例如: classes.names

watermelon
banana
apple
milk
red
green
pepper
cake
cola
potato
tomato

该标签索引文件的含义是*:在 YOLO 的 .txt 标签文件中,索引 0 对应 watermelon,索引 1 对应 banana,以此类推,顺序必须与类别一致。

数据集配置文件 mydata.data (自制)

以下仅为示例,请根据你的项目实际情况调整路径配置,但格式需保持一致:

classes = 11  # 目标检测类别数量
train = /root/darknet_AutoDL/abaaba/datasets/train.txt  # 训练集图片路径列表文件
valid = /root/darknet_AutoDL/abaaba/datasets/val.txt    # 验证集图片路径列表文件 
names = /root/darknet_AutoDL/abaaba/classes.names       # 类别名称文件,每行一个类别名称
backup = root/darknet_AutoDL/backup                     # 训练过程中权重文件的保存目录

模型配置文件:yolov3-tiny.cfg (修改)

该文件位于 yolo/darknet/cfg/yolov3-tiny.cfg 中,我们需要根据实际情况修改一些参数。

第一处修改

在 yolov3-tiny.cfg 文件的开头几行,根据训练或测试阶段的不同,注释掉不需要的配置在训练时,注释掉测试相关的配置;在测试时,注释掉训练相关的配置。

以训练时为例:

# 测试/推理阶段配置 (训练时注释掉这几行)
# batch=1      # 推理时每批处理1张图片
# subdivisions=1  # 不需要进行批次细分

# 训练阶段配置 (测试/推理时注释掉这几行)
batch=96        # 每次迭代训练96张图片
subdivisions=2  # 将batch分成2份,降低GPU显存占用
                # 实际每次处理: batch/subdivisions = 2张图片
                # 较小的subdivisions训练更快但需要更多显存
                # 如果显存不足,可以增加subdivisions的值

第二处修改

在 darknet 配置文件的第 20 行左右,找到 max_batches 参数,并根据实际需求修改。
该参数表示模型将在多少次迭代后停止训练,是迭代的总次数。

对于 max_batches 参数的设置,一般建议将其设置为 类别数 * 2000。

max_batches = 22000   # 11*2000 = 22000

适当增加该参数可以提高模型的性能,但过大的值可能会导致过拟合。根据数据集的大小和类别数调整这一参数,以达到最佳训练效果。

需要注意的是
darknet 的训练方式与 PyTorch 不同。darknet 是基于每次迭代来更新模型,而 PyTorch 是基于每轮训练来更新。具体来说,darknet 中一次迭代对应一次完整的 batch 训练,例如如果 batch 大小为 64,那么一次迭代就是使用 64 张图片进行训练并更新权重。

第三处修改

  1. 找到文件中的多个 [yolo] 标签
  2. 将每个 [yolo] 标签下的 classes 修改为实际检测的类别数量
  3. 修改每个 [yolo] 标签的上面紧挨的 [convolutional] 层,将其中的 filters 参数设置为 filters = 3 * (classes + 5),例如,如果类别为 4,则 filters = 3 * (4 + 5) = 27

每个 [yolo] 标签和紧挨着的 [convolutional] 层中的这两个参数都需要根据实际情况进行修改

例如:

# 卷积层配置
[convolutional]
size=1
stride=1
pad=1
filters=48        # filters = 3 * ( classes + 5 ),如,filters= 3*(11+5) = 48
activation=linear

# yolo配置
[yolo]
mask = 3,4,5
anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319
classes=11        #自定义数据集的类别数
num=6
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

预先准备文件夹

预先准备的文件夹 abaaba 如下图所示,用于上传到服务器进行训练。
在这里插入图片描述

模型训练

将上文准备好的 abaaba 文件夹放置于项目根目录下。

  • 如果自制的数据集与 COCO 数据集差异较大,可以使用 conv.15 文件从头开始训练自己的数据集:
./darknet detector train /root/darknet_AutoDL/abaaba/mydata.data /root/darknet_AutoDL/abaaba/yolov3-tiny.cfg /root/darknet_AutoDL/abaaba/yolov3-tiny.conv.15

或者使用续行符

./darknet detector train \
    /root/darknet_AutoDL/abaaba/mydata.data \
    /root/darknet_AutoDL/abaaba/yolov3-tiny.cfg \
    /root/darknet_AutoDL/abaaba/yolov3-tiny.conv.15
  • 如果自制的数据集与 COCO 数据集差异较小,可以基于 yolov3-tiny.weights 进行微调:
./darknet detector train /root/darknet_AutoDL/abaaba/mydata.data /root/darknet_AutoDL/abaaba/yolov3-tiny.cfg /root/darknet_AutoDL/abaaba/yolov3-tiny.weights

或者使用续行符

./darknet detector train \
    /root/darknet_AutoDL/abaaba/mydata.data \
    /root/darknet_AutoDL/abaaba/yolov3-tiny.cfg \
    /root/darknet_AutoDL/abaaba/yolov3-tiny.weights

请注意,参数的顺序必须严格按照上述顺序,这是固定的顺序。

拓展知识:

  • yolov3-tiny.weights 是在 COCO 数据集上完整训练的模型权重文件,包含了所有层的参数(卷积层 + 检测层),已学习 COCO 数据集的 80 个类别的特征,适合迁移学习/微调。如果你的任务与 COCO 类别相似,使用该权重可以加快收敛。

  • yolov3-tiny.conv.15 只包含模型前 15 层的卷积层权重,没有涉及与特定类别相关的检测层权重,适合从头开始训练自己的数据集,避免 COCO 数据集类别特征的干扰。

导出训练结果

模型权重文件的保存位置由 mydata.data 文件中的 backup 参数指定,通常默认保存在项目根目录下的 backup 文件夹中。

具体示例:

backup/
├── yolov3-tiny_last.weights    # 最后一次迭代的权重
├── yolov3-tiny_1000.weights    # 第1000次迭代的权重
├── yolov3-tiny_2000.weights    # 第2000次迭代的权重
└── yolov3-tiny_best.weights    # 最佳性能的权重

相关文章:

  • uniapp超简单ios截屏和上传app store构建版本方法
  • 什么是视图,数据库的视图本质上就是个提前写好的sql语句,创建的一个虚拟表
  • VMWare Ubuntu 详细安装教程
  • 贪心算法(11)(java)加油站
  • Flask接口开发--引入mysql
  • 刷机维修进阶教程-----adb禁用错了系统app导致无法开机 如何保数据无损恢复机型
  • 2025年- G27-Lc101-542. 01 矩阵--java版
  • SQL GROUP BY 自定义排序规则
  • Linux:一些命令记录
  • vue3+vite+js快速搭建前端项目
  • OpenCV正确安装及环境变量配置
  • Langchain 自定义工具和内置工具
  • 关于脏读,不可重复读和幻读
  • LeetCode热题100JS(69/100)第十三天|34|33|153|4|20
  • 论文写作篇#7:YOLO论文中的全称和缩写,什么时候全称什么时候缩写,全称和缩写谁在括号里?
  • 约束文件SDC常用命令
  • 【Go】数组
  • 中间件监控:保障应用稳定性和响应速度
  • Servlet中request、response、session 用法
  • C++学习笔记(二十五)——vector
  • 移动互联网未成年人模式正式发布
  • 李铁案二审今日宣判
  • 丁俊晖连续7年止步世锦赛16强,中国军团到了接棒的时候
  • 大理杨徐邱再审上诉案宣判:驳回上诉,维持再审一审判决
  • 国家发改委:建立实施育儿补贴制度
  • 上海首个航空前置货站落户松江综合保税区,通关效率可提升30%