
简介这份资源面向计算机视觉方向的开发者与深度学习学习者聚焦Meta发布的Segment Anything Model 2SAM2在图像分割任务中的落地实践配套Ultralytics框架下的调用与测试代码帮助读者快速理解并复现SAM2的提示式分割与全图分割能力。压缩包共7个文件包含4个pt权重文件、2个Python脚本和1张示例图片整体约690.55MB其中权重覆盖tiny、base、small、large四种规格脚本分别对应带提示分割与全图分割两种典型用法示例图片可直接用于验证效果。目前已有1265人学习下载说明该资源在SAM2入门与实验场景中具备一定参考价值。读者可借助现成权重与脚本省去环境搭建与模型下载的繁琐环节直接对比不同规模模型的分割精度与推理速度并在此基础上迁移到自定义数据集或二次开发适合作为图像分割项目起步的实用素材。1. SAM2 遇上 Ultralytics一条命令跑通图像分割的捷径如果你最近在找能直接落地的图像分割方案大概率已经刷到过 SAM2 和 Ultralytics 这两个词。SAM2Segment Anything Model 2是 Meta 推出的第二代分割基础模型主打「提示即分割」——给一个点、一个框它就能把目标抠出来而 Ultralytics 是 YOLO 系列背后的那套工程框架把训练、推理、导出、部署串成了一条流水线。把这两者拼在一起意味着你不用再手写几十行预处理和后处理代码直接from ultralytics import SAM就能对一张图做分割。这篇笔记面向的是想快速验证 SAM2 效果、又不想被官方仓库那套复杂依赖劝退的工程师。我会从环境安装讲到参数调优再到实际踩过的坑目标是让你在本地半小时内跑出第一张分割掩码图并且知道哪些参数该动、哪些别乱动。2. 环境搭建与最小推理闭环从 pip 安装到第一张掩码图2.1 为什么选 Ultralytics 而不是官方 SAM2 仓库官方segment-anything-2仓库功能全但依赖链偏重需要单独装torch、torchvision、hydra、iopath还要手动下载 checkpoint 并配置路径。对于只想做推理验证的人来说这套流程的摩擦系数太高。Ultralytics 把 SAM2 封装成了和 YOLO 一致的 API 风格安装只需要一个包模型权重会在首次调用时自动下载。常见做法是直接用 pip 装 ultralytics然后SAM(sam2_b.pt)就能加载。这里有个细节Ultralytics 支持的 SAM2 模型规格包括sam2_t.pt、sam2_s.pt、sam2_b.pt、sam2_l.pt分别对应 tiny、small、base、large 四个尺寸。tiny 和 small 适合边缘设备或快速验证base 是精度和速度的平衡点large 精度最高但显存占用也最大。我一般先用sam2_b.pt做效果确认确认可行后再根据部署目标换小模型。2.2 安装命令与依赖版本控制# 创建独立环境避免和已有 torch 版本冲突 conda create -n sam2-ultra python3.10 -y conda activate sam2-ultra # 安装 ultralytics会自动拉取兼容的 torch 和 torchvision pip install ultralytics # 验证安装是否成功 yolo version这段命令的逻辑很直接先隔离环境再装 ultralytics。关键参数说明Python 版本建议 3.9 到 3.113.12 在部分 torch 版本上会有兼容问题pip install ultralytics默认会装最新版 torch如果你机器上已经有 CUDA 12.1 对应的 torch建议先手动装好 torch 再装 ultralytics避免它拉一个 CPU 版本覆盖掉。验证那步用yolo version而不是python -c import ultralytics是因为前者会同时输出 ultralytics 版本和它检测到的 torch、CUDA 状态信息更全。如果输出里 CUDA 显示为None说明当前装的是 CPU 版 torch推理会慢一个数量级需要重新装 GPU 版。2.3 用点提示做单张图像分割from ultralytics import SAM # 加载 base 规格的 SAM2 模型首次运行会自动下载权重 model SAM(sam2_b.pt) # 对单张图做分割points 参数指定提示点的坐标 [x, y] results model(street.jpg, points[400, 300], labels[1]) # 保存分割结果图 results[0].save(street_seg.jpg) # 打印掩码数量和张量形状 print(fmasks: {results[0].masks.data.shape})这段代码是整个流程的核心。points[400, 300]表示在图像坐标 (400, 300) 处给一个正样本提示点labels[1]表示这个点是前景。如果想排除某个区域可以加一个labels[0]的负样本点。results[0].masks.data是一个形状为(N, H, W)的张量N 是分割出的掩码数量H 和 W 是原图高宽。注意SAM2 的提示点坐标是相对于原图尺寸的不是归一化坐标这点和 YOLO 的标注格式不同容易搞混。如果图片很大比如 4K建议先缩放到 1024 左右再推理因为 SAM2 的内部处理分辨率是 1024传太大的图不会提升精度只会增加显存和耗时。2.4 用框提示做批量分割from ultralytics import SAM model SAM(sam2_b.pt) # bboxes 格式为 [x1, y1, x2, y2]可以传多个框 results model( street.jpg, bboxes[100, 150, 500, 600], labels[1] ) # 批量处理多张图 results_batch model([img1.jpg, img2.jpg, img3.jpg], points[200, 200], labels[1]) for i, r in enumerate(results_batch): r.save(fbatch_{i}_seg.jpg)框提示比点提示更稳定因为框已经限定了目标的大致范围SAM2 只需要在框内做精细分割。bboxes参数接受一个扁平列表[x1, y1, x2, y2]多个框就传多个四元组。批量推理时Ultralytics 会自动做批处理但注意每张图的提示点坐标是共用的——如果你对不同图想用不同提示点需要分开调用。实际项目中我一般用框提示做初筛再用点提示做修正这样比纯点提示的召回率高不少。3. 参数调优与模型导出让 SAM2 在真实场景里跑得动3.1 影响分割质量的三个关键参数SAM2 在 Ultralytics 里暴露的参数不多但每个都影响很大。第一个是imgsz默认 1024调小到 512 能提速约 3 倍但小目标边缘会变毛糙调到 2048 对显存要求翻倍精度提升却很有限我实测在广告牌图像分割场景里 1024 和 2048 的 IoU 差距不到 2 个百分点。第二个是conf默认 0.25这是掩码置信度阈值调高到 0.5 能过滤掉大部分碎片掩码但可能漏掉低对比度目标调低到 0.1 会保留很多噪点掩码后处理负担加重。第三个是retina_masks默认 False开启后会输出原图分辨率的高质量掩码而不是 256x256 的低分辨率版本代价是显存占用增加约 30%。我的习惯是验证阶段开retina_masksTrue看上限部署阶段关掉换速度。3.2 模型导出为 ONNX 和 TensorRTfrom ultralytics import SAM model SAM(sam2_b.pt) # 导出为 ONNX动态 batch 和动态输入尺寸 model.export(formatonnx, dynamicTrue, simplifyTrue, opset17) # 导出为 TensorRT 引擎FP16 精度 model.export(formatengine, halfTrue, dynamicTrue, workspace4)导出 ONNX 时dynamicTrue允许输入尺寸和 batch 动态变化simplifyTrue会调用 onnx-simplifier 做图优化opset17是兼容性较好的版本。导出 TensorRT 时halfTrue启用 FP16 量化速度能提升 1.5 到 2 倍精度损失通常在 1% 以内workspace4表示分配 4GB 显存给 TensorRT 做优化搜索如果显存紧张可以降到 2。注意SAM2 的 TensorRT 导出对版本敏感TensorRT 8.6 以上才支持动态 shape 的 mask decoder低于这个版本会导出失败。导出后的 engine 文件只能在相同 GPU 架构上运行换机器需要重新导出。3.3 量化模型的实际收益与代价SAM2 的量化模型FP16 和 INT8是热搜里经常出现的词。FP16 量化通过halfTrue就能开启几乎无痛显存减半、速度提升 40% 到 60%。INT8 量化需要校准数据集Ultralytics 目前没有直接暴露 INT8 导出接口得走 TensorRT 的trtexec手动校准。我试过用 500 张街景图做校准INT8 模型比 FP16 再快 30%但掩码边缘出现了明显的锯齿在医学图像分割这种对边界敏感的场景里不可接受。所以我的建议是通用场景用 FP16 就够了INT8 只在算力极度受限且对边缘精度要求不高的场景下考虑。3.4 用 Python 脚本做批量推理与结果统计from ultralytics import SAM from pathlib import Path import numpy as np model SAM(sam2_b.pt) img_dir Path(./images) results_all [] for img_path in img_dir.glob(*.jpg): r model(str(img_path), points[320, 240], labels[1], retina_masksTrue) mask_area r[0].masks.data.sum().item() results_all.append({ file: img_path.name, num_masks: len(r[0].masks), total_area: mask_area }) r[0].save(f./output/{img_path.stem}_seg.jpg) # 输出统计表 for item in results_all: print(f{item[file]}: masks{item[num_masks]}, area{item[total_area]:.0f})这个脚本做了三件事遍历目录、逐张推理、统计掩码数量和总面积。retina_masksTrue保证保存的掩码图是原图分辨率。r[0].masks.data.sum()计算所有掩码的像素总数可以用来快速判断分割结果是否合理——如果某张图的掩码面积接近全图说明提示点可能落在了背景上需要检查。实际项目中我会把这个统计结果导出成 CSV方便后续做质量筛选。4. 避坑与排查SAM2 在 Ultralytics 里最容易翻车的五个地方4.1 首次运行卡在下载权重现象执行SAM(sam2_b.pt)后终端长时间无输出像是卡死。原因Ultralytics 会从远端拉取权重文件网络不稳定时下载会静默重试。解决提前手动下载权重放到~/.cache/ultralytics/目录下或者设置环境变量YOLO_OFFLINE1并确保权重已在本地。我一般会在 Dockerfile 里预下载好权重避免运行时拉取。4.2 提示点坐标对不上现象明明点在目标上分割结果却跑到了别的地方。原因SAM2 的points参数期望的是原图坐标但如果你在推理前对图片做了 resize 却没同步缩放坐标就会错位。解决要么不 resize要么把提示点坐标按缩放比例换算回去。常见做法是先用cv2.imread读原图记录原始尺寸再决定是否缩放。4.3 显存溢出导致推理中断现象处理 4K 图或批量推理时抛出 CUDA out of memory。原因imgsz默认 1024但retina_masksTrue会在原图分辨率上做上采样显存占用和原图面积成正比。解决把imgsz降到 512或者关闭retina_masks或者用sam2_t.pt小模型。如果都不行就分块推理再拼接。4.4 导出 ONNX 后推理结果和 PyTorch 不一致现象PyTorch 下分割正常ONNX Runtime 下掩码偏移或缺失。原因SAM2 的 mask decoder 里有动态 shape 操作某些 opset 版本导出时会丢失动态维度信息。解决导出时指定opset17并开simplifyTrue推理时用onnxruntime的providers[CUDAExecutionProvider]不要用 CPU provider 做精度对比。如果还是不一致检查输入尺寸是否固定成了导出时的尺寸。4.5 批量推理时提示点被复用现象对多张图传同一个points参数结果只有第一张图分割正确。原因Ultralytics 的批量推理接口会把同一组提示应用到所有图它不会自动为每张图区分提示。解决要么逐张调用要么把提示点组织成和图片列表等长的嵌套列表。我一般写一个循环逐张处理虽然慢一点但逻辑清晰不容易出错。5. 进阶技巧用 SAM2 做自动分割与掩码后处理5.1 不給提示也能分割自动掩码生成SAM2 支持points_per_side参数做网格化自动分割不需要手动给提示点。用法是model(img.jpg, points_per_side32)它会在图像上均匀撒 32x32 个点每个点独立生成掩码再去重合并。这个模式适合做数据标注的预标注或者对未知场景做探索性分割。代价是推理时间随points_per_side平方增长32 大概需要 10 到 15 秒一张图base 模型GPU。我一般用 16 做快速预览确认效果后再用 32 做精细标注。5.2 掩码后处理过滤、合并与边缘平滑import cv2 import numpy as np from ultralytics import SAM model SAM(sam2_b.pt) r model(img.jpg, points[400, 300], labels[1], retina_masksTrue) # 获取第一个掩码并转为 uint8 mask r[0].masks.data[0].cpu().numpy().astype(np.uint8) * 255 # 形态学开运算去除小噪点 kernel np.ones((5, 5), np.uint8) mask_clean cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 高斯模糊后重新二值化平滑边缘 mask_blur cv2.GaussianBlur(mask_clean, (7, 7), 0) _, mask_smooth cv2.threshold(mask_blur, 127, 255, cv2.THRESH_BINARY) cv2.imwrite(mask_smooth.png, mask_smooth)这段后处理的逻辑是先开运算去掉孤立噪点再高斯模糊加阈值做边缘平滑。kernel大小根据目标尺寸调整5x5 适合中等目标小目标用 3x3大目标可以用 7x7。高斯核必须是奇数7x7 的平滑力度适中不会把细小结构抹掉。实际项目中我会把这一步封装成函数对每个掩码都跑一遍再根据面积阈值过滤掉太小的掩码。5.3 把 SAM2 嵌入到检测加分割的流水线一个常见的落地模式是先用 YOLO 做目标检测拿到 bbox 后传给 SAM2 做精细分割。这样比纯 SAM2 自动分割更可控也比纯 YOLO 分割的边界更准。代码上就是先YOLO(yolo11n.pt)推理得到 bboxes再把 bboxes 传给SAM(sam2_b.pt)。注意两个模型的输入尺寸要一致否则 bbox 坐标需要换算。这个组合在广告牌图像分割、医学图像分割这类需要精确边界的场景里特别实用。5.4 一个我反复用的验证习惯每次换模型规格或调参数后我会固定用三张图做回归测试一张单目标、一张多目标、一张小目标。记录每张图的掩码数量、总面积和推理耗时和上一次的结果对比。如果掩码数量突变或面积偏差超过 20%就说明参数改动引入了问题。这个习惯帮我省了很多「改完参数不知道有没有变差」的后悔药。SAM2 在 Ultralytics 里的封装虽然简单但简单不代表可以随便调固定验证集是唯一靠谱的参照系。希望帮到你。本文还有配套的精品资源点击获取