Jesse A. Green / notebook

Segment Anything Model (SAM) — Admin Guide

Generated June 2026 from facebookresearch/segment-anything at dca509f

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

SAM follows a three-component encoder–decoder architecture designed around prompt-based mask prediction. Every inference pass flows through these stages:

Input Image → ImageEncoderViT → Image Embedding (256-dim, 64×64)
                                        ↓
Prompts → PromptEncoder → Sparse + Dense Embeddings
                                        ↓
                              MaskDecoder (TwoWayTransformer)
                                        ↓
                              Masks + IoU Scores

Note

The image encoder runs once per image. Multiple prompts can be evaluated against the same embedding without re-encoding, making interactive use efficient.

1.1 Component Responsibilities

Component Class Purpose
Image Encoder ImageEncoderViT ViT backbone with windowed attention; produces 256-channel spatial embeddings
Prompt Encoder PromptEncoder Encodes points, boxes, and masks into sparse/dense embedding vectors
Mask Decoder MaskDecoder Cross-attends prompt tokens to image embeddings; produces masks and quality scores
Orchestrator Sam Composes the three components; handles preprocessing, batching, and postprocessing

1.2 Image Encoding Pipeline

The Sam model preprocesses images before encoding:

  1. Resize — ResizeLongestSide(1024) scales the longest dimension to 1024 pixels, preserving aspect ratio
  2. Normalize — subtract pixel_mean=[123.675, 116.28, 103.53], divide by pixel_std=[58.395, 57.12, 57.375] (ImageNet statistics)
  3. Pad — zero-pad to a square 1024×1024 tensor
  4. Encode — ImageEncoderViT produces a (1, 256, 64, 64) feature map

ImageEncoderViT uses a Vision Transformer with:

  • Patch embedding via PatchEmbed (kernel 16×16, stride 16) converting 3×1024×1024 → (64×64) × embed_dim
  • Stacked Block modules with multi-head self-attention (Attention) and MLPBlock
  • Windowed attention with configurable window_size (14 for global, applied every few blocks)
  • Decomposed relative positional encoding via add_decomposed_rel_pos
  • Final neck: Conv2d(embed_dim→256) → LayerNorm2d → Conv2d(256→256) → LayerNorm2d

1.3 Prompt Encoding

PromptEncoder converts three prompt types into embeddings:

Prompt Type Encoding Method Output
Points PositionEmbeddingRandom + learned label embeddings (foreground=1, background=0, padding=-1) Sparse embeddings
Boxes Two corner points (top-left + bottom-right) with learned corner embeddings Sparse embeddings (2 tokens per box)
Masks Conv2d(1→4, k=2, s=2) → GELU → Conv2d(4→16, k=2, s=2) → GELU → Conv2d(16→256, k=1) Dense embedding (256×64×64)

When no mask prompt is provided, a learned no_mask_embed tensor is used as the dense embedding.

1.4 Mask Decoding

MaskDecoder combines prompt and image information through a TwoWayTransformer:

  1. Token preparation — concatenate IoU output token + mask tokens (4 for multi-mask, 1 for single) + sparse prompt tokens
  2. Image embedding — sum image embedding with dense prompt embedding and positional encoding
  3. TwoWayTransformer — 2 layers of TwoWayAttentionBlock:
    • Self-attention on token sequence
    • Cross-attention: tokens → image
    • MLP on tokens
    • Cross-attention: image → tokens
    • Final token-to-image cross-attention (no skip-first-layer-PE trick on layer 0)
  4. Upscale — ConvTranspose2d(256→64, k=2, s=2) → GELU → ConvTranspose2d(64→32, k=2, s=2) → GELU producing (32, 4H, 4W)
  5. Hypernetwork — each mask token passes through a 3-layer MLP to produce a (32,) vector
  6. Dot product — hypernetwork_output @ upscaled_image → per-mask spatial prediction
  7. IoU head — separate MLP predicts quality score per mask

Important

When multimask_output=True, SAM returns 3 masks + 3 IoU scores (slicing from index 1:). When multimask_output=False, it returns 1 mask + 1 score (index 0 only). The first token is always the single-mask token.

1.5 Module Dependency Graph

