wikillm

Paper · 2023-10-23 · cs.CV

SAM-Med3D: Towards General-purpose Segmentation Models for Volumetric Medical Images

Promptable segmentation for 3D medical volumes: a fully 3D ViT encoder, a point-prompt encoder and a 3D mask decoder, trained from scratch on SA-Med3D-140K (22K volumes, 143K masks) in two stages. Author-reported Dice: 76.27% overall with one 3D point, against 36.83% for SAM-Med2D with N points (one per slice). With 10 points, 80.71%.

Promptable segmentationSemantic segmentationVision Transformer (ViT) backbonesmedical-imagingvolumetric-segmentationpromptable-segmentationinteractive-segmentationvision-transformer

arXivPDFCodeMarkdown18 min read

AI-compiled by claude-haiku-5-5 on 2026-10-19, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.

In plain words

A medical scan is a stack of many slices, like a loaf of bread, and a doctor often needs the outline of one organ or tumour through the whole stack. Earlier tools for this were built for flat photos and worked one slice at a time, which meant the user had to click on many slices. They also lost track of how one slice connects to the next.

This paper builds a model that works on the whole 3D stack at once. The user clicks a single point inside the target, and the model returns the 3D outline of that structure. The model is trained on a large, mixed collection of public and private 3D scans with labelled structures, and it is trained from scratch rather than being adapted from a flat-image model.

The authors report that one click is enough to match or beat the older slice-by-slice tools on their validation set, which covers many organs, lesions and scan types. Those results come from the authors' own tests, so treat them as their claims until someone else reproduces them.

TL;DR

  • A promptable 3D segmentation model for CT, MR and ultrasound volumes: a 3D ViT image encoder, a 3D point-prompt encoder and a 3D mask decoder §4.1 fig. 3.
  • Trained from scratch on SA-Med3D-140K, which the authors say has 22K volumes and 143K 3D masks in 245 categories §1 §3.1.
  • Training has two stages: pre-training on all 131K training masks for 800 epochs, then fine-tuning on about 75K filtered masks §4.2.
  • Author-reported: 76.27% overall Dice with one 3D point, against 36.83% for SAM-Med2D with N points tab. 3. Ten 3D points give 80.71% tab. 3.
  • The released code has no sliding-window inference and does not reproduce the paper's data cleaning or stage-2 selection. Several training details differ from the text. See Paper vs code and Pitfalls.

Problem

Flat-image segmentation models do not handle volumes well. The 2D Segment Anything Model (SAM) is not usable directly on volumetric medical images, because it does not model 3D structure and the domain differs from natural photos §1. The two common workarounds both have costs. Slice-by-slice methods need a prompt for every slice and do not model how slices connect §1. Adapter methods keep a frozen 2D encoder and learn only a new dimension, and they train on small, narrow datasets §1 §2.

The paper argues that models built for one task generalise poorly to other organs and modalities §1. Its pre-experiment compares three ways of adapting SAM to 3D: a 3D adapter on a frozen SAM, fine-tuning with SAM weights, and training a 3D model from scratch. Each is scored on seen and unseen targets, and training from scratch gives the best average Dice tab. 2 §4.1. The approach therefore depends on having enough labelled 3D data to train from scratch, which is the role of the dataset described under Method.

Method

Architecture. All three parts are 3D §4.1 fig. 3.

  • Image encoder. A 3D ViT with a 3D patch embedding, a learned absolute position embedding, and transformer blocks. Most blocks use window attention and four blocks use global attention. A convolutional neck maps the tokens to the prompt embedding width image_encoder3D.py.
  • Prompt encoder. Each point is encoded with a random-Fourier 3D position encoding, plus a learned embedding for positive points, negative points, and "no point" padding prompt_encoder3D.py. A previous low-resolution mask, when given, is embedded with three 3D convolutions prompt_encoder3D.py.
  • Mask decoder. A two-layer two-way transformer over the image tokens and the prompt tokens. Output tokens are upsampled by two stride-2 transposed convolutions, and each mask token is turned into a dot-product mask with the upsampled features. A small MLP predicts a mask-quality score §4.1 mask_decoder3D.py.

