Sam3
The SAM 3 matting wrapper — config, forward, prompts and instance outputs.
from nobg import Sam3
from nobg.sam3.modeling_sam3 import Sam3ConfigWraps transformers' Sam3Model (the Apache-2.0 reimplementation of
SAM 3) and collapses
its prompt-conditioned segmentation into a single alpha matte, so the output matches BiRefNet's. The
instance-level outputs pass through untouched.
feyninc/multimatte — MultiMatte — is the published checkpoint, and AutoModel resolves this class
from its nobg-sam3 tag.
Meta's weights are a separate matter
nobg redistributes no SAM weights. Sam3.from_origin("facebook/sam3") converts Meta's upstream
checkpoint, downloading it from their gated repo under the
SAM License.
Sam3Config
The three nobg-specific fields turn a promptable detector into a background remover; the rest are
forwarded to the transformers SAM3 sub-configs.
Prop
Type
Architecture fields, forwarded to the sub-configs:
| Group | Fields |
|---|---|
| Vision tower | vision_hidden_size (1024), vision_intermediate_size (4736), vision_num_hidden_layers (32), vision_num_attention_heads (16), vision_patch_size (14), vision_window_size (24), vision_global_attn_indexes ([7, 15, 23, 31]), vision_pretrain_image_size (336), fpn_hidden_size (256) |
| Detector stack | hidden_size (256), intermediate_size (2048), num_attention_heads (8), geometry_num_layers (3), detr_encoder_num_layers (6), detr_decoder_num_layers (6), num_queries (200), num_upsampling_stages (3) |
| Text tower (CLIP) | text_vocab_size (49408), text_hidden_size (1024), text_intermediate_size (4096), text_projection_dim (512), text_num_hidden_layers (24), text_num_attention_heads (16), text_max_position_embeddings (32) |
__post_init__ raises if aggregate is not one of the three values, or if image_size is not
divisible by vision_patch_size.
Choosing aggregate
Measured on facebook/sam3 against FeyNobg, on two photos:
aggregate | MAE | IoU | Soft pixels | score_threshold |
|---|---|---|---|---|
"semantic" | 0.035 / 0.039 | 0.976 / 0.983 | 19 / 29 % | ignored |
"max" / "mean" | 0.144 / 0.150 | — | 71 / 79 % | respected |
Per-query mask logits are trained to be binarized at 0.5, so as soft alpha they come out much
mushier. Under "max"/"mean", queries are scored the way SAM3's own instance post-processing scores
them (pred_logits.sigmoid() * presence.sigmoid()), aggregation stays in logit space, and if nothing
clears the threshold the single best-scoring query is kept — so the matte is never empty.
forward
forward(
pixel_values,
input_ids=None,
attention_mask=None,
input_boxes=None,
input_boxes_labels=None,
labels=None,
score_threshold=None,
**kwargs,
) -> dictProp
Type
Returns:
| Key | Notes |
|---|---|
logits | (B, 1, H, W) raw alpha-matte logits, upsampled to the input size |
pred_masks | Per-query mask logits, untouched |
pred_boxes | Per-query boxes |
pred_logits | Per-query classification logits |
presence_logits | Is-the-concept-present head; sigmoid() is a usable confidence |
semantic_seg | SAM3's semantic head, the default matte source |
loss | Only when labels was passed |
forward raises a clear ValueError when input_ids is missing or pixel_values is not
config.image_size square, rather than failing deep inside attention.
predict
predict(
processor, image, prompt=None, boxes=None, *,
score_threshold=None, batch_size=1, return_type="cutout", **processor_kwargs,
)Positional order is the fixed argument first, then the varying ones by how often they are supplied.
prompt applies to every image in the call; boxes is per-image, in the original image's pixel
coordinates. See Text and box prompts.
The matte is never empty
A prompt for something absent from the image still returns a matte. Call forward and read
presence_logits when you need to know whether the concept is actually there.
process
process(
image, prompt=None, boxes=None, *,
tokenizer=None, score_threshold=None, batch_size=1, return_type="cutout", **processor_kwargs,
)predict with the processor default_processor(tokenizer) describes.
default_processor
default_processor(tokenizer=None) -> Sam3ProcessorThe image side follows config.image_size and the prompt-free default follows
config.default_prompt, but SAM3 also needs a text tokenizer, which no config.json describes. It is
resolved in order:
tokenizer argument — an instance, a repo id or a local directory.from_origin loaded this model from.openai/clip-vit-large-patch14, which is ungated and is the same BPE vocabulary (49408 entries) SAM3's text tower uses.Raises OSError if no candidate loads, and ValueError if the resolved tokenizer's vocabulary is
larger than config.text_vocab_size — i.e. it can emit token ids the text embedding has no row for.
The no-argument result is cached on the model.
from_origin
@classmethod
from_origin(origin, config=None, *, token=None, **overrides) -> Sam3Reads an upstream transformers SAM3 checkpoint (nested config, upstream weight keys) or another nobg
Sam3 — a repo id, a local directory or a live module — and produces a nobg Sam3, injecting every
weight whose key and shape still match. It also records where the weights came from, so
default_processor() can look for a tokenizer there.
model = Sam3.from_origin("facebook/sam3") # convert Meta's weights
model = Sam3.from_origin("feyninc/multimatte", aggregate="max") # re-configure MultiMatteThis is also the only loader that takes config-field overrides: from_pretrained passes the
checkpoint's own config and nothing else. Passing both an explicit config and overrides raises
ValueError.
criterion
Defaults to nobg.loss.sam3_loss — SAM 3's own semantic-segmentation objective (weighted focal +
dice) rather than BiRefNet's BCE+IoU+SSIM, so fine-tuning matches how the checkpoint was trained.
Sam3 always passes a single-element scaled_preds list. See Losses.
ONNX hooks
onnx_dynamo = False— the TorchScript tracer, because SAM3's decoder sizes tensors from data, whichtorch.exportrefuses to guard on.onnx_dummy_inputs(batch_size)addsinput_idsandattention_mask(a synthetic 32-token prompt) topixel_values.input_boxesis deliberately left out, since including it would make boxes mandatory for every call.
See ONNX.