
简介面向目标检测初学者的YOLOv8自定义数据集训练完整笔记内容覆盖环境安装、图片与标签文件整理、数据集切分与格式转换、模型训练及断点续训等关键环节。整套资源仅包含一份Worddocx格式文档大小约2.18MB以步骤化叙述和命令示例组织便于对照实操当前已有448人学习。文档详细说明安装依赖包和ultralytics库的指令演示将标注好的图片与XML文件分别放入images与xml目录、运行脚本划分训练集和验证集、再转换为YOLO训练所需格式的做法同时逐一解释task、mode、model、data、epochs、batch等训练参数的含义并介绍预训练模型下载与训练命令写法。此外针对训练中可能出现的Arial字体下载失败问题给出了下载并放置到项目根目录的解决办法也讲解了修改default.yaml或使用resume参数实现断点续训的方式能够帮助读者避开常见坑点按流程完成自定义数据集的YOLOv8训练。1. YOLOv8训练自定义数据集把“别人家的模型”变成自己的检测器做目标检测的人多半经历过这种尴尬对着COCO上表现亮眼的YOLOv8权重跑demo一切正常一旦换成自己拍的安全帽、工件或者遥感图精度直接垮掉。原因不复杂——预训练权重没见过你的数据分布迁移学习也得按规矩喂数据、调参数、看损失曲线才能收敛出能用的模型。这份《YOLOv8训练自定义数据集》笔记就是把从原始图片到可用权重的全过程拆开环境怎么搭、目录怎么摆、标注怎么转、超参怎么改、报错怎么查适合手里有数据集但没完整跑通过自训练流程的从业者也适合刚接触YOLOv8想复现一套标准pipeline的新手。下面按我实际跑项目的顺序来写每一节都是踩过坑之后的固定动作。2. 环境与工程骨架先把训练环境装成“不折腾”的样子2.1 版本选型为什么我锁在YOLOv8.1.0附近YOLOv8的ultralytics仓库更新很频繁几个月不用可能API就变了。早年跑通一套流程过阵子换新版本model.train的参数表和回调接口可能已经改了名网上教程对不上号。所以我一般建议锁一个相对稳定的版本而不是追最新。常见做法是pip install ultralytics8.1.0 pip list | grep torch逻辑说明ultralytics这个包自带YOLOv8的模型定义、训练器和数据集工具版本锁住之后复现成本低。torch版本建议2.0以上因为YOLOv8的某些增强操作依赖新版CUDA算子老torch可能跑不起来。参数说明如果你用的是GTX 1660 Ti这类6GB显存的显卡torch别装太高版本CUDA 11.8对应的torch 2.0.x就够用。显存不够时后面训练只能开小batch这个在第4章会细说。2.2 目录约定一张图理清数据、权重和输出有了训练环境下一步是搭目录。YOLOv8对数据集路径要求不算严但目录结构清晰能让你少踩很多“找不到文件”的坑。我习惯这样建yolov8-custom ├── data │ ├── images │ │ ├── train │ │ └── val │ └── labels │ ├── train │ └── val ├── weights ├── runs └── config.yaml逻辑说明data/images/train放训练图片data/images/val放验证图片labels下是对应的标注txt文件。weights放预训练权重runs放每次训练的输出目录config.yaml是数据集配置。参数说明图片和标注的txt必须同名比如img001.jpg对应img001.txt否则训练时YOLOv8会直接跳过这张图。这是新手最容易翻车的地方文件名对不上训练半天损失不降一看日志全是“WARNING: 0 labels found”。2.3 config.yaml写法类别数错了训练就是玄学数据集配置是训练入口内容不多但每个字段都关键。按YOLOv8的约定path: ./data train: images/train val: images/val names: 0: helmet 1: person逻辑说明path是数据集根目录的路径可以用相对路径但建议在config.yaml被调用的那个目录下启动训练避免相对路径找不到。train和val填图片目录的相对路径YOLOv8会自动拼接。names是类别名与索引的映射顺序必须和标注txt里的类别ID一一对应。参数说明类别ID从0开始不是1。如果标注文件里写了1而你的names里0对应的才是helmet那模型训练时会把helmet当背景损失曲线看着正常实际学了个寂寞。3. 数据准备把VOC转成YOLO格式转换脚本与四个边界坑3.1 为什么非转不可YOLO要的是归一化坐标YOLOv8要求的标注是txt格式每行一个目标格式是class x_center y_center width height四个坐标值都是相对于图片宽高的归一化结果。而我们拿到手的标注数据最常碰到的两种格式是VOC的XML和LabelImg导出的XML里面存的是xmin ymin xmax ymax绝对像素坐标。直接用绝对坐标喂给YOLOv8训练会出问题因为缩放和增强时坐标体系对不上。转换方式不复杂核心就一步import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_map): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: class_map {helmet: 0, person: 1} xml_dir xmls out_dir labels os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, xml_file), os.path.join(out_dir, xml_file.replace(.xml, .txt)), class_map)逻辑说明遍历XML目录把每个XML里的object信息解析出来计算出归一化的中心点和宽高写成一行一目标的txt。class_map控制类别到ID的映射和config.yaml里的names必须一致。参数说明坐标输出保留了6位小数够用。归一化计算时除以的是图片原始宽高不是缩放后的。如果你的数据集是直接用ROI截出来的图注意核对XML里size字段和实际图片尺寸是否一致不一致时转换出的坐标全是错的。3.2 边界坑一类别不在映射表里转换时如果XML里有names之外的类别比如背景、未知脚本默认continue跳过。但训练时这类目标就完全不会被学习。我的习惯是把这些类别单独导出一个ignore列表方便回头统计而不是直接丢。3.3 边界坑二零面积框和超界框标注软件有时会标出xmin等于xmax的框归一化后w就是0训练时YOLOv8的loss计算会崩。常见解决是在转换脚本里加一个过滤if w 0 or h 0: continue3.4 边界坑三中文路径和中文类名Windows下如果数据集路径带中文ultralytics内部读图或写日志时容易报编码错误。类名更直接names里如果用中文训练日志和输出权重都能正常出但做部署推理时标签回显会乱码。建议所有类名只用英文字母和下划线路径保持ASCII。3.5 边界坑四数据划分别在脚本里随机做常见做法是先把所有图片放一个文件夹脚本按比例随机划分到train和val。这个思路没错但要注意随机种子问题。我见过有人跑两次转换同一张图一次在train一次在val导致模型过拟合评估失真。正确做法是转换前先把图片清单写好按清单复制图片和对应的txt不做多次随机。4. 训练参数与启动从命令行到损失曲线一次说清4.1 训练入口为什么我推荐命令行而不是Python脚本YOLOv8支持两种训练方式yolo train命令行和from ultralytics import YOLO的Python脚本。两种本质跑的是同一套东西但命令行更适合做实验记录参数直接打在shell里每改一次就是一个可追溯的版本。我的固定写法是yolo train modelyolov8s.pt dataconfig.yaml epochs100 imgsz640 batch8 device0 projectruns/helmet_2024 nameexp1逻辑说明model填预训练权重的路径data是数据集配置epochs是训练轮数imgsz是训练输入尺寸batch是每个batch的图片数device表示用哪张GPU。这行命令跑完模型权重、损失曲线、验证指标全在runs/helmet_2024/exp1里。参数说明imgsz默认640如果你的目标是小物体比如远处的安全帽可以尝试896或1280但显存占用会明显上涨。batch在6GB显存的卡上最多开到8到16根据显存动态调爆显存就先减半。4.2 batch大小与显存的博弈batch不是越大越好小显存硬开大batch会导致OOM训练中断。更隐蔽的问题是过小的batch加默认的增强策略可能出现类别不均衡放大某些类别收敛慢。我一般这么测yolo train modelyolov8s.pt dataconfig.yaml epochs3 imgsz640 batch16 device0逻辑说明先用3个epoch跑通流程观察显存占用接近上限还是有余量再决定正式训练时batch的档位。参数说明OOM时报错信息通常是CUDA out of memory看到这个直接调小batch。如果用了batch-1YOLOv8会自动根据显存算最大batch但实测这个自动值偏激进我会手动减2再跑。4.3 损失曲线怎么看何时加epoch何时该停训练结束后乍一看results.png几条下降曲线训练集和验证集分开长。新手容易犯的错误是只看train的loss忽略val的指标。实际判断标准是import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/helmet_2024/exp1/results.csv) plt.plot(df[epoch], df[train/box_loss], labeltrain box) plt.plot(df[epoch], df[val/box_loss], labelval box) plt.legend() plt.show()逻辑说明results.csv记录每一项指标包括三类loss、精度、召回率、mAP50和mAP50-95。训练过程中如果val/box_loss连续20个epoch不降或反升说明过拟合早停更合理不用硬跑100轮。参数说明如果前10个epoch训练loss就降到很低但val的mAP50不到0.3大概率是数据集类别不均衡或标注质量有问题先回去查数据不是调参能解决的。5. 避坑常见问题排查五条血泪经验5.1 训练日志一堆WARNINGloss不降现象训练时日志滚动输出WARNING: 0 labels found in ...loss数值变化不大。原因图片文件名和标注txt文件名不一致最常见的是图片是.jpgtxt是.txt但大小写不匹配或者标注目录下存在没有对应txt的图。解决写个脚本核对images/train和labels/train下的同名文件数量不一致的分出来处理。常见做法是for f in data/images/train/*.jpg; do base$(basename $f .jpg) if [ ! -f data/labels/train/$base.txt ]; then echo missing label: $f fi done5.2 显存爆了但减小batch还是报错现象CUDA out of memory反复出现batch从16降到8仍然报错。原因除了batchimgsz和workers也会影响显存。输入图越大特征图越占显存workers开太高会导致CPU/GPU数据搬运排队显存空不出来。解决先降imgsz到416跑通后再逐步提回640。workers适中调整比如workers4。5.3 训练正常但验证结果全黑现象训练跑完验证集上mAP为0val_batch_labels.jpg里没有框。原因类别映射和标注类别ID对不上或者验证集中的图本身就没有目标。解决检查config.yaml的names数量和顺序确认转换脚本里class_map完全一致。用打开一张验证图和对应的txt目测坐标是否在图片范围内。5.4 预训练权重加载报错现象Error loading pretrained weight但权重文件明明存在。原因下载的权重文件不完整或者权重版本和ultralytics版本不匹配。解决删除权重文件重新下或换用YOLOv8官方提供的yolov8s.pt不要用第三方转换的中间格式。5.5 数据集大但训练非常慢现象GPU利用率只有30%左右训练一个epoch耗时过长。原因数据加载瓶颈workers太低图片存储在高延迟设备上或者图像解码消耗CPU。解决把图片压成较小尺寸长边不超过1280再训练减少解码负担确认workers至少不低于4如果内存足够可以先将小数据集整体缓存到内存中。但更推荐的方案是保持原图分辨率先用一半的epoch观察收敛趋势再决定是否增补数据。6. 进阶技巧用验证集输出反向查漏训练收敛之后第一件事不是直接部署,而是把验证集的预测结果导出来用框叠在原图上肉眼检查一遍。这一步能发现指标上看不出来的问题比如小目标漏检、同类目标紧贴时被合并框。我的习惯是跑一次model.val再把验证输出目录里的val_batch_pred.jpg逐张过一遍重点看置信度低于0.5的漏检框。具体做法是from ultralytics import YOLO model YOLO(runs/helmet_2024/exp1/weights/best.pt) results model.val(dataconfig.yaml, conf0.25, iou0.6, save_jsonTrue) results.save_dir逻辑说明conf控制置信度阈值iou控制NMS的IoU阈值save_jsonTrue会导出COCO格式的预测结果方便后续做误差分析。results.save_dir是可视化输出的目录所有预测图都在里面。参数说明conf0.25是验证时的常用默认值但实际业务场景如果要求低漏检率可以降到0.1再看这时候能找出哪些目标确实没被训练好而不是被置信度阈值过滤掉。验证通过后下一步才是导出部署格式。如果你要部署到RK3588这类边缘设备那边接收的格式和PC端推理不一样建议在导出ONNX之前先用yolo export modelbest.pt formatonnx imgsz640走一遍确认输出层的shape符合预期。在这之前先回到训练配置里核对类别名和预处理尺寸保证导出时用的参数和训练时完全一致。从那以后我每次训练完都强制走一遍“验证集视觉检查 低置信度漏检分析”再决定要不要调数据或加训练轮数。这套习惯帮我筛出过不少指标漂亮但实际不能用的模型。希望这份笔记能帮你在YOLOv8自训练这条路上少翻几次车。本文还有配套的精品资源点击获取