Prompting at evaluation §4.3. The first click is a random foreground voxel. Each later click is a random voxel of the error region, positive where the prediction misses the target and negative where it marks extra tissue. The released inference code follows the same rule infer_utils.py.

Large-volume inference §4.3. For volumes larger than 128 voxels per axis, the paper crops a 128-voxel patch around the first point. If the prediction reaches the patch edge, it extends the prediction with a sliding window that overlaps by 50% and keeps the prompt visible at the edge. The release does not implement this (see Paper vs code).

Data §3. SA-Med3D-140K is built from 70 public and 24 private 3D datasets, which the authors describe as 22K images with 143K masks, 245 categories and 28 modalities (CT, ultrasound and 26 MR sequences) §1 §3.1. The paper lists four cleaning steps: remove masks below 1 cm³ or with any dimension under 1.5 cm; drop masks where background covers over 99% of the volume; keep only the five largest connected components; split symmetric organs into left and right §3.2. Resampling uses 1.5 mm isotropic spacing §3.2. The training split has 131K masks (58 public datasets plus all private data) and the validation split has 12K masks from 16 public datasets §3.3. The authors say 58% of the validation cases come from data sources the training set does not contain §3.3.

Training. Stage 1 uses all 131K training masks for 800 epochs §4.2. Stage 2 fine-tunes on about 75K high-quality masks chosen from the training set §4.2. The paper does not describe the click simulation used during training, and it defers training details to a supplement that is not in the arXiv source. The released training code is described under Hyperparameters and Pitfalls.

The sketches below follow the code. They are not the paper's algorithms, which it does not give. Each step cites the code it follows.

Pseudocode
# Interactive inference on one 128^3 ROI  [§4.3]
# Input:  roi_image (1, 1, 128, 128, 128), z-scored
# Input:  roi_gt (1, 1, 128, 128, 128), binary; num_clicks (int)
# Output: binary mask (128, 128, 128)

def segment_roi(model, roi_image, roi_gt, num_clicks):
    # Run the 3D encoder once per volume
    # [code: utils/infer_utils.py#L112]
    image_embeddings = model.image_encoder(roi_image)
    # Start with no clicks and an empty previous mask
    # [code: utils/infer_utils.py#L114-L124]
    points = empty((1, 0, 3))
    labels = empty((1, 0))
    prev_low_res = zeros((1, 1, 32, 32, 32))
    prev_mask = zeros((128, 128, 128))
    for click_index in range(num_clicks):
        # Foreground voxel first, then the error region
        # [code: utils/infer_utils.py#L39-L54]
        new_point, new_label = sample_click(prev_mask, roi_gt)
        # Keep every click so far
        # [code: utils/infer_utils.py#L145-L146]
        points = concat(points, new_point, dim=1)
        labels = concat(labels, new_label, dim=1)
        # Embed the points and the previous low-res logits
        # [code: utils/infer_utils.py#L148-L152]
        sparse, dense = model.prompt_encoder(points, labels, prev_low_res)
        low_res = model.mask_decoder(image_embeddings, sparse, dense)
        prev_low_res = low_res.detach()
        # Probability above 0.5 feeds the next error region
        # [code: utils/infer_utils.py#L164-L168]
        prev_mask = sigmoid(upsample(low_res, 128)) > 0.5
    # Final mask: probability above 0.5
    # [code: utils/infer_utils.py#L172-L179]
    return sigmoid(upsample(low_res, 128)) > 0.5
Pseudocode
# One training volume: 11 simulated clicks, loss summed  [§4.2]
# Input:  image (1, 1, 128, 128, 128), z-scored; gt (1, 1, 128, 128, 128)
# Output: scalar loss, summed over the clicks