Sam
├── ImageEncoderViT
│   ├── PatchEmbed
│   ├── Block (×depth)
│   │   ├── Attention (with optional relative positional encoding)
│   │   └── MLPBlock
│   └── Neck (Conv2d → LayerNorm2d → Conv2d → LayerNorm2d)
├── PromptEncoder
│   ├── PositionEmbeddingRandom
│   ├── Learned point embeddings (4 labels)
│   ├── Learned mask downscaling (Conv2d ×3)
│   └── no_mask_embed
└── MaskDecoder
    ├── TwoWayTransformer
    │   └── TwoWayAttentionBlock (×2)
    │       ├── Attention (self + cross ×2)
    │       └── MLPBlock
    ├── output_upscaling (ConvTranspose2d ×2)
    ├── output_hypernetworks_mlps (MLP ×4)
    └── iou_prediction_head (MLP)

2. System Requirements

2.1 Hardware

Component ViT-B ViT-L ViT-H
Parameters ~91M ~308M ~636M
Checkpoint size ~375 MB ~1.25 GB ~2.56 GB
GPU VRAM (inference) ~2 GB ~4 GB ~8 GB
Recommended GPU Any CUDA GPU 8+ GB VRAM 16+ GB VRAM

Tip

For CPU-only inference, all model variants work but are significantly slower. The ONNX-exported decoder can run on CPU efficiently since only the prompt encoder and mask decoder are exported (the expensive image encoder runs separately).

2.2 Software Dependencies

Core:

Python >= 3.8
PyTorch >= 1.7
torchvision >= 0.8

Required for full functionality:

opencv-python    # Image I/O and preprocessing
pycocotools      # COCO RLE encoding for automatic mask generation

Optional — ONNX export:

onnx             # Model export
onnxruntime      # Python ONNX inference

Optional — development (from setup.py extras_require["dev"]):

black, flake8, isort, mypy

Demo app (Node.js):

Node.js + npm
onnxruntime-web  # Browser-based ONNX inference
npyjs            # Load .npy embeddings in browser
react, react-dom

2.3 Installation Paths

Standard install (from GitHub):

pip install git+https://github.com/facebookresearch/segment-anything.git

Editable install (for development):

git clone https://github.com/facebookresearch/segment-anything.git
cd segment-anything
pip install -e .

With all optional dependencies:

pip install -e ".[all]"

Note

The setup.py declares version="1.0" with no install_requires — PyTorch and torchvision are assumed pre-installed. The extras_require has "all": ["opencv-python", "pycocotools", "matplotlib", "onnxruntime", "onnx"] and "dev": ["black", "flake8", "isort", "mypy"].


3. Configuration Reference

SAM has no configuration files. All behavior is controlled through Python constructor parameters and method arguments.

3.1 Model Registry

sam_model_registry maps string identifiers to builder functions:

Key Builder Backbone embed_dim depth num_heads
"default" build_sam_vit_h ViT-H 1280 32 16
"vit_h" build_sam_vit_h ViT-H 1280 32 16
"vit_l" build_sam_vit_l ViT-L 1024 24 16
"vit_b" build_sam_vit_b ViT-B 768 12 12

All builders accept a single checkpoint parameter (path to .pth file). The internal _build_sam() function constructs the full Sam model with these fixed architecture constants:

  • image_size=1024
  • patch_size=16
  • prompt_embed_dim=256
  • mask_decoder depth=2, num_heads=8, mlp_dim=2048
  • window_size=14 for windowed attention blocks
  • Global attention block indices vary by model: ViT-H uses [7, 15, 23, 31], ViT-L uses [5, 11, 17, 23], ViT-B uses [2, 5, 8, 11]

3.2 SamPredictor Parameters

Constructor:

Parameter Type Description
sam_model Sam Loaded SAM model instance

set_image():

Parameter Type Default Description
image np.ndarray — HWC uint8 image
image_format str "RGB" "RGB" or "BGR". If BGR, channels are reversed before processing

predict():

Parameter Type Default Description
point_coords np.ndarray or None None Nx2 array of point coordinates (x, y)
point_labels np.ndarray or None None N-length array: 1=foreground, 0=background
box np.ndarray or None None Length-4 array in XYXY format
mask_input np.ndarray or None None 1×256×256 low-resolution mask (logits from prior prediction)
multimask_output bool True Return 3 masks or 1
return_logits bool False Return raw logits instead of binary masks

