ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLOv8自定义数据集训练全流程:从数据标注到部署的关键避坑指南

YOLOv8自定义数据集训练全流程:从数据标注到部署的关键避坑指南

第一次用YOLOv8训练自己的数据集,大多数人不是倒在模型上,而是倒在数据上。这句话我反复跟身边想跑目标检测项目的朋友说,他们一开始都不信,觉得既然框架都封装好了,训练不就是敲一条命令的事?结果真到自己上手,先被标注折腾到怀疑人生,再被loss曲线搞得一脸懵,最后模型出了结果却又不知道好坏。这篇东西就是写给准备从零开始训练YOLOv8的人看的,不管你是学生做毕设、工程师做落地项目,还是只想拿开源模型跑通一个Demo,希望你能少走我踩过的那些弯路。YOLOv8的完整流程可以拆成五步:数据准备、环境搭建、模型训练、结果评估、导出部署。每一步都有隐藏的坑,我会按这个顺序把值得注意的细节和判断依据全部讲清楚。

1. 为什么选YOLOv8:从项目需求反推技术选型

1.1 YOLO家族走到v8这一步,到底改了什么

YOLO系列的迭代速度在目标检测圈里一直是独一档的。从v3开始,YOLO成为工业落地的主力,到v5把易用性做到极致,再到v8把训练和部署的体验进一步拉平。很多人只知道YOLOv8是Ultralytics出的新版本,但说不清它相对老一代的v5到底强在哪。

v8最大的结构变化是从anchor-based转向了anchor-free。以前YOLO系列需要预设一组先验框,模型输出的是相对先验框的偏移量,锚框的尺寸和数量直接影响训练效果,调起来还挺玄学。v8改成无锚框设计之后,模型直接预测目标中心点到边界框四边的距离,省去了聚类分析锚框的工作,代码层面简化了不少。配合C2f模块和decoupled head,v8的收敛速度和精度上限都提高了,尤其在中大型模型上表现更明显。

另一个容易被忽略的变化是训练策略上的调整。v8在训练时会使用一些更现代的trick,比如EMA(指数移动平均)来稳定权重、更灵活的Mosaic数据增强比例,以及自动化的超参数优化入口。这些不是可以在论文里看到的具体公式,而是实打实反映在收敛曲线上的改进。对我这种工程向的人来说,最直观的感受是:同样的数据,v8比v5更容易在不多调参的情况下训到一个能用的水平。

1.2 场景优势与适用边界

选YOLOv8不代表它万能。我一般会先想清楚部署环境再选模型。如果你是做边缘设备推理,比如Jetson、RK3588这类算力受限的平台,v8n和v8s是首选,吞吐量和精度比较平衡;如果服务器端推理且有GPU,v8m到v8l可以往上加;v8x的精度最高,但推理延迟也明显上来了,适合对实时性要求不高的离线处理场景。

YOLOv8的短板也很明确。它对极小目标的检测能力依然一般,比如一张大图中几十个像素大小的缺陷点,或者密集排列的细胞核这类场景,纯靠YOLOv8往往不如专门的小目标检测方案,常见的做法是先做图像切片再检测,但这也变相提高了工程复杂度。另外如果目标之间有大量重叠且类别数量很多,边界框的NMS后处理会让人头疼,需要单独调阈值。建议你在项目启动前就把这些问题考虑进去,而不是训完才发现模型满足不了业务。

1.3 动手前先回答的三个问题

我开始做数据集之前,通常会逼自己回答三个问题,这三个问题的答案直接决定了后面的所有配置:

第一,类别之间是不是互斥的?比如你要同时检测"戴安全帽的人"和"没戴安全帽的人",这种类别定义在边界上就会打架:同一个目标可能因为角度问题被两个类别同时"沾边",标注的人会疯掉,模型也会学得混乱。尽量把类别定义成物理上可区分、不会互相包含的对象,比如"人"和"安全帽"单独设类别。

第二,你的采样场景是否覆盖了真实运行环境?这是最容易被忽略的。模型只是在数据分布上做拟合,你给它看的训练图全是白天、晴天、正视角,那它在夜晚、雨天、俯视角的表现几乎必然崩盘。训练之前先列一个环境清单:光照(白天/黑夜/逆光/强反光)、距离(近/中/远)、遮挡程度(完全可见/部分遮挡/密集重叠)、相机角度(平视/俯视/倾斜)。每个组合至少要保证有足够的代表性样本。

