YOLO11 自定义目标检测模型训练全流程

从数据标注到模型部署的完整教程——以国标直流充电口检测为例

Ubuntu 22.04 Python 3.10 Conda Ultralytics YOLO11 Roboflow

整体流程概览

📷 采集照片
🏷️ Roboflow 标注
📦 生成 Version
⬇️ 导出数据集
🏋️ 本地训练
🚀 部署推理
1

环境准备

1.1 创建 Conda 虚拟环境

# 创建 Python 3.10 环境 conda create -n yolo_env python=3.10 -y conda activate yolo_env

1.2 安装 Ultralytics

pip install ultralytics

1.3 验证安装

python -c "from ultralytics import YOLO; print('OK')"

1.4 下载初始预训练权重

首次运行时 ultralytics 会自动下载,也可手动下载放到项目目录:

# 在项目目录下运行,自动下载 yolo11n.pt python -c "from ultralytics import YOLO; YOLO('yolo11n.pt')"
💡 说明:yolo11n.pt 是 YOLO11 nano 版本,参数量最小、速度最快,适合实时检测场景。后续训练以此为基础进行迁移学习(fine-tune)。
模型参数量适用场景
yolo11n.pt2.6M实时检测,CPU 可用
yolo11s.pt9.4M精度与速度平衡
yolo11m.pt20.1M较高精度
2

Roboflow 项目创建与图片上传

2.1 注册并创建项目

  1. 访问 app.roboflow.com,注册账号并登录
  2. 点击 New Project
  3. Project Type 选择 Object Detection
  4. 填写项目名称,点击 Create Project

2.2 上传图片

  1. 进入项目后,点击左侧 Upload Data
  2. 拖拽图片文件夹或点击选择文件(支持 JPG/PNG)
  3. 等待上传完成,点击 Finish Uploading

2.3 采集建议

变量建议覆盖范围
拍摄距离30cm / 50cm / 80cm / 100cm
拍摄角度正对、左偏 15°/30°、右偏、上偏
光照条件室内顶灯、室外自然光、侧光、暗光
最少数量50 张以上(100 张以上效果更好)
💡 建议:手机照片和相机照片都可以用于训练。初期用手机快速积累数据,后期再补充实际部署相机(如 DaBai DCW2)拍摄的照片进行 fine-tune。
3

数据标注规范

3.1 类别定义

在 Roboflow 标注界面,使用以下类别(以充电口检测为例):

类别名框住的目标用途
charging_port整个充电口(含外框)YOLO 检测定位
DC_holeDC+ 和 DC- 大孔(各一个框)PnP 位姿估计关键点
PEPE 接地孔PnP 位姿估计关键点
⚠️ 注意:DC+ 和 DC- 外观完全相同,使用同一类别 DC_hole 标注两个框。代码中通过 x 坐标排序区分左右(x 较小的为 DC+)。

3.2 标注操作步骤

  1. 进入 Annotate 页面,选择一张图片
  2. B 键进入画框模式
  3. 拖拽鼠标画矩形框,松开后在弹出框中选择类别
  4. 每张图标注 4 个框:1 个 charging_port + 2 个 DC_hole + 1 个 PE
  5. 进入下一张

3.3 快捷键

快捷键功能
BBounding Box 画框模式
→ / ←下一张 / 上一张
Ctrl + Z撤销
Esc取消当前操作
Delete删除选中的框

3.4 标注质量要求

  • 框应贴合目标边缘,不要留太多空白
  • charging_port 框住整个圆形充电口及其外环
  • DC_hole 框住孔的外圆边缘
  • 确保每张图的 4 个框都标完再翻页
💡 AI 辅助标注:积累约 20 张手动标注的图片后,可以先训练一版模型,再回到 Roboflow 使用 "Find Objects with AI" 按钮进行自动预标注,然后人工审核修正,效率可提升 3~5 倍。
4

生成数据集 Version

Version 是数据集的快照,包含分割比例、预处理和数据增强配置。每次训练前必须生成一个 Version。

4.1 进入 Versions 页面

点击左侧菜单 Versions → 右侧表单填写配置

4.2 设置 Train/Test Split(步骤 2)

点击 Train/Test Split 右侧的 Edit,设置比例:

