简介:一套结合SAM与YOLOv8的开集实例分割期末大作业资料包,面向AI、电子信息、自动化等计算机相关专业学生与科研人员,可用于课程设计、毕业设计或项目演示。资料含完整源码、流程详解与模型下载指引,帮助读者快速跑通目标检测与实例分割流程,并理解开集分割思路。压缩包共20个文件,以6个Python脚本、5个Jupyter Notebook为主,辅以Markdown说明文档和环境依赖requirements.txt,兼顾代码运行与理论学习。包体约10.76MB,轻量易部署。已有100人学习下载,内容经过全面测试,功能稳定、易于复现。源码涵盖预处理、自动检测与分割、多目标识别、SAM掩码可视化及YOLOv8+SAM自动标注等模块,既可直接用于作业提交,也适合在基础上二次开发,拓展更多功能。
1. 期末大作业怎么把“开集分割”从概念变成能跑通的代码
又到了一年两度的期末大作业冲刺期。如果你这次拿到的是“SAM结合YOLOv8实现开集实例分割”这个题,那恭喜——题目本身有一层天然的保护壳:它其实是用成熟的 YOLOv8 做通用目标检测,把检测框交给强大的 SAM 模型去做二次抠图,通过模型集成的方式,让你预测的类别列表外的新目标也能被精准分割出来。这套思路不依赖魔改网络结构,所有难点集中在数据流衔接和参数调优上。我见过很多同学在这里翻车,不是环境装不上,就是坐标对不齐,最后图里出现一大堆空洞掩码。这篇文章就是帮你把这条链路彻底理顺,从环境、权重到推理流程,一步步带着你把开源模型变成自己的期末作品。
2. YOLOv8 负责找、SAM 负责抠:开集实例分割的组合逻辑与选型权衡
2.1 为什么单独的 YOLOv8 和单独的 SAM 都完不成这个任务
YOLOv8 本身非常强,但它强在“封闭集检测”。它训练时见过的类别就固定在那 80 个 COCO 类目里,遇到一张图像里出现从未见过的目标、或者是自定义场景下的特殊物体,它要么直接漏检,要么硬生生把目标归到某一个近似的已知类别里。比如一个工业场景中的异形夹具,YOLOv8 大概率会把它算成“剪刀”或者“钳子”,这种语义错位在很多工程落地里不可接受。
SAM 则完全是另一回事。它是一个基于 Transformer 的通用分割模型,设计上没有类别概念,而是接受点、框、掩码这类提示词,根据提示词在图像里定位并生成目标的高质量掩码。它的泛化能力极强,对任何视觉上连续的物体基本都能切出来。但它的缺陷也很明显——如果你直接让它跑全图的自动掩码生成,它会把图像里所有可疑的物体轮廓都切一遍,输出几百个掩码,且完全不知道哪些掩码才是你关心的“前景目标”。所以单独的 SAM 只能做无差别抠图,没法完成“实例”层面的对象筛选。
这正是两者结合的价值所在。YOLOv8 相当于一个高效率的“区域提案网络”,它以极快的速度找出图像中可能存在目标的边界框;SAM 则相当于一个高精度的“目标分割执行器”,针对每个边界框精细切割出像素级 mask。这个组合天然支持开集推理——由于 SAM 不依赖固定的类别语义,只要 YOLOv8 的边界框框住了目标,SAM 就能把它分割出来,无论它是 COCO 80 类以内的常见物品,还是你数据集里独有的新品种。
2.2 开集实例分割的标准 Pipeline 设想
我一般会把这个任务的完整流水线拆成四段,这也是代码实现时的骨架。第一段是图像预处理,包括统一读图方式、色彩空间转换以及将图像尺寸标准化到 YOLOv8 需要的输入尺寸;第二段是 YOLOv8 推理,执行前向传播、非极大值抑制,输出一组候选边界框和对应的置信度分数;第三段是坐标适配,这一步是整个流程中最容易出错的环节,需要把 YOLOv8 输出的、基于原始图像尺寸的边界框坐标,正确传给 SAM 的图像编码器接口;第四段是 SAM 推理与后处理,对每个边界框执行提示掩码生成,再对输出的置信度掩码做阈值化、连通域分析和可视化叠加。
在选型层面,YOLOv8 提供了 n、s、m、l、x 五个不同规模的版本。考虑到期末作业通常会反复调试,而且你大概率不会拥有多卡机器,我会优先推荐yolov8s.pt或yolov8n.pt。比如yolov8s.pt在 COCO 验证集上的 mAP50 大约能保持在 44.9% 左右,同时推理速度相对充裕,不会在调试时让你等到怀疑人生。SAM 官方提供的权重则主要是 ViT-B、ViT-L 和 ViT-H 三个规格,参数量从 91M 到 636M 不等。除非你的机器显存有 16GB 以上,否则我不太建议直接上 ViT-H,它会频繁触发 CUDA out of memory,尤其是当你输入图像尺寸偏大时。
2.3 内存占用与推理速度的实测权衡
显存占用是这两个模型叠加之后最现实的问题。YOLOv8s 在推理阶段大概占用 1.5GB 到 2GB 显存,而 SAM 的 ViT-B 在set_image阶段占用约 2.5GB,ViT-L 约 5GB,ViT-H 则可能飙到 8GB 以上。如果你在跑完 YOLO 后紧接着加载 SAM 权重,并且希望同时常驻两个模型,那么总共 12GB 显存会显得非常紧张。常见做法是让两个模型都常驻显存,因为 SAM 编码一次图像特征后,可以供多个边界框复用,这是效率最高的方案;如果显存实在不够,则可以采用串行模式,即先跑完 YOLO 释放一部分显存,再加载 SAM 权重执行分割,缺点是每次都要重复从磁盘加载权重,速度会慢很多。
我个人的习惯是优先保证 SAM 一次加载常驻。因为 SAM 对同一张图像的编码过程开销极大,重复加载权重还好说,但如果重复对同一张图调用多轮set_image,哪怕是 ViT-B 也会把分钟级的时间白白耗在重复计算上。实践中只需要predictor.set_image(image_rgb)一次,后续多个边界框都能复用它缓存好的图像特征,这才是追求效率的正确姿势。
3. 把 YOLOv8 和 SAM 装进同一张显卡:环境配置与模型加载全流程
3.1 环境要求与安装命令:先确认你没有走到版本地狱
正式写代码之前,先把虚拟环境确认好。YOLOv8 官方支持 Python 3.8 到 3.12,SAM 对 Python 版本没有特别硬性要求,但为了稳妥我建议用 3.9 或 3.10。需要特别注意 PyTorch 和 CUDA 的匹配关系,比如你如果装的是 PyTorch 2.0.1,配套 CUDA 11.7 或 11.8 都没有问题;如果显卡驱动是较新的,你可以直接安装 PyTorch 2.1 以上的版本并搭配 CUDA 12.1。以下是我在实际项目中验证过的一组安装命令,可以直接复制使用:
# 1. 创建虚拟环境 conda create -n open_set_seg python=3.9 -y conda activate open_set_seg # 2. 安装 PyTorch,这里以 CUDA 11.8 为例 pip install torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/cu118 # 3. 安装 YOLOv8 官方库 pip install ultralytics==8.0.45 # 4. 安装 SAM 官方代码库 pip install git+https://github.com/facebookresearch/segment-anything.git # 5. 安装依赖的图形处理库 pip install opencv-python==4.8.0.74 numpy==1.24.3 pillow参数与版本说明:ultralytics==8.0.45是相对稳定且 API 变化较小的版本,有些新版本把boxes.xyxy的内部结构换了,会导致下游代码不兼容;segment-anything通过 git 链接安装是最贴近官方仓库源码的方式,能保证sam_model_registry这些类和最新 API 对齐;opencv-python和numpy的版本需要留意,SAM 源码内部用到了np.float,如果你装的是 NumPy 1.24+ 会直接报AttributeError,这也是新手最常见的拦路虎。
装完之后一定要在终端跑一条验证命令,确认 PyTorch 能看到你的显卡。很多同学在这里会踩一个坑——装错了 CPU 版 PyTorch,后续所有代码都会变慢几百倍。验证方式很简单:
python -c "import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.get_device_name(0))"如果torch.cuda.is_available()返回True,说明环境正常。如果返回False,请直接卸载 PyTorch 重装对应 CUDA 版本,不要试图用 CPU 模式硬扛,SAM 的 ViT 模型在 CPU 上跑一张图可能要等一分钟以上,根本没法做调试。
3.2 模型下载与目录结构:把权重文件摆放整齐是后面不迷路的前提
环境就绪后进入权重准备阶段。YOLOv8 的权重文件很小,yolov8s.pt只有 22.5MB,使用ultralytics库会自动从官方下载到用户目录下。SAM 的权重就大得多了,ViT-B 是 375MB,ViT-L 是 1.2GB,ViT-H 达到 2.4GB,官方托管在某个开源文件平台上。这里有一个值得注意的坑,很多校园网环境访问该平台会间歇性中断,导致下载文件不完整,而 SAM 的加载函数对文件完整性非常敏感,缺一个字节都会报.pth文件无法解析。我一般建议先下载到本地再摆进项目目录,通过断点续传工具或直接在浏览器里下载都会比在 Python 脚本里下载更稳。
项目目录的组织方式我会这么整理,这也直接对应解压后压缩包里的文件摆放习惯:
open_set_seg/ ├── checkpoints/ │ └── sam_vit_b_01ec64.pth ├── datasets/ │ └── test_image/ │ ├── image1.jpg │ └── image2.jpg ├── outputs/ ├── infer.py └── requirements.txt说明一下各目录的作用:checkpoints专门放所有预训练权重,注意 SAM 的权重文件名里带着哈希后缀,下载后不要随意改名,因为官方代码里对文件名做了硬校验;datasets放测试图像,建议先用三到五张图像跑通全流程,不要一上来就整批量测试,否则很难定位到底是哪张图引发了报错;outputs用来存放分割可视化结果,方便你对照原图检查掩码质量。
完成目录创建后,我可以给你一个非常直接的下载 Python 脚本,避免你手忙脚乱:
# download_weights.py import os import requests os.makedirs("checkpoints", exist_ok=True) # SAM ViT-B 权重的官方下载链接 url = "https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth" target_path = "checkpoints/sam_vit_b_01ec64.pth" if not os.path.exists(target_path): print("开始下载 SAM 权重文件...") response = requests.get(url, stream=True) total_size = int(response.headers.get("content-length", 0)) with open(target_path, "wb") as f: downloaded = 0 for chunk in response.iter_content(chunk_size=1024 * 1024): f.write(chunk) downloaded += len(chunk) print(f"已下载 {downloaded / 1024 / 1024:.1f} MB / {total_size / 1024 / 1024:.1f} MB") print("下载完成") else: print("权重文件已存在,跳过下载")这段脚本采用流式下载方式,可以实时显示进度。使用requests.get(stream=True)并循环读取chunk的好处是避免一次性把整个文件加载进内存,对于 SAM ViT-H 这种 2.4GB 的庞然大物来说,如果不按流式下载,你机器的内存可能会直接爆掉。
3.3 模型加载与推理前自检:先跑通“零分割”,再跑完整逻辑
权重文件就位后,写一个最小的模型加载测试脚本,确认两个模型能否在同一个进程中正常初始化。这一步非常重要,因为 SAM 的build_sam_vit_h会初始化一个巨大的 Transformer 网络,如果你不先跑通这一步,后面整个流程的报错会非常难以定位。一个小技巧是加载完成后立刻打印模型参数数量,确认与预期一致。
# test_load.py import torch from ultralytics import YOLO from segment_anything import sam_model_registry, SamPredictor device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 加载 YOLOv8s yolo_model = YOLO("yolov8s.pt") yolo_model.to(device) # 加载 SAM ViT-B sam_model = sam_model_registry["vit_b"](checkpoint="checkpoints/sam_vit_b_01ec64.pth") sam_model.to(device) # 计算参数量 yolo_params = sum(p.numel() for p in yolo_model.model.parameters()) sam_params = sum(p.numel() for p in sam_model.parameters()) print(f"YOLOv8s 参数量: {yolo_params / 1e6:.2f} M") print(f"SAM ViT-B 参数量: {sam_params / 1e6:.2f} M") print("模型加载成功")运行这段脚本时,第一个容易出现的异常是AttributeError: module 'numpy' has no attribute 'float',这就是前面提到过的 NumPy 版本问题,解决方案是把numpy降到 1.24.3 以下或者直接修改 SAM 源码里的np.float为float。第二个异常是 CUDA 显存不够分配,这通常意味着你需要更换更小的模型规格,或者干脆先把 SAM 放在cpu上测试流程正确性。
4. 从 YOLO 边界框到 SAM 细粒度掩码:核心推理流程与代码逐段详解
4.1 步骤一:YOLOv8 检测阶段,如何调出足以覆盖未知类别的候选框
整个推理代码的核心集中在图像预处理、检测框获取和 SAM 提示生成这三个环节。我先写出完整的推理脚本,然后逐段拆解参数含义,这样你既能直接运行,也能理解每一处逻辑。
# infer.py import cv2 import numpy as np import torch from ultralytics import YOLO from segment_anything import sam_model_registry, SamPredictor # ------------------- 全局配置 ------------------- DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") YOLO_CONF_THRESHOLD = 0.25 # YOLO 置信度阈值,开集场景下调低以保留更多候选框 YOLO_IOU_THRESHOLD = 0.3 # NMS 的 IoU 阈值,调低可以降低对重叠框的抑制 SAM_MASK_THRESHOLD = 0.5 # SAM 输出的 mask 置信度阈值 IMAGE_PATH = "datasets/test_image/image1.jpg" SAVE_PATH = "outputs/result.jpg" # ------------------- 加载模型 ------------------- print("正在加载 YOLOv8 模型...") yolo_model = YOLO("yolov8s.pt").to(DEVICE) print("正在加载 SAM 模型...") sam_model = sam_model_registry["vit_b"](checkpoint="checkpoints/sam_vit_b_01ec64.pth") sam_model.to(DEVICE) sam_predictor = SamPredictor(sam_model) # ------------------- 图像读取与预处理 ------------------- img_bgr = cv2.imread(IMAGE_PATH) img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) h, w, _ = img_rgb.shape print(f"原始图像尺寸: {w} x {h}") # 将图像编码到 SAM 的特征空间 sam_predictor.set_image(img_rgb) # ------------------- YOLOv8 推理 ------------------- results = yolo_model.predict( source=img_rgb, imgsz=640, conf=YOLO_CONF_THRESHOLD, iou=YOLO_IOU_THRESHOLD, device=DEVICE, verbose=False, ) boxes_xyxy = results[0].boxes.xyxy.cpu().numpy().astype(np.float32) scores = results[0].boxes.conf.cpu().numpy().astype(np.float32) print(f"YOLOv8 检测到 {len(boxes_xyxy)} 个候选目标") # ------------------- 遍历框并利用 SAM 生成掩码 ------------------- mask_results = [] for i, box in enumerate(boxes_xyxy): x1, y1, x2, y2 = box # 避免空框或极端小框 if x2 - x1 < 5 or y2 - y1 < 5: continue # 将坐标限制在图像边界内 x1 = max(0, int(x1)) y1 = max(0, int(y1)) x2 = min(w, int(x2)) y2 = min(h, int(y2)) # SAM 推理 masks, iou_predictions, _ = sam_predictor.predict( box=[x1, y1, x2, y2], multimask_output=False, ) # masks 形状为 (1, 1, H, W),取第一张 mask mask = masks[0][0].cpu().numpy() mask = (mask > SAM_MASK_THRESHOLD).astype(np.uint8) # 保存掩码与对应的检测信息 mask_results.append({ "box": [x1, y1, x2, y2], "score": scores[i], "mask": mask, }) print(f"目标 {i}: box=({x1}, {y1}, {x2}, {y2}), score={scores[i]:.2f}, mask面积={mask.sum()}") # ------------------- 可视化绘制 ------------------- result_img = img_bgr.copy() colors = [(0, 255, 0), (0, 0, 255), (255, 0, 0), (0, 255, 255), (255, 255, 0)] for idx, item in enumerate(mask_results): mask = item["mask"] color = colors[idx % len(colors)] # 在原图上绘制半透明掩码 colored_mask = np.zeros_like(img_bgr, dtype=np.uint8) colored_mask[mask == 1] = color alpha = 0.5 result_img = cv2.addWeighted(result_img, 1, colored_mask, alpha, 0) # 绘制边界框和置信度 x1, y1, x2, y2 = item["box"] cv2.rectangle(result_img, (x1, y1), (x2, y2), color, 2) cv2.putText( result_img, f"{item['score']:.2f}", (x1, max(0, y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2, ) cv2.imwrite(SAVE_PATH, result_img) print(f"结果已保存至 {SAVE_PATH}")4.2 步骤二:坐标传递与图像尺寸对齐的深层原理
这段代码里最关键的行是sam_predictor.set_image(img_rgb)与sam_predictor.predict(box=[x1, y1, x2, y2])。我需要解释清楚它们之间的坐标关系,因为这正是大多数人翻车的地方。
YOLOv8 的predict方法内部默认会把输入图像缩放至 640x640,但results[0].boxes.xyxy返回的边界框坐标是经过坐标映射还原到原始图像尺寸的,这个机制在ultralytics中会通过scale_coords自动完成,所以我们可以直接拿着x1, y1, x2, y2当作原始图像坐标系中的边界框。与此同时,sam_predictor.set_image()会把原始图像按长边为 1024 的规则缩放到 SAM 模型的输入尺寸,并且在内部存储了原始尺寸到模型尺寸的变换矩阵。当你调用predict(box=...)时,SAM 内部会把你传入的原始坐标自动转换为模型坐标系,所以坐标无需手动归一化或缩放。
如果你强制手动做缩放,反而会引发严重错位。比如有同学习惯先把 YOLO 输出的坐标除以 640 得到归一化坐标,再乘以 1024 给 SAM 用,这就闹出了把图像坐标系来回变换导致的全图乱套。正确做法就是像我代码里这样,直接传原始坐标系下的整数像素坐标,剩下的交给 SAM 的内部机制处理。
4.3 步骤三:mask 后处理与置信度阈值选择
sam_predictor.predict的输出masks是一个四维张量,形状为(num_prompts, num_masks_per_prompt, H, W)。因为我们只传入一个框,且设置了multimask_output=False,所以最终得到(1, 1, H, W)。这里必须做一次阈值过滤,因为 SAM 输出的不是直接的 0/1 掩码,而是概率图,取值范围在 0 到 1 之间。我默认设置的SAM_MASK_THRESHOLD = 0.5是一个中庸值,如果你的图像里前景与背景对比度较低,可以降到 0.3,这样能保留更多边缘细节;反之如果掩码出现明显噪点、一团乱麻,则上调到 0.7 会更干净。
还有一个我踩过多次的坑是multimask_output参数。当它设置为True时,SAM 会为同一个边界框预测三个不同粒度的掩码,分别对应整体轮廓、局部细节和中间平衡,这在处理某些形状复杂的目标时是福利,但在处理简单目标时,三个掩码的边界会有较大差异,直接取masks[0][0]可能选到最差的那个。最稳的做法是把它固定为False,让 SAM 只输出一个最自信的掩码,期末答辩时可视化效果也会更干净。
4.4 完整脚本的运行与结果检查
运行上述脚本的方式非常简单,直接在终端执行python infer.py。如果没有报错,你会在终端看到每一帧图像中目标的检测数量、边界框坐标和掩码面积。输出图像中,每个目标会被绘制不同颜色的半透明蒙版和边界框,这基本上就是期末大作业需要展示的核心效果图。
如果你跑出来的图像中出现了掩码和边界框位置错乱、或者掩码完全为空的情况,那么你需要回到第五章的排查思路里去逐一核验。尤其要注意的是,当 YOLOv8 检测到目标前景颜色与周围背景近似时,SAM 有时会只生成非常小的掩码,这是正常的模型现象,不是代码错误,可以先通过降低SAM_MASK_THRESHOLD观察是否恢复。
5. 五大高频报错与调参避坑:坐标错位、显存溢出、重复掩码的排查思路
5.1 现象:掩码区域和检测框位置完全对不上,甚至整张图出现了复制平移的伪影
这是我在协助 A 同学调试时遇到的第一类典型问题。他的现象是:SAM 生成的第一张掩码区域明显偏向图像左上角,而且边界和 YOLO 框完美错开。这个问题的原因几乎可以确定是坐标被二次缩放。A 同学在把 YOLO 输出传给 SAM 之前,先手动将坐标除以 640,再通过某个预测函数内部乘以 1024 来还原,结果相当于对局部坐标做了一次平移和放大,导致 SAM 的框提示位置整体偏移。解决方式非常粗暴——删掉所有手动坐标变换代码,直接向sam_predictor.predict(box=[x1, y1, x2, y2])传入原始坐标。这是最基本也是最重要的原则:YOLO 传给 SAM 的坐标一定是以原始图像为参照系的。
5.2 现象:SAM 加载后程序报CUDA out of memory,而后台显卡占用已经到顶
这个问题在显存小于 8GB 的笔记本上出现的概率极高。原因主要有两个:一是你选择了 ViT-H 这类巨型模型,单模型权重就接近 3GB,再加上推理过程中的激活值缓存;二是你没有调用torch.cuda.empty_cache(),导致 PyTorch 的显存缓存越积越多。我给你的建议是优先选择 ViT-B,并且在sam_predictor.set_image()执行完成后,不要频繁释放和重新加载模型。如果显存还是不够,可以在set_image前手动调用sam_model = sam_model.float()将推理精度降到 FP32 并缩小模型输入尺寸,也可以直接把图像分辨率预处理到 640x640,这样 SAM 内部的set_image就不会自动放大到 1024。
5.3 现象:YOLOv8 识别出的边界框太多,导致 SAM 推理时间从秒级变成分钟级
这种情况经常出现在开放式场景的图像中,比如一个杂乱桌面或街头十字路口。YOLOv8 在conf=0.25的低阈值下会输出几十上百个边界框,其中大量是低质量的重叠框或背景误检,而 SAM 的框提示推理是逐个执行的,五十个框就需要跑五十次反卷积和上采样,速度直线下滑。我一般会在 YOLO 推理阶段加入一层候选框过滤机制,按置信度排序后只保留前十个框,并且对重叠严重的框做一次额外的贪心去重。这一步改动非常小,加在boxes_xyxy获取之后即可。优先用得分最高的框去抑制与之高度重叠的其余框,能够显著减少后续 SAM 的无效计算。
5.4 现象:单个目标内部被掩码切割成多个碎片,或者一个目标生成了多个重叠掩码
这个问题的根源往往在于 YOLOv8 的 NMS 参数设置不当。如果在代码里把iou阈值设得过高,比如 0.7,那么 NMS 抑制强度会非常弱,一个目标可能同时对应多个边界框,每个框都会传给 SAM,导致同一个目标被分割成好几块重叠掩码。我的建议是调低iou到 0.3 左右,同时调整conf阈值保证目标不被漏掉。另外,如果筛选后的边界框仍然过密,可以在循环里增加一个判断:当两个框的 IoU 大于 0.6 时,只保留置信度更高的那个框,这样 SAM 的输出会干净许多。
5.5 现象:程序正常运行但输出图像完全空白,终端显示掩码面积全为 0
这个现象通常和SAM_MASK_THRESHOLD设置过高有关,也有可能是cv2.imread读取到灰度图后导致通道数不匹配。我遇到过一位同学用手机拍摄的图像是 16 位 PNG,读取后 SAM 内部特征提取正常,但阈值化阶段因为数据类型是uint16导致比较失败,全部变成 0。排查时先打印一下mask数组的dtype和最大值,确认 SAM 输出的概率值真的是在 0 到 1 之间。如果概率值正常,只是偏小,那就把阈值往下调,比如 0.2;如果概率值最大值只有 0.3,说明 SAM 对目标本身的分割信心低,这种情况需要调整图像对比度,或者直接在输入 SAM 前对图像做一次直方图均衡化。
6. 更进一步:合并掩码、输出语义标签并验证你的分割到底准不准
当你能稳定跑出基本的开集分割效果后,下一步就是把结果变得更像一份“期末大作业成绩单”。我建议你做三件进阶优化:第一件是掩码合并,当同一个目标被多个边界框命中时,通过逻辑或操作合并掩码,让最终呈现的效果是每个实例只对应唯一的像素区域;第二件是给掩码补齐语义标签,这里可以用一个非常直接的手段——计算每个掩码和它的 YOLO 边界框内的置信度,然后将 YOLO 预测的类别名称作为默认标签,如果 SAM 分割出的掩码中心落在边界框内,则沿用原标签,这在展示时会让结果看起来更专业。第三件是对分割质量做量化验证。你可以在数据集里手工标注一些简单目标的真值掩码,计算模型输出的 IoU。比如你想验证开集性能,就专门挑一些 COCO 类别之外的物体进行标注,真实理解“开集”的含义是——它到底能不能切出训练时完全没见过的东西。
最后分享一点我个人的习惯和教训。我刚接触这类多模型拼接任务时,也一度陷入过度关注网络结构细节的泥潭,后来才意识到,这类组合模型的工作重心其实应该在数据流和接口上。你要把 YOLOv8 和 SAM 当成两个黑匣子,搞清楚每个接口的输入输出格式,明确坐标、通道和尺寸对应关系,再通过合理的阈值调参让它们协同运转。以后再做任何多模型融合项目,我都会先画出数据流图,标注每个节点上张量的维度和坐标系,这能帮你自动避开 90% 的翻车现场。希望我这份踩坑经验对你有帮助,照着跑通这一次,你就真正理解了什么叫做“模型是别人的,工程是自己的”。
本文还有配套的精品资源,点击获取