def training_step(model, image, gt):
    # Encode the volume once, under autocast
    # [code: train.py#L348-L349]
    image_embedding = model.image_encoder(image)
    prev_low_res = zeros((1, 1, 32, 32, 32))
    prev_logits = zeros_like(gt)
    # Mask-only step at a random index in 2..8  [code: train.py#L273]
    insert_at = random_int(2, 8)
    total_loss = 0
    # Eleven clicks, hard-coded  [code: train.py#L359]
    for click_index in range(11):
        # Click from the error region of the raw logits
        # [code: train.py#L247-L248]
        new_point, new_label = sample_error_click(prev_logits, gt)
        if click_index in (insert_at, 10):
            # Mask-only step: the new click is not passed
            # [code: train.py#L277-L282]
            prompt = None
        else:
            # Only the newest click, since multi_click is off
            # [code: train.py#L262-L264]
            prompt = (new_point, new_label)
        sparse, dense = model.prompt_encoder(prompt, prev_low_res)
        low_res = model.mask_decoder(image_embedding, sparse, dense)
        # Raw logits, not detached  [code: train.py#L241-L245]
        prev_logits = upsample(low_res, gt.shape[-3:])
        # Dice plus cross-entropy on logits, summed
        # [code: train.py#L289-L290]
        total_loss += dice_ce_loss(prev_logits, gt)
        prev_low_res = low_res
    return total_loss
Pseudocode
# Training click: one random voxel of the error region
# [code: utils/click_method.py#L191-L223]
# Input:  prev_logits (1, 1, D, H, W) raw logits; gt (1, 1, D, H, W)
# Output: one (point, label) pair per volume

def sample_error_click(prev_logits, gt):
    # Predicted foreground: logit above 0.5
    # [code: utils/click_method.py#L199]
    pred = prev_logits > 0.5
    truth = gt > 0
    false_negative = truth and not pred
    false_positive = not truth and pred
    error = false_negative or false_positive
    # Uniform over the error voxels
    # [code: utils/click_method.py#L204-L209]
    point = random_choice(argwhere(error))
    # Positive label for a false negative
    # [code: utils/click_method.py#L211-L214]
    label = 1 if false_negative[point] else 0
    return point, label

Hyperparameters

Rows that cite §... or tab. ... come from the paper. Every other row comes from the released code: its defaults, its shell scripts, or its functions. The released checkpoint's architecture is not stated in the repository (see Pitfalls).