数据集大小推荐比例
40~100 张Train 80% / Valid 20% / Test 0%
100 张以上Train 70% / Valid 20% / Test 10%

4.3 预处理配置(步骤 3)

保留以下两项默认设置,无需修改:

  • Auto-Orient:自动校正手机照片的旋转方向
  • Resize to 512×512:统一图片尺寸

4.4 数据增强配置(步骤 4)

点击 Augmentation → Edit,开启以下增强项:

增强项推荐参数作用
FlipHorizontal(水平翻转)模拟充电口镜像场景
Rotation-15° ~ +15°模拟相机轻微倾斜
Brightness-25% ~ +25%模拟不同光照条件
⚠️ 不要开启过多增强项,对于小数据集,过多增强反而会引入噪声导致训练不稳定。

4.5 创建 Version(步骤 5)

  • Maximum Version Size:选 3x(训练集图片数 × 3 倍增强)
  • 点击 Create,等待几秒生成完成
5

导出数据集到本地

5.1 进入 Version 页面

左侧菜单点击 Versions,选择刚生成的版本,点击右上角 Download Dataset

5.2 选择格式

  • Format 选择 YOLOv11
  • Download Options 选择 Download zip to computer
  • 点击 Continue,浏览器自动下载 zip 文件

5.3 解压到指定目录

# 将 zip 文件移动到项目的 datasets 目录 mkdir -p ~/项目目录/datasets mv ~/Downloads/你的项目名.zip ~/项目目录/datasets/ # 解压 cd ~/项目目录/datasets unzip *.zip

解压后目录结构如下:

datasets/ └── DC charging port.v1i.yolov11/ ├── data.yaml # 数据集配置文件 ├── train/ │ ├── images/ # 训练图片 │ └── labels/ # 标注文件(.txt) ├── valid/ │ ├── images/ │ └── labels/ └── test/ ├── images/ └── labels/
⚠️ 注意:如果网络无法连接 Roboflow 服务器(curl 下载失败),必须使用浏览器手动下载 zip 文件,不要使用 Code snippet 中的 curl 命令。
6

修正 data.yaml 路径

Roboflow 导出的 data.yaml 使用相对路径,在本地训练时容易找不到文件,必须改为绝对路径

6.1 打开 data.yaml

# 查看默认内容 cat "datasets/你的数据集目录/data.yaml"

默认内容(相对路径,需要修改):

train: ../train/images val: ../valid/images test: ../test/images nc: 3 names: ['DC_hole', 'PE', 'charging_port']

6.2 修改为绝对路径

用文本编辑器打开 data.yaml,将路径改为绝对路径:

train: /home/用户名/项目路径/datasets/数据集目录/train/images val: /home/用户名/项目路径/datasets/数据集目录/valid/images test: /home/用户名/项目路径/datasets/数据集目录/test/images nc: 3 names: ['DC_hole', 'PE', 'charging_port']
💡 获取绝对路径:在终端中 cd 到数据集目录,然后运行 pwd 即可得到完整路径。
7

本地训练模型

7.1 创建训练脚本

在项目目录下创建 train.py

from ultralytics import YOLO # 加载预训练权重(首次训练用 yolo11n.pt) # 二次训练用上一次的 best.pt 进行 fine-tune model = YOLO("yolo11n.pt") model.train( data="/绝对路径/datasets/数据集目录/data.yaml", epochs=100, # 训练轮数 imgsz=512, # 图片尺寸,与 Roboflow 预处理一致 batch=16, # 批大小,显存不足时改为 8 name="dc_charging_v1", # 本次训练的名称 project="runs/detect", # 结果保存目录 )

7.2 运行训练

conda activate yolo_env cd /你的项目目录 python train.py
⚠️ 命令行路径含空格时的注意事项:如果数据集路径包含空格(如 DC charging port),必须用引号包裹路径,或者将路径写在 Python 脚本中,不要在命令行直接拼接。

7.3 训练参数说明

参数说明建议值
epochs训练总轮数100(小数据集)
imgsz输入图片尺寸512(与 Roboflow 预处理一致)
batch每批图片数量16(CPU)/ 32(GPU)
patience早停耐心值50(可选,防止过拟合)

7.4 训练输出目录

