FastSAM 模型接口深度解析:基于 Ultralytics 的实时分割推理、提示交互与验证实战
【免费下载链接】yolov10YOLOv10: Real-Time End-to-End Object Detection [NeurIPS 2024]项目地址: https://gitcode.com/GitHub_Trending/yo/yolov10
FastSAM(Fast Segment Anything Model)是 Ultralytics 框架中面向"分割一切(Segment Anything)"任务的实时 CNN 解决方案,本文以 FastSAM 参考文档 为骨架,深入讲解其模型接口FastSAM的设计原理、推理管线、Prompt 交互机制与验证流程。读完本文,你将掌握如何加载 FastSAM 权重、调用everything / box / text / point四类提示完成交互式分割,并能从源码层面理解其"两阶段"工作方式与单类分割约束。
一、FastSAM 模型接口总览
参考文档docs/en/reference/models/fastsam/model.md指向的核心类是ultralytics.models.fastsam.model.FastSAM,其完整实现位于 模型接口源码。这是一个继承自ultralytics.engine.model.Model(即 YOLO 基类)的专用子类,代码量虽小,却承担着"把 FastSAM 权重接入 Ultralytics 全套引擎"的关键职责。
从 模块导出文件 可以看到,fastsam包对外暴露四个构件:
FastSAM:模型接口(本文核心);FastSAMPredictor:专用推理器;FastSAMPrompt:Prompt 交互处理器;FastSAMValidator:专用验证器。
它们分别位于predict.py、prompt.py、val.py中,并在 顶层__init__.py中被导出,因此可以通过from ultralytics import FastSAM直接使用。
二、模型初始化:默认权重与任务约束
FastSAM.__init__是理解接口行为的入口,其核心逻辑如下(model.py):
def __init__(self, model="FastSAM-x.pt"): if str(model) == "FastSAM.pt": model = "FastSAM-x.pt" assert Path(model).suffix not in (".yaml", ".yml"), "FastSAM models only support pre-trained models." super().__init__(model=model, task="segment")需要特别关注的三点设计:
- 默认权重是
FastSAM-x.pt:当用户传入别名FastSAM.pt时,会自动改写为官方发布的FastSAM-x.pt权重; - 只支持预训练权重,禁止从 YAML 构建:源码通过
assert显式拒绝.yaml/.yml配置,原因是 FastSAM 没有对应的网络结构配置文件,其结构直接固化在权重中。这一约束与 Ultralytics 官方 FastSAM 文档 中"FastSAM-s / FastSAM-x 两个预训练权重"的说明一致——目前公开可用的是FastSAM-s.pt与FastSAM-x.pt两档模型; - 任务固定为
segment:初始化时向父类传入task="segment",声明这是一个实例分割模型。
任务映射表(task_map)
FastSAM通过task_map属性把segment任务绑定到专用组件(model.py):
@property def task_map(self): return {"segment": {"predictor": FastSAMPredictor, "validator": FastSAMValidator}}这是 Ultralytics 引擎的"插件点":训练、预测、验证等模式会通过task_map查找对应的实现类。FastSAM 在此把预测器替换为FastSAMPredictor、验证器替换为FastSAMValidator,从而实现与普通 YOLO 分割模型不同的行为。
与标准分割模型的分工
值得强调的是,FastSAM基类直接复用 YOLO 基类 的predict / val / export等方法,自身只负责"接线"(任务映射与默认权重)。真正体现 FastSAM 差异的是预测器与验证器,下面两节逐一展开。
三、推理管线:FastSAMPredictor 的定制化后处理
FastSAMPredictor继承自 检测预测器DetectionPredictor,但针对 SAM 类模型做了三处关键定制,全部体现在 predict.py 中。
3.1 任务强制为 segment
构造函数中除了调用父类,还显式设置self.args.task = "segment"(predict.py),确保后续流程按分割任务处理输出。
3.2 NMS 强制单类(nc=1)
postprocess中调用 NMS 时,将类别数硬编码为 1(predict.py):
p = ops.non_max_suppression( preds[0], self.args.conf, self.args.iou, agnostic=self.args.agnostic_nms, max_det=self.args.max_det, nc=1, # set to 1 class since SAM has no class predictions classes=self.args.classes, )这正是 FastSAM 的"单类"本质:SAM 系列模型不做类别预测,所有检测到的实例统一视为同一类。因此官方文档特别提醒:若要对 FastSAM 做验证/微调,数据集的全部类别 ID 必须转换为 0。
3.3 整图全框(full_box)融合
NMS 之后,预测器构造一个覆盖整幅图像的full_box,并计算其与每个候选框的 IoU(predict.py):
full_box = torch.zeros(p[0].shape[1], device=p[0].device) full_box[2], full_box[3], full_box[4], full_box[6:] = img.shape[3], img.shape[2], 1.0, 1.0 critical_iou_index = bbox_iou(full_box[0][:4], p[0][:, :4], iou_thres=0.9, image_shape=img.shape[2:])逻辑是:当某个候选框与整图 IoU 超过 0.9(即基本覆盖全图、属于背景大块)时,把该框的置信度与 mask 系数替换为full_box的默认值。其作用是抑制"背景级"的大面积误检,保证everything_prompt返回的是真正的前景实例。
3.4 结果组装与 mask 生成
随后按retina_masks选择两种 mask 生成路径(predict.py):
retina_masks=True:使用ops.process_mask_native在原始图像分辨率上直接生成高分辨率 mask;- 默认路径:使用
ops.process_mask在模型输出尺度生成 mask 再上采样。
最终每个预测被封装为 Results 对象,包含boxes(前 6 列:xyxy + conf + 单类 id)与masks。
四、Prompt 交互:FastSAMPrompt 的四类提示
FastSAM 的"第二阶段:提示引导选择"由 prompt.py 中的FastSAMPrompt实现。该类持有推理结果,提供四种交互方式,并负责可视化。
4.1 构造与 CLIP 依赖
prompt_process = FastSAMPrompt(source, everything_results, device='cpu')构造函数接收推理源、Results列表与设备,并在内部加载 CLIP(OpenAI CLIP,用于文本提示的图文匹配)。若环境中未安装 CLIP,会触发check_requirements("git+https://github.com/openai/CLIP.git")自动安装提示(prompt.py)。
4.2 everything_prompt:直接返回全量结果
不做任何筛选,直接返回第一步生成的全实例 mask(prompt.py),等价于"分割一切"。
4.3 box_prompt:框选目标
传入[x1, y1, x2, y2]形式的边界框,计算该框与每个 mask 的 IoU,保留 IoU 最高的那个 mask(prompt.py):
ann = prompt_process.box_prompt(bbox=[200, 200, 300, 300])实现细节:内部先把用户坐标按原图与 mask 尺寸的比例缩放对齐,再逐 mask 计算"框内面积 / 并集面积"作为 IoU,取argmax对应的 mask 作为最终结果。
4.4 point_prompt:正负点提示
points传坐标列表,point_label用1表示前景、0表示背景(prompt.py):
ann = prompt_process.point_prompt(points=[[200, 200]], pointlabel=[1])实现时遍历所有 mask,对每个提示点:若该点落在某 mask 内且标签为前景,则累加该 mask;若标签为背景则做减法,最后取>= 1的布尔区域合并为最终 mask。这实现了"点一下选目标、再点一下排除干扰"的交互。
4.5 text_prompt:文本引导
利用 CLIP 对每个候选 mask 裁剪出的图像块与文本计算余弦相似度,取相似度最高的 mask(prompt.py):
ann = prompt_process.text_prompt(text='a photo of a dog')底层retrieve方法(prompt.py)将图像特征与文本特征归一化后做点积,再经 softmax 打分。注意:文本提示依赖 CLIP,若未安装会自动拉取依赖。
4.6 plot:可视化与保存
prompt_process.plot(annotations=ann, output='./')plot方法(prompt.py)负责把 mask 叠加到原图:支持mask_random_color(随机配色)、better_quality(形态学闭运算 + 开运算提升 mask 质量)、retina(高分辨率 mask)、with_contours(绘制轮廓)等参数,并把带标注结果保存到output目录。轮廓绘制使用 OpenCV 的findContours与drawContours,最终通过 matplotlib 输出透明背景 PNG。
五、验证流程:FastSAMValidator 与 SegmentMetrics
尽管 FastSAM 主要用于推理(官方文档标注其不支持训练),仍可通过model.val(...)评估分割质量,这由 val.py 中的FastSAMValidator完成:
class FastSAMValidator(SegmentationValidator): def __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None): super().__init__(dataloader, save_dir, pbar, args, _callbacks) self.args.task = "segment" self.args.plots = False # disable ConfusionMatrix and other plots to avoid errors self.metrics = SegmentMetrics(save_dir=self.save_dir, on_plot=self.on_plot)两个关键点(val.py):
- 强制关闭绘图:
self.args.plots = False,注释明确说明这是为了避免 ConfusionMatrix 等绘图在单类模型上产生错误; - 使用
SegmentMetrics:评估指标体系与 YOLO 分割任务保持一致(mAP 等)。
六、辅助工具:bbox_iou 与图像边界处理
utils.py 提供两个推理链路中实际调用的工具:
adjust_bboxes_to_image_border(boxes, image_shape, threshold=20):把距离图像边缘小于threshold像素的框"吸附"到边界(x1→0、y1→0、x2→w、y2→h),避免边缘框与整图框计算 IoU 时出现边界偏差;bbox_iou(box1, boxes, iou_thres=0.9, image_shape=(640, 640), raw_output=False):计算单个框与一批框的 IoU,支持返回原始 IoU 值(raw_output=True)或返回超过阈值的索引。它正是第三节中full_box融合逻辑(iou_thres=0.9)的底层实现。
七、完整实战示例
7.1 Python API:四类提示 + 可视化
以下示例完整继承自 官方 FastSAM 文档 并附带参数说明:
from ultralytics import FastSAM from ultralytics.models.fastsam import FastSAMPrompt # 定义推理源 source = 'path/to/bus.jpg' # 创建 FastSAM 模型(FastSAM-s.pt 或 FastSAM-x.pt) model = FastSAM('FastSAM-s.pt') # 执行推理: # device='cpu' 指定设备;retina_masks=True 输出高分辨率 mask; # imgsz=1024 输入尺度;conf=0.4 置信度阈值;iou=0.9 NMS 的 IoU 阈值 everything_results = model(source, device='cpu', retina_masks=True, imgsz=1024, conf=0.4, iou=0.9) # 创建 Prompt 处理对象 prompt_process = FastSAMPrompt(source, everything_results, device='cpu') # 1) Everything prompt:返回全部分割结果 ann = prompt_process.everything_prompt() # 2) Bbox prompt:框选目标,bbox 格式 [x1, y1, x2, y2] ann = prompt_process.box_prompt(bbox=[200, 200, 300, 300]) # 3) Text prompt:文本引导选择目标 ann = prompt_process.text_prompt(text='a photo of a dog') # 4) Point prompt:正负点提示 # points 默认 [[0,0]],格式 [[x1,y1],[x2,y2]] # point_label 默认 [0],取值 1 表示前景、0 表示背景 ann = prompt_process.point_prompt(points=[[200, 200]], pointlabel=[1]) # 可视化并保存标注结果 prompt_process.plot(annotations=ann, output='./')7.2 CLI 方式
# 加载 FastSAM 模型并分割图像中的一切物体 yolo segment predict model=FastSAM-s.pt source=path/to/bus.jpg imgsz=6407.3 验证模型
from ultralytics import FastSAM # 创建 FastSAM 模型 model = FastSAM('FastSAM-s.pt') # 在 COCO8-seg 示例数据集上验证 results = model.val(data='coco8-seg.yaml')CLI 等价写法:
yolo segment val model=FastSAM-s.pt data=coco8.yaml imgsz=640八、使用限制与测试验证
单类分割约束
FastSAM 只支持单类目标的检测与分割。所有实例都被识别并分割为同一类,因此在准备验证/训练数据集时,必须把所有目标类别 ID 统一转换为 0。这也解释了前文 NMS 中nc=1的硬编码。
官方测试用例佐证
仓库中的 测试用例(test_fastsam)完整复现了官方使用流程:先执行yolo segment val与yolo segment predict的 CLI 命令,再通过 Python API 依次调用everything / box / text / point四类 prompt,最后调用plot保存结果。该测试还演示了一个实用技巧——用 SAM 的Predictor.remove_small_regions(..., min_area=20)去除小面积噪点区域。此外测试以imgsz=32等小尺度参数运行以加速 CI,说明 FastSAM 推理在极小输入下也能稳定工作。
九、总结
从参考文档出发可以看到,Ultralytics 对 FastSAM 的集成遵循清晰的"引擎复用 + 专用组件"架构:
| 组件 | 文件 | 职责 |
|---|---|---|
FastSAM | model.py | 模型入口:默认权重、禁止 YAML、task="segment"、任务映射 |
FastSAMPredictor | predict.py | 单类 NMS、整图 full_box 融合、retina mask 生成 |
FastSAMPrompt | prompt.py | 四类提示交互(everything / box / text / point)与可视化 |
FastSAMValidator | val.py | 关闭绘图、基于SegmentMetrics的验证 |
bbox_iou等 | utils.py | 边界吸附与 IoU 计算的底层支撑 |
FastSAM 的核心价值在于用 CNN 与 YOLOv8-seg 的结构先验显著降低"分割一切"任务的计算成本:第一阶段用检测器一次性产出全实例 mask,第二阶段借助 Prompt 处理器按需选择感兴趣区域。理解FastSAM接口及其背后的预测、提示、验证三大组件,即可在 Ultralytics 框架内高效落地实时交互式分割应用。
【免费下载链接】yolov10YOLOv10: Real-Time End-to-End Object Detection [NeurIPS 2024]项目地址: https://gitcode.com/GitHub_Trending/yo/yolov10
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考