第三,部署端的算力能跑多大的模型、期望的延迟是多少?这个问题直接决定了你选yolov8s还是yolov8l,进而影响标注数据量的要求和训练时间。别先训了再说,后面发现部署不上,真是白费功夫。

2. 数据准备:决定精度的第一道工序

2.1 图片采集的"三个覆盖"

很多新手把精力全放在标注上,忽略了采集环节。实际上采集的丰富程度比标注数量更影响模型的上限。我习惯用"三个覆盖"来检查采集质量:覆盖姿态、覆盖光照、覆盖背景。

覆盖姿态是指同一个物体不能总是以同一个角度、同一种形态出现。比如做安全帽检测,如果1000张图里全是正脸戴帽子的工人,模型很可能学到的是"正脸+帽子"这个整体特征,一旦有人背对镜头戴帽子,框就会不稳定。覆盖光照要求你的训练集不能是清一色的均匀光线,要包括侧光、逆光、暗光甚至过曝的样本,这些才贴近真实场景。覆盖背景更直白——同一个物体出现在不同颜色、不同纹理的背景上,模型才不会把背景也当成目标的特征。

举个例子,某项目做厂区皮带机托辊异物检测,最初采集的样本都是在干净背景下的高清图,训练时mAP50到了0.95,一上现场就漏检严重。后来排查发现是现场有大量粉尘和油渍,背景干扰完全不在训练集里。加大量的带噪现场图重新训练之后,问题才解决。这个经验我记到现在:宁可不要高清摆拍图,也要多搞真实环境的"脏图"。

2.2 标注工具选型与标注规范

标注工具方面,老牌的LabelImg依然适合新手入门,它启动简单、操作直观,支持Pascal VOC和YOLO两种导出格式,对几百上千张图的小项目完全够用。但如果你数据集量大、目标形态重复度高,我建议直接用X-AnyLabeling这类支持半自动标注的工具。它内置了多种预训练检测/分割模型,可以先让模型帮你预标注,人工再做修正,速度和纯手动标注完全不是一个量级。

标注规范才是真正拉开差距的地方。我踩过一个很典型的坑:对于"半遮挡的目标到底框到哪"没有统一标准。后来定下来的规则是:如果目标有超过50%的部分可见,就完整标注其外接矩形;如果可见部分不足50%、但能清楚辨认出类别,同样要标出来;完全看不到关键特征的则跳过。还有一个容易犯的错误是,多人协作标注时每人对模糊目标的判断尺度不一样,导致同类目标在不同图上标注的风格漂移。解决方法是先抽一批图让大家分别标注,再对比差异统一口径,这个过程很有必要。

另外一定要记住:漏标比错标更致命。错标只是给某个目标打了错误标签,模型还能从大量正确样本里纠正回来;漏标等于告诉模型"你眼前的这个东西不是目标",它会在检测时主动忽略同类物体,你后期补都难补。我检查数据时有个习惯——图里明明有明显目标却没标框的,优先级最高。

2.3 格式转换与目录组织

YOLOv8要求的标注格式是每张图片对应一个同名的txt文件,文件里每一行是:class_id x_center y_center width height,其中位置信息全部是相对于图像宽高的归一化数值。手工用LabelImg导出时,工具会自动生成这个格式,不用自己计算坐标,这点对新手很友好。如果你是从COCO或VOC数据集转过来,可以用Ultralytics提供的数据转换脚本,也可以自己写,但一定要验证归一化坐标没有越界。

目录结构我强烈建议直接按YOLOv8默认的惯例组织:

dataset/ ├── images/ │ ├── train/ │ └── val/ └── labels/ │ ├── train/ │ └── val/ └── data.yaml

不少人在这一步图省事,把所有图片放一个文件夹,然后靠脚本随机分train和val。结果训练时经常出现train和val里包含同一张原始图的情况,造成指标虚高,模型泛化能力被高估。我建议在采集阶段就给每个来源的数据打上分组标记,按时间或者按场景切片划分,比如前十天采集的图做train、后两天做val,这样能更真实地反映模型在未见数据上的表现。

2.4 训练前最后一道关卡:数据清洗与可视化检查

