SAM3 base
facebook/sam3Meta's PyTorch model in FP16, 840.4M parameters. Every prompt runs the whole network, and every mask is resized to the full frame on the GPU.
How SAM3 went from 4.0 GB of VRAM to 1.47 GB while it runs, with the model itself down from 3.7 GB to 1.2 GB: which model files exist, which ones stay loaded, and which run only once.
Three stages, one workload: a fixed list of prompts, one image at a time.
Meta's PyTorch model in FP16, 840.4M parameters. Every prompt runs the whole network, and every mask is resized to the full frame on the GPU.
Built from Embedl's INT8 ONNX export (embedl/sam3). The vision encoder runs once per image, the decoder once per prompt. The decoder still carries the 353M-parameter text encoder.
The text encoder runs once, offline, on CPU, and its outputs are saved to a prompt bank. The GPU keeps the vision encoder and a 26M-parameter decoder.
facebook/sam3 weights in PyTorch 2.6, FP16. Stages 2 and 3: TensorRT 10.3 engines built --fp16 --int8.| Input frame | 1 · SAM3 base | 2 · Split | 3 · Text-free |
|---|---|---|---|
| 1006×679 | 2,428 MiB | 1,872 MiB | 1,474 MiB |
| 1920×1080 | 2,794 MiB | 1,872 MiB | 1,474 MiB |
| 3840×2160 | 4,028 MiB | 1,872 MiB | 1,474 MiB |
The official post-processing resizes every predicted mask to the full frame on the GPU, and PyTorch keeps that peak memory reserved. The split pipelines take a fixed 924×924 input and resize masks on the CPU, so their GPU memory is the same for any frame.
The production app runs a fixed list of prompts on one image at a time: one vision encode, then one decode per prompt. With that workload every file falls into one of four groups.
sam3_encoder.engine.sam3_decoder_notext.engine.prompt_bank.npz, and production keeps only the vision encoder and a 26M-parameter decoder on the GPU.Memory each engine holds once loaded, measured as the drop in free VRAM. The whole saving is weights: the text encoder left the GPU, and nothing else moved.
| Engine | Params | Weights | Working memory | I/O buffers | Total in VRAM |
|---|---|---|---|---|---|
| sam3_encoder both | 455.2M | 529 MiB | 140 MiB | 99 MiB | 768 MiB |
| sam3_decoder stage 2 | 379.4M | 450 MiB | 303 MiB | 143 MiB | 896 MiB |
| sam3_decoder_notext stage 3 | 26.0M | 49 MiB | 302 MiB | 143 MiB | 494 MiB |
| Stage 2 total | 834.6M | 979 MiB | 443 MiB | 242 MiB | 1,664 MiB |
| Stage 3 total | 481.2M | 578 MiB | 442 MiB | 242 MiB | 1,262 MiB |
| Saved | 353.4M | 401 MiB | 1 MiB | 0 MiB | 402 MiB (−24%) |
pred_masks alone is 200×264×264 float32, 53 MiB.Both TensorRT pipelines were compared with the FP32 model: sam3_decoder.onnx run in full precision by ONNX Runtime, on the same image features. 1 test image, 7 prompts, 72 reference detections at score > 0.25. A sanity check, not a benchmark.
| Measure | Stage 2 | Stage 3 |
|---|---|---|
| Detections that differ from FP32 | 8 of 72 | 1 of 72 |
| Mean score error on detections | 0.0135 | 0.0036 |
| Mean mask IoU vs FP32 | 0.9855 | 0.9898 |
| Decode, per prompt | 32.2 ms | 30.5 ms |
| 1 encode + 4 decodes, with CPU post-processing | 270 ms | 260 ms |
| Tokenizer in the production process | yes | no |
In the INT8/FP16 engine, the text encoder's output was about 30% off the FP32 value (mean absolute error 0.24 on features of mean magnitude 0.81). That error reached every prediction. The text encoder now runs only once, so the prompt bank is computed in FP32 and that error is gone.
At 32 tokens the text encoder was cheap to run. Its cost was the memory it held, which is what stage 3 removed.
Four ONNX files ship in the model repo. You build the two engines and the prompt bank yourself. Disk sizes in MB; VRAM in MiB.
| File | Comes from | On disk | Params | What it is | When it's used |
|---|---|---|---|---|---|
| sam3_encoder.onnx | model repo | 1,821 | 455.2M | Vision encoder. Image in, 3 feature maps out. | build Source of the encoder engine. |
| sam3_decoder_notext.onnx | model repo | 104 | 26.0M | Detector head: fusion encoder, DETR decoder, mask head. Feature maps and text embeddings in, detections out. | build Source of the decoder engine. |
| sam3_text_encoder.onnx | model repo | 1,414 | 353.4M | Text encoder with its 1024→256 projection. Token ids in, text_features and text_padding_mask out. | offline once Builds the prompt bank, on CPU. |
| sam3_decoder.onnx | model repo (stage 2) | 1,518 | 379.4M | Stage-2 decoder: text encoder and detector head in one graph. | not in production Verification and rollback. |
| sam3_encoder.engine | you build it | 512 | 455.2M | TensorRT build (--fp16 --int8). Runs once per image. | production Loaded the whole time. |
| sam3_decoder_notext.engine | you build it | 44 | 26.0M | TensorRT build (--fp16 --int8). Runs once per prompt. | production Loaded the whole time. |
| prompt_bank.npz | you create it | 0.033 / prompt | none | For each prompt: the string, its 32 token ids, text_features and text_padding_mask. Plain arrays, not tied to a GPU. | production Host RAM, read at startup. |
Every model's outputs carry the same names as the next model's inputs, so tensors pass straight through by name.
Found the text-only part.
Every node in sam3_decoder.onnx that is reachable from tokenized_text but not from the image features is text encoder: 353.4M of the decoder's 379.4M parameters (93%).
Found the narrowest cut.
A minimum vertex cut between the token ids and the image-dependent nodes has exactly two tensors: the projected text features and the padding mask. They were renamed text_features and text_padding_mask.
Split the decoder and checked it.
In FP32 ONNX Runtime, text encoder → text-free decoder matches sam3_decoder.onnx bit for bit (largest difference 0.0 on all 4 outputs, 4 prompts).
Built the new decoder engine.
Same --fp16 --int8 recipe: 44 MB, against 465 MB for the stage-2 decoder engine.
Kept the text encoder off TensorRT.
As an INT8/FP16 engine its output was about 30% off FP32. It runs only once, so the prompt bank is computed in FP32 with ONNX Runtime on CPU.
Verified end to end.
1 of 72 detections differs from FP32 (stage 2: 8), and the running process dropped from 1,872 to 1,474 MiB.
Full code, including an ONNX Runtime reference pipeline, is on the model card.
tok = AutoTokenizer.from_pretrained("facebook/sam3"); tok.pad_token_id = 0
ids = tok(prompts, padding="max_length", max_length=32, truncation=True, return_tensors="np")["input_ids"]
text_encoder = ort.InferenceSession("sam3_text_encoder.onnx")
# run each prompt's ids through text_encoder and save the outputs to prompt_bank.npztrtexec --onnx=sam3_encoder.onnx --fp16 --int8 --builderOptimizationLevel=5 --memPoolSize=workspace:4G --saveEngine=sam3_encoder.engine trtexec --onnx=sam3_decoder_notext.onnx --fp16 --int8 --builderOptimizationLevel=5 --memPoolSize=workspace:4G --saveEngine=sam3_decoder_notext.engine
features = encoder.run({"image": x}) # once per image
for prompt in prompts: # once per prompt
outputs = decoder.run({**features, **prompt_bank[prompt]})