NameValueWhereNotes
ROI size (train and inference)128 × 128 × 128 voxels§4.3 train.py infer_utils.pyCrop is centred on the mask; inference resamples first
Target spacing1.5 mm isotropic§3.2 infer_utils.pyTraining does not resample in train.py; resampling happens offline
Patch size16 × 16 × 16build_sam3D.pyNon-overlapping 3D convolution
Tokens per ROI8 × 8 × 8derived from 128 / 16build_sam3D.py
Encoder width / depth / heads (vit_b_ori)768 / 12 / 12build_sam3D.pyTrain default; the paper's model size is not stated
MLP ratio, qkv bias, relative position4, on, onbuild_sam3D.pyLayer-norm eps 1e-6 build_sam3D.py
Global attention blocksindices 2, 5, 8, 11 (0-based)build_sam3D.pyOther blocks use window attention
Window size14build_sam3D.pyZero-padded to multiples of 14 (see Pitfalls)
Absolute position embeddinglearned, shape (1, 8, 8, 8, 768)image_encoder3D.pyFixed to the ROI size
Neck1×1×1 conv 768→384 (no bias), layer norm, 3×3×3 conv 384→384 (pad 1, no bias), layer normimage_encoder3D.pyOutput 384 channels at 8³
Prompt embedding width384build_sam3D.pyShared with the decoder
Position encodingrandom Fourier features, Gaussian matrix 3 × 128, scale 1.0prompt_encoder3D.py prompt_encoder3D.pyThird block uses sin (see Pitfalls)
Point embeddings2 (negative, positive) + "not a point"prompt_encoder3D.pyPadding point appended when no box is given prompt_encoder3D.py
Mask-input encoderconv 1→4 (k2 s2), layer norm, GELU, conv 4→16 (k2 s2), layer norm, GELU, conv 16→384 (k1)prompt_encoder3D.pyInput is the previous low-res logits
Decoder transformer2 layers, width 384, 8 heads, MLP 2048, attention downsample 2mask_decoder3D.py
Mask tokens1 IoU token, 4 mask tokens (index 0 single, 1–3 multi)mask_decoder3D.py mask_decoder3D.pyTraining uses single-mask output
Output upsampling2 transposed 3D convs (k2 s2), 384→96→48mask_decoder3D.pyLow-res logits at ROI/4 = 32³ for 128 input
Hypernetwork MLPs4 MLPs, 3 layers, 384→384→48mask_decoder3D.py
IoU headMLP, depth 3, hidden 256, 4 outputsmask_decoder3D.pyNot trained (see Pitfalls)
CT intensity clamp[−1000, 1000], training onlydata_loader.pyApplied when the path contains /ct_
Intensity normalisationz-score over voxels > 0train.py train.py infer_utils.pyNot stated in the paper
Training volume filterskip if label voxels ≤ 1000data_loader.py train.pyNot stated in the paper
Augmentationrandom flip on each of the 3 axestrain.pyPad or crop to 128³ centred on the mask train.py
OptimiserAdamW, betas (0.9, 0.999), weight decay 0.1train.py train.pyCode default
Learning rate8e-4 (default)train.pyShell scripts use 8e-5 train.sh train_ddp.sh
Learning rate, prompt encoder and decoder0.1 × lrtrain.pyImage encoder uses the full lr
ScheduleMultiStepLR, milestones [120, 180], gamma 0.1, 200 epochstrain.py train.pyCode defaults; stepped once per epoch train.py
Batch size12 (default); 2 on one GPU; 6 per GPU on 8 GPUstrain.py train.sh train_ddp.shPer GPU in the DDP script
Gradient accumulation20 micro-batches (default, not overridden)train.py train.pyDerived effective batch: 2 × 20 = 40 on one GPU; 6 × 8 × 20 = 960 on 8 GPUs
Gradient clippingnonetrain.pyNo clipping call in the code
LossMONAI DiceCE, sigmoid, squared prediction, mean; summed over clickstrain.py train.pyApplied to raw logits
Clicks per volume11 (hard-coded)train.pySampled count train.py is unused
Mask-only stepsat click index random 2..8, and at the last clicktrain.py train.pyNot in the paper
Mixed precisionCUDA autocast; grad scalertrain.py train.py
Seed (training)2023 (single GPU); 2023 + rank (DDP)train.py train.py
Stage 1 length800 epochs§4.2Repository default is 200 epochs train.py; no stage-1 config
Stage 2 dataabout 75K masks§4.2Selection code not in the repository
Evaluation clicks1, 3, 5, 10 pointstab. 3Released scripts use 1 click medim_val_single.py
Evaluation seed233infer_utils.py
Binary threshold, evaluationsigmoid > 0.5infer_utils.py infer_utils.py
Binary threshold, training clicks and Diceraw logit > 0.5click_method.py train.pyDiffers from evaluation (see Pitfalls)
Dice2·|A∩B| / (|A|+|B|)metric_utils.pyEmpty-mask conventions in Pitfalls

Results

Author-reported throughout. The main evaluation uses the 16 public validation datasets §3.3. Table 3 gives N, the number of slices containing the target, as 10 ≤ N ≤ 200 tab. 3. The paper says the 2D baselines SAM and SAM-Med2D are compared on the same validation set, and that all compared methods use a single model §4.3. Which weights were used for SAM and SAM-Med2D is not stated there. For the task-specific comparison, the authors trained nnU-Net and UNETR on each benchmark and used official weights for the general-purpose models §5.1.2.

Pre-experiment: three ways to adapt SAM to 3D (Dice %, averaged over 1 and 10 points, trained on AMOS and tested on seen and unseen targets) tab. 2:

MethodSeenUnseenOverall
3D adapter with frozen SAM49.0838.6043.84
Fine-tuning with SAM pre-training69.1318.4343.78
Training from scratch on 3D data55.7934.6345.21

Overall comparison on 16 public validation datasets (Dice %, N = slices containing the target) tab. 3:

ModelPromptInference time (s)SeenUnseenOverall
SAMN ptsN(τ+0.13)16.7911.7316.15
SAM-Med2DN ptsN(τ+0.04)38.9122.5536.83
SAM-Med3D1 ptτ+281.9837.0276.27
SAM3N pts3N(τ+0.19)34.6115.9432.24
SAM-Med2D3N pts3N(τ+0.07)51.4629.7048.70
SAM-Med3D3 pts3τ+384.1443.8079.02
SAM5N pts5N(τ+0.25)49.3921.8645.89
SAM-Med2D5N pts5N(τ+0.10)51.8930.4149.17
SAM-Med3D5 pts5τ+484.6246.2679.75
SAM-Med3D10 pts10τ+685.1949.9280.71

The paper's headline gain is 60.12 points over SAM with one point per volume §5.1.1 §6. τ is the user's interaction time, which the paper says is usually more than one second tab. 3 caption.

Task-specific and general-purpose models on six public benchmarks (Dice %;

  • marks a data source or modality not in the training set) tab. 4:
DatasetModalityUNETRnnU-NetSAM-Med2D (N pts)SegVol (pt+text)Ours (1 pt)Ours (10 pts)
TotalsegmentatorCT75.0585.2238.26-84.6887.59
KiTS21CT70.7575.3268.74-72.0675.37
AMOS-CTCT78.3388.8749.61-79.9483.99
AMOS-MRMR76.2986.9245.53-75.4181.13
BTCV*CT78.9981.9250.0573.8179.1783.01
TDSC-ABUS23*US*-45.0849.39-36.0854.35

The paper says the 10-point model is best on four of the six benchmarks §5.1.2.

By anatomy and lesion, on the 16-dataset validation set (Dice %) tab. 5:

ModelPromptAbd&ThoBoneBrainCardiacMuscleLesionUnseen organUnseen lesion
SAMN pts19.9317.8529.738.443.9311.5612.148.88
SAM-Med2DN pts50.4732.7036.0040.1843.8524.9019.3644.87
SAM-Med3D1 pt80.7683.3843.7487.1289.7458.0635.9944.22
SAM3N pts31.9742.0740.4218.948.4624.5216.1814.21
SAM-Med2D3N pts58.9447.4854.5747.0656.0542.6027.2546.87
SAM-Med3D3 pts84.0684.7453.3489.7191.0161.7342.2055.02
SAM5N pts43.4559.8749.8533.5716.9438.8621.6723.22
SAM-Med2D5N pts59.5247.8155.0247.3856.3643.9027.9547.66
SAM-Med3D5 pts84.6885.0256.8690.3691.2962.9444.5158.46
SAM-Med3D10 pts85.4285.3461.2790.9791.6264.8048.1062.72

Transfer as a pre-trained encoder for semantic segmentation (Dice %, UNETR with and without a SAM-Med3D encoder) tab. 6 §5.1.6:

Pre-trainAMOSTotalsegmentatorCAS2023SEG.A.2023Avg.
none76.2982.6786.3487.0583.09
SAM-Med3D81.9285.1788.3987.5785.79

The paper reports a maximum gain of 5.63 Dice points, on AMOS §5.1.6.

Fine-tuning data for promptable segmentation (Dice %). The caption says the table excludes FeTA22 for fairness, so its validation set is not the one used in Table 5 tab. 7:

Fine-tune targetFine-tune datasetAbd&ThoBone (vert.)Bone (other)BrainCardiacMuscleLesionUnseen organUnseen lesion
--58.6166.0528.0856.3468.5069.4547.8727.8048.44
organAMOS67.2358.5930.5159.7271.8977.3950.4738.3037.43
vertebraeVerse2035.0878.8423.777.7761.0237.7535.4218.3824.69
brainFeTA2250.2851.1425.3462.5662.9543.7045.8944.8124.73
all44 datasets85.4285.9884.9061.9190.9791.6264.8048.1062.72

The last row is the model fine-tuned on high-quality data from 44 datasets tab. 7 caption. Table 7 splits bone into two columns, and its Brain value (61.91) differs from the 10-point Brain value in Table 5 (61.27). Because the validation sets differ, do not read the two tables as one series.