runs/detect/dc_charging_v1/ ├── weights/ │ ├── best.pt # 最佳权重(mAP50 最高时保存)← 用这个 │ └── last.pt # 最后一个 epoch 的权重 ├── results.csv # 每个 epoch 的指标记录 ├── results.png # 训练曲线图 └── confusion_matrix.png # 混淆矩阵
8

解读训练结果

8.1 训练完成时的输出示例

Class Images Instances Box(P R mAP50 mAP50-95 all 8 32 0.989 1 0.995 0.819 DC_hole 8 16 0.996 1 0.995 0.834 PE 8 8 0.990 1 0.995 0.696 charging_port 8 8 0.982 1 0.995 0.927

8.2 关键指标含义

指标全称含义目标
P(Precision) 精确率 检测到的框中,正确的比例 > 0.9
R(Recall) 召回率 所有真实目标中,被检测到的比例 > 0.9
mAP50 Mean Average Precision @IoU=0.5 IoU≥0.5 视为正确时的平均精度,主要指标 > 0.85
mAP50-95 Mean Average Precision @IoU=0.5:0.95 多 IoU 阈值平均,衡量定位精度 > 0.5

8.3 结果评估

mAP50评价建议
> 0.95优秀可直接部署使用
0.85 ~ 0.95良好可用,建议补充更多数据
< 0.85待改进增加数据量,检查标注质量

8.4 使用 best.pt 进行验证预测

from ultralytics import YOLO model = YOLO("runs/detect/dc_charging_v1/weights/best.pt") # 对单张图片预测 results = model("测试图片.jpg", conf=0.5) results[0].show() # 查看检测到的类别和置信度 for box in results[0].boxes: print(results[0].names[int(box.cls)], float(box.conf))
9

替换模型并运行实时检测

9.1 修改 live_detect.py 中的模型路径

将脚本中的模型路径从通用预训练模型改为你训练好的权重:

# 修改前(通用 YOLO11 模型) model = YOLO("yolo11n.pt") # 修改后(你自己训练的充电口模型) model = YOLO("runs/detect/dc_charging_v1/weights/best.pt")

9.2 运行实时检测

conda activate yolo_env cd /你的项目目录 # 设置库路径 export PYTHONPATH=$PYTHONPATH:$(pwd)/pyorbbecsdk/install/lib export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/pyorbbecsdk/install/lib # 启动检测 python live_detect.py
💡 简化启动:将上述 export 命令写入 run.sh 脚本,以后只需运行 bash run.sh 即可:
#!/bin/bash cd "$(dirname "$0")" export LD_LIBRARY_PATH="$(pwd)/pyorbbecsdk/install/lib:$LD_LIBRARY_PATH" export PYTHONPATH="$(pwd)/pyorbbecsdk/install/lib:$PYTHONPATH" /home/用户名/miniconda3/envs/yolo_env/bin/python live_detect.py

9.3 检测窗口说明

  • 绿色框:检测到的目标(charging_port / DC_hole / PE)
  • 框上方文字:类别名 + 置信度 + 距离(米)
  • 红色圆点:bbox 中心点(用于采样深度值)
  • QESC 退出
10

后续迭代:增加数据重新训练

10.1 迭代策略

新增数据量推荐策略起始权重epochs
10~30 张Fine-tune(继续训练)上一次的 best.pt50
50 张以上重头训练yolo11n.pt100

10.2 Fine-tune 脚本

from ultralytics import YOLO # 从上一次训练的 best.pt 继续 model = YOLO("runs/detect/dc_charging_v1/weights/best.pt") model.train( data="/绝对路径/datasets/新版数据集/data.yaml", epochs=50, # 轮数可以少一些 imgsz=512, batch=16, name="dc_charging_v2", # 版本号递增 project="runs/detect", )

10.3 完整迭代流程

  1. 在 Roboflow 上传新照片并完成标注
  2. 重新生成一个新的 Version(版本号自动递增)
  3. 导出新 Version 的数据集 zip 文件
  4. 解压,修改 data.yaml 为绝对路径
  5. 运行 fine-tune 脚本,等待训练完成
  6. live_detect.py 中的模型路径改为新的 best.pt
  7. 测试效果

10.4 操作检查清单

  • 新照片已上传到 Roboflow
  • 所有新图片已完成标注(每张 4 个框)
  • 已生成新版本 Version(包含增强配置)
  • 已下载并解压新数据集 zip
  • data.yaml 路径已修改为绝对路径
  • 已运行训练脚本
  • 训练完成后 mAP50 > 0.95
  • live_detect.py 已替换为新的 best.pt
  • 实测摄像头检测效果正常
?

常见问题 FAQ

Q1:预训练权重(yolo11n.pt)的作用是什么?Fine-tune 后还能识别原来的物体吗?

预训练权重的价值在于迁移学习能力,而不是"保留原有类别的记忆"。

用 COCO 数据集训练过的模型,其骨干网络(Backbone)已经学会了提取边缘、纹理、形状等通用视觉特征。Fine-tune 时,这部分能力被保留并迁移,使模型只需几十张图片就能学会识别充电口这类新类别。

💡 类比:就像一个见过上万种物品的人,学认"充电口型号"时只需看几十个样品——因为他的眼睛已经很"会看"了。但专门学了充电口之后,如果没有继续复习,之前认识的物体知识会逐渐模糊

Fine-tune 时,data.yamlnc: 3 与原模型的 nc: 80 不一致,Ultralytics 会自动丢弃原有检测头并重新初始化。因此:

Fine-tune 后状态
骨干网络的视觉特征提取能力✅ 保留(这是迁移学习的价值所在)
COCO 原有 80 类的识别能力❌ 丢失(检测头被重建)
⚠️ 注意:这是深度学习中灾难性遗忘(Catastrophic Forgetting)的固有问题,不是 bug,无法通过调参规避。

Q2:标注 DC_hole 和 PE 对提升充电口识别精度有帮助吗?

charging_port 的检测精度几乎没有直接帮助,但有其独立用途。

类别实际用途是否必须
charging_portYOLO 检测定位充电口位置✅ 必须
DC_holePnP 位姿估计,计算充电口三维朝向,供机器人精准插枪按需选择
PEPnP 位姿估计关键点按需选择
💡 结论:如果目标仅是检测充电口在哪里(2D 定位),只标注 charging_port 即可。如果后续需要精准对准插枪(计算三维位姿),则 DC_holePE 是必要的关键点。

Q3:训练完后原本 YOLO 能识别的 80 类物体都不能识别了,怎么办?

这是正常现象(原因见 Q1)。工程上有三种应对方案:

Q3.1 保留两个独立模型(推荐)

# 原始模型,识别通用 80 类 model_general = YOLO("yolo11n.pt") # 你的模型,识别充电口 model_custom = YOLO("runs/detect/dc_charging_v1/weights/best.pt") # 按场景分别调用 results = model_custom(frame)

这是工业界最常见的做法——专用模型比通用模型精度更高,按场景切换使用即可。

Q3.2 使用 YOLO-World(开放词汇检测)

YOLO-World 无需重新训练,直接用文字描述类别,80 类识别能力始终保留:

from ultralytics import YOLOWorld model = YOLOWorld("yolov8s-world.pt") model.set_classes(["person", "car", "charging port"]) results = model.predict("image.jpg")
⚠️ 缺点:对"充电口"这类专业类别,识别精度低于专门训练的模型。

Q3.3 双模型并行推理

同时运行两个模型,合并输出结果:

results_general = model_general(frame) # 通用 80 类 results_custom = model_custom(frame) # 充电口专用 # 合并两组结果后显示

Q4:收集到更多图片后,需要把所有图片重新训练一遍吗?

是的,每次都把所有标注好的图片放在一起全量训练,这是标准做法。如果只用新图片训练,模型会遗忘旧图片学到的知识,效果反而变差。

正确的迭代方式:以上一版 best.pt 为起点,用全量数据继续训练:

# 第二版:42张旧图 + 新增图片,全部放入 data.yaml model = YOLO("runs/detect/dc_charging_v1/weights/best.pt") # 上一版起点,收敛更快 model.train( data="/路径/新版data.yaml", # 包含所有图片 epochs=50, # 已有基础,轮数可减少 name="dc_charging_v2", project="runs/detect", )
图片数量预期效果
20~50 张流程跑通,场景泛化差(换角度/光线可能失败)
100~200 张较稳定,覆盖主要场景变化
500 张以上生产级别可靠性