Ultralytics SAM3 模型构建源码深度解析:从视觉骨干到交互式跟踪器的组装管线
【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics
导读
build_sam3.py是 Ultralytics 仓库中负责组装SAM3(Segment Anything Model 3)完整模型的唯一入口模块,位于 ultralytics/models/sam/build_sam3.py。它把分布于 ultralytics/models/sam/sam3/ 与 ultralytics/models/sam/modules/ 下的视觉骨干、多模态 Transformer、几何编码器、分割头与视频记忆解码器等众多子模块"粘合"成两类可运行的模型——用于 Promptable Concept Segmentation(PCS)的SAM3SemanticModel与用于交互式/视频分割(PVS)的SAM3Model。读完本文,你将掌握该模块五个核心函数各自组装了什么组件、每个关键超参的默认值与作用、checkpoint 如何被加载与重映射,以及这些函数在SAM3SemanticPredictor、SAM3VideoPredictor等推理入口中的实际调用关系,从而能够独立解读与调试 SAM3 相关代码。
模块定位:一个函数集,两类模型
SAM3 架构本身由detector(检测器)与tracker(跟踪器)组成:检测器面向图像级的概念分割(输入文本短语或示例框,输出所有匹配实例),跟踪器继承 SAM2 的记忆机制完成视频级分割。build_sam3.py通过一组工厂函数把这两个子系统的组件分别装配为两个顶层模型类:
| 顶层模型类 | 适用场景 | 对应构建函数 |
|---|---|---|
SAM3SemanticModel(sam3_image.py) | 图像概念分割(文本/exemplar 提示) | build_sam3_image_model() |
SAM3Model(modules/sam.py) | 交互式单目标分割与视频跟踪 | build_interactive_sam3() |
从源码头部注释(Copyright (c) Meta Platforms, Inc.)可以看出,该文件系对 Meta 官方 SAM3 实现的移植,整体在 AGPL-3.0 许可下发布。
该模块内部可细分为五个函数,本文逐一定位它们的作用、默认参数与底层证据。
_create_vision_backbone():构建视觉骨干与特征金字塔
定义于 build_sam3.py#L26-L69。它创建"可学习的正弦位置编码 + ViT 骨干 + 多尺度 FPN 颈部",返回Sam3DualViTDetNeck对象,是图像侧唯一真正的特征提取器。
位置编码
position_encoding = PositionEmbeddingSine( num_pos_feats=256, # 每个维度的正弦/余弦特征数 normalize=True, # 归一化到 [0, 1] 范围 scale=None, # 使用默认缩放 temperature=10000, # 正弦频率温度系数 )该类定义在 ultralytics/models/sam/modules/blocks.py,用于给特征图补充位置信息。
ViT 骨干
_create_vision_backbone内部实例化 sam3/vitdet.py 的ViT:
vit_backbone = ViT( img_size=1008, # 推理输入分辨率 pretrain_img_size=336, # 预训练时图像尺寸 patch_size=14, # patch 边长,1008/14 = 72×72 网格 embed_dim=1024, # 隐藏维度 depth=32, # Transformer 层数 num_heads=16, # 注意力头数 mlp_ratio=4.625, # MLP 扩展比(约 4736) drop_path_rate=0.1, qkv_bias=True, use_abs_pos=True, # 使用可学习绝对位置嵌入 tile_abs_pos=True, # 大图推理时按 tile 插值绝对位置 global_att_blocks=(7, 15, 23, 31), # 使用全局注意力的层 rel_pos_blocks=(), # 不使用相对位置(改用 RoPE) use_rope=True, # 启用旋转位置编码 RoPE use_interp_rope=True, # 大图场景对 RoPE 做插值 window_size=24, # 局部注意力窗口大小 pretrain_use_cls_token=True, retain_cls_token=False, # 前向时不保留 CLS token ln_pre=True, ln_post=False, return_interm_layers=False, # 只在最后一层输出 bias_patch_embed=False, compile_mode=compile_mode, # torch.compile 模式 )值得注意的几点:输入尺寸为 1008,patch 大小为 14,因此骨干输出的 token 网格为 72×72;除第 7、15、23、31 层执行全局注意力外,其余层均采用 windowed attention 以控制计算量;位置信息完全交给 RoPE(rel_pos_blocks=()),并通过use_interp_rope支持高分辨率推理。
多尺度颈部
return Sam3DualViTDetNeck( position_encoding=position_encoding, d_model=256, scale_factors=[4.0, 2.0, 1.0, 0.5], # 4 个 FPN 级别的上/下采样因子 trunk=vit_backbone, add_sam2_neck=enable_inst_interactivity, # 是否追加 SAM2 风格颈部 )Sam3DualViTDetNeck(sam3/necks.py#L15)把 72×72 的 ViT 输出展开为 4 个尺度特征(scale_factors 对应 4.0/2.0/1.0/0.5,即分别上采样/下采样到 288、144、72、36 分辨率级别,输出通道统一为d_model=256)。当需要"交互式实例分割"(SAM2 风格点/框提示)时,add_sam2_neck=True会追加第二个用于 SAM2 头部的特征金字塔——这正是参数名为Dual的含义。该参数由build_sam3_image_model调用时固定传入enable_inst_interactivity=True。
_create_sam3_transformer():概念检测器的编码器与解码器
定义于 build_sam3.py#L72-L132,返回一个TransformerWrapper(sam3/model_misc.py),内部封装融合编码器与 DETR 风格解码器。
融合编码器
encoder = TransformerEncoderFusion( layer=TransformerEncoderLayer( d_model=256, dim_feedforward=2048, dropout=0.1, pos_enc_at_attn=True, pos_enc_at_cross_attn_keys=False, pos_enc_at_cross_attn_queries=False, pre_norm=True, # Pre-LN 结构 self_attention=nn.MultiheadAttention( # 自注意力 8 头 num_heads=8, dropout=0.1, embed_dim=256, batch_first=True), cross_attention=nn.MultiheadAttention( # 文本交叉注意力 num_heads=8, dropout=0.1, embed_dim=256, batch_first=True), ), num_layers=6, d_model=256, num_feature_levels=1, frozen=False, use_act_checkpoint=True, # 激活检查点省显存 add_pooled_text_to_img_feat=False, pool_text_with_mask=True, # 文本特征按 mask 做池化 )TransformerEncoderFusion(sam3/encoder.py)的 forward 同时接收图像特征src与文本 prompt 特征,在每层内做自注意力并通过cross_attention让图像 token 吸收文本 token 的信息,实现"以概念条件化图像特征"。6 层、隐藏 256、FFN 2048 与 8 头是该检测器编码器的基础配置。
解码器
decoder = TransformerDecoder( layer=TransformerDecoderLayer( d_model=256, dim_feedforward=2048, dropout=0.1, cross_attention=nn.MultiheadAttention(num_heads=8, dropout=0.1, embed_dim=256), n_heads=8, use_text_cross_attention=True, # 额外对文本做交叉注意力 ), num_layers=6, num_queries=200, # 每图 200 个目标查询 return_intermediate=True, # 输出每层中间结果用于深度监督 box_refine=True, # 逐层迭代式框回归 num_o2m_queries=0, # 不使用 one-to-many 查询 dac=True, # 动态锚框查询(Dynamic Anchor Queries) boxRPB="log", # 参考框对数空间旋转位置编码 d_model=256, frozen=False, interaction_layer=None, dac_use_selfatt_ln=True, use_act_checkpoint=True, presence_token=True, # 启用 presence token(概念是否出现) )解码器(sam3/decoder.py)面向图像概念分割输出:200 个可学习查询逐层 refine 边界框(box_refine=True),并且presence_token=True会额外维护一个学习到的全局 token,用来在整图层面预测"该概念是否出现"——这正是 SAM3 论文中"解耦识别(what)与定位(where)"的 presence head 在解码器层面的实现载体。返回的TransformerWrapper(encoder, decoder, d_model=256)统一了二者的前向接口。
build_sam3_image_model():概念分割模型的完整装配
定义于 build_sam3.py#L135-L255,是PCS 检测器(SAM3SemanticModel)的唯一构建入口。
def build_sam3_image_model(checkpoint_path: str, enable_segmentation: bool = True, compile: bool = False):| 参数 | 默认值 | 含义 |
|---|---|---|
checkpoint_path | 必填 | 权重文件路径(如sam3.pt) |
enable_segmentation | True | 是否挂载 mask 分割头(置False时只做检测级输出) |
compile | False | 为True时以"default"模式编译视觉骨干,可提速但会增加首次编译开销 |
该函数的装配步骤对应源码中清晰的注释段,拆解如下。
1) 文本编码器依赖注入:CLIP tokenizer
try: import clip except ImportError: from ultralytics.utils.checks import check_requirements check_requirements("git+https://github.com/ultralytics/CLIP.git") import clipSAM3 文本侧依赖 Ultralytics 维护的clip包提供 tokenizer。若环境未安装,这里会调用 ultralytics/utils/checks.py 的check_requirements自动安装其 GitHub fork 版本。这也与 docs/en/models/sam-3.md 中提示的TypeError: 'SimpleTokenizer' object is not callable问题一致——只要装了 PyPI 上错误的clip包,代码内文本编码就会报错,需按文档卸载并用该 fork 重装。
2) 视觉 + 语言双塔拼接为 VL 骨干
vision_encoder = _create_vision_backbone(compile_mode=compile_mode, enable_inst_interactivity=True) text_encoder = VETextEncoder( tokenizer=clip.simple_tokenizer.SimpleTokenizer(), d_model=256, width=1024, heads=16, layers=24, # 24 层、16 头、宽 1024 的 CLIP 文本编码器 ) backbone = SAM3VLBackbone(visual=vision_encoder, text=text_encoder, scalp=1)VETextEncoder(sam3/text_encoder_ve.py)是一套 24 层 Transformer 的 CLIP 风格文本编码器,输出投影到 256 维与视觉特征对齐。SAM3VLBackbone(sam3/vl_combiner.py)负责把两个塔"缝合"成一个统一前向接口,并提供forward_image/forward_text/forward_image_sam2等方法。
3) 点积打分器与 prompt MLP
dot_prod_scoring = DotProductScoring( d_model=256, d_proj=256, prompt_mlp=MLP(input_dim=256, hidden_dim=2048, output_dim=256, num_layers=2, residual=True, out_norm=nn.LayerNorm(256)), )DotProductScoring(sam3/model_misc.py)在对象查询与 prompt 嵌入之间计算相似度,用于对"该查询是否匹配当前概念"打分;prompt 先经两层 MLP(含残差与 LayerNorm)投影。
4) 通用分割头 + 像素解码器
segmentation_head = UniversalSegmentationHead( hidden_dim=256, upsampling_stages=3, # 上采样 3 级直至全分辨率 aux_masks=False, # 不输出辅助 mask presence_head=False, # presence 判断交给解码器 dot_product_scorer=None, act_ckpt=True, cross_attend_prompt=nn.MultiheadAttention(num_heads=8, dropout=0, embed_dim=256), pixel_decoder=PixelDecoder( num_upsampling_stages=3, interpolation_mode="nearest", # 逐级最近邻插值 hidden_dim=256, compile_mode=compile_mode, ), ) if enable_segmentation else NoneUniversalSegmentationHead与PixelDecoder都定义于 sam3/maskformer_segmentation.py。该头沿用 Mask2Former 式的"查询 → 像素嵌入点积出 mask"范式:像素解码器把多尺度骨干特征逐级上采样融合,分割头再把对象查询转化为每个对象的 mask logits。当enable_segmentation=False时整个分割头被置为None,模型只做检测级预测。
5) 几何提示编码器(exemplar 框/点的注入)
input_geometry_encoder = SequenceGeometryEncoder( pos_enc=PositionEmbeddingSine(num_pos_feats=256, normalize=True, ...), encode_boxes_as_points=False, boxes_direct_project=True, # 框区域直接投影为 token boxes_pool=True, # 聚合框内视觉特征 boxes_pos_enc=True, # 为框补充位置编码 d_model=256, num_layers=3, layer=TransformerEncoderLayer(d_model=256, dim_feedforward=2048, dropout=0.1, ...), use_act_ckpt=True, add_cls=True, add_post_encode_proj=True, )SequenceGeometryEncoder(sam3/geometry_encoders.py)把图像 exemplar 框/点等几何提示编码为与文本同空间的特征序列,使"一张示例框图 = 一段视觉 token 序列",从而让 PCS 既能吃文本也能吃示例图像,甚至二者组合。它默认把框区域内容投影(boxes_direct_project)并做池化与位置编码后送入 3 层 Transformer。
6) 组装SAM3SemanticModel并装载权重
model = SAM3SemanticModel( backbone=backbone, transformer=transformer, input_geometry_encoder=input_geometry_encoder, segmentation_head=segmentation_head, num_feature_levels=1, # 单尺度特征级 o2m_mask_predict=True, dot_prod_scoring=dot_prod_scoring, use_instance_query=False, # 不使用单实例查询(面向概念而非单个物体) multimask_output=True, ) model = _load_checkpoint(model, checkpoint_path) model.eval()SAM3SemanticModel(sam3/sam3_image.py)串起整条推理链:VL 骨干提取图像与文本特征 → 融合编码器吸收文本条件 → 解码器产出边界框与 presence 判断 → 几何编码器处理 exemplar → 分割头生成 mask。装配完成后立即eval(),返回推理就绪的模型。
build_interactive_sam3():SAM2 兼容的交互/视频跟踪模型
定义于 build_sam3.py#L258-L348,装配tracker 侧的SAM3Model,支持点/框交互式分割与视频多目标跟踪(PVS 任务)。
def build_interactive_sam3(checkpoint_path: str, compile=None, with_backbone=True) -> SAM3Model:记忆编码器与记忆注意力
memory_encoder = MemoryEncoder(out_dim=64, interpol_size=[1152, 1152]) memory_attention = MemoryAttention( batch_first=True, d_model=256, pos_enc_at_input=True, layer=MemoryAttentionLayer( dim_feedforward=2048, dropout=0.1, self_attn=RoPEAttention(embedding_dim=256, num_heads=1, rope_theta=10000.0, feat_sizes=[72, 72]), d_model=256, cross_attn=RoPEAttention(embedding_dim=256, num_heads=1, kv_in_dim=64, rope_theta=10000.0, feat_sizes=[72, 72], rope_k_repeat=True), ), num_layers=4, )这部分对应 SAM2/SAM3 的视频记忆机制:MemoryEncoder(modules/encoders.py)把历史预测 mask 压缩成 64 维记忆特征,MemoryAttention(modules/memory_attention.py)通过 4 层、带 RoPE 的跨帧注意力(self/cross attention 均为num_heads=1、feat_sizes=[72,72])把历史记忆融入当前帧特征。interpol_size=[1152,1152]提示记忆特征会被上采样到 1152×1152 参与前向。
可选骨干与跟踪器模型
backbone = (SAM3VLBackbone(scalp=1, visual=_create_vision_backbone(compile_mode=compile), text=None) if with_backbone else None)与 image 模型不同,交互式/跟踪模型的骨干只含视觉塔(text=None),并且with_backbone可关闭。SAM3VideoSemanticPredictor.setup_model在构建时显式传入with_backbone=False(见 ultralytics/models/sam/predict.py#L2598-L2606),因为视频语义跟踪场景下视觉骨干已由 detector(image 模型)提供,tracker 仅复用其记忆解码模块,避免重复加载两份骨干。
最后构造的SAM3Model(modules/sam.py)带有大量跟踪行为相关开关,从源码可见其核心设置:image_size=1008、backbone_stride=14、num_maskmem=7(记忆缓存帧数)、pred_obj_scores=True、multimask_output_for_tracking=True,以及一组控制 object pointer 的选项(use_obj_ptrs_in_encoder=True、fixed_no_obj_ptr=True等)。它同时传入sam_mask_decoder_extra_args,为 mask 解码器开启基于稳定性的动态多 mask 选择(dynamic_multimask_via_stability等),整体目标是让单目标视觉提示与多目标跟踪共享同一解码器。
两种入口的汇合
需要注意,SAM3 的 image detector 与 interactive tracker 共享同一个视觉骨干但前向路径不同:SAM3SemanticPredictor.get_im_features调用self.model.backbone.forward_image(im)取图像特征(predict.py#L2234-L2237),而 tracker 侧则通过_create_vision_backbone中add_sam2_neck=True追加的 SAM2 特征层经forward_image_sam2取高分辨率特征。该设计可从上文 neck 参数推断得出。
_load_checkpoint():权重装载与前缀重映射
定义于 build_sam3.py#L351-L382,被上述两个构建函数共用,负责把官方发布的权重装进不同结构的模型。
def _load_checkpoint(model, checkpoint, interactive=False): with open(checkpoint, "rb") as f: ckpt = torch_load(f) # 经 ultralytics 补丁后的安全 torch.load if "model" in ckpt and isinstance(ckpt["model"], dict): ckpt = ckpt["model"] # 解包带 model 键的包装格式 # 统一剥离 detector. 前缀(image 模型权重命名) sam3_image_ckpt = {k.replace("detector.", ""): v for k, v in ckpt.items() if "detector" in k}torch_load来自 ultralytics/utils/patches.py,是仓库为保证加载安全而对标准torch.load的封装。对 checkpoint 的装载策略为:官方权重通常带有detector.、tracker.、backbone.等前缀,这里一律先取包含detector前缀的键并剥掉前缀,得到 image 侧权重字典;随后再按interactive分支做"tracker → interactive 模型"的键名映射:
if interactive: # backbone.vision_backbone.* → image_encoder.vision_backbone.* # tracker.transformer.encoder.* → memory_attention.* # tracker.maskmem_backbone.* → memory_encoder.* # tracker.* → *(剥离剩余 tracker 前缀)最后统一model.load_state_dict(sam3_image_ckpt, strict=False)——strict=False意味着允许权重与模型结构不完全一一对应,这是 SAM3 这样一个由 image 模型 + interactive 模型共享部分权重(尤其视觉骨干)的框架得以复用单一sam3.pt文件的基础。可以推断:官方发布的一个 checkpoint 同时承载了detector.(概念检测)与tracker.(视频跟踪/交互分割)两部分权重,通过该函数按需提取。
在推理链路中的真实调用关系
虽然build_sam3.py不被用户直接调用,但它是所有 SAM3 推理类的模型工厂,调用点集中在 ultralytics/models/sam/predict.py:
| 调用方 | 调用的构建函数 | 说明 |
|---|---|---|
SAM3SemanticPredictor.get_model()(predict.py#L2228-L2232) | build_sam3_image_model(self.args.model, compile=self.args.compile) | 概念分割:文本/exemplar 提示 |
SAM3Predictor.get_model()(predict.py#L2218-L2222) | build_interactive_sam3(self.args.model, compile=self.args.compile) | SAM2 风格的交互式分割 |
SAM3VideoSemanticPredictor.setup_model()(predict.py#L2598-L2606) | build_interactive_sam3(self.args.model, with_backbone=False) | 视频语义跟踪,复用 detector 骨干 |
SAM._load()(ultralytics/models/sam/model.py#L76-L79) | build_interactive_sam3(weights) | SAM("sam3.pt")走 SAM2 兼容视觉提示路径 |
各调用方普遍对导入做**延迟(slow import)**处理——把build_sam3及其牵涉的大量模块放到get_model/setup_model阶段才导入,避免用户仅加载其他模型时承担 SAM3 庞大的依赖与初始化开销,这一点从 predict.py#L2220 等处的注释与结构可以确认。
使用前提与实践约束
把模块源码与仓库文档结合,使用前需要满足两个前提:
- 权重需单独获取。与其它自动下载的 Ultralytics 模型不同,
sam3.pt权重并不会在首次运行时自动下载;build_sam3_image_model与build_interactive_sam3都要求传入真实存在的checkpoint_path。权重获取流程与前置准备见 docs/en/models/sam-3.md。 clip依赖必须来自 Ultralytics fork。image 模型构建会用到clip.simple_tokenizer.SimpleTokenizer;若环境中安装的是 PyPI 同名但接口不同的clip包,运行会出现'SimpleTokenizer' object is not callable。build_sam3_image_model虽在ImportError时会自动调用check_requirements("git+https://github.com/ultralytics/CLIP.git")尝试修复,但更稳妥的做法是按文档预先安装正确依赖。
总结
build_sam3.py 是整个 SAM3 功能的"装配车间":_create_vision_backbone与_create_sam3_transformer是基础件工厂,build_sam3_image_model面向概念分割(PCS)组装含文本编码器、presence token、分割头与几何编码器的SAM3SemanticModel,build_interactive_sam3面向视觉提示与视频跟踪(PVS)组装带记忆机制的SAM3Model,而_load_checkpoint以非严格方式完成官方权重的前缀重映射与装载。理解这五个函数及其在SAM3SemanticPredictor/SAM3VideoPredictor/SAM中的接线方式,就等于掌握了在 Ultralytics 生态中实例化、扩展与调试 SAM3 的钥匙。
【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考