Qualitative results are shown in fig. 5. The text cites fig. 1 and fig. 5 for fewer prompts needed and better consistency between slices §5.2. These are visual claims, not measurements.

Paper vs code

Checked against the code at f3de1fa10da98e46f49f176773d2b1e306ba131f.

  • Cleaning rules. The paper removes masks below 1 cm³ or with any dimension under 1.5 cm §3.2. The preparation script drops a mask when its voxel count times the header spacing in mm³ is below 10, which is 0.01 cm³. It has no dimension rule prepare_data_from_nnUNet.py. Its only dataset list is AMOS_val prepare_data_from_nnUNet.py. The other cleaning steps (background over 99%, five largest components, left and right split) are not in the repository. The connected-component code that does exist is SAM's 2D mask generator and is not used for 3D data amg.py.
  • Large-volume inference. The paper uses 128-voxel patches with a 50% overlapping sliding window for volumes larger than 128 §4.3. The release crops one 128³ ROI around the ground-truth mask and runs it once infer_utils.py infer_utils.py. No sliding-window code exists in the 3D path.
  • Stage 1 length. The paper trains for 800 epochs §4.2. The training default is 200 train.py. The repository has no stage-1 config. The shell scripts fine-tune from the released checkpoint train.sh.
  • Stage 2 data. The paper filters about 75K high-quality masks §4.2. The repository has no filter or list of masks. train.py trains on whatever the configured directories contain data_paths.py.
  • Training clicks. The paper does not describe the click simulation. The code uses 11 clicks, mask-only steps and a loss summed over clicks train.py.
  • Released checkpoint. The README says the released checkpoint is SAM-Med3D-turbo, fine-tuned on 44 datasets readme.md readme.md. The paper's reported models are not stated to be that checkpoint. The inference scripts load it through the external medim package medim_val_single.py.
  • Positional encoding. The paper names a 3D positional encoding without a formula §4.1. The code builds the three blocks as sin, cos and sin prompt_encoder3D.py.
  • Evaluation clicks. The paper reports 1, 3, 5 and 10 points tab. 3. The released scripts run one click medim_val_single.py medim_val_dataset.py.
  • Consistent. The first-click rule §4.3 matches infer_utils.py. The 1.5 mm spacing §3.2 matches prepare_data_from_nnUNet.py and infer_utils.py.

