YOLO26 训练自定义数据集:从零到部署的保姆级教程
文章目录
- [YOLO26 训练自定义数据集:从零到部署的保姆级教程](#YOLO26 训练自定义数据集:从零到部署的保姆级教程)
-
- [🚀 开篇:YOLO26 来了,这次真的不一样](#🚀 开篇:YOLO26 来了,这次真的不一样)
- 一、环境准备与避坑指南
-
- [1.1 一键安装](#1.1 一键安装)
- [1.2 环境验证](#1.2 环境验证)
- [1.3 路径注意事项](#1.3 路径注意事项)
- 二、数据集准备(核心重点)
-
- [2.1 YOLO 标注格式详解](#2.1 YOLO 标注格式详解)
- [2.2 标准数据集目录结构](#2.2 标准数据集目录结构)
- [2.3 data.yaml 配置文件模板](#2.3 data.yaml 配置文件模板)
- [2.4 数据集划分脚本](#2.4 数据集划分脚本)
- 三、模型训练实战
-
- [3.1 工业级训练脚本](#3.1 工业级训练脚本)
- [3.2 关键参数详解](#3.2 关键参数详解)
- [3.3 训练过程监控](#3.3 训练过程监控)
- 四、模型推理与验证
-
- [4.1 图片推理](#4.1 图片推理)
- [4.2 推理参数速查表](#4.2 推理参数速查表)
- [4.3 模型导出](#4.3 模型导出)
- 五、常见错误与避坑指南
-
- [5.1 错误一:CUDA Out of Memory](#5.1 错误一:CUDA Out of Memory)
- [5.2 错误二:标注格式不对导致训练不收敛](#5.2 错误二:标注格式不对导致训练不收敛)
- [5.3 错误三:训练到一半 mAP 突然下降](#5.3 错误三:训练到一半 mAP 突然下降)
- 六、总结
-
- [6.1 核心要点回顾](#6.1 核心要点回顾)
- [6.2 YOLO26 训练速查命令](#6.2 YOLO26 训练速查命令)
- [🎯 互动话题](#🎯 互动话题)
🚀 开篇:YOLO26 来了,这次真的不一样
先说一个数字:43%。
这是 YOLO26n 在 CPU 上比 YOLO11n 快的比例。不是 GPU,是 CPU。这意味着你可以在树莓派、Jetson Nano、甚至一台没有独显的笔记本上跑实时目标检测。
2026 年,Ultralytics 发布了 YOLO26。这一次的更新不是"换了个更大的模型",而是架构级的变革:
- 🔥 NMS-Free 端到端推理:默认不需要 NMS 后处理,直接出结果,延迟更低、部署更简单
- 🔥 DFL-Free 回归:砍掉了 Distribution Focal Loss,检测头更轻量,导出更友好
- 🔥 MuSGD 优化器:融合 SGD + Muon,借鉴大语言模型训练经验,收敛更稳定
- 🔥 ProgLoss + STAL:渐进式损失 + 小目标标签增强,小目标检测能力大幅提升
- 🔥 双头架构:one-to-one(默认,无 NMS)+ one-to-many(高精度,需 NMS),按需切换
五个模型规格(n/s/m/l/x),mAP 从 40.9 到 57.5,T4 TensorRT 延迟从 1.7ms 到 11.8ms。
但再好的模型,不会训练自己的数据集也是白搭。
今天这篇教程,我会带你走完从环境搭建、数据标注、配置训练到模型推理的完整闭环。每一步都有代码、有注释、有避坑提示。跟着做,你就能训练出自己的 YOLO26 模型。
一、环境准备与避坑指南
1.1 一键安装
YOLO26 基于 ultralytics 框架,安装极其简单:
bash
# 安装 ultralytics(包含 YOLO26)
pip install ultralytics
# 如果需要完整功能(导出、日志等)
pip install ultralytics[export]
⚠️ 避坑提示:建议在虚拟环境中安装,避免依赖冲突。
bashconda create -n yolo26 python=3.10 -y conda activate yolo26 pip install ultralytics
1.2 环境验证
一行代码确认安装成功:
python
from ultralytics import YOLO
# 加载 YOLO26n 预训练模型(会自动下载)
model = YOLO("yolo26n.pt")
# 快速推理测试
results = model("https://ultralytics.com/images/bus.jpg", show=False)
print(f"检测到 {len(results[0].boxes)} 个目标")
如果输出了检测到的目标数量,说明环境一切正常。
1.3 路径注意事项
bash
# ⚠️ 服务器用户注意:代码和数据集放在数据盘,不要放系统盘
# 正确做法:
cd /data/projects # 切换到数据盘
git clone # 代码放这里
mkdir -p datasets # 数据集放这里
# 错误做法:
cd ~ # 系统盘,空间小,容易爆
核心原则:代码和数据都放在空间大的数据盘,系统盘只放环境。
二、数据集准备(核心重点)
2.1 YOLO 标注格式详解
YOLO 使用归一化坐标的 txt 标注格式,每张图片对应一个同名的 .txt 文件。
格式规范:
class_id x_center y_center width height
| 参数 | 说明 | 取值范围 |
|---|---|---|
class_id |
类别编号(从 0 开始) | 0, 1, 2, ... |
x_center |
边界框中心点 X 坐标 | 0.0 ~ 1.0(归一化) |
y_center |
边界框中心点 Y 坐标 | 0.0 ~ 1.0(归一化) |
width |
边界框宽度 | 0.0 ~ 1.0(归一化) |
height |
边界框高度 | 0.0 ~ 1.0(归一化) |
示例:
text
# 一张 640x480 的图片中,有一个狗(类别0)和一个猫(类别1)
# 狗的框:中心(320, 240),宽 200,高 300
# 猫的框:中心(500, 150),宽 100,高 80
# dog.txt
0 0.500000 0.500000 0.312500 0.625000
# cat_and_dog.txt
0 0.500000 0.500000 0.312500 0.625000
1 0.781250 0.312500 0.156250 0.166667
⚠️ 最常见的错误:直接用像素坐标而不归一化!
text# ❌ 错误:像素坐标 0 320 240 200 300 # ✅ 正确:归一化坐标(除以图片宽高) 0 0.5 0.5 0.3125 0.625
2.2 标准数据集目录结构
datasets/
└── my_dataset/
├── data.yaml # 数据集配置文件
├── images/
│ ├── train/ # 训练集图片
│ │ ├── img_001.jpg
│ │ ├── img_002.jpg
│ │ └── ...
│ └── val/ # 验证集图片
│ ├── img_101.jpg
│ ├── img_102.jpg
│ └── ...
└── labels/
├── train/ # 训练集标注(与图片同名 .txt)
│ ├── img_001.txt
│ ├── img_002.txt
│ └── ...
└── val/ # 验证集标注
├── img_101.txt
├── img_102.txt
└── ...
💡 命名技巧 :图片和标注必须完全同名(仅后缀不同)。建议用数字编号,方便批量处理。
2.3 data.yaml 配置文件模板
yaml
# data.yaml --- YOLO26 数据集配置文件
# 数据集根目录(绝对路径或相对路径)
path: /data/projects/datasets/my_dataset
# 训练集和验证集路径(相对于 path)
train: images/train
val: images/val
# 测试集(可选)
# test: images/test
# 类别数量
nc: 5
# 类别名称列表(顺序必须与 class_id 一致)
names:
0: person
1: car
2: bicycle
3: dog
4: cat
参数详解:
| 参数 | 必填 | 说明 |
|---|---|---|
path |
✅ | 数据集根目录,建议用绝对路径 |
train |
✅ | 训练集图片路径(相对 path) |
val |
✅ | 验证集图片路径(相对 path) |
nc |
✅ | 类别数量,必须与 names 长度一致 |
names |
✅ | 类别名称,key 从 0 开始,顺序与标注 class_id 一致 |
⚠️ 常见错误 :
nc写错了!如果你的 names 有 5 个类别,nc 必须是 5,不能多也不能少。nc 不等于 names 数量 = 训练直接报错。
2.4 数据集划分脚本
python
# split_dataset.py --- 将数据集按比例划分为训练集和验证集
import os
import random
import shutil
from pathlib import Path
def split_dataset(
source_dir: str, # 原始数据目录(包含 images 和 labels)
output_dir: str, # 输出目录
train_ratio: float = 0.8 # 训练集比例
):
"""
将数据集划分为训练集和验证集
Args:
source_dir: 原始数据目录
output_dir: 输出目录
train_ratio: 训练集占比(默认 0.8,即 80% 训练 + 20% 验证)
"""
source = Path(source_dir)
output = Path(output_dir)
# 获取所有图片文件
img_dir = source / "images"
img_files = list(img_dir.glob("*.jpg")) + \
list(img_dir.glob("*.png")) + \
list(img_dir.glob("*.jpeg"))
# 随机打乱
random.seed(42)
random.shuffle(img_files)
# 划分
split_idx = int(len(img_files) * train_ratio)
train_files = img_files[:split_idx]
val_files = img_files[split_idx:]
print(f"总图片数: {len(img_files)}")
print(f"训练集: {len(train_files)} 张")
print(f"验证集: {len(val_files)} 张")
# 复制文件到目标目录
for split, files in [("train", train_files), ("val", val_files)]:
img_out = output / "images" / split
lbl_out = output / "labels" / split
img_out.mkdir(parents=True, exist_ok=True)
lbl_out.mkdir(parents=True, exist_ok=True)
for img_file in files:
# 复制图片
shutil.copy2(img_file, img_out / img_file.name)
# 复制对应标注
label_file = source / "labels" / (img_file.stem + ".txt")
if label_file.exists():
shutil.copy2(label_file, lbl_out / (img_file.stem + ".txt"))
else:
print(f"⚠️ 警告: {img_file.name} 没有对应的标注文件")
print("✅ 数据集划分完成!")
# 使用示例
if __name__ == "__main__":
split_dataset(
source_dir="./raw_data",
output_dir="./datasets/my_dataset",
train_ratio=0.8
)
三、模型训练实战
3.1 工业级训练脚本
python
# train.py --- YOLO26 自定义数据集训练脚本
from ultralytics import YOLO
import torch
import os
def train_yolo26():
"""使用 YOLO26 训练自定义数据集"""
# ========== 1. 基础配置 ==========
# 选择模型规格:n(轻量) / s(小) / m(中) / l(大) / x(超大)
MODEL_SIZE = "n" # 新手建议从 n 或 s 开始
# 数据集配置文件路径
DATA_YAML = "datasets/my_dataset/data.yaml"
# 输出目录
PROJECT = "runs/train"
NAME = f"yolo26{MODEL_SIZE}_custom"
# ========== 2. 加载模型 ==========
# 方式一:从预训练权重开始(推荐,迁移学习)
model = YOLO(f"yolo26{MODEL_SIZE}.pt")
# 方式二:从配置文件开始(从头训练,需要更多数据和算力)
# model = YOLO(f"yolo26{MODEL_SIZE}.yaml")
# ========== 3. 训练参数 ==========
results = model.train(
# --- 数据 ---
data=DATA_YAML, # 数据集配置文件
# --- 训练轮数 ---
epochs=100, # 训练轮数(小数据集 50-100,大数据集 100-300)
# --- 批次与尺寸 ---
batch=16, # 批次大小(显存不够就减小)
imgsz=640, # 输入图像尺寸
# --- 优化器 ---
optimizer="auto", # YOLO26 默认使用 MuSGD
lr0=0.01, # 初始学习率(小数据集可适当降低)
lrf=0.01, # 最终学习率因子
# --- 数据增强 ---
mosaic=1.0, # Mosaic 增强概率(YOLO26 默认 0.9-1.0)
mixup=0.1, # MixUp 增强概率
copy_paste=0.1, # Copy-Paste 增强概率
degrees=0.0, # 旋转角度(YOLO26 大模型默认 ~0)
scale=0.5, # 缩放比例
fliplr=0.5, # 水平翻转概率
hsv_h=0.015, # 色调变化
hsv_s=0.7, # 饱和度变化
hsv_v=0.4, # 亮度变化
# --- 训练策略 ---
close_mosaic=10, # 最后 10 个 epoch 关闭 Mosaic(重要!)
warmup_epochs=3, # 预热轮数
cos_lr=True, # 余弦学习率衰减
# --- 设备 ---
device=0, # GPU 编号(CPU 用 "cpu")
workers=8, # 数据加载线程数
# --- 保存与验证 ---
save=True, # 保存模型
save_period=10, # 每 10 个 epoch 保存一次
val=True, # 每个 epoch 后验证
plots=True, # 生成训练曲线图
# --- 输出 ---
project=PROJECT, # 项目目录
name=NAME, # 实验名称
exist_ok=True, # 覆盖同名目录
# --- 预训练权重 ---
pretrained=True, # 使用预训练权重
)
# ========== 4. 输出结果路径 ==========
print(f"\n✅ 训练完成!")
print(f"📁 最佳模型: {results.save_dir}/weights/best.pt")
print(f"📁 最后模型: {results.save_dir}/weights/last.pt")
print(f"📊 训练曲线: {results.save_dir}/results.png")
return results
if __name__ == "__main__":
# 检查 GPU
if torch.cuda.is_available():
print(f"🚀 GPU 可用: {torch.cuda.get_device_name(0)}")
print(f"💾 显存: {torch.cuda.get_device_properties(0).total_mem / 1e9:.1f} GB")
else:
print("💻 使用 CPU 训练(速度较慢)")
train_yolo26()
3.2 关键参数详解
📐 epochs(训练轮数)
| 数据集规模 | 推荐 epochs | 说明 |
|---|---|---|
| < 1000 张 | 100-200 | 小数据集,多跑几轮 |
| 1000-10000 张 | 50-100 | 中等数据集 |
| > 10000 张 | 30-50 | 大数据集,快速收敛 |
📦 batch(批次大小)
python
# 显存与 batch 对照表(YOLO26n,640x640)
# 4GB 显存 → batch=4
# 6GB 显存 → batch=8
# 8GB 显存 → batch=16
# 12GB 显存 → batch=24
# 24GB 显存 → batch=48
⚠️ batch 太小会导致训练不稳定 。如果显存不够,考虑减小
imgsz(如 416)而不是无脑减 batch。
🎯 close_mosaic(关闭 Mosaic)
这是 YOLO26 训练中最重要的参数之一。Mosaic 增强在训练初期很有用,但在最后阶段会破坏真实数据分布。
python
close_mosaic=10 # 最后 10 个 epoch 关闭 Mosaic
YOLO26 官方配方:所有规格都设置了 close_mosaic=10。不要省略这个参数!
🔄 end2end(端到端训练)
YOLO26 默认使用 NMS-Free 的 one-to-one 头进行端到端训练:
python
# 默认:端到端训练(推荐)
model.train(data="data.yaml", epochs=100)
# 如果需要 NMS 后处理(精度略高,但推理更慢)
model.train(data="data.yaml", epochs=100, end2end=False)
3.3 训练过程监控
训练开始后,你会看到类似这样的输出:
text
Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size
1/100 3.2G 2.15 3.82 1.24 42 640: 100%
Class Images Instances Box(P R mAP50 mAP50-95)
all 200 2100 0.652 0.58 0.634 0.452
关键指标解读:
| 指标 | 含义 | 正常范围 |
|---|---|---|
box_loss |
边界框回归损失 | 持续下降 |
cls_loss |
分类损失 | 持续下降 |
mAP50 |
IoU=0.5 时的平均精度 | 越高越好 |
mAP50-95 |
IoU 0.5-0.95 的平均精度 | 越高越好 |
💡 训练正常信号 :loss 持续下降 + mAP 持续上升 = 一切正常。
⚠️ 过拟合信号:训练 loss 降但验证 mAP 不升 = 数据不够或增强不足。
四、模型推理与验证
4.1 图片推理
python
# detect.py --- YOLO26 推理脚本
from ultralytics import YOLO
import cv2
import os
def detect_images():
"""批量图片推理"""
# 加载训练好的模型
model = YOLO("runs/train/yolo26n_custom/weights/best.pt")
# 单张图片推理
results = model(
source="test_images/demo.jpg", # 图片来源
conf=0.25, # 置信度阈值(低于此值不显示)
iou=0.7, # NMS 的 IoU 阈值
save=True, # 保存结果图片
show=False, # 是否弹窗显示
project="runs/detect", # 输出目录
name="results", # 实验名称
exist_ok=True, # 覆盖同名目录
)
# 打印检测结果
for r in results:
boxes = r.boxes # 检测框
if boxes is not None:
print(f"检测到 {len(boxes)} 个目标:")
for box in boxes:
cls_id = int(box.cls[0])
conf = float(box.conf[0])
xyxy = box.xyxy[0].tolist() # [x1, y1, x2, y2]
print(f" 类别 {cls_id}: 置信度 {conf:.3f}, 位置 {xyxy}")
def detect_folder():
"""批量文件夹推理"""
model = YOLO("runs/train/yolo26n_custom/weights/best.pt")
# 对整个文件夹推理
results = model(
source="test_images/", # 文件夹路径
conf=0.25,
save=True,
save_txt=True, # 保存 txt 格式结果
save_conf=True, # txt 中包含置信度
project="runs/detect",
name="batch_results",
)
print(f"✅ 处理完成,结果保存在 runs/detect/batch_results/")
def detect_video():
"""视频推理"""
model = YOLO("runs/train/yolo26n_custom/weights/best.pt")
# 视频推理
results = model(
source="test_videos/demo.mp4", # 视频文件(或 0 表示摄像头)
conf=0.25,
save=True,
project="runs/detect",
name="video_results",
)
print("✅ 视频处理完成")
if __name__ == "__main__":
detect_images()
# detect_folder()
# detect_video()
4.2 推理参数速查表
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
source |
str | --- | 图片来源:文件路径/文件夹/URL/摄像头(0) |
conf |
float | 0.25 | 置信度阈值,低于此值的检测框不显示 |
iou |
float | 0.7 | NMS 的 IoU 阈值,高于此值的重叠框被抑制 |
save |
bool | False | 是否保存结果图片 |
save_txt |
bool | False | 是否保存 txt 格式检测结果 |
save_conf |
bool | False | txt 结果中是否包含置信度 |
show |
bool | False | 是否弹窗显示结果 |
project |
str | "runs/detect" | 输出根目录 |
name |
str | "exp" | 实验名称(结果保存在 project/name/) |
end2end |
bool | True | 是否使用端到端推理(无 NMS) |
4.3 模型导出
训练完成后,导出为 ONNX 或 TensorRT 格式用于部署:
python
# export.py --- 模型导出脚本
from ultralytics import YOLO
model = YOLO("runs/train/yolo26n_custom/weights/best.pt")
# 导出 ONNX(通用格式,支持 CPU/GPU)
model.export(format="onnx", imgsz=640)
# 导出 TensorRT(NVIDIA GPU 专用,最快)
model.export(format="engine", imgsz=640, half=True)
# 导出 OpenVINO(Intel CPU 优化)
model.export(format="openvino", imgsz=640)
# 导出 TFLite(移动端/嵌入式)
model.export(format="tflite", imgsz=320) # 移动端建议用小尺寸
print("✅ 模型导出完成")
五、常见错误与避坑指南
5.1 错误一:CUDA Out of Memory
text
RuntimeError: CUDA out of memory. Tried to allocate 256.00 MiB
原因:batch 或 imgsz 太大,显存放不下。
解决:
python
# 方案1:减小 batch
model.train(data="data.yaml", batch=4)
# 方案2:减小图像尺寸
model.train(data="data.yaml", imgsz=416)
# 方案3:使用混合精度(节省约 40% 显存)
model.train(data="data.yaml", amp=True)
# 方案4:梯度累积(小 batch 模拟大 batch)
model.train(data="data.yaml", batch=4, accumulate=4) # 等效 batch=16
5.2 错误二:标注格式不对导致训练不收敛
text
mAP 一直在 0.01 以下,loss 不下降
原因:标注坐标没有归一化,或 class_id 超出范围。
排查脚本:
python
# check_labels.py --- 标注文件检查脚本
import os
from pathlib import Path
def check_labels(label_dir: str, num_classes: int):
"""检查 YOLO 标注文件格式"""
label_files = list(Path(label_dir).glob("*.txt"))
errors = []
for lf in label_files:
with open(lf, "r") as f:
for line_num, line in enumerate(f, 1):
parts = line.strip().split()
# 检查:每行必须有 5 个值
if len(parts) != 5:
errors.append(f"{lf.name}:{line_num} 格式错误({len(parts)} 个值,需要 5 个)")
continue
cls_id, cx, cy, w, h = map(float, parts)
# 检查:class_id 在有效范围内
if cls_id < 0 or cls_id >= num_classes:
errors.append(f"{lf.name}:{line_num} class_id={int(cls_id)} 超出范围 [0, {num_classes-1}]")
# 检查:坐标是否归一化(0-1 之间)
for name, val in [("cx", cx), ("cy", cy), ("w", w), ("h", h)]:
if val < 0 or val > 1:
errors.append(f"{lf.name}:{line_num} {name}={val:.2f} 未归一化(应在 0-1 之间)")
# 检查:边界框不超出图像
if cx - w/2 < 0 or cx + w/2 > 1 or cy - h/2 < 0 or cy + h/2 > 1:
errors.append(f"{lf.name}:{line_num} 边界框超出图像范围")
if errors:
print(f"❌ 发现 {len(errors)} 个错误:")
for e in errors[:20]: # 只显示前 20 个
print(f" {e}")
else:
print(f"✅ 检查了 {len(label_files)} 个标注文件,全部通过!")
# 使用
check_labels("datasets/my_dataset/labels/train", num_classes=5)
5.3 错误三:训练到一半 mAP 突然下降
text
前 50 个 epoch mAP 正常上升,第 51 个 epoch 突然暴跌
原因 :没有设置 close_mosaic,Mosaic 增强一直开着。
解决:
python
# ✅ 正确:最后 10 个 epoch 关闭 Mosaic
model.train(data="data.yaml", epochs=100, close_mosaic=10)
# ❌ 错误:Mosaic 全程开启
model.train(data="data.yaml", epochs=100) # 没有 close_mosaic
这是 YOLO26 训练中最常见的坑。官方配方明确要求 close_mosaic=10,不要省略!
六、总结
6.1 核心要点回顾
| 步骤 | 关键操作 | 易错点 |
|---|---|---|
| 环境 | pip install ultralytics |
用虚拟环境,避免依赖冲突 |
| 数据 | YOLO 归一化格式 + data.yaml | 坐标必须归一化,nc 必须等于类别数 |
| 训练 | 预训练权重 + MuSGD 优化器 | 必须设置 close_mosaic=10 |
| 推理 | conf 阈值 + save 参数 | 结果路径在 runs/detect/ 下 |
| 导出 | ONNX/TensorRT/OpenVINO | 导出前先 model.fuse() |
6.2 YOLO26 训练速查命令
bash
# 一行命令训练(CLI 方式)
yolo detect train \
data=datasets/my_dataset/data.yaml \
model=yolo26n.pt \
epochs=100 \
imgsz=640 \
batch=16 \
close_mosaic=10 \
device=0
🎯 互动话题
你打算用 YOLO26 训练什么数据集?人脸检测、工业缺陷、还是交通标志?
评论区聊聊你的项目,我会挑 3 个最有代表性的场景,下期出一篇专项调优指南 🐾
下一篇预告:《YOLO26 模型部署全攻略:ONNX → TensorRT → 边缘设备,一条龙搞定》
参考链接:
- Ultralytics YOLO26 官方文档:https://docs.ultralytics.com/models/yolo26
- YOLO26 训练配方指南:https://docs.ultralytics.com/guides/yolo26-training-recipe
- YOLO26 论文:https://arxiv.org/abs/2606.03748
- Roboflow 标注工具:https://roboflow.com/
- Ultralytics GitHub:https://github.com/ultralytics/ultralytics