Caution

Calling predict() or predict_torch() before set_image() raises RuntimeError: 'An image must be set with .set_image(...) before mask prediction.' Similarly, get_image_embedding() without a set image raises RuntimeError: 'An image must be set with .set_image(...) to generate an embedding.'

3.3 SamAutomaticMaskGenerator Parameters

Parameter Type Default Description
model Sam — SAM model instance
points_per_side int or None 32 Grid density per side. 32 → 1024 points. Mutually exclusive with point_grids
points_per_batch int 64 Points processed per batch
pred_iou_thresh float 0.88 Minimum predicted IoU to keep a mask
stability_score_thresh float 0.95 Minimum stability score
stability_score_offset float 1.0 Offset for stability score calculation
box_nms_thresh float 0.7 NMS IoU threshold for deduplication
crop_n_layers int 0 Number of additional crop layers (0 = whole image only)
crop_nms_thresh float 0.7 NMS threshold across crops
crop_overlap_ratio float 512/1500 Overlap fraction between crops
crop_n_points_downscale_factor int 1 Point density reduction per crop layer
point_grids List[np.ndarray] or None None Custom point grids (overrides points_per_side)
min_mask_region_area int 0 Post-processing: remove connected regions smaller than this (requires OpenCV)
output_mode str "binary_mask" "binary_mask", "uncompressed_rle", or "coco_rle"

Warning

Setting both points_per_side and point_grids to None raises ValueError: "Can't have both points_per_side and point_grid be None." At least one must be specified.

3.4 ONNX Export Parameters (scripts/export_onnx_model.py)

Flag Default Description
--checkpoint required Path to SAM checkpoint
--output required Output ONNX file path
--model-type "default" vit_h, vit_l, or vit_b
--return-single-mask False Export for single mask output
--opset 17 ONNX opset version (must be >= 11)
--quantize-out None Path for quantized model output
--gelu-approximate False Use approximate GELU (for compatibility)
--use-stability-score False Replace IoU prediction with stability score
--return-extra-metrics False Return additional metrics (stability score, IoU)

3.5 Automatic Mask Generation CLI (scripts/amg.py)

Flag Default Description
--input required Input image or directory
--output required Output directory
--model-type "default" vit_h, vit_l, or vit_b
--checkpoint required Path to SAM checkpoint
--device "cuda" cuda or cpu
--convert-to-rle False Save masks as COCO RLE instead of binary

All SamAutomaticMaskGenerator constructor parameters are also exposed as CLI flags with matching names and defaults.


4. Deployment & Scaling

4.1 ONNX Deployment Architecture

The ONNX export strategy separates the model into two stages:

Stage 1 (Python/PyTorch):
  Image → ImageEncoderViT → image_embedding.npy (saved to disk)

Stage 2 (ONNX Runtime, any platform):
  image_embedding + prompts → SamOnnxModel → masks + scores

Important

SamOnnxModel wraps only the prompt encoder and mask decoder. The image encoder is NOT exported to ONNX. This is by design — the encoder runs once per image and is the most expensive component. Pre-computing embeddings allows the lightweight decoder to run interactively.

Export workflow:

python scripts/export_onnx_model.py \
  --checkpoint sam_vit_h_4b8939.pth \
  --output sam_onnx.onnx \
  --model-type default

# Optional: quantize for smaller model + faster CPU inference
python scripts/export_onnx_model.py \
  --checkpoint sam_vit_h_4b8939.pth \
  --output sam_onnx.onnx \
  --quantize-out sam_onnx_quantized.onnx \
  --model-type default

ONNX model inputs:

Input Shape Description
image_embeddings (1, 256, 64, 64) Pre-computed image encoder output
point_coords (1, N, 2) Point coordinates (x, y)
point_labels (1, N) Point labels (1=fg, 0=bg)
mask_input (1, 1, 256, 256) Prior mask logits (zeros if none)
has_mask_input (1,) 1.0 if mask_input is provided, 0.0 otherwise
orig_im_size (2,) Original image (H, W) for output scaling

4.2 Demo App Deployment