标注完不等于数据准备完。我在训练前一定会跑一遍检查脚本,把每张训练图的标注框叠加回原图,输出成可视化图集,然后快速浏览一遍。这一步能发现很多纯看txt发现不了的问题:比如某张图的标签和图像内容完全不匹配、框明显偏移、重复的样本,还有归一化坐标写错导致的巨大矩形。我自己就曾经把一张图的坐标写反,训练的时候loss崩成NaN,排查了半小时才发现是数据问题。

数据清洗的另一项工作是检查负样本。负样本指不包含任何目标、但会在真实场景中出现的背景图。加入适当的负样本可以降低误检率。我常用的比例是正样本数的5%到10%作为负样本,不需要标注,直接放空label文件即可。这个操作很简单,但对抑制模型乱框有奇效。

至于数据增强,v8在训练阶段默认开启了Mosaic、随机翻转、HSV扰动等策略,所以大部分情况下不需要再额外做离线增强。有些教程会建议预先做旋转、裁剪、加噪来扩充数据集,我的建议是谨慎:离线增强会让模型见过重复样本,如果数据量不大反而容易过拟合,而且增加了磁盘占用和加载时间。优先保证原始样本的多样性,而不是盲目堆增强图像。

3. 环境搭建与训练配置:把坑提前踩平

3.1 安装环节的几个关键选择

环境这块不复杂,但不注意版本匹配会浪费很多时间。我的建议是先用conda建一个独立环境,Python版本选3.9或3.10,然后安装PyTorch。PyTorch的安装要跟你的CUDA驱动版本匹配,nvidia-smi里显示的CUDA版本只是驱动支持的版本上限,实际要用的是PyTorch里绑定的CUDA运行库。至今还有同学在第一步搞混这两个概念,导致torch装上去但GPU用不了。

装完PyTorch后验证一下:

python -c "import torch; print(torch.cuda.is_available())"

输出True再继续。然后是Ultralytics包,直接用pip:

pip install ultralytics

这个包会把核心依赖都装上,日常训练推理完全够用。我额外提醒两点:第一,训练代码最好在requirements.txt里锁定版本,比如ultralytics==8.2.0,因为新版本偶尔会调整参数默认值,不同版本训练同一份数据的指标可能略有差异,锁定版本才能保证可复现;第二,如果你的需求只是用官方接口训练和推理,不要去网上找那些"魔改版"代码,容易跟新版本冲突。

3.2 data.yaml与模型配置文件的写法

YOLOv8训练的核心配置是data.yaml。它的字段不多,但格式必须严格。常见写法如下:

path: /home/yourname/dataset train: images/train val: images/val names: 0: person 1: hardhat 2: vest

需要特别注意的是path字段最好写绝对路径,或者保证相对路径的层级是正确的。很多新手把data.yaml放在别的目录下,结果train路径配错,训练时一直报"no labels found"。我建议把data.yaml和数据集放在同一个顶层目录里,train和val字段只用相对路径,这样迁移到别的机器上改一行path就行。另外names里的id顺序必须和标注txt文件里的class_id完全一致,否则模型训练得越久错得越离谱。

模型配置文件一般不需要自己改。你可以在命令行里直接指定model=yolov8s.pt,Ultralytics会加载对应的结构和预训练权重。如果你想自定义模型的宽度或深度,可以复制yolov8.yaml然后修改scale参数,但对绝大多数场景没有必要,直接选n/s/m/l/x五个规格之一就够了。

3.3 预训练权重到底是干什么用的

这个问题值得好好讲。YOLOv8的模型权重分两类:一类是.pt格式的完整权重,包含模型结构和参数,比如yolov8s.pt;另一类是纯YAML配置文件,里面只有网络结构定义,没有训练过的参数。我第一次训练的时候,以为用yolov8s.yaml指定结构、然后从头训才是"干净",结果花了两倍时间才收敛,精度还不如用预训练权重微调。

正常的做法是:使用在COCO数据集上预训练好的yolov8s.pt作为初始权重,在你的自定义数据集上做fine-tune。因为预训练权重已经学到了大量通用的边缘、纹理、形状特征,你的数据量哪怕只有几百张,也能在一个较优的起点上继续优化。除非你的任务和自然图像差异极大,比如X光图像、超声图像这些,才需要考虑从零训练。但即便是这种场景,先拿预训练权重试一下通常也不会亏,毕竟损失的是少量训练时间,获得的是可能更快的收敛。

