Skip to content

Building the SAMURAI engines

nvmmsamurai loads five TensorRT engines plus a constants file, and nvmminfer loads a YOLO engine. None of these are bundled in the repo — you build them yourself from public, open-source weights. This page is the end-to-end recipe. Everything runs in Docker.

The scripts live in tools/samurai/:

Script What it does
export_onnx.py Export the 5 sub-models (image/prompt/mask-decoder/memory-encoder/memory-attention) to ONNX. Wraps the stock public SAM2 modules with synthetic trace inputs — no captured data; matches the out1..out6 / dynamic-sparse contracts the C++ binds.
pack_consts.py Gather the out-of-engine learned constants (temporal pos-enc, no-mem/no-obj embeddings, obj-ptr projections, image PE, empty-prompt sparse/dense) into the self-describing samurai_consts.bin.
build_engines.sh trtexec the five ONNX → fp16 engines on the Jetson; profiles the mask-decoder dynamic sparse axis for Np∈{2,3}.

Open-source inputs

Artifact Source
SAM 2.1 base_plus checkpoint Meta — facebookresearch/sam2 · sam2.1_hiera_base_plus.pt
SAMURAI model + configs yangchris11/samurai (project page)
YOLO detector Ultralytics YOLO26 (yolo26n)

The tracker runs the SAM 2.1 image encoder at the nvmmsamurai crop-size (default 512×512, not SAM2's native 1024), so the export overrides image_size to match. At the 512 default that gives image_embed 32×32, feat_s0 128×128, feat_s1 64×64; a non-512 crop-size needs the whole engine set re-exported at that size (the token grid scales as crop/16) — see the crop-size note.

1. Fetch the open-source repo + checkpoint

git clone --recurse-submodules https://github.com/yangchris11/samurai.git
mkdir -p ckpt && wget -O ckpt/sam2.1_hiera_base_plus.pt \
  https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt

2. Export the SAM2.1 sub-models to ONNX + pack the constants

ONNX export is hardware-agnostic, so it runs in a stock PyTorch container (CPU is fine). Install SAM2 with the CUDA extension disabled (SAM2_BUILD_CUDA=0) — the export needs only the Python graph:

docker run --rm -v "$PWD":/work -v <repo>/tools/samurai:/scripts \
  -w /work/samurai/sam2 pytorch/pytorch:2.4.1-cuda12.1-cudnn9-runtime bash -c '
    export SAM2_BUILD_CUDA=0
    pip install -e /work/samurai/sam2 onnx loguru scipy
    python3 /scripts/export_onnx.py  --ckpt /work/ckpt/sam2.1_hiera_base_plus.pt --out /work/onnx --device cpu
    python3 /scripts/pack_consts.py  --ckpt /work/ckpt/sam2.1_hiera_base_plus.pt --out /work/onnx/samurai_consts.bin --device cpu
'

This writes image_encoder.onnx, prompt_encoder.onnx, mask_decoder.onnx, memory_encoder.onnx, memory_attention.onnx, and samurai_consts.bin to onnx/. export_onnx.py wraps the stock public modules (no upstream patch): it flattens the image-encoder dict to the out1..out6 order the C++ binds, and re-implements the mask-decoder hypernetwork batched so it exports cleanly to TRT (candidate selection stays in the C++).

3. Export the YOLO detector to ONNX

docker run --rm -v "$PWD":/work -w /work \
  pytorch/pytorch:2.4.1-cuda12.1-cudnn9-runtime bash -c '
    pip install ultralytics
    yolo export model=yolo26n.pt format=onnx opset=17 imgsz=1088,1920
'

Pick imgsz to match your input video; see the Ultralytics export docs. Any Ultralytics detector works — nvmminfer only needs the engine.

4. Build the TensorRT engines (on the Jetson)

trtexec must be the version the runtime links against, so the engine build runs in gst-nvmm-infer:jp6 on the Orin. Copy the onnx/ dir to the Jetson, then:

docker run --rm --runtime nvidia --network host \
  -v <repo>:/src -v <onnx_dir>:/onnx -v <out_dir>:/out gst-nvmm-infer:jp6 \
  bash /src/tools/samurai/build_engines.sh

This builds the five SAMURAI engines (fp16) into <out_dir>, with the mask_decoder's dynamic sparse axis profiled for Np∈{2,3} (empty-prompt tracking vs box-seed), and copies samurai_consts.bin alongside. Build the YOLO engine with trtexec --onnx=yolo26n.onnx --fp16 --saveEngine=/out/yolo.engine.

Point the pipeline at <out_dir> via nvmmsamurai engine-dir=… / nvmminfer engine-file=… — see the tracker pipeline walkthrough.

Generic engine builder

build_engines.sh above is SAMURAI-specific (it names the five segments). For anything else — a YOLO detector, a re-exported encoder at a different crop, any one-off ONNX — tools/build_engine.sh is a thin trtexec wrapper that turns a single .onnx into an .engine on the box the element loads it on:

tools/build_engine.sh model.onnx model.engine            # fp16 by default
# dynamic input axis (name it as the ONNX declares it):
tools/build_engine.sh mask_decoder.onnx mask_decoder.engine \
  --minShapes=sparse:1x2x256 --optShapes=sparse:1x3x256 --maxShapes=sparse:1x3x256
# encoder exported with dynamic spatial dims — pin the crop at build time:
tools/build_engine.sh image_encoder_384.onnx image_encoder.engine \
  --shapes=input:1x3x384x384

Anything after the two paths is passed straight to trtexec. Because a serialized engine is locked to the TensorRT version and GPU arch that built it, run this on the target (or a container matching its TensorRT), not on a build host — an engine built elsewhere fails to deserialize with a version-tag mismatch.

Note on licences

The model weights are governed by their upstream licences (SAM 2.1 and the YOLO weights you choose); review them before redistributing any engines you build.