The React demo (demo/) runs SAM's decoder entirely in-browser via onnxruntime-web:

cd demo
npm install
npm start        # Development server (webpack-dev-server)
npm run build    # Production build

Tip

The demo loads pre-computed image embeddings as .npy files via npyjs. To deploy for custom images: (1) run the image encoder in Python to produce .npy embedding files, (2) serve them alongside the ONNX decoder model, (3) the browser handles prompting and mask decoding.

Build configuration (webpack):

  • Development: webpack-dev-server with hot reload on port 8081
  • Production: minification, source maps, output to build/
  • TypeScript via ts-loader with tsconfig.json targeting ES2017

4.3 Batch Processing

For processing many images, use the scripts/amg.py CLI:

python scripts/amg.py \
  --input ./images/ \
  --output ./masks/ \
  --checkpoint sam_vit_h_4b8939.pth \
  --model-type default \
  --device cuda \
  --convert-to-rle

This processes all images in a directory, writing per-image JSON mask files. Each JSON contains a list of mask annotations with segmentation, bounding box, area, predicted IoU, point coordinates, stability score, and crop box.


5. Operations

5.1 Model Checkpoint Management

SAM checkpoints are standard PyTorch state_dict files. In _build_sam() the Sam model is constructed first, then the checkpoint is opened in binary mode and loaded with torch.load(f) (no map_location is passed — weights load onto their saved device, so move the model with sam.to(device=...) after building). Finally sam.load_state_dict(state_dict) applies the weights.

Three official checkpoints:

Model Filename Approximate Size
ViT-H sam_vit_h_4b8939.pth 2.56 GB
ViT-L sam_vit_l_0b3195.pth 1.25 GB
ViT-B sam_vit_b_01ec64.pth 375 MB

5.2 Memory Management

  • SamPredictor stores the image embedding, original image size, and input size as instance state after set_image(). Call reset_image() to free this memory
  • SamAutomaticMaskGenerator processes points in batches of points_per_batch (default 64) to control peak GPU memory
  • Crop layers (crop_n_layers > 0) multiply memory usage since each crop is processed independently

5.3 Output Formats

SamAutomaticMaskGenerator.generate() returns a list of dicts per mask:

Key Type Description
segmentation np.ndarray or RLE dict Binary mask or encoded mask
bbox list[int] [x, y, w, h] bounding box
area int Mask area in pixels
predicted_iou float Model's predicted IoU quality score
point_coords list[list[float]] Input point that generated this mask
stability_score float Stability score from threshold perturbation
crop_box list[int] [x, y, w, h] of the crop used

6. Performance

6.1 Computational Profile

Phase Cost Notes
Image encoding ~150ms (ViT-H, A100) Runs once per image; dominates single-image latency
Prompt encoding <1ms Lightweight embedding lookup + small convolutions
Mask decoding ~5ms per prompt set 2-layer transformer + upscaling
Automatic generation Seconds to minutes Depends on points_per_side (default 32 → 1024 points)

6.2 Tuning Automatic Mask Generation

Note

Automatic mask generation performance is primarily controlled by three parameters: points_per_side (grid density), points_per_batch (GPU batching), and crop_n_layers (multi-scale crops).

Speed vs. quality tradeoffs:

Scenario Recommended Settings
Fast preview points_per_side=16, crop_n_layers=0
Balanced points_per_side=32, crop_n_layers=0 (defaults)
High quality points_per_side=64, crop_n_layers=1
Maximum coverage points_per_side=64, crop_n_layers=2, crop_n_points_downscale_factor=2

Stability score (calculate_stability_score): measures mask consistency under threshold perturbation. For each mask, it compares the binary mask at mask_threshold vs. mask_threshold ± stability_score_offset and computes IoU. Higher thresholds filter less-confident masks.

6.3 Multi-GPU and Batched Inference

Sam.forward() accepts batched_input — a list of dicts, each containing an image tensor and optional prompts. This supports batch inference when all images share the same dimensions (after preprocessing). For heterogeneous image sizes, process sequentially via SamPredictor.


7. Security Considerations

Caution

SAM processes arbitrary image inputs and loads model checkpoints via torch.load(), which uses Python's pickle module. Only load checkpoints from trusted sources — malicious checkpoint files can execute arbitrary code during loading.

