ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv8实例分割实战:从环境搭建、数据标注到模型部署全流程

YOLOv8实例分割实战:从环境搭建、数据标注到模型部署全流程 自己做过一段时间YOLOv8目标检测本来觉得已经够用了。直到有个项目要求把检测出来的目标轮廓抠出来而不是简单画个框我才真正意识到检测和分割之间那道分水岭。目标检测告诉你这里有东西输出的是矩形框坐标实例分割告诉你这个东西具体占哪些像素输出的是逐像素的掩码。对于很多场景来说后者才是真正能落地到业务里的结果。这篇内容就围绕YOLOv8实例分割展开从环境搭建、数据集制作、模型训练到评估和部署把全流程的实操细节和踩坑记录都过一遍。覆盖的环境是Windows PyCharm NVIDIA显卡这套组合也是日常问得最多的。无论你是刚接触YOLO系列想从检测转分割还是已经在训练但结果不理想想排查问题这篇都可以当一份操作手册来翻。1. 为什么选YOLOv8做分割模型家族与硬件匹配分析1.1 实例分割和目标检测的本质差异目标检测的输出很好理解每个目标一个框附带一个类别标签和置信度。YOLOv8检测模型的输出形式是(x_center, y_center, width, height, class_scores)框是矩形是目标的最小外接矩形。问题是真实物体几乎没有矩形轮廓一个框很容易把背景也包含进去。实例分割的输出是一个二进制掩码对每个像素做判断——这个像素属于哪个目标实例。YOLOv8-seg模型的输出除了检测分支外还额外有一个分割分支输出原型掩码和掩码系数两者做矩阵乘法得到最终的分割结果。这种方式比直接预测稠密掩码更高效也是YOLOv8分割速度能保持实时的核心原因。打个比方检测像用粗笔圈出重点分割像用精细的笔沿着边界描出来。前者快但粗糙后者细但计算量大。实际项目中怎么选如果你的下游任务只需要定位、计数、筛选检测足够如果要算面积、测量尺寸、做精细裁剪、判断边缘缺陷那就必须上分割。1.2 YOLOv8-seg模型家族与参数对比YOLOv8分割系列同样分为n/s/m/l/x五个尺寸从轻量到高精度依次递进。训练自己的数据集时模型选型直接决定训练速度和最终效果不能盲目上大模型。模型参数量(约)输入尺寸适用场景最低推荐显存YOLOv8n-seg3.4M640边缘设备、实时推理2GB可跑推理4GB可训练YOLOv8s-seg11.8M640入门训练首选、中等精度需求6GB可训练YOLOv8m-seg27.3M640精度优先、显卡不低于8GB8GBYOLOv8l-seg46.9M640高精度场景12GB以上YOLOv8x-seg71.7M640追求极致精度16GB以上热词里有人问GTX 1660 Ti能不能跑YOLOv8这里明确回答能跑而且训练也没问题。GTX 1660 Ti是6GB显存对应上表用yolov8n-seg或yolov8s-seg搭配合理的batch size完全可行。我自己就在1660 Ti上跑过yolov8s-segbatch size设8图片缩放到640训练一个3000张图的数据集单epoch大概两三分钟整体能接受。但如果想跑m或l版本6GB显存会非常吃力容易爆显存不建议。1.3 显存不够时的调参降级策略很多人的显卡是6GB甚至4GB显存又必须训练较大模型这时候有几个降级方案按优先级排降低batch size这是最直接的手段比如从16降到4显存占用能减少一半以上。batch太小会导致梯度震荡可以搭配梯度累积来弥补。缩小输入分辨率imgsz从640降到512或416显存占用随分辨率平方级下降。代价是精度会有一定损失小目标受影响最明显。开启混合精度训练YOLOv8默认已经开启AMP自动混合精度训练时显存占用能降低约30%而且速度更快。梯度累积batch size设4累积4步再更新梯度等效于batch size 16的效果。这个操作需要手动改训练脚本或调用ultralytics库的底层API才能做到。我的实际经验是如果显存只有6GB优先选s版本imgsz 640batch 8这个组合在精度和训练速度之间最平衡。如果显存只有4GB老老实实选n版本或者把imgsz降到512。2. 环境配置的黄金组合Windows PyCharm下从零跑通YOLOv8-seg2.1 版本组合避坑CUDA、cuDNN、PyTorch三者如何匹配环境配置这块是新手最大的拦路虎。很多人装了半天最后torch.cuda.is_available()返回False问题几乎都出在版本匹配上。先说结论我推荐一套目前比较稳妥的组合组件推荐版本Python3.9或3.10PyTorch2.0.0或2.0.1CUDA Toolkit11.8配合PyTorch 2.0.x默认编译版本cuDNN8.6.0或8.7.0ultralytics8.0.x及以上建议保持最新NVIDIA驱动525以上为什么推荐CUDA 11.8而不是12.x因为PyTorch 2.0.x的官方预编译包从CUDA 11.7和11.8开始支持11.8版本生态最成熟编译出来的wheel兼容性最好。CUDA 12.x能用但需要确认你的驱动版本支持PyTorch 2.1之后才完全适配CUDA 12.1。注意nvidia-smi里显示的CUDA Version是驱动支持的最高CUDA版本不等于你要安装的CUDA工具包版本。比如驱动显示CUDA 12.1你照样可以用CUDA 11.8的PyTorch因为PyTorch自带CUDA运行库不依赖系统里装的CUDA Toolkit。这个认知能帮你避开很多困惑。Python版本建议3.9或3.103.11以上部分依赖包可能会有兼容问题虽然ultralytics官方支持3.8到3.12但我在3.11环境下遇到过某些第三方库编译失败的问题老老实实用3.10最省心。2.2 conda环境创建与安装命令尽量用conda管理Python环境与系统Python隔离避免把环境搞乱。具体步骤如下# 创建Python 3.10环境 conda create -n yolov8 python3.10 -y conda activate yolov8 # 安装PyTorchCUDA 11.8版本 pip install torch2.0.0 torchvision0.15.0 --index-url https://download.pytorch.org/whl/cu118 # 安装ultralytics pip install ultralytics # 安装标注工具后面数据集环节会用到 pip install labelme如果显卡是30系或更老的20系CUDA 11.8都能跑得很好。40系显卡也没问题PyTorch 2.0对40系的Ada架构已经有完整支持。2.3 验证环境是否成功配置完环境先别急着训练先做两个验证import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))如果输出True和你的显卡型号说明PyTorch正确调用了GPU。如果输出False大概率是装成了CPU版本或者CUDA版本不匹配。然后跑一个最简单的预测脚本验证整体流程from ultralytics import YOLO # 加载预训练分割模型 model YOLO(yolov8n-seg.pt) # 跑一张官方示例图 results model(https://ultralytics.com/images/bus.jpg, saveTrue)第一次运行会自动下载yolov8n-seg.pt权重文件跑完会在当前目录生成runs/segment/predict文件夹里面保存了分割可视化结果。能看到每个目标被不同颜色的掩码标记出来说明整个环境链路已经通了。2.4 PyCharm里的配置要点在PyCharm里使用conda环境时注意三点在Settings → Project → Python Interpreter中选择刚才创建的yolov8环境而不是系统默认环境。如果终端命令找不到conda activate在Settings → Tools → Terminal里修改Shell path为cmd.exe然后在终端里正常激活环境。训练时如果提示内存不足在PyCharm的Help → Change Memory Settings里把堆内存调大一点虽然训练主要在GPU上但数据加载阶段的CPU内存占用也不小。3. 数据集准备从LabelMe标注到YOLO格式转换全流程3.1 标注工具选型对比做实例分割标注工具的选择直接影响效率。我对比过几个主流工具工具优点缺点适用场景LabelMe轻量、安装简单、多边形标注功能相对基础个人项目、小规模数据X-AnyLabeling支持AI辅助标注、自动分割安装相对复杂大规模数据标注CVATWeb端协作、功能丰富需要部署服务端团队协作标注LabelStudio支持多模态标注配置偏重综合型项目对于入门和中等规模数据集LabelMe完全够用。如果数据量超过几千张强烈建议用X-AnyLabeling的自动分割功能做预标注然后人工修正效率能提升好几倍。3.2 LabelMe标注操作流程安装完LabelMe后命令行输入labelme启动然后按以下流程操作点击左侧Open Dir选择图片文件夹。点击Edit → Create Polygons用鼠标沿着目标轮廓边缘打点一个多边形可以打几十个点点越多轮廓越精细。每画完一个多边形弹窗里输入类别名一定要和后续data.yaml中的names严格一致这里最容易踩坑。点击Save保存JSON文件默认保存到图片相同路径建议后续统一规划目录时再移动。标注小技巧对于弯曲边缘不必密集到每个像素都打点多边形顶点间距在边缘弯曲处适当加密、直线处稀疏即可YOLO的分割头对标注精度的容忍度比想象中高。但如果要计算面积或做精细质检标注密度就要高一些。我自己标注的经验是一条平滑弧线大概需要8-12个点复杂轮廓可以到20个点。3.3 JSON转YOLO格式的脚本实现LabelMe保存的是JSON格式YOLO训练需要的是TXT格式每行代表一个目标格式为class_id x1 y1 x2 y2 ... xn yn其中坐标是归一化后的除以图片宽高n是顶点数。下面是我用的转换脚本可以直接复制使用import json import os from pathlib import Path from PIL import Image def convert_labelme_json_to_yolo(json_path, output_dir, class_dict): 将LabelMe的JSON转换为YOLO分割格式TXT with open(json_path, r, encodingutf-8) as f: data json.load(f) image_path data[imagePath] image_full_path os.path.join(os.path.dirname(json_path), image_path) with Image.open(image_full_path) as img: img_width, img_height img.size output_lines [] for shape in data[shapes]: label shape[label] if label not in class_dict: print(f警告未知类别 {label}跳过) continue class_id class_dict[label] points shape[points] # 坐标归一化 normalized_points [] for x, y in points: nx min(max(x / img_width, 0.0), 1.0) ny min(max(y / img_height, 0.0), 1.0) normalized_points.extend([nx, ny]) line f{class_id} .join([f{p:.6f} for p in normalized_points]) output_lines.append(line) if output_lines: output_filename Path(json_path).stem .txt output_path os.path.join(output_dir, output_filename) with open(output_path, w) as f: f.write(\n.join(output_lines)) print(f已转换: {output_filename}) else: print(f跳过空标注: {json_path}) # 使用示例 class_dict {bottle: 0, cup: 1, chair: 2} # 类名和ID对应关系 # 注意假设json_path是单个文件的路径实际使用时用循环遍历整个目录 json_path path/to/your/file.json output_dir path/to/output/labels convert_labelme_json_to_yolo(json_path, output_dir, class_dict)实际使用时写一个循环处理整个目录的JSON文件核心逻辑就是上面这段。坐标归一化有两个容易算错的地方一是忘记除以图片宽高二是把x除以高度、y除以宽度这两个错误会导致训练时模型完全学不到东西。3.4 数据校验转换后必须做的一步转换完标签后建议写一个可视化脚本把TXT里的坐标画回原图检查标注是否错位。这一步能发现坐标归一化错误、类别ID错乱、标签文件与图片不匹配等问题。import cv2 import numpy as np def verify_yolo_label(image_path, label_path, class_names): 将YOLO格式的标签可视化到原图上 img cv2.imread(image_path) h, w img.shape[:2] with open(label_path, r) as f: lines f.readlines() colors [(0, 255, 0), (0, 0, 255), (255, 0, 0), (0, 255, 255)] for line in lines: parts line.strip().split() if len(parts) 7: # 至少需要class_id 3个点 continue class_id int(parts[0]) points np.array([(float(parts[i]) * w, float(parts[i1]) * h) for i in range(1, len(parts), 2)], dtypenp.int32) cv2.polylines(img, [points], True, colors[class_id % len(colors)], 2) cv2.putText(img, class_names[class_id], (points[0][0], points[0][1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, colors[class_id % len(colors)], 2) return img # 使用 class_names [bottle, cup, chair] img verify_yolo_label(image.jpg, label.txt, class_names) cv2.imshow(Verify, img) cv2.waitKey(0)如果看到多边形和目标轮廓完全吻合说明标签数据没问题可以放心进入训练环节。如果发现所有标注都偏移了一个固定量多半是归一化时没有除以图片宽高需要回头检查转换脚本。4. 训练核心配置与参数调优让别人踩坑你避坑4.1 数据集目录结构与data.yaml配置数据集目录我推荐按照YOLO官方约定的结构组织datasets/ ├── mydataset/ │ ├── images/ │ │ ├── train/ # 训练图片 │ │ └── val/ # 验证图片 │ ├── labels/ │ │ ├── train/ # 训练标签TXT │ │ └── val/ # 验证标签TXT │ └── data.yaml图片和标签要严格按images/xxx.jpg对应labels/xxx.txt文件名必须完全一致不含扩展名的部分。划分train/val时建议按8:2或9:1的比例随机划分但要注意同一场景的连续帧图片不要同时出现在训练集和验证集否则会导致验证结果虚高。data.yaml文件内容是训练配置的核心位置放在mydataset/目录下path: D:/datasets/mydataset # 数据集根目录的绝对路径 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 nc: 3 # 类别数 names: [bottle, cup, chair] # 类别名称必须和标注时的名称一致这里特别提醒两个坑path路径分隔符Windows上用反斜杠\会出现转义问题建议使用正斜杠/或者D:/datasets/mydataset这样的格式YOLO在Windows上解析路径时对正斜杠支持更好。names和nc一致性nc必须等于names列表的长度且类别顺序要和你转换标签时的class_dict保持一致。如果标签里class_id是1代表cup但names列表里第1位是bottle类别就完全对不上了训练出来预测结果会张冠李戴。4.2 训练命令与关键参数解读数据准备好后一行命令启动训练yolo segment train dataD:/datasets/mydataset/data.yaml modelyolov8s-seg.pt epochs100 imgsz640 batch8 device0 workers4逐个解读关键参数model指定预训练权重。用yolov8s-seg.pt做预训练比从零训练收敛快很多这叫迁移学习。YOLO的预训练权重是在COCO数据集上训练的虽然你的数据集和COCO差异可能很大但底层特征提取器的泛化能力仍然能迁移过来。epochs训练轮数。起步建议100轮然后根据损失曲线和mAP曲线决定是否继续。数据量小几千张时100轮足够数据量大可以设200到300轮。imgsz输入图片尺寸。训练和推理时会做letterbox缩放保持长宽比不变。640是默认值兼顾精度和速度。如果只有小目标可以适当增加到960或1280但显存占用会显著上升。batch批量大小受显存限制。6GB显存设88GB显存设1612GB以上可以设32或更大。device指定GPU编号device0表示使用第一张显卡。CPU训练强烈不推荐一个epoch可能要跑几十分钟。workers数据加载线程数Windows上建议设为2或4设置过大会出现DataLoader worker错误。训练开始后终端会实时打印每个epoch的训练损失、验证损失、mAP50、mAP50-95等指标。训练过程中如果loss出现NaN立即停止训练先检查数据中是否有空标签文件或异常坐标通常问题出在数据上。4.3 损失函数曲线绘制训练过程的可视化监控训练过程中产生的所有指标都会保存到runs/segment/trainX/results.csv文件里用pandas读出来画图可以直观判断训练状态。热词里有人专门搜yolov8画损失函数曲线图这里给出我一直在用的绘图脚本import pandas as pd import matplotlib.pyplot as plt # 读取训练日志 df pd.read_csv(runs/segment/train2/results.csv) # 去除列名首尾空格 df.columns df.columns.str.strip() # 创建子图 fig, axes plt.subplots(2, 2, figsize(12, 8)) # 绘制训练损失 axes[0, 0].plot(df[epoch], df[train/box_loss], labelBox Loss) axes[0, 0].plot(df[epoch], df[train/seg_loss], labelSeg Loss) axes[0, 0].plot(df[epoch], df[train/cls_loss], labelCls Loss) axes[0, 0].set_title(Training Loss) axes[0, 0].legend() axes[0, 0].set_xlabel(Epoch) # 绘制验证损失 axes[0, 1].plot(df[epoch], df[val/box_loss], labelVal Box Loss) axes[0, 1].plot(df[epoch], df[val/seg_loss], labelVal Seg Loss) axes[0, 1].plot(df[epoch], df[val/cls_loss], labelVal Cls Loss) axes[0, 1].set_title(Validation Loss) axes[0, 1].legend() axes[0, 1].set_xlabel(Epoch) # 绘制mAP曲线 axes[1, 0].plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) axes[1, 0].plot(df[epoch], df[metrics/mAP50-95(B)], labelmAP50-95) axes[1, 0].set_title(mAP) axes[1, 0].legend() axes[1, 0].set_xlabel(Epoch) # 绘制精确率和召回率 axes[1, 1].plot(df[epoch], df[metrics/precision(B)], labelPrecision) axes[1, 1].plot(df[epoch], df[metrics/recall(B)], labelRecall) axes[1, 1].set_title(Precision Recall) axes[1, 1].legend() axes[1, 1].set_xlabel(Epoch) plt.tight_layout() plt.savefig(training_curves.png, dpi150) plt.show()参数说明df中的列名会因为YOLO版本不同而有差异手动打印df.columns查看一下实际列名再画图。画出来的曲线怎么判断训练状态训练损失持续下降、验证损失也开始下降但还没到平台期继续训练。训练损失下降但验证损失不再下降甚至上升开始过拟合早停或减少epochs。训练损失和验证损失都几乎不下降学习率可能不合适或者数据有问题标注错误、类别错乱。所有loss都很低但mAP低大概率是类别不平衡或数据分布问题检测模型没学好少数类。4.4 模型文件的保存与选择训练结束后runs/segment/trainX/weights/目录下会生成两个文件best.pt验证集上mAP最高的模型后续推理和部署用它。last.pt最后一个epoch的模型用来继续训练加resumeTrue参数。我见过很多人在测试时用了last.pt发现效果不好以为是训练失败了。实际上如果训练后期过拟合last.pt可能比best.pt差很多。推理和部署一律选择best.pt这是经验教训。5. 模型评估、预测可视化与部署转换5.1 评估指标怎么看mAP50、mAP50-95和PR曲线训练完不要急着部署先在验证集上做一次评估命令yolo segment val modelruns/segment/train2/weights/best.pt dataD:/datasets/mydataset/data.yaml评估完成后会自动在runs/segment/valX/目录下生成混淆矩阵、PR曲线、F1曲线等图表。核心要关注两个指标mAP50IoU阈值0.5下的平均精度反映大致能检测到目标的能力。mAP50-95多个IoU阈值0.5到0.95下的平均精度反映掩码边界预测的精确度这个指标更严苛。实际项目中我见过mAP50高达0.95但mAP50-95只有0.6的情况说明模型能检测到目标但分割的边界不够精细。如果是这种情况可以在predict时把掩码后处理做得细致一点或者收集更多边界复杂的数据重新训练。5.2 用训练好的模型做预测单张图片、图片文件夹、视频都可以用predict命令处理# 预测单张图片 yolo segment predict modelruns/segment/train2/weights/best.pt sourcetest.jpg conf0.25 saveTrue # 预测整个文件夹 yolo segment predict modelruns/segment/train2/weights/best.pt source./test_images/ conf0.25 saveTrue # 预测视频 yolo segment predict modelruns/segment/train2/weights/best.pt sourcetest_video.mp4 conf0.25 saveTrue # 摄像头实时预测 yolo segment predict modelruns/segment/train2/weights/best.pt source0 conf0.25 showTrueconf参数是置信度阈值默认0.25。如果你的场景中目标容易被遮挡或形态复杂可以降低到0.1或0.15来减少漏检如果场景中误检很多就提高到0.4或0.5。这个阈值需要在具体场景上测试调整没有通用最优值。在Python代码里调用更灵活可以拿到掩码数组做后续处理from ultralytics import YOLO model YOLO(runs/segment/train2/weights/best.pt) results model(test.jpg, conf0.25) for result in results: # 检测框坐标 boxes result.boxes.xyxy.cpu().numpy() # 类别ID class_ids result.boxes.cls.cpu().numpy().astype(int) # 分割掩码多边形点坐标 masks result.masks.xy # 每个目标的多边形坐标 # 分割掩码布尔矩阵 mask_matrix result.masks.data.cpu().numpy() # shape: [num_objects, H, W]拿到mask_matrix后可以对每个目标做面积计算、轮廓提取、图像裁剪等操作。比如要统计每个目标的像素面积用mask_matrix.sum(axis(1,2))就得到每个目标的面积占像素数再结合相机标定参数可以映射到实际物理面积。5.3 模型导出与边缘设备部署要点训练好的.pt文件不能直接在手机上或边缘设备上运行需要先做格式转换。YOLOv8支持的导出格式很多常用的是ONNX和TensorRT# 导出ONNX格式 yolo export modelruns/segment/train2/weights/best.pt formatonnx imgsz640 opset12 # 导出TensorRT格式仅限NVIDIA GPU yolo export modelruns/segment/train2/weights/best.pt formatengine imgsz640 halfTrueONNX是跨平台的中间格式可以转到各个平台的推理引擎。热词里提到的RK3588和香橙派5这类边缘设备部署流程通常是PyTorch模型 → ONNX → RKNN瑞芯微NPU的模型格式转换过程中要注意几个点输入输出节点确认ONNX模型的输入名和输出名后续转RKNN时需要指定。算子支持RKNN对某些算子支持不完整遇到不支持的算子需要改模型结构或换版本。YOLOv8基本都能转成功但如果你改动了网络结构就要小心了。量化边缘设备部署一般用INT8量化来提升推理速度但量化后精度会掉1到3个百分点实际接受不必要去调整。输出后处理RKNN的输出是未经过NMS的原始张量需要在设备端自己实现NMS和掩码解码。我在RK3588上部署YOLOv8n-seg时全流程处理一张640x640图片大约需要30到50毫秒基本满足实时需求。如果追求更高帧率可以试试RK3588的NPU加速配合yolov8n-seg帧率能到20fps以上但精度会略低于GPU推理。5.4 分割结果的后处理掩码叠加与原图融合预测出掩码后如果要在图像上叠加半透明掩码用OpenCV实现import cv2 import numpy as np def overlay_mask(image, mask_matrix, alpha0.5): 将多个目标的掩码叠加到原图上 overlay image.copy() colors [ (0, 255, 0), (0, 0, 255), (255, 0, 0), (0, 255, 255), (255, 255, 0), (255, 0, 255) ] for i in range(mask_matrix.shape[0]): mask mask_matrix[i].astype(np.uint8) color colors[i % len(colors)] colored_mask np.zeros_like(image) colored_mask[mask 1] color overlay cv2.addWeighted(overlay, 1, colored_mask, alpha, 0) return overlay如果要保存分割后的目标本身透明背景PNG用mask索引原图即可# 提取第一个目标 mask mask_matrix[0].astype(np.uint8) # mask中1的部分保留原图0的部分设为透明 result np.zeros((mask.shape[0], mask.shape[1], 4), dtypenp.uint8) result[mask 1, :3] image[mask 1] result[mask 1, 3] 255 # 不透明6. 实例分割实战中遇到的高频坑与完整排查思路6.1 标注类别和names顺序对不上这是问得最多的问题。症状是训练过程loss正常下降mAP曲线也正常但predict时预测的类别和实际物体完全对不上。原因就是data.yaml的names列表顺序和转换脚本里的class_dict不一致。我遇到过最典型的一次标注时类别是person, carclass_dict定义为{person: 0, car: 1}但后来重新写yaml时写成了names: [car, person]。训练出来的模型看到车识别为person看到人识别为car就是完全错位。排查方法很简单随机抽一张验证集图片读取对应TXT文件的第一列class_id对照names里的名字判断名字是否对得上。训练前这一步必须做不要偷懒。6.2 图片与标签文件名不匹配症状是训练时提示找不到某些图片的标签文件或者部分图片没有被加载。常见原因标注时生成JSON的命名和原图不一致或者转换脚本写错了stem导致TXT文件名和JPG文件名对不上。严格遵循images/train/xxx.jpg对应labels/train/xxx.txt的规则空标签文件也要保留它代表这张图没有目标否则可能出现训练时图片和标签数目对不齐的问题。写个批处理脚本检查一下import os image_dir datasets/mydataset/images/train label_dir datasets/mydataset/labels/train images [f[:-4] for f in os.listdir(image_dir) if f.endswith(.jpg)] labels [f[:-4] for f in os.listdir(label_dir) if f.endswith(.txt)] missing set(images) - set(labels) print(f缺少标签的图片数: {len(missing)}) for name in list(missing)[:10]: print(name)6.3 训练时显存溢出OOM的排查链路显存溢出是最直接、最常见的报错。遇到CUDA out of memory别慌按顺序排查检查batch size是否过大1660 Ti6GB上用yolov8s-segbatch从16降到8通常就能解决。检查imgsz从640降到512显存占用能降一半。检查是否有其他程序占用显存Windows下用nvidia-smi查看关闭其他占用显存的进程。检查是否启用了AMP混合精度默认开启如果手动关闭了显存占用会明显上升。如果以上都试过还是OOM换更小的模型s换n或启用梯度累积。6.4 训练损失不下降或下降极慢训练了十几个epochloss纹丝不动这种事遇到过好几回。原因排查按以下顺序数据问题最大检查标注坐标有没有异常值比如超过1或小于0标注点顺序对不对坐标点可以不按顺时针排YOLO的polygon处理对点的顺序鲁棒性还可以但如果有重复点或相同点会出问题。写个脚本检测所有TXT文件看看有没有超出[0,1]范围的坐标。检查类别是否平衡如果99%的目标是A类只有1%是B类模型倾向于全部预测A类B类学不进去。可以考虑给B类增加数据或者用类别权重。检查学习率YOLO默认的学习率调度策略一般没问题但如果你改了lr0参数可以试试恢复到默认值0.01。检查数据量少于500张图的数据集分割任务很难收敛到理想效果至少要1000张以上才算基本够用。6.5 预测时完全没有检测结果训练完跑predict一张目标很明显的图却什么也没检测出来。排查思路置信度阈值太高把conf降到0.1试试如果能看到结果说明模型其实学到了只是置信度不高。imgsz不匹配训练时用640预测时如果设成1280小目标可能被放大后变形导致检测不到尽量保持训练和推理的imgsz一致。类别名称和数量不对检查data.yaml的names如果在推理时传入的names和训练时不一致预测结果的类别索引会错乱。输入图片格式有些PNG带透明通道直接读图可能有问题用OpenCV的cv2.imread读取时会自动丢弃alpha通道但ultralytics库内部对不同格式处理不同遇到奇怪问题先转成JPG测试一下。关于模型推理速度与精度的进一步分析在实际项目交付中客户往往同时关注精度和速度尤其是边缘设备或实时系统。YOLOv8-seg在COCO数据集上的速度-精度平衡已经很优秀但换到自己的数据上需要重新审视几个因素。首先如果训练数据中的目标大小分布和COCO差异很大建议在训练时针对性地调整imgsz。小目标密集场景下把imgsz从640提高到960或1280往往能带来显著的mAP提升但对显存要求成倍增加。如果显卡撑不住优先减小batch size而不要减小imgsz。其次anchor-free的YOLOv8对不同长宽比目标的适应能力较强但如果你的目标很大几乎占满整张图或很小几个像素默认模型不一定是最优解。可以尝试修改默认的模型结构但这种操作需要比较深的模型修改经验如果没有把握先把数据量堆上去更实在。最后如果你的应用场景是视频实时推理建议在部署时配合目标跟踪算法比如ByteTrack或DeepSORT避免重复检测造成的ID切换问题。YOLOv8-seg配合跟踪可以做很多之前只能靠人工完成的工作统计车流量、分析人流密度、检测生产线缺陷等。我自己在使用中最大的感受是实例分割模型的精度上限往往不取决于模型本身而取决于数据质量。同样的YOLOv8s-seg在一份标注准确、类别平衡、样本充足的数据集上效果可以超过在粗糙数据集上训练的YOLOv8x-seg。花在数据准备上的时间永远是最值得的投资。
返回列表