Pitfalls

  • Click prompts differ between training and evaluation. Training sends only the newest click unless --multi_click is set, and that flag defaults to off train.py train.py. Evaluation keeps every click so far infer_utils.py. The paper does not say which rule its numbers use.
  • Two thresholds for the same mask. Training decides the next click and the Dice on raw logits above 0.5, a probability of about 0.62 click_method.py train.py train.py. Evaluation uses a probability above 0.5, which is a logit above 0 infer_utils.py. Copying one rule into the other gives different click placements.
  • The last click never reaches the decoder during training. At the final click, and at one earlier random step, the decoder runs with no point prompt train.py. The point sampled at that step is discarded.
  • The sampled click count is ignored. train() draws a count from 1 to 20 each epoch and passes it to train_epoch, which hard-codes 11 clicks train.py train.py.
  • Empty error regions crash training. The training click sampler indexes an empty set when prediction equals ground truth click_method.py. Evaluation falls back to a foreground voxel infer_utils.py. Add a guard before porting.
  • Gradients flow through all clicks. The previous low-res logits are passed on without detaching train.py. The graph therefore spans every decoder call in one volume. Memory grows with the click count, even though the encoder runs once train.py.
  • The IoU head is never trained. batch_forward discards its output train.py, and the loss ignores it. Do not use its scores without training it.
  • Two different input normalisations. Sam3D.forward subtracts SAM's pixel mean and divides by SAM's pixel std sam3D.py sam3D.py build_sam3D.py. Those constants have three values, so by reading they cannot broadcast against a one-channel 128³ volume. I did not run it. Training and evaluation skip this step and call the encoder directly on z-scored data train.py infer_utils.py infer_utils.py.
  • Z-scoring includes the padding. Statistics come from voxels above zero, but the transform is applied to every voxel. Background and padding become (0 − mean) / std, not zero train.py train.py.
  • Window attention attends to zeros. Blocks pad each window with zeros and the attention has no padding mask image_encoder3D.py image_encoder3D.py. For the 128 setting, one 14³ window holds 512 real tokens and 2,232 padding tokens.
  • The ROI size is fixed. The absolute position embedding is created for 8³ tokens and cannot be used with another ROI size without resizing image_encoder3D.py.
  • The registry default is not the training default. The registry's default entry builds the ViT-H-sized encoder (width 1280, depth 32) build_sam3D.py build_sam3D.py. Training defaults to vit_b_ori train.py. The released checkpoint's architecture is not stated in the repository. Read it from the tensor shapes.
  • The shipped inference function may not run as written. sam_model_infer calls the mask decoder without multimask_output infer_utils.py. This repository's MaskDecoder3D.forward requires that argument mask_decoder3D.py. The medim model may use a different class. I did not run the code, so this is from reading only.
  • Objects larger than the ROI are cut off. One 128-voxel ROI covers 192 mm at 1.5 mm spacing. The paper's sliding window is not in the release infer_utils.py.
  • Inference needs ground truth. Clicks are sampled from the label mask, so the README says a fake label must be supplied for unlabelled images readme.md.
  • CT clamping happens only in training. The training loader clamps /ct_ paths to [−1000, 1000] data_loader.py. The inference preprocessing does not clamp infer_utils.py.
  • Training skips small labels. A volume with 1000 or fewer label voxels is replaced by another randomly chosen case. The paper does not mention this data_loader.py.
  • Multi-class labels overwrite each other. Classes are processed one at a time, and a later class overwrites an earlier one where they overlap infer_utils.py.
  • Coordinates are array indices. Prompts are indices in the (D, H, W) order of the canonical ROI array, not NIfTI (x, y, z) click_method.py infer_utils.py. Match the axis order of the volume.
  • Empty masks have conventions. Both empty gives NaN, and an empty ground truth with a non-empty prediction gives 0 metric_utils.py. Per-class averages use nanmean metric_utils.py.
  • Costs the abstract hides. The timing formulas in tab. 3 add a constant of 2 to 6 seconds on top of τ per click. The main text gives no training hardware or memory figures. Training decodes eleven steps per volume with the graph kept (see above), so memory is higher than one decoder pass.
  • The 24 private datasets are not in the release. The paper uses them in training §3.1. The README links a separate SA-Med3D-140K download readme.md. Its licence is not checked here, so check it before reusing any masks.

Lineage

  • Builds on: SAM, arXiv:2304.02643, whose promptable design this code extends. The repository's header carries SAM's Meta copyright sam3D.py. The ViT block code is adapted from ViTDet, as its comment says image_encoder3D.py.
  • Compared against: SAM-Med2D, arXiv:2308.16184 (fine-tuned SAM for 2D medical images, used as the main general-purpose baseline) §4.3. Also MedLSAM, arXiv:2306.14752; SAM3D, arXiv:2309.03493; MA-SAM, arXiv:2309.08842; MSA, arXiv:2304.12620; 3DSAM-Adapter, arXiv:2306.13465 tab. 1. SegVol, arXiv:2311.13385 tab. 4. Task-specific baselines are UNETR and nnU-Net tab. 4.
  • Dataset used in the pre-experiment and as a benchmark: AMOS, arXiv:2206.08023 tab. 2 tab. 4.
  • Superseded by: none recorded in this wiki.

Source and license

Adapted from “SAM-Med3D: Towards General-purpose Segmentation Models for Volumetric Medical Images” by Haoyu Wang, Sizheng Guo, Jin Ye, Zhongying Deng, Junlong Cheng, Tianbin Li, Jianpin Chen, Yanzhou Su, Ziyan Huang, Yiqing Shen, Bin Fu, Shaoting Zhang, Junjun He, Yu Qiao (arXiv:2310.15161), used under CC BY-SA 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. This page is licensed under CC BY-SA 4.0. Code citations refer to https://github.com/uni-medical/SAM-Med3D at commit f3de1fa10da9 (Apache-2.0). Any quoted code is shown under that license.