7.1 Input Validation

SAM performs minimal input validation:

  • SamPredictor.set_image() does not validate image dimensions or dtype — malformed inputs will propagate to the encoder and may produce garbage output or CUDA errors
  • SamAutomaticMaskGenerator.__init__() validates that at least one of points_per_side or point_grids is not None
  • No bounds checking on point coordinates or box dimensions — out-of-bounds prompts may produce unexpected masks

7.2 ONNX Model Security

When deploying ONNX models:

  • The exported ONNX file contains only the prompt encoder and mask decoder weights — no image encoder weights are included
  • ONNX Runtime provides a sandboxed execution environment compared to torch.load()
  • Pre-computed embeddings (.npy files) should be treated as opaque tensors — validate array shapes before passing to the model

7.3 Demo App

The React demo uses onnxruntime-web for client-side inference. All computation happens in the browser:

  • No server-side model execution
  • Image data stays on the client
  • Pre-computed embeddings must be served as static assets

8. Developer Internals

8.1 Class Reference

19 classes across 4 packages:

Class Module Base Purpose
Sam modeling.sam nn.Module Top-level model orchestrator
ImageEncoderViT modeling.image_encoder nn.Module ViT image backbone
Block modeling.image_encoder nn.Module Transformer block with windowed attention
Attention modeling.image_encoder nn.Module Multi-head attention with optional relative positional encoding
PatchEmbed modeling.image_encoder nn.Module Convolutional patch embedding
PromptEncoder modeling.prompt_encoder nn.Module Multi-type prompt embedding
PositionEmbeddingRandom modeling.prompt_encoder nn.Module Fourier positional encoding
MaskDecoder modeling.mask_decoder nn.Module Mask prediction head
MLP modeling.mask_decoder nn.Module Multi-layer perceptron (hypernetwork)
TwoWayTransformer modeling.transformer nn.Module Bidirectional cross-attention transformer
TwoWayAttentionBlock modeling.transformer nn.Module Single bidirectional attention layer
Attention modeling.transformer nn.Module Attention with optional downsampling
MLPBlock modeling.common nn.Module Feed-forward block
LayerNorm2d modeling.common nn.Module Channel-wise layer normalization for 2D feature maps
SamPredictor predictor — High-level single-image prediction interface
SamAutomaticMaskGenerator automatic_mask_generator — Grid-based whole-image segmentation
SamOnnxModel utils.onnx nn.Module ONNX export wrapper for decoder
ResizeLongestSide utils.transforms — Aspect-preserving image/coordinate transforms
MaskData utils.amg — Dict-like container for mask metadata with batch filtering

8.2 Key Utility Functions (segment_anything/utils/)

amg.py — mask generation utilities:

Function Purpose
build_point_grid(n_per_side) Generate uniform n×n grid of normalized coordinates
build_all_layer_point_grids(n_per_side, n_layers, scale_per_layer) Grids for base + crop layers
generate_crop_boxes(im_size, n_layers, overlap_ratio) Compute overlapping crop regions
calculate_stability_score(masks, mask_threshold, threshold_offset) Threshold perturbation stability
batched_mask_to_box(masks) Convert binary masks to XYXY bounding boxes
mask_to_rle_pytorch(tensor) PyTorch-based RLE encoding
rle_to_mask(rle) Decode RLE to binary NumPy mask
coco_encode_rle(uncompressed_rle) Convert to pycocotools-compatible COCO RLE
remove_small_regions(mask, area_thresh, mode) OpenCV-based connected component filtering
batch_iterator(batch_size, *args) Yield batched slices of input arrays
is_box_near_crop_edge(boxes, crop_box, orig_box, atol) Filter masks near crop boundaries
uncrop_boxes_xyxy / uncrop_points / uncrop_masks Transform coordinates from crop space to image space

transforms.py — ResizeLongestSide:

Method Purpose
apply_image(image) Resize NumPy image (preserves aspect ratio)
apply_coords(coords, original_size) Scale coordinates to match resized image
apply_boxes(boxes, original_size) Scale boxes (delegates to apply_coords)
apply_image_torch / apply_coords_torch / apply_boxes_torch Tensor variants
get_preprocess_shape(oldh, oldw, long_side_length) Static: compute target dimensions