3.4 超参数:batch、epoch、imgsz、lr的设置原则

这些参数官方给了默认值,但默认值不一定是适合你的值。先说batch size,它受显存限制,不同规格模型在相同batch下的显存占用相差很大。以16G显存为例,yolov8s开batch=16基本没问题,yolov8l可能只能开batch=8。一个粗略估算公式是:显存占用约等于每张图的像素数乘以batch还有一些中间变量,通常用batch=16起步,显存不够就降为8、4。

关于epoch,官方默认是100。但如果你的数据集不大,100轮通常足够收敛,甚至会有过拟合风险。我习惯先跑100轮,看val曲线是否在后期还在下降,如果还在下降就增加到150到200轮。另一个技巧是直接开启early stopping,YOLOv8默认就带有早停功能,连续多个epoch val指标没有提升就会自动停止训练,省时省力。

imgsz即训练尺寸,默认640。如果你的目标整体偏小,比如摄像头下30米远的行人,可以尝试把imgsz调到960甚至1280,检测效果往往有显著提升,代价是显存和时间成本成倍增加。学习率一般用默认的0.01即可,如果loss震荡明显,降到0.005试一下。让新手一开始就做贝叶斯超参搜索意义不大,先用默认值跑通流程,再基于loss曲线做微调才是务实的路径。

4. 训练过程的监控与调优:从loss曲线里读问题

4.1 训练命令与日志解读

数据准备好了,环境没问题,就可以启动训练了。我常用的命令是这样:

yolo train data=data.yaml model=yolov8s.pt epochs=150 imgsz=640 batch=16 device=0

训练开始后终端会滚动输出每个epoch的指标,包括box_loss、cls_loss、dfl_loss,以及precision、recall、mAP50、mAP50-95这些关键数字。第一次跑的人往往会盯着mAP看,其实训练前期更应该关注loss的下降趋势。loss下降正常说明模型在"学到东西",mAP在早期偏低是完全正常的,不用焦虑。

训练结果会统一保存在runs/detect/train目录下,每次训练生成一个带编号的文件夹。里面除了每个epoch的权重,还有训练过程的曲线图、验证集的预测可视化图,以及混淆矩阵。我强烈建议养成习惯,每轮训练结束后都打开results.png看一下全局指标曲线,再打开val_batch的预测图直观感受检测效果,比只看数字全面得多。

4.2 loss曲线的正常形态与异常形态

看loss曲线有几个基本判断标准。正常情况下,train loss和val loss应该都是平滑下降的,前期下降快,后期趋缓并逐渐平稳。train loss持续下降、val loss却不再下降甚至回升,这是过拟合的典型信号,通常在训练后期出现。如果两个loss都在震荡、毫无下降趋势,常见的原因是学习率太大,或者是数据本身存在大量错误的标注框,模型一直在被互相矛盾的监督信号拉扯。

还有个很容易被忽略的点:YOLOv8的loss有多种组成部分,box_loss和cls_loss的下降速度并不一致。如果你看到cls_loss下降很慢,先检查类别定义是否模糊、标注的类别是否正确,而不是急着调学习率。我自己遇到过一类工业品检测,两个类别外观极其相似,cls_loss始终降不下去,后来重新审视标注规范,把类别边界重新划定,问题才改善。

4.3 mAP50与mAP50-95的实用读法

mAP的全称是mean Average Precision,多类别的平均精度。mAP50指的是IoU阈值为0.5时的平均精度,它衡量的是模型"大概找得到目标"的能力,对框的精确位置要求不高;mAP50-95则是在0.5到0.95多个IoU阈值下计算的均值,对边界框的定位精度要求非常严格,是学术界的主流评判标准,也是衡量模型综合能力更严格的指标。

实操中怎么读这两个数?如果你的业务只是"判断画面里有没有目标、目标大概在哪",比如安防领域的人形检测,mAP50达到0.9以上已经相当可用;如果后续要做机械臂抓取、自动分拣这类对框精度敏感的工位,就必须同时关注mAP50-95,它反映的是框贴合目标边缘的程度。我见过一个团队,模型的mAP50很好看,结果接到一个需要精确裁剪目标的业务,做出来的图边界误差大得无法使用,就是因为在训练阶段没有盯mAP50-95。

