YOLO11自定义数据集训练教程_基于ultralytics-8.3.253_2026版
Windows 下复现 YOLO11 目标检测训练:数据准备、环境安装、训练验证与模型导出
文章摘要
本文以 Ultralytics 8.3.253 源码版本为基础,重新整理 YOLO11 自定义目标检测数据集训练流程。文章从版本固定、数据采集、标注规范、目录整理、Windows 环境安装、数据集 YAML 配置、CLI 与 Python 两种训练方式、预测验证、结果查看、模型导出和常见问题排查几个角度展开。重点不是介绍 YOLO11 的理论细节,而是让读者能够在自己的电脑上把数据集跑通,并为后续 YOLO11 改进、部署和项目实战文章打好统一代码基础。
CSDN 标签
- YOLO11
- Ultralytics
- 目标检测
- PyTorch
- Windows
- 深度学习
- 自定义数据集
- 模型训练
前言
很多 YOLO 教程写得比较早,里面使用的命令、源码路径和模型名称已经和现在的 Ultralytics 项目不完全一致。如果直接拿旧文章去套 YOLO11,经常会遇到两个问题:一个是读者找不到对应文件,另一个是后面写模型改进文章时,不同版本代码结构对不上。
所以这篇文章重新基于 ultralytics-8.3.253 版本来写。本文不追求把所有参数都讲完,而是先把目标检测训练最核心的一条线跑通:
准备图片 -> 标注目标 -> 整理数据集 -> 配置环境 -> 训练 YOLO11 -> 验证模型 -> 导出权重
后续如果要做 YOLO11 添加注意力机制、替换 Neck、导出 ONNX、TensorRT 部署等内容,都可以继续沿用这个版本,减少因为版本变化带来的复现问题。
一、先把版本固定住:为什么本文使用 Ultralytics 8.3.253
本文使用的是本地源码压缩包:
ultralytics-8.3.253.zip
解压后可以在 ultralytics/__init__.py 中看到版本号:
__version__ = "8.3.253"
这个版本已经包含 YOLO11 的模型配置,目标检测模型配置文件在:
ultralytics/cfg/models/11/yolo11.yaml
固定版本有三个好处:
- 后面修改源码时,文件位置不会变来变去。
- 写系列文章时,读者能使用同一套代码复现。
- 出现报错时,更容易判断是代码问题、环境问题还是数据集问题。
需要注意的是,直接执行 pip install ultralytics 可能会安装到更新版本。如果本文是为了后续改进 YOLO11 源码,建议使用源码安装方式,而不是只安装 PyPI 最新包。
二、先规划数据来源:别急着训练模型
训练目标检测模型之前,最容易被忽略的是数据质量。模型能不能学好,很多时候不是由训练命令决定的,而是由图片是否贴近真实应用场景决定的。
常见数据来源可以分成几类:
| 数据来源 | 适合情况 | 注意点 |
|---|---|---|
| 自己拍摄 | 工业检测、农业检测、安防监控等真实项目 | 场景最贴近实际,但采集成本高 |
| 开源数据集 | 类别常见、任务通用 | 类别定义和实际业务可能不完全一致 |
| 网络图片 | 快速补充样本 | 要注意版权、重复图片和低质量图片 |
| 视频抽帧 | 监控、车载、流水线检测 | 相邻帧重复度高,需要抽样筛选 |
| 合成图片 | 特殊目标难采集时 | 只能辅助,不能完全替代真实数据 |
如果是第一次训练,可以先准备一个小数据集试跑,例如每个类别几十到几百张图片。确认流程没问题后,再扩充数据量。
数据采集时建议提前想清楚这几个问题:
- 要检测的类别有几个?
- 每个类别是否都有足够样本?
- 图片中目标大小是否接近真实使用场景?
- 是否包含白天、夜晚、遮挡、不同角度等情况?
- 是否有大量重复图片?
这些问题比盲目增加训练轮数更重要。
三、标注数据集:统一类别编号和框选规则
YOLO11 目标检测使用的标签格式仍然是 YOLO 检测格式。每张图片对应一个同名 .txt 文件,标签文件中每一行表示一个目标:
类别编号 目标中心点x 目标中心点y 目标宽度 目标高度
这里的坐标不是像素值,而是归一化后的比例值,范围一般在 0~1 之间。
例如:
0 0.5123 0.4382 0.1634 0.2851
1 0.3128 0.6610 0.0924 0.1375
含义是:
- 第一列:类别编号,从
0开始 - 第二列:目标框中心点的 x 坐标
- 第三列:目标框中心点的 y 坐标
- 第四列:目标框宽度
- 第五列:目标框高度
标注工具可以选择自己顺手的,例如:
- LabelImg
- CVAT
- Roboflow
- Make Sense
- Label Studio
标注时重点检查这几件事:
- 同一个类别不要一会儿叫
helmet,一会儿叫hardhat。 - 类别编号必须从 0 开始,不能跳号。
- 图片和标签文件必须同名。
- 框不要明显偏离目标,也不要把目标框少一半。
- 没有目标的图片可以保留,但要确认训练逻辑是否需要空标签文件。
举个例子,图片和标签应该这样对应:
000001.jpg -> 000001.txt
000002.jpg -> 000002.txt
000003.jpg -> 000003.txt
如果文件名对不上,后面训练时很容易出现标签读取异常,或者明明有图片却没有标签的情况。
四、整理数据集目录:推荐使用 images 和 labels 对称结构
为了让后续配置更清楚,建议把数据集整理成下面这种结构:
SafetyHelmet/
├── images/
│ ├── train/
│ ├── val/
│ └── test/
├── labels/
│ ├── train/
│ ├── val/
│ └── test/
└── helmet.yaml
这里以安全帽检测数据集举例,实际项目中可以换成自己的数据集名称。
各目录作用如下:
| 目录 | 作用 |
|---|---|
images/train |
训练图片 |
labels/train |
训练标签 |
images/val |
验证图片 |
labels/val |
验证标签 |
images/test |
测试图片,可选 |
labels/test |
测试标签,可选 |
如果你的图片和标签一开始都混在一个文件夹里,可以先写一个简单脚本划分。下面这个脚本会读取原始图片目录,然后按照比例复制到新目录中。
from pathlib import Path
import random
import shutil
def make_yolo_dataset(src_images, src_labels, dst_root, train=0.75, val=0.15):
src_images = Path(src_images)
src_labels = Path(src_labels)
dst_root = Path(dst_root)
image_files = []
for ext in ("*.jpg", "*.jpeg", "*.png", "*.bmp"):
image_files.extend(src_images.glob(ext))
random.seed(2026)
random.shuffle(image_files)
train_num = int(len(image_files) * train)
val_num = int(len(image_files) * val)
split_map = {
"train": image_files[:train_num],
"val": image_files[train_num:train_num + val_num],
"test": image_files[train_num + val_num:],
}
for split_name, files in split_map.items():
image_out = dst_root / "images" / split_name
label_out = dst_root / "labels" / split_name
image_out.mkdir(parents=True, exist_ok=True)
label_out.mkdir(parents=True, exist_ok=True)
for image_path in files:
label_path = src_labels / f"{image_path.stem}.txt"
shutil.copy2(image_path, image_out / image_path.name)
if label_path.exists():
shutil.copy2(label_path, label_out / label_path.name)
else:
print(f"未找到标签文件:{label_path}")
make_yolo_dataset(
src_images=r"D:/dataset_raw/helmet/images",
src_labels=r"D:/dataset_raw/helmet/labels",
dst_root=r"D:/datasets/SafetyHelmet",
)
这段脚本的重点不是复杂,而是保证图片和标签同步移动。实际使用时,只需要修改最后三行路径。
五、安装训练环境:使用源码方式更适合后续改进
本文默认在 Windows 环境下操作。先创建一个新的 conda 环境:
conda create -n yolo11_83253 python=3.10
conda activate yolo11_83253
然后进入解压后的源码目录:
cd D:\AIProjects\ultralytics-8.3.253
执行源码安装:
pip install -e .
-e 的意思是 editable,也就是可编辑安装。这样做的好处是:你后面修改源码文件后,不需要每次重新打包安装。
安装完成后,检查一下当前环境中的版本:
python -c "import ultralytics; print(ultralytics.__version__)"
如果输出:
8.3.253
说明当前环境已经指向本文使用的代码版本。
再检查 PyTorch 是否能识别 GPU:
import torch
print("PyTorch:", torch.__version__)
print("CUDA available:", torch.cuda.is_available())
print("CUDA version:", torch.version.cuda)
如果 torch.cuda.is_available() 输出 False,训练仍然可以用 CPU 跑通流程,但速度会慢很多。正式训练建议配置好 CUDA 版本的 PyTorch。
六、编写数据集配置 YAML:训练前最该仔细检查的文件
Ultralytics 训练时需要通过 YAML 文件告诉程序:训练图片在哪、验证图片在哪、类别有哪些。
以安全帽数据集为例,可以新建:
D:/datasets/SafetyHelmet/helmet.yaml
内容如下:
path: D:/datasets/SafetyHelmet
train: images/train
val: images/val
test: images/test
names:
0: helmet
1: no_helmet
这个文件很短,但很关键。
字段解释:
path:数据集根目录train:训练集图片路径val:验证集图片路径test:测试集图片路径,没有测试集可以先不写names:类别编号和类别名称
Windows 下建议路径使用 /,例如:
path: D:/datasets/SafetyHelmet
不要写成容易转义出错的形式:
path: D:\datasets\SafetyHelmet
另外,如果标签文件中出现类别编号 2,但是 names 只写到 1,训练时就会报类别越界相关错误。
七、第一次训练 YOLO11:先跑通,不要一开始就堆参数
YOLO11 检测模型可以直接使用预训练权重开始训练。第一次建议使用 yolo11n.pt,因为它比较轻,适合快速验证数据集和环境是否正常。
命令如下:
yolo detect train model=yolo11n.pt data=D:/datasets/SafetyHelmet/helmet.yaml epochs=100 imgsz=640 batch=16 device=0
这条命令可以拆开理解:
| 参数 | 说明 |
|---|---|
detect |
目标检测任务 |
train |
训练模式 |
model=yolo11n.pt |
使用 YOLO11n 预训练权重 |
data=...helmet.yaml |
数据集配置文件 |
epochs=100 |
训练 100 轮 |
imgsz=640 |
输入尺寸为 640 |
batch=16 |
每次训练读取 16 张图片 |
device=0 |
使用第 0 张 GPU |
如果没有 NVIDIA GPU,可以先用 CPU 测试流程:
yolo detect train model=yolo11n.pt data=D:/datasets/SafetyHelmet/helmet.yaml epochs=5 imgsz=640 batch=4 device=cpu
CPU 训练很慢,但用来检查数据集格式是可以的。
如果显存不够,优先改这几个参数:
batch=8
imgsz=512
model=yolo11n.pt
不要一上来就用 yolo11x.pt。大模型更吃显存,数据集没检查好之前没有必要。
八、用 Python 脚本训练:更适合后续做实验对比
如果后续要写改进文章,建议准备一个 Python 训练脚本,方便切换模型和参数。
新建 train_helmet_yolo11.py:
from ultralytics import YOLO
def main():
model = YOLO("yolo11n.pt")
model.train(
data=r"D:/datasets/SafetyHelmet/helmet.yaml",
epochs=100,
imgsz=640,
batch=16,
device=0,
workers=4,
project="runs/helmet",
name="yolo11n_baseline",
)
if __name__ == "__main__":
main()
运行:
python train_helmet_yolo11.py
这里额外设置了:
project="runs/helmet":把实验结果统一放到runs/helmet下面name="yolo11n_baseline":给本次实验命名为 baseline
后面做模型改进时,可以继续使用类似命名:
yolo11n_baseline
yolo11n_cbam
yolo11n_bifpn
yolo11n_slimneck
这样不同实验结果会更清楚。
九、训练结果保存在哪里:重点看 best.pt 和 results.csv
如果使用上面的 Python 脚本,训练结果会保存在:
runs/helmet/yolo11n_baseline/
常用文件如下:
runs/helmet/yolo11n_baseline/
├── weights/
│ ├── best.pt
│ └── last.pt
├── results.csv
├── results.png
├── confusion_matrix.png
└── args.yaml
文件说明:
| 文件 | 作用 |
|---|---|
best.pt |
验证集表现最好的权重,后续预测一般用它 |
last.pt |
最后一轮训练保存的权重 |
results.csv |
每轮训练和验证指标 |
results.png |
损失和指标曲线图 |
confusion_matrix.png |
混淆矩阵 |
args.yaml |
本次训练使用的参数 |
如果要写实验结果,建议优先根据 results.csv 和 results.png 来整理,不要凭感觉写“效果很好”。
十、预测图片和视频:先用 best.pt 看实际效果
训练完成后,可以先找几张没有参与训练的图片做预测。
命令行预测:
yolo detect predict model=runs/helmet/yolo11n_baseline/weights/best.pt source=D:/datasets/demo_images save=True conf=0.25
参数说明:
model:训练得到的权重source:图片、文件夹、视频或摄像头save=True:保存预测结果conf=0.25:置信度阈值
如果要预测视频:
yolo detect predict model=runs/helmet/yolo11n_baseline/weights/best.pt source=D:/videos/test.mp4 save=True
如果要调用摄像头:
yolo detect predict model=runs/helmet/yolo11n_baseline/weights/best.pt source=0 show=True
Python 预测写法:
from ultralytics import YOLO
model = YOLO("runs/helmet/yolo11n_baseline/weights/best.pt")
model.predict(
source=r"D:/datasets/demo_images",
save=True,
conf=0.25,
)
预测结果通常会保存到 runs/detect/predict 或新的递增目录中。
十一、验证模型:mAP50 和 mAP50-95 要分清楚
验证命令如下:
yolo detect val model=runs/helmet/yolo11n_baseline/weights/best.pt data=D:/datasets/SafetyHelmet/helmet.yaml device=0
Python 方式:
from ultralytics import YOLO
model = YOLO("runs/helmet/yolo11n_baseline/weights/best.pt")
metrics = model.val(data=r"D:/datasets/SafetyHelmet/helmet.yaml", device=0)
print("mAP50-95:", metrics.box.map)
print("mAP50:", metrics.box.map50)
print("mAP75:", metrics.box.map75)
这里一定要注意:
metrics.box.map50是 mAP50metrics.box.map是 mAP50-95
很多文章会把这两个指标混着写,这是不严谨的。一般情况下,mAP50 会比 mAP50-95 高,因为 mAP50 的 IoU 阈值更宽松。
本文不展示未经实际训练得到的指标数值。完成自己的训练后,可以结合 results.csv、results.png 和验证命令输出查看 mAP50、mAP50-95、Precision 与 Recall,所有结果均应以本机实际运行记录为准。
十二、导出模型:为部署提前准备 ONNX 等格式
训练得到的 .pt 权重适合在 PyTorch / Ultralytics 环境中使用。如果要部署到其他推理框架,通常需要导出。
导出 ONNX:
yolo export model=runs/helmet/yolo11n_baseline/weights/best.pt format=onnx imgsz=640
Python 写法:
from ultralytics import YOLO
model = YOLO("runs/helmet/yolo11n_baseline/weights/best.pt")
model.export(format="onnx", imgsz=640)
常见格式可以这样理解:
| 导出格式 | 适合场景 |
|---|---|
| ONNX | 通用部署,ONNX Runtime、OpenCV DNN 常用 |
| TensorRT | NVIDIA GPU 推理加速 |
| OpenVINO | Intel CPU / 核显部署 |
| TorchScript | PyTorch 生态部署 |
| NCNN | 移动端和边缘设备部署 |
如果只是训练和测试,暂时不导出也可以。导出主要是为了后续写部署、界面调用、端侧推理等内容。
十三、常见问题:先从路径、标签和显存查起
1. yolo 命令无法识别
现象:
'yolo' 不是内部或外部命令
原因: 没有激活正确环境,或者 ultralytics 没有安装成功。
解决方法:
conda activate yolo11_83253
cd D:\AIProjects\ultralytics-8.3.253
pip install -e .
然后重新执行:
yolo version
2. 训练时报数据集路径不存在
原因: helmet.yaml 中的 path、train、val 路径拼接后找不到真实目录。
排查方式: 先手动打开路径,例如:
D:/datasets/SafetyHelmet/images/train
D:/datasets/SafetyHelmet/images/val
确认目录真实存在,并且里面有图片。
3. 标签类别编号越界
现象: 标签中出现了某个类别编号,但 YAML 中没有定义这个类别。
例子:
names:
0: helmet
1: no_helmet
但标签文件里出现:
2 0.5 0.5 0.2 0.2
这时类别 2 就是非法编号。需要重新检查标注类别。
4. 图片有标签,但训练时提示标签缺失
原因: 图片名和标签名没有完全对应。
例如:
images/train/001.jpg
labels/train/001.txt
这是正确的。
下面这种就容易出问题:
images/train/001.jpg
labels/train/001.xml
YOLO 检测训练需要 .txt 格式标签。
5. CUDA 显存不足
解决思路:
batch=8
imgsz=512
model=yolo11n.pt
如果还不够,就继续降低 batch,或者先使用 CPU 跑几轮检查流程。
6. Windows 下 dataloader 多进程报错
可以先把 workers 调小:
yolo detect train model=yolo11n.pt data=D:/datasets/SafetyHelmet/helmet.yaml workers=0
如果 workers=0 可以正常运行,再逐步调到 2 或 4。
7. 预测结果保存目录找不到
Ultralytics 会自动创建递增目录,例如:
runs/detect/predict
runs/detect/predict2
runs/detect/predict3
如果不是第一次预测,结果可能不在 predict,而是在后面的递增目录。
十四、总结
本文围绕 Ultralytics 8.3.253 版本,把 YOLO11 自定义目标检测训练流程重新整理了一遍。整个流程的重点不是把命令堆在一起,而是先固定代码版本,再保证数据集格式、环境安装、训练命令和结果查看都能对应起来。
实际做项目时,建议先使用 yolo11n.pt 跑通小规模数据集,确认图片、标签、YAML 和环境没有问题。流程稳定后,再考虑换更大的模型、增加数据量、调整超参数或加入改进模块。
后续如果继续写 YOLO11 改进文章,可以把本篇作为基础环境篇。这样朋友们可以先跑通 baseline,再去看注意力机制、Neck 替换、损失函数修改、模型导出部署等内容,会更容易复现,也更容易判断改进是否真的有效。
更多推荐




所有评论(0)