onnx.py — SamOnnxModel.forward() inputs and processing:

  • select_masks() — choose best mask by IoU score (single mask mode) or return all (multi-mask mode)
  • resize_longest_image_size() — compute resize dimensions for mask postprocessing
  • mask_postprocessing() — bilinear interpolation to input size, then crop to original size

8.3 Code Patterns

State management: SamPredictor uses instance variables (self.features, self.orig_size, self.input_size, self.is_image_set) to cache the image embedding between calls. The @torch.no_grad() decorator is applied to set_image, predict, and predict_torch.

Atomic model construction: _build_sam() constructs all three components, assembles Sam, loads weights, and calls .eval() in one function — no partial initialization possible.

Coordinate conventions: all external coordinates are (x, y) order. Internal ViT processing uses (H, W). ResizeLongestSide handles the conversion.

Mask threshold: Sam.mask_threshold = 0.0 — logits > 0 are foreground. This constant is referenced by SamPredictor.predict() when return_logits=False.

8.4 Error Conditions

Error Location Trigger
ValueError: "Can't have both points_per_side and point_grid be None." automatic_mask_generator.py:110 Neither grid source specified
RuntimeError: 'An image must be set with .set_image(...)...' predictor.py:134, 214 predict() / predict_torch() without set_image()
RuntimeError: 'An image must be set with .set_image(...)...' predictor.py:252 get_image_embedding() without set_image()
TypeError: f'MaskData key {k} has an unsupported type {type(v)}.' amg.py:57, 70 Unsupported value type in MaskData.cat() or filter()

8.5 Known Issues (from GitHub)

Warning

Issue #277: batch size > 1 with SamPredictor.predict_torch() may cause RuntimeError due to shape mismatches. Process prompts individually or use the Sam.forward() batched interface instead.

  • #585: quantize_dynamic() got an unexpected keyword argument 'optimize_model' — the export script calls onnxruntime.quantization.quantize.quantize_dynamic(..., optimize_model=True, ...); newer onnxruntime releases removed that argument. Pin a compatible onnxruntime or drop the argument
  • #446: torch.compile with TensorRT backend incompatibilities
  • #678: Demo ModuleNotFoundError — ensure dependencies are installed via npm install
  • #849: Notebook execution errors — verify checkpoint path and Python environment match

9. Quick Reference

9.1 Minimal Inference

from segment_anything import sam_model_registry, SamPredictor

sam = sam_model_registry["vit_h"](checkpoint="sam_vit_h_4b8939.pth")
sam.to(device="cuda")

predictor = SamPredictor(sam)
predictor.set_image(image_rgb)  # HWC uint8 RGB

masks, scores, logits = predictor.predict(
    point_coords=np.array([[500, 375]]),
    point_labels=np.array([1]),
    multimask_output=True,
)
best_mask = masks[np.argmax(scores)]

9.2 Full Automatic Segmentation

from segment_anything import sam_model_registry, SamAutomaticMaskGenerator

sam = sam_model_registry["vit_h"](checkpoint="sam_vit_h_4b8939.pth")
sam.to(device="cuda")

generator = SamAutomaticMaskGenerator(
    model=sam,
    points_per_side=32,
    pred_iou_thresh=0.88,
    stability_score_thresh=0.95,
    crop_n_layers=1,
    min_mask_region_area=100,
)
masks = generator.generate(image_rgb)

9.3 ONNX Export + Inference

python scripts/export_onnx_model.py \
  --checkpoint sam_vit_h_4b8939.pth \
  --output sam_decoder.onnx \
  --model-type vit_h
import onnxruntime

# Pre-compute embedding with PyTorch
predictor.set_image(image)
embedding = predictor.get_image_embedding().cpu().numpy()

# Run decoder with ONNX Runtime
session = onnxruntime.InferenceSession("sam_decoder.onnx")
masks, scores, low_res = session.run(None, {
    "image_embeddings": embedding,
    "point_coords": point_coords,
    "point_labels": point_labels,
    "mask_input": np.zeros((1, 1, 256, 256), dtype=np.float32),
    "has_mask_input": np.array([0.0], dtype=np.float32),
    "orig_im_size": np.array([H, W], dtype=np.float32),
})