文章目录
- 1. Abstract
- 2. 背景介绍
- 3. 框架详情 (Methodology)
- 3.1 Overview
- 3.2 All-instance Segmentation
- 3.3 Prompt-guided Selection
- 4. Experiments
- 4.1 Run-time Efficiency Evaluation
- 4.2 Zero-Shot Edge Detection
- 4.2.1 BSDS500
- 4.2.2 Sobel filtering
- 4.2.3 NMS
- 4.3 Zero-Shot Object Proposal Generation
- 4.4 Zero-Shot Instance Segmentation
- 4.5 Zero-Shot Object Localization with Text Prompts
- 5. Real-world Applications
- 6. Discussion
- 7. model.py: FastSAM
- 8. prompt.py: FastSAMPrompt
- Reference
1. Abstract
SAM正在成为许多高级任务的基础步骤,如图像分割、图像字幕和图像编辑。然而,其巨大的计算成本使其无法在行业场景中得到更广泛的应用。计算主要来自高分辨率输入的Transformer架构。
研究者为这项基本任务提出了一种性能相当的加速替代方法。通过将任务重新表述为片段生成和提示,我们发现具有实例分割分支的常规CNN检测器也可以很好地完成该任务。具体而言,我们将该任务转换为研究充分的实例分割任务,并仅使用SAM作者发布的SA-1B数据集的1/50直接训练现有的实例分割方法。使用我们的方法,我们在50倍的运行时速度下实现了与SAM方法相当的性能。我们给出了足够的实验结果来证明它的有效性。
2. 背景介绍
SAM被视为一个里程碑式的愿景基础模型。它可以在各种可能的用户交互提示的引导下分割图像中的任何对象。SAM利用了在广泛的SA-1B数据集上训练的Transformer模型,这使其能够熟练地处理各种场景和对象。SAM为一项激动人心的新任务打开了大门,该任务被称为Segment Anything。这项任务,由于其可推广性和潜力,具有成为未来广泛愿景任务基石的所有条件。
然而,尽管SAM和后续模型在处理细分市场任何任务方面取得了这些进步和有希望的结果,但其实际应用仍然具有挑战性。突出的问题是与SAM架构的主要部分Transformer(ViT)模型相关的大量计算资源需求。与卷积技术相比,ViT因其繁重的计算资源需求而脱颖而出,这给其实际部署带来了障碍,尤其是在实时应用中。因此,这种限制阻碍了SA任务的进展和潜力。
针对工业上对SAM实时分割的需求,本文设计了一个SA任务的实时解决方案FastSAM。我们将SA任务解耦为两个连续的阶段,即全实例分割(all-instance segmentation)和提示引导选择(prompt-guided selection)。第一阶段是基于卷积神经网络(CNN)检测器的实现。它生成图像中所有实例的分割掩码。然后在第二阶段,输出与提示符相对应的感兴趣区域。通过利用cnn的计算效率,我们证明了在不影响性能质量的情况下,任何模型的实时分段都是可以实现的。我们希望所提出的方法将促进分割任何东西的基本任务的工业应用。
我们提出的FastSAM基于YOLOv8-seg [16], YOLOv8-seg是一种配备实例分割分支的目标检测器,它利用了YOLACT[4]方法。我们还采用了SAM发布的广泛的SA-1B数据集。通过仅在SA-1B数据集的2%(1/50)上直接训练该CNN检测器,它实现了与SAM相当的性能,但大大减少了计算和资源需求,从而实现了实时应用。我们还将其应用于多个下游分割任务,以展示其泛化性能。在MS COCO上的目标提议任务[13]上,我们在AR1000下实现了63.7,比在32× 32点提示输入下的SAM高1.2分,但在单个NVIDIA RTX 3090上运行速度快50倍。
实时分段模型对工业应用很有价值。它可以应用于许多场景。所提出的方法不仅为大量的视觉任务提供了一种新的、实用的解决方案,而且速度非常快,比crre快几十倍或几百倍。它还为一般视觉任务的大型模型体系结构提供了新的视图。我们认为,对于特定的任务,特定的模型仍然可以获得更好的效率和准确性权衡。然后,在模型压缩的意义上,我们的方法证明了一条路径的可行性,该路径可以通过在结构之前引入人工先验来显着减少计算量。我们的贡献可以概括如下:
- 介绍了一种新颖的、基于cnn的实时分段任意任务解决方案,该解决方案在保持竞争性性能的同时显著降低了计算需求。
- 这项工作提出了将CNN检测器应用于任何任务的第一个研究,为轻量级CNN模型在复杂视觉任务中的潜力提供了见解。
- 在多个基准上对所提出的方法和SAM进行比较评估,可以深入了解该方法在分段任何领域中的优缺点。
3. 框架详情 (Methodology)
3.1 Overview
下图给出了所提出的Fast-SAM方法的概述。该方法由两个阶段组成,即所有实例分割和提示引导选择。前一阶段是基础,第二阶段本质上是面向任务的后处理。与端到端变换器不同,整体方法引入了许多与视觉分割任务相匹配的人类先验,如卷积的局部连接和感受野相关的对象分配策略。这使得它能够针对视觉分割任务进行定制,并且可以在较小数量的参数上更快地收敛。
检测分支输出类别和边界框,而分割分支输出k个原型(在FastSAM中默认为32)以及k个掩码系数。分割和检测任务是并行计算的。分割分支输入高分辨率特征图,保留空间细节,还包含语义信息。该映射通过卷积层进行处理,放大,然后通过另外两个卷积层输出掩码。掩码系数,类似于探测头的分类分支,范围在-1和1之间。实例分割结果是通过将掩模系数与原型相乘,然后将其相加而获得的。
from fastsam import FastSAM, FastSAMPromptmodel = FastSAM('./weights/FastSAM.pt')
IMAGE_PATH = './images/dogs.jpg'
DEVICE = 'cpu'
everything_results = model(IMAGE_PATH, device=DEVICE, retina_masks=True, imgsz=1024, conf=0.4, iou=0.9,)
prompt_process = FastSAMPrompt(IMAGE_PATH, everything_results, device=DEVICE)# everything prompt
ann = prompt_process.everything_prompt()# bbox default shape [0,0,0,0] -> [x1,y1,x2,y2]
ann = prompt_process.box_prompt(bbox=[[200, 200, 300, 300]])# text prompt
ann = prompt_process.text_prompt(text='a photo of a dog')# point prompt
# points default [[0,0]] [[x1,y1],[x2,y2]]
# point_label default [0] [1,0] 0:background, 1:foreground
ann = prompt_process.point_prompt(points=[[620, 360]], pointlabel=[1])prompt_process.plot(annotations=ann,output_path='./output/dog.jpg',)
3.2 All-instance Segmentation
3.3 Prompt-guided Selection
在使用YOLOv8成功分割图像中的所有对象或区域之后,分割任何对象任务的第二阶段是使用各种提示来识别感兴趣的特定对象。它主要涉及点提示、框提示和文本提示的使用。
Point prompt 包括将选定的点与从第一阶段获得的各种遮罩进行匹配。目标是确定点所在的遮罩。与SAM类似,我们在方法中使用前地面/背景点作为提示。在前景点位于多个遮罩中的情况下,可以利用背景点来过滤出与手头任务无关的遮罩。通过使用一组前景/背景点,我们能够在感兴趣的区域内选择多个遮罩。这些遮罩将合并为一个遮罩,以完全标记感兴趣的对象。此外,我们还利用形态学运算来提高掩模合并的性能。
Box prompt 长方体提示涉及在选定长方体和与第一阶段中的各种遮罩相对应的边界框之间执行并集交集(IoU)匹配。其目的是用所选框识别具有最高IoU分数的掩码,从而选择感兴趣的对象。
Text prompt 在文本提示的情况下,使用CLIP模型提取文本的相应文本嵌入。然后确定相应的图像嵌入,并使用相似性度量将其与每个掩模的内在特征相匹配。然后选择与文本提示的图像嵌入具有最高相似性得分的掩码。
通过仔细实施这些提示引导选择技术,FastSAM可以从分割图像中可靠地选择感兴趣的特定对象。上述方法提供了一种实时完成任何分割任务的有效方法,从而大大提高了YOLOv8模型在复杂图像分割任务中的实用性。一种更有效的即时引导选择技术留给了未来的探索。
4. Experiments
4.1 Run-time Efficiency Evaluation
Segmentation Results of FastSAM
在表1中,我们报告了SAM和FastSAM在单个NVIDIA GeForce RTX 3090 GPU上的运行速度。可以看出,FastSAM在所有提示数上都超过SAM。此外,FastSAM的运行速度不会随着提示符的变化而变化,这使它成为Everything模式的更好选择。
4.2 Zero-Shot Edge Detection
SAM和Fast-SAM比较
4.2.1 BSDS500
FastSAM is assessed on the basic low-level task of edge detection using BSDS500.
Pablo Arbelaez, Michael Maire, Charless Fowlkes, and Jitendra Malik. Contour detection and hierarchical image segmentation.
IEEE transactions on pattern analysis and machine intelligence, 33(5):898–916, 2010.
4.2.2 Sobel filtering
Irwin Sobel, Gary Feldman, et al. A 3x3 isotropic gradient operator for image processing. a talk at the Stanford Artificial Project in, pages 271–272, 1968.
4.2.3 NMS
edge NMS step
John Canny. A computational approach to edge detection.
IEEE Transactions on pattern analysis and machine intelligence, (6):679-698, 1986
4.3 Zero-Shot Object Proposal Generation
4.4 Zero-Shot Instance Segmentation
与SAM方法类似,我们利用ViTDet[23]生成的边界框(bounding box, bbox)作为提示符来完成实例分割任务。如第3.3节所述,我们选择具有最高交集/联合(IoU)的掩码,bbox作为预测掩码。结果。
表6给出了评估结果。在此任务中,我们未能实现高AP。我们推断这主要是因为分割掩码精度或基于盒的掩码选择策略。第6节给出了几个例子。
4.5 Zero-Shot Object Localization with Text Prompts
在上图中显示了定性结果。FastSAM可以根据文本提示很好地分割对象。然而,文本到掩模分割的运行速度并不令人满意,因为每个掩模区域都需要被馈送到CLIP特征提取器中。如何将CLIP嵌入提取器组合到FastSAM的骨干网络中,仍然是关于模型压缩的一个有趣的问题。
5. Real-world Applications
6. Discussion
7. model.py: FastSAM
# Ultralytics YOLO 🚀, AGPL-3.0 license
"""
FastSAM model interface.Usage - Predict:from ultralytics import FastSAMmodel = FastSAM('last.pt')results = model.predict('ultralytics/assets/bus.jpg')
"""from ultralytics.yolo.cfg import get_cfg
from ultralytics.yolo.engine.exporter import Exporter
from ultralytics.yolo.engine.model import YOLO
from ultralytics.yolo.utils import DEFAULT_CFG, LOGGER, ROOT, is_git_dir
from ultralytics.yolo.utils.checks import check_imgszfrom ultralytics.yolo.utils.torch_utils import model_info, smart_inference_mode
from .predict import FastSAMPredictorclass FastSAM(YOLO):@smart_inference_mode()def predict(self, source=None, stream=False, **kwargs):"""Perform prediction using the YOLO model.Args:source (str | int | PIL | np.ndarray): The source of the image to make predictions on.Accepts all source types accepted by the YOLO model.stream (bool): Whether to stream the predictions or not. Defaults to False.**kwargs : Additional keyword arguments passed to the predictor.Check the 'configuration' section in the documentation for all available options.Returns:(List[ultralytics.yolo.engine.results.Results]): The prediction results."""if source is None:source = ROOT / 'assets' if is_git_dir() else 'https://ultralytics.com/images/bus.jpg'LOGGER.warning(f"WARNING ⚠️ 'source' is missing. Using 'source={source}'.")overrides = self.overrides.copy()overrides['conf'] = 0.25overrides.update(kwargs) # prefer kwargsoverrides['mode'] = kwargs.get('mode', 'predict')assert overrides['mode'] in ['track', 'predict']overrides['save'] = kwargs.get('save', False) # do not save by default if called in Pythonself.predictor = FastSAMPredictor(overrides=overrides)self.predictor.setup_model(model=self.model, verbose=False)try:return self.predictor(source, stream=stream)except Exception as e:return Nonedef train(self, **kwargs):"""Function trains models but raises an error as FastSAM models do not support training."""raise NotImplementedError("Currently, the training codes are on the way.")def val(self, **kwargs):"""Run validation given dataset."""overrides = dict(task='segment', mode='val')overrides.update(kwargs) # prefer kwargsargs = get_cfg(cfg=DEFAULT_CFG, overrides=overrides)args.imgsz = check_imgsz(args.imgsz, max_dim=1)validator = FastSAM(args=args)validator(model=self.model)self.metrics = validator.metricsreturn validator.metrics@smart_inference_mode()def export(self, **kwargs):"""Export model.Args:**kwargs : Any other args accepted by the predictors. To see all args check 'configuration' section in docs"""overrides = dict(task='detect')overrides.update(kwargs)overrides['mode'] = 'export'args = get_cfg(cfg=DEFAULT_CFG, overrides=overrides)args.task = self.taskif args.imgsz == DEFAULT_CFG.imgsz:args.imgsz = self.model.args['imgsz'] # use trained imgsz unless custom value is passedif args.batch == DEFAULT_CFG.batch:args.batch = 1 # default to 1 if not modifiedreturn Exporter(overrides=args)(model=self.model)def info(self, detailed=False, verbose=True)