4.4 过拟合、欠拟合的识别与对策

过拟合在目标检测里的表现是:train loss降得很低,val指标变差,或者val曲线在某个epoch后开始回落。对策从易到难排列:第一是加大数据增强力度,YOLOv8的开源增强策略已经内置了参数,可以在配置里调高Mosaic的概率;第二是降低模型复杂度,比如从yolov8l换到yolov8s,让模型没有那么多容量去记忆训练集;第三是减少epoch,配合早停机制,训练到拐点就停。还有一个容易被忽略的办法:增加val集的数据多样性,如果val集本身就太小、太单一,曲线的波动会让你误判过拟合。

欠拟合的表现则是train和val的loss都居高不下,模型在训练集上就没学好。首先检查是不是学习率太低或者模型太小,其次更大概率是数据问题——噪声数据过多、标注质量太差、样本数量不够。我在这种情况下会先做一次"数据体检":抽取五十张训练图,人工核对标注框质量,只要发现超过两三张有明显问题,就先清洗数据再继续调参。数据不干净,调什么都白搭。

5. 模型评估与部署:从val到真实场景的闭环

5.1 用混淆矩阵和PR曲线精准定位问题

训练结束后,官方会在结果目录里自动生成confusion_matrix.png。这张图在分类问题里很常见,在检测里类似,可以告诉你哪些类别之间被模型混淆。我在项目里遇到过一个经典场景:工人和叉车同时出现在画面里,模型经常把站在叉车旁边的人框成叉车,或者反过来。看混淆矩阵发现person和forklift这两个类别之间有大量互相误判,说明两者外形轮廓在某些角度下确实接近,或者标注时没有严格区分"被车挡住一半的人"。这时候去补一批难样本并重标,比盲调参数有效得多。

PR曲线图(precision-recall curve)则反映了置信度阈值变化时精度与召回率的权衡关系。如果曲线在左上角贴着坐标轴走,说明模型很健康;如果曲线明显凹陷,说明在低置信度区域有大量误检。结合业务需求选择置信度阈值时,可以直接从这张图上找到平衡点:宁可误报也不漏报的场景,阈值就调低一点;宁可漏报也不误报的场景,阈值则调高一些。

5.2 导出ONNX与TensorRT的完整流程

模型在PyTorch里验证通过,只是第一步,生产部署通常需要转换格式。ONNX是目前最通用的中间表示,导出命令很简单:

yolo export model=runs/detect/train/weights/best.pt format=onnx opset=12

导出后可以用ONNX Runtime做CPU或GPU推理,也可以用OpenVINO在Intel设备上跑。如果部署平台是NVIDIA的GPU,更进一步的优化是直接导出TensorRT引擎:

yolo export model=runs/detect/train/weights/best.pt format=engine device=0 half=True

这里有个容易踩的大坑:TensorRT生成的engine和具体的GPU型号、显存大小、CUDA版本、TensorRT版本都强绑定。你在开发机上导出的engine,拷到另一台不同型号的服务器上,大概率无法直接加载,需要在目标设备上重新导出。所以正确的流程是:代码和权重统一,engine在部署机上现场生成。

5.3 推理脚本里最容易被忽略的三个参数

官方yolo predict命令简单好用,但到生产环境你通常要自己封装推理逻辑。三个参数必须认真对待:置信度阈值conf、IoU阈值iou和输入尺寸imgsz。

置信度阈值直接影响误检和漏检的平衡,默认0.25。业务场景里报警类应用通常要低误报,我会把conf提高到0.4甚至0.5;如果目标是尽可能不丢目标、允许人工翻看,conf降到0.1到0.15也可以,但要注意误报会明显增加。iou阈值是NMS用的,默认0.7,如果检测目标之间有大量重叠,比如车厢里的人挤在一起,iou调低一点(0.45到0.5)可以避免相邻目标被NMS合并丢失;反之目标稀疏的场景,可以保持默认。

输入尺寸的一致性更关键。训练时用了640,推理时如果把图片直接resize成512,模型看到的目标尺度比例就不对了,精度会无谓下降。YOLO系推理通常会做letterbox预处理,即等比缩放后用灰色填充到目标尺寸,而不是拉伸变形。这一点在自写推理脚本时特别容易踩,很多奇怪的低精度问题都是resize方式不匹配导致的。

6. 高频踩坑清单:按现象快速定位根因

6.1 loss为NaN或训练直接崩溃

训练刚开始loss就是NaN,这种事碰到过的人都懂那种无力感。我的排查顺序是:先看是不是显存不够导致OOM,日志里通常会有明确的CUDA out of memory字样,这种情况需要降batch或开启gradient accumulation。排除显存后看学习率,学习率过大会让loss直接爆炸成NaN,调回0.001到0.01再试。如果学习率也没问题,就要怀疑数据了——打开所有训练图对应的txt,检查框的坐标是否异常,比如width或height为0、坐标值超出0到1范围、类别id超出names列表长度。还有一种隐蔽的情况是输入图本身存在损坏的像素值,用PIL读出来是None或者全黑图,这种图会让预处理阶段产生NaN,需要提前写脚本把坏图筛掉。

6.2 检测效果差:漏检、误检、边界框偏移的归因顺序

模型训完但效果不如预期,最先要做的是把问题分类:是漏检(该框没框)、误检(不该框乱框),还是框偏(框了但位置不准)。漏检优先查数据集是否覆盖了对应场景,很多时候模型没见过"那个角度的目标",漏检是必然结果;其次调低置信度阈值看是否有改善,如果阈值一低就出来了,说明模型其实学到了,只是置信度分数偏低。误检先看负样本是否足够,再看类别定义是否太宽泛,比如"人"这个类别包含了各种姿态和穿着,出现大量误检时可以拆分出更细的子类。框偏则优先看标注质量,框偏移通常和标注框本身就不准强相关。

某仓储机器人项目的经历很典型:模型在实验室的白天环境mAP50有0.93,一到现场晚上就漏检严重。团队起初疯狂调模型参数,没有任何改善。后来有人拍了几张现场夜视图加到训练集,重新训练后效果立刻有明显提升。这个案例我经常拿来提醒别人:数据分布和真实场景的差距,是模型效果差的第一嫌疑对象。

6.3 显存不足与训练速度异常的排查

显存不足的处理比较直接:降低batch、降低imgsz、改用更小的模型。但训练异常的慢则要分开看。先检查GPU利用率,在训练另一个终端跑nvidia-smi -l 1,如果GPU利用率经常掉到50%以下,说明瓶颈在数据读取。此时把数据预取worker数从默认的8往上调,或者检查是否用了机械硬盘读取大量小图,改用SSD会有明显改善。如果GPU利用率接近100%但单epoch时间仍长,那确实是模型计算量太大,需要换小模型或降低输入尺寸。

另外推荐开启AMP混合精度训练,也就是amp=True,在绝大多数GPU上能把训练时间缩短近一半,精度损失极小。官方训练命令默认就开启了这个选项,但如果你使用自定义的训练脚本,记得确认。

6.4 随机种子与结果可复现

同一个数据集、同一个命令,两次训练的结果不可能完全一致,这是深度学习里的常态。但差异太大就有问题。YOLOv8官方提供了seed参数,设置seed=0能尽量减少随机性。对项目团队协作来说,我强烈建议把训练命令、seed、数据版本、依赖版本都记录在一个固定的配置文件里。之前帮某开发者排查问题,发现同一个数据集在两个环境上mAP50差了接近0.03,最后定位到两边Ultralytics版本差了三个小版本,数据增强细节有改动导致指标差异。从那以后,我凡是做跨机器协作,一定锁死版本并记录完整的复现命令。

关于数据版本管理,最好给每个版本的训练集打个标签,比如hardhat_dataset_v1.2。不要用"最终版""最终版2"这种命名,也别在图集文件夹上直接覆盖更新,因为一旦模型效果变差,你根本不知道用的是哪批数据训练的,回溯问题会非常痛苦。

最后再说一点自己的习惯。我每次训练完,除了看指标曲线之外,一定会点开results目录里那几张预测可视化图,特别是val_batch1_pred.jpg。指标告诉你好不好,可视化告诉你到底哪里好、哪里不好——框的位置准不准、漏了哪个角落的目标、有没有莫名的重复框,这些在数字里看不出来的问题,一眼扫过去就有数。模型训练是门实践手艺,跑通一次流程不难,难的是在每次训练后多花十分钟做这个"复盘"。坚持几轮下来,你会对YOLOv8的脾气摸得很透,以后再换任何数据集都胸有成竹。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进