Medical & Scientific Vision

nnU-Net

A self-configuring framework for biomedical image segmentation that keeps a plain U-Net and sets everything around it, from target spacing, normalization, patch and batch size and network depth to the choice of 2D, 3D and cascaded configurations, from a fingerprint of the training data by fixed parameters, rules and cross-validation.

intermediate

nnU-Net is a framework for biomedical semantic segmentation that configures a complete pipeline for a new dataset without manual tuning. Fabian Isensee, Klaus Maier-Hein and colleagues at the German Cancer Research Center (DKFZ) in Heidelberg introduced it in 2018 as their entry to the Medical Segmentation Decathlon, describing it as a “no-new-Net”: the network is a plain U-Net in 2D and 3D, and the work goes into the decisions around it (Isensee et al., 2018). The method was published in Nature Methods in 2021, whose abstract models these decisions as “a set of fixed parameters, interdependent rules and empirical decisions” (Isensee et al., 2021). From a fingerprint of the training data it sets the target voxel spacing, intensity normalization, patch size, batch size and network depth per axis, trains up to three configurations by five-fold cross-validation and selects the best one or a pair of them. It is a common baseline in medical image segmentation, and the software is maintained as an open-source package; this article follows release 2.8.1 (July 2026) for the rules and the papers for their rationale.

Problem Addressed

A U-Net is short to write, but applying one to a new 3D dataset involves many interdependent choices, from resampling and normalization to patch size, downsampling, batch size, loss, augmentation, patch stitching and post-processing. The nnU-Net authors argued that these choices, more than architectural novelty, decide performance, and that a U-Net used as a baseline often underperforms because they are made poorly (Isensee et al., 2018). In arXiv v2 they supported the argument with the 2019 Kidney and Kidney Tumor Segmentation (KiTS) leaderboard: the top 15 entries were all 3D U-Net-like, none of the common modifications (residual or dense connections, attention, dilated convolutions) was necessary for a good rank, and entries built on the challenge winner’s architecture, a residual 3D U-Net, were spread over the whole leaderboard (Isensee et al., arXiv v2, 2020).

The alternative to manual configuration was automatic search (AutoML, neural architecture search), which re-optimizes for every task at a large cost in compute and data. nnU-Net instead condenses expert knowledge into explicit rules that are executed once per dataset, so that only a small number of choices are left to cross-validation (Isensee et al., arXiv v2, 2020).

Architecture

The papers divide the pipeline into three kinds of parameters. arXiv v2 calls them blueprint, inferred and empirical parameters (Isensee et al., arXiv v2, 2020); the journal version’s abstract speaks of fixed parameters, interdependent rules and empirical decisions (Isensee et al., 2021), and the documentation of release 2.8.1 of fixed, rule-based and empirical parameters, the terms used here.

  • Fixed parameters do not depend on the data: the U-Net template, the loss, the optimizer and schedule, augmentation and the inference procedure.
  • Rule-based parameters are computed from the dataset fingerprint: target spacing, resampling, normalization, patch size, batch size and the topology of the network.
  • Empirical parameters are chosen by cross-validation on the training data: which configuration or pair of configurations to use, and whether to remove all but the largest connected component.

In the software the steps are separate commands: nnUNetv2_extract_fingerprint writes the fingerprint, nnUNetv2_plan_experiment turns it into a plans file in JSON, nnUNetv2_preprocess resamples and normalizes the data, nnUNetv2_train trains one fold of one configuration, and nnUNetv2_find_best_configuration compares configurations and ensembles and decides the post-processing (nnUNetv2_plan_and_preprocess runs the first three).

Dataset Fingerprint

The training cases are first cropped to the bounding box of their nonzero voxels, which matters for skull-stripped brain MRI and hardly for CT (Isensee et al., arXiv v2, 2020). The fingerprint then records, for every case, the voxel spacing and the shape after cropping, the median fraction of the volume that cropping kept, and, pooled over all cases and for each input channel, the mean, standard deviation, median, minimum, maximum and the 0.5th and 99.5th percentiles of intensities inside the labelled foreground. In 2.8.1 these statistics come from a sample of foreground voxels, 10810^8 in total divided equally among the cases and drawn with replacement under a fixed seed, so they are reproducible (fingerprint_extractor.py). The channel names and the number of classes and training cases are read from the dataset’s dataset.json.

Fixed Parameters: the U-Net Template

All configurations instantiate the same template, close to the original U-Net and the 3D U-Net: two convolutions per resolution in encoder and decoder, each followed by instance normalization and a leaky ReLU (negative slope 0.01), downsampling by strided convolution and upsampling by transposed convolution, 32 feature maps at the highest resolution, doubled at every downsampling and capped at 320 in 3D and 512 in 2D (Isensee et al., arXiv v2, 2020). Instance normalization was chosen because most 3D configurations train with a batch of two, for which batch normalization works poorly. The networks are trained with deep supervision, so the decoder also predicts at lower resolutions. No residual, dense or attention blocks are used in the default configuration. The plans file of 2.8.1 names the class PlainConvUNet from the dynamic_network_architectures package and stores all of these settings, so a network can be rebuilt from the plans alone.

Rule-Based Parameters

The rules below are those of arXiv v2, checked against the default planner (ExperimentPlanner) of release 2.8.1. Where the two differ, the difference is stated.

Target spacing. Every case is resampled to one spacing so that a voxel step means the same distance throughout. The default is the median of the training spacings, taken per axis. For anisotropic datasets the median can leave too few slices and cause severe interpolation artifacts, so when both the spacing and the voxel counts are anisotropic, the low-resolution axis takes the 10th percentile of its training spacings instead (Isensee et al., arXiv v2, 2020). In 2.8.1 the test uses the anisotropy threshold of 3 and the median spacings s~\tilde{s} and median shapes n~\tilde{n} after cropping: with a∗a^\ast the axis of largest median spacing, the exception applies if

s~a∗>3max⁡a≠a∗s~aand3 n~a∗<min⁡a≠a∗n~a,\tilde{s}_{a^\ast} > 3 \max_{a \neq a^\ast} \tilde{s}_a \quad \text{and} \quad 3\, \tilde{n}_{a^\ast} < \min_{a \neq a^\ast} \tilde{n}_a ,

and the 10th percentile is raised to just above the coarsest other axis if it would fall below it (determine_fullres_target_spacing). The planner also transposes the axes so that the lowest-resolution axis comes first; the 2D configuration then works on slices of the two finer axes.

Resampling. Images are resampled with third-order splines. If a case or its target is anisotropic (largest spacing more than three times the smallest), interpolation is split: third-order splines in the plane and nearest-neighbour interpolation along the coarse axis, because contours change much more between thick slices than within them. Label maps are resampled one class at a time with linear interpolation (nearest-neighbour along the coarse axis of anisotropic cases) and recombined by taking, at each voxel, the class with the largest value (Isensee et al., arXiv v2, 2020). The 2.8.1 plans store exactly these orders (order: 3 for images, order: 1 for labels, order_z: 0), and the threshold of 3 is the constant ANISO_THRESHOLD in configuration.py.

Intensity normalization. For channels named CT, intensities are clipped to the 0.5th and 99.5th foreground percentiles and standardized with the global foreground mean μfg\mu_{\mathrm{fg}} and standard deviation σfg\sigma_{\mathrm{fg}} of the training set, the same for every image, since CT values in Hounsfield units are quantitative (Computed Tomography explains the scale):

x′=clip⁡(x,P0.5,P99.5)−μfgσfg.x' = \frac{\operatorname{clip}(x, P_{0.5}, P_{99.5}) - \mu_{\mathrm{fg}}}{\sigma_{\mathrm{fg}}} .

All other channels, including MRI, are z-scored per image. If cropping shrank the cases by a quarter or more, z-scoring is computed inside the nonzero mask and the zero voxels around it are ignored (Isensee et al., arXiv v2, 2020); in 2.8.1 they stay at zero. arXiv v2 states the cropping criterion for the average size; 2.8.1 tests the median relative size against 3/4. Release 2.8.1 also offers channel names for no normalization, rescaling to [0,1][0, 1] and RGB images (map_channel_name_to_normalization.py).

Topology. Downsampling is planned from the patch size and the target spacing. An axis is pooled while its feature map stays at least 4 voxels long after pooling, and only while its spacing is within a factor of two of the finest current spacing; a finer axis is therefore pooled alone until it has caught up with a coarser one, after which all axes are pooled together. Kernels are 3×3×33 \times 3 \times 3 (or 3×33 \times 3 in 2D), except that an axis whose spacing is more than twice the finest gets kernel size 1, making those stages pseudo-2D, until the spacings are within a factor of two; from then on its kernel stays 3 (Isensee et al., arXiv v2, 2020). The patch is padded to a multiple of 2da2^{d_a} along each axis, where dad_a is the number of poolings along it (network_topology.py).

Patch and batch size. nnU-Net prefers large patches, which give more context, and pays for them with small batches, kept at two or more with a high momentum for stability. The memory a configuration needs is estimated from the total size of its feature maps, which needs no GPU, and compared with a reference value known to fit the memory budget. The patch is shrunk step by step along the axis that is largest relative to the median image shape, by 2da2^{d_a} voxels per step, re-planning the topology each time, until the estimate fits. If the patch had to shrink, the batch size is 2; otherwise spare memory raises it, but never beyond 5% of all voxels in the training set, and never below 2 (Isensee et al., arXiv v2, 2020). In 2.8.1, with EE the estimate, RR the reference value and brefb_{\mathrm{ref}} the batch size it corresponds to (2 in 3D, 12 in 2D),

b=max⁡ ⁣(2, min⁡ ⁣(round⁡ ⁣(brefRE), round⁡ ⁣(0.05 N VmedVpatch))),b = \max\!\left(2,\ \min\!\left(\operatorname{round}\!\left(b_{\mathrm{ref}} \frac{R}{E}\right),\ \operatorname{round}\!\left(0.05\, \frac{N\, V_{\mathrm{med}}}{V_{\mathrm{patch}}}\right)\right)\right),

where NN is the number of training cases, VmedV_{\mathrm{med}} the voxel count of the median resampled image and VpatchV_{\mathrm{patch}} that of the patch. The reference value is proportional to the GPU memory target, 8 GB by default; a source comment says the two reference values were set to reproduce nnU-Net v1’s configurations. The papers and the code differ in the starting patch: arXiv v2 starts from the median image shape, whereas 2.8.1 starts from a box with the volume of a 2563256^3 patch (204822048^2 in 2D), shaped by the inverse spacing and then clipped to the median shape, a clipping the code comment marks as different from nnU-Net v1.

Configurations

By default nnU-Net plans three configurations (Isensee et al., arXiv v2, 2020):

  • 2D U-Net (2d) on slices of the two finest axes, at their median spacing, with no resampling across slices. The 2018 entry included it because 3D methods had been reported to suffer on anisotropic data such as the Decathlon’s prostate MRI (Isensee et al., 2018).
  • 3D full-resolution U-Net (3d_fullres) at the target spacing above. Its patch may cover only part of a large image, which limits the context it sees.
  • 3D U-Net cascade (3d_lowres, then 3d_cascade_fullres): a first 3D U-Net segments downsampled images, its output is upsampled and given as extra one-hot input channels to a second, full-resolution 3D U-Net that refines it. The low-resolution spacing is found by increasing the spacing step by step, only along the finer axes while the spacing is anisotropic by more than a factor of two, until the low-resolution patch covers at least a quarter of the low-resolution median image.

arXiv v2 creates the cascade only when the full-resolution patch covers less than 12.5% of the median image and increases the spacing in steps of 1%. In 2.8.1 the search starts below 25% coverage, uses steps of 3% (a comment notes that it used to be 1%), and then drops the low-resolution configuration unless its median image has at most half the voxels of the full-resolution one; this last check is absent from the planner at the v2.0 tag. The documentation of 2.8.1 notes that not every dataset receives every configuration.

Empirical Parameters

Each configuration is trained on the same five folds (a seeded split in 2.8.1). The configurations and every pair of them, ensembled by averaging softmax probabilities, are compared by the mean foreground Dice coefficient over the cross-validation predictions, and the best is selected; ties go to the simpler candidate in 2.8.1. Post-processing is then tested on the same predictions. With all foreground classes treated as one, keeping only the largest connected component is adopted if it raises the mean foreground Dice without lowering it for any class; building on that outcome, the same step is then tested for each class (Isensee et al., arXiv v2, 2020), and 2.8.1 adopts it for a class if that class’s Dice rises (remove_connected_components.py).

Example: Planning Three Synthetic Datasets

The script below writes three tiny datasets in nnU-Net’s raw format and runs fingerprint extraction and experiment planning on the CPU. It uses nnunetv2 2.8.1 with PyTorch 2.15.0, SimpleITK 2.5.7 and NumPy 2.5.4; no network is trained and nothing is downloaded. Each dataset holds six synthetic CT-like volumes, a soft-tissue body in air with a labelled, brighter ellipsoidal “organ” and Gaussian noise, on 0.8 mm pixels. The three datasets differ only in slice spacing, nominally 0.8, 2 and 5 mm, scaled per case so that spacings vary within a dataset as they do in practice.

# make_datasets.py: three synthetic CT-like datasets in nnU-Net's raw format
import json, os, sys
import numpy as np
import SimpleITK as sitk

RAW = sys.argv[1]                                # the nnUNet_raw folder
INPLANE, NXY, Z_MM = 0.8, 256, 160.0             # 0.8 mm pixels, 256 x 256, 160 mm long
FACTORS = [0.6, 0.8, 1.0, 1.0, 1.2, 1.2]         # per-case slice spacing / nominal
DATASETS = {801: ("Iso", 0.8), 802: ("Slice2mm", 2.0), 803: ("Slice5mm", 5.0)}

def make_case(rng, dz):
    nz = int(round(Z_MM / dz))
    z = (np.arange(nz) + 0.5) * dz - Z_MM / 2               # slice centres in mm
    y = (np.arange(NXY) + 0.5) * INPLANE - NXY * INPLANE / 2
    Z, Y, X = np.meshgrid(z, y, y, indexing="ij")           # array order (z, y, x)
    body = (X / 90) ** 2 + (Y / 70) ** 2 < 1                # elliptical body
    c = rng.uniform(-10, 10, size=3)                        # organ centre jitter (mm)
    organ = ((X - 25 - c[0]) / 50) ** 2 + ((Y - c[1]) / 35) ** 2 + ((Z - c[2]) / 40) ** 2 < 1
    hu = np.where(body, 40.0, -1000.0)                      # soft tissue / air
    hu[organ] = 100.0                                       # enhancing "organ"
    hu += rng.normal(0, 20, hu.shape)
    return hu.astype(np.int16), organ.astype(np.uint8)

def write(arr, path, dz):
    img = sitk.GetImageFromArray(arr)
    img.SetSpacing((INPLANE, INPLANE, dz))                  # SimpleITK order (x, y, z)
    sitk.WriteImage(img, path, useCompression=True)

for did, (name, dz0) in DATASETS.items():
    rng = np.random.default_rng(did)
    root = os.path.join(RAW, f"Dataset{did}_{name}")
    os.makedirs(os.path.join(root, "imagesTr"), exist_ok=True)
    os.makedirs(os.path.join(root, "labelsTr"), exist_ok=True)
    for i, f in enumerate(FACTORS):
        dz = round(dz0 * f, 3)
        hu, lab = make_case(rng, dz)
        write(hu, os.path.join(root, "imagesTr", f"case{i:02d}_0000.nii.gz"), dz)
        write(lab, os.path.join(root, "labelsTr", f"case{i:02d}.nii.gz"), dz)
    with open(os.path.join(root, "dataset.json"), "w") as fh:
        json.dump({"channel_names": {"0": "CT"}, "labels": {"background": 0, "organ": 1},
                   "numTraining": len(FACTORS), "file_ending": ".nii.gz"}, fh, indent=2)

The channel name CT selects CT normalization, and the _0000 suffix numbers the input channel. A shell script sets the three folders nnU-Net expects, runs the two official commands with their default planner and prints a summary of the plans:

# run.sh WORKDIR  (python and the nnUNetv2_* commands of nnunetv2 2.8.1 on the PATH)
set -e
export nnUNet_raw=$1/nnUNet_raw nnUNet_preprocessed=$1/nnUNet_preprocessed nnUNet_results=$1/nnUNet_results
mkdir -p "$nnUNet_raw" "$nnUNet_preprocessed" "$nnUNet_results"
python make_datasets.py "$nnUNet_raw"
nnUNetv2_extract_fingerprint -d 801 802 803 -np 2 --verify_dataset_integrity --no_pbar > "$1/fingerprint.log" 2>&1
nnUNetv2_plan_experiment -d 801 802 803 > "$1/plan.log" 2>&1
python summarize_plans.py "$nnUNet_preprocessed"
grep -m1 -o "Dropping 3d_lowres.*" "$1/plan.log"
# summarize_plans.py: the parts of nnUNetPlans.json that the fingerprint decided
import glob, json, os, sys
import numpy as np

def r(v, n=2):
    return [round(float(x), n) for x in v]

for folder in sorted(glob.glob(os.path.join(sys.argv[1], "Dataset8*"))):    # nnUNet_preprocessed
    fp = json.load(open(os.path.join(folder, "dataset_fingerprint.json")))
    plans = json.load(open(os.path.join(folder, "nnUNetPlans.json")))
    cfgs = plans["configurations"]
    n_cases = len(fp["spacings"])
    print(f"== {plans['dataset_name']}: slice spacings {sorted(r([s[0] for s in fp['spacings']]))} mm")
    print(f"   median spacing {r(plans['original_median_spacing_after_transp'])}, "
          f"median shape {plans['original_median_shape_after_transp']}, configurations {list(cfgs)}")
    n_vox = np.prod(cfgs["3d_fullres"]["median_image_size_in_voxels"]) * n_cases
    for name in ("2d", "3d_fullres"):
        c = cfgs[name]
        a = c["architecture"]["arch_kwargs"]
        cap = round(n_vox * 0.05 / np.prod(c["patch_size"]))          # the planner's 5% rule
        pools = np.sum(np.array(a["strides"]) == 2, axis=0).tolist()
        kernels = " ".join("".join(map(str, k)) for k in a["kernel_sizes"])
        print(f"   {name:10s} spacing {r(c['spacing'])}  image {[int(round(x)) for x in c['median_image_size_in_voxels']]}"
              f"  patch {c['patch_size']}  batch {c['batch_size']} (5% cap {cap})")
        cover = np.prod(c["patch_size"]) / np.prod(c["median_image_size_in_voxels"])
        print(f"   {'':10s} {a['n_stages']} stages, poolings per axis {pools}, kernels {kernels}, patch/image {cover:.0%}")
fg = fp["foreground_intensity_properties_per_channel"]["0"]
print(f"CT normalization ({plans['dataset_name']}): clip to [{fg['percentile_00_5']:.0f}, {fg['percentile_99_5']:.0f}],"
      f" subtract {fg['mean']:.1f}, divide by {fg['std']:.1f}")
== Dataset801_Iso: slice spacings [0.48, 0.64, 0.8, 0.8, 0.96, 0.96] mm
   median spacing [0.8, 0.8, 0.8], median shape [200, 256, 256], configurations ['2d', '3d_fullres']
   2d         spacing [0.8, 0.8]  image [256, 256]  patch [256, 256]  batch 49 (5% cap 60)
              7 stages, poolings per axis [6, 6], kernels 33 33 33 33 33 33 33, patch/image 100%
   3d_fullres spacing [0.8, 0.8, 0.8]  image [200, 256, 256]  patch [112, 160, 128]  batch 2 (5% cap 2)
              6 stages, poolings per axis [4, 5, 5], kernels 333 333 333 333 333 333, patch/image 18%
== Dataset802_Slice2mm: slice spacings [1.2, 1.6, 2.0, 2.0, 2.4, 2.4] mm
   median spacing [2.0, 0.8, 0.8], median shape [80, 256, 256], configurations ['2d', '3d_fullres']
   2d         spacing [0.8, 0.8]  image [256, 256]  patch [256, 256]  batch 24 (5% cap 24)
              7 stages, poolings per axis [6, 6], kernels 33 33 33 33 33 33 33, patch/image 100%
   3d_fullres spacing [2.0, 0.8, 0.8]  image [80, 256, 256]  patch [56, 192, 192]  batch 2 (5% cap 1)
              6 stages, poolings per axis [3, 5, 5], kernels 133 333 333 333 333 333, patch/image 39%
== Dataset803_Slice5mm: slice spacings [3.0, 4.0, 5.0, 5.0, 6.0, 6.0] mm
   median spacing [5.0, 0.8, 0.8], median shape [32, 256, 256], configurations ['2d', '3d_fullres']
   2d         spacing [0.8, 0.8]  image [256, 256]  patch [256, 256]  batch 14 (5% cap 14)
              7 stages, poolings per axis [6, 6], kernels 33 33 33 33 33 33 33, patch/image 100%
   3d_fullres spacing [3.5, 0.8, 0.8]  image [46, 256, 256]  patch [40, 224, 192]  batch 2 (5% cap 1)
              6 stages, poolings per axis [3, 5, 5], kernels 133 133 333 333 333 333, patch/image 57%
CT normalization (Dataset803_Slice5mm): clip to [48, 151], subtract 99.6, divide by 20.0
Dropping 3d_lowres config because the image size difference to 3d_fullres is too small. 3d_fullres: [200. 256. 256.], 3d_lowres: [173, 221, 221]

Running it twice in fresh folders gave identical output and byte-identical fingerprint and plans files.

The target spacing shows the anisotropy rule. With 2 mm slices the median slice spacing is 2.5 times the pixel size, below the threshold of 3, so the median is kept. With 5 mm slices both tests pass, and the slice axis takes the 10th percentile of the six slice spacings, which NumPy’s linear interpolation puts halfway between 3 and 4 mm, so the resampled median volume gains slices. The topology follows the spacing: in the isotropic dataset all axes are pooled together with 3×3×33 \times 3 \times 3 kernels, while the anisotropic datasets start with 1×3×31 \times 3 \times 3 kernels and in-plane pooling until the in-plane spacing has caught up with the slice spacing, one stage at 2 mm and two at 3.5 mm. The slice axis is pooled only three times because its patch is short and a feature map must stay at least 4 voxels long.

The batch sizes show the memory rule and its two limits. Every 3D patch had to be shrunk to fit the 8 GB reference, so the 3D batch is 2; for the anisotropic datasets the 5% rule would allow a single patch, and the minimum of 2 wins. In 2D the isotropic batch is set by memory, the other two by the 5% cap, because six short volumes contain few voxels. In the isotropic dataset the full-resolution patch covers less than the 25% that starts the search for a low-resolution configuration in 2.8.1, but the spacing at which the low-resolution patch covered a quarter of the image shrank the median image by a factor of about 1.55 in voxels, short of the required 2, so the planner dropped it and no cascade was planned; under the 12.5% threshold of arXiv v2 the search would not have started. The CT clipping window comes from foreground voxels only, so it is set by the organ, and the soft tissue and air are clipped to its lower end. By the trainer’s rule in 2.8.1 (below), the patches of both anisotropic datasets, whose longest side is more than three times the slice extent, would be augmented slice-wise in 2D, and the isotropic one in 3D.

Training starts from nnUNetPlans.json, so the same file can also configure a network written in plain PyTorch.

Training

Training is identical for every dataset (Isensee et al., arXiv v2, 2020). Each network is trained from scratch for 1000 epochs of 250 mini-batches, with stochastic gradient descent with Nesterov momentum 0.99, an initial learning rate of 0.01 and the polynomial (“poly”) learning-rate schedule

ηe=0.01(1−e1000)0.9,\eta_e = 0.01 \left(1 - \frac{e}{1000}\right)^{0.9},

where ee is the epoch; 2.8.1 adds a weight decay of 3×10−53 \times 10^{-5}. The loss is the sum of cross-entropy and a soft Dice loss, applied at each deep-supervision output against a correspondingly downsampled reference:

L=∑kwk(LCE(k)+LDice(k)),wk+1=12wk,∑kwk=1,\mathcal{L} = \sum_{k} w_k \left( \mathcal{L}_{\mathrm{CE}}^{(k)} + \mathcal{L}_{\mathrm{Dice}}^{(k)} \right), \qquad w_{k+1} = \tfrac{1}{2} w_k, \quad \sum_k w_k = 1 ,

with k=0k = 0 the full resolution and no losses at the two lowest resolutions. In 2.8.1 the Dice term is the negative soft Dice averaged over the foreground classes, with a smoothing constant of 10−510^{-5} (MemoryEfficientSoftDiceLoss). It is computed over the whole batch as one pseudo-volume for the 2D configuration and for the full-resolution 3D configuration when a cascade exists, and per sample otherwise (the batch_dice entry of the plans); the 2018 preprint gives the rationale that per-sample Dice suits 3D networks that see nearly entire patients (Isensee et al., 2018).

Each mini-batch draws its cases at random. A third of the patches (at least one per batch) is forced to contain a foreground class present in the case, the rest are taken at random positions, which keeps small structures from vanishing in the sampling (Isensee et al., arXiv v2, 2020). Data augmentation is applied on the fly: rotation, scaling, Gaussian noise, Gaussian blur, brightness, contrast, simulated low resolution, gamma and mirroring. In 2.8.1, rotation and scaling are each applied with probability 0.2 (scaling by 0.7 to 1.4) and elastic deformation is off; 3D patches whose longest side is more than three times their first, coarsest axis are augmented as 2D slices with rotations in the plane only (configure_rotation_dummyDA_mirroring_and_inital_patch_size). For the second stage of the cascade, the low-resolution segmentation given as input is perturbed by random morphological operations and removal of connected components, so that the network does not simply copy it (Isensee et al., 2018; the same transforms are in 2.8.1).

The authors tested the fixed parameters by bootstrapped rankings on the ten Decathlon datasets, swapping one at a time: cross-entropy or TopK loss alone, residual connections in the encoder, three convolutions per resolution, a lower momentum, the Adam optimizer, batch normalization, and no augmentation. Several variants ranked first on at least one dataset, none improved consistently, and the default configuration ranked first when the rankings were aggregated over the ten datasets (Isensee et al., arXiv v2, 2020).

Inference

The input is a case in the training format, one file per channel, and the output is a label map on the original grid. Images are cropped, resampled and normalized as in training and predicted with a sliding window of the training patch size, adjacent windows overlapping by half a patch. Because accuracy falls towards the window border, predictions are aggregated with a Gaussian importance weight that favours the window centre; in 2.8.1 its standard deviation is one eighth of the patch size along each axis. Test-time augmentation mirrors each window along all axes (Isensee et al., arXiv v2, 2020). The five models from cross-validation are used as an ensemble by default in 2.8.1, and when the selected candidate is a pair of configurations, both are run and their softmax outputs averaged. The network outputs are resampled back to the original spacing with linear interpolation (nearest-neighbour along the coarse axis of anisotropic data) before each voxel is assigned its most probable class, and the post-processing chosen by cross-validation is applied last. With mirroring along three axes and half-patch overlap, a voxel in the interior of a 3D volume receives up to 64 predictions per model (Isensee et al., 2018).

Performance

Medical Segmentation Decathlon (2018). The challenge asked for one method that would run unchanged on ten tasks in CT and MRI: seven development tasks and three “mystery” tasks revealed only after the methods were frozen, scored on held-out test sets by Dice and normalized surface distance and ranked across tasks (Antonelli et al., 2022). nnU-Net ranked first in both phases, with a median Dice of 0.79 (interquartile range 0.61 to 0.88) over the development phase and 0.71 (0.58 to 0.82) over the mystery phase; the organizers found it at rank 1 for nearly every task and bootstrap sample. In the two years after the challenge, sometimes with minor modifications, it won 33 of 53 further segmentation tasks it entered, with a median rank of 1, including the BraTS brain-tumour challenge of 2020 (Antonelli et al., 2022). Medical Image Segmentation describes the Decathlon’s protocol.

arXiv v2 (2020). The authors applied nnU-Net, trained from scratch on each challenge’s own data, to 10 challenges with 19 datasets and 49 segmentation tasks in CT, MRI and electron microscopy. The rules had been developed on the ten Decathlon training sets, and the remaining datasets served as independent tests. Compared with the challenge leaderboards as of 12 December 2019, it set a new state of the art in 29 of the 49 tasks and was otherwise on par with or close to the top entries; on the KiTS 2019 open leaderboard it set a new state of the art with a plain 3D U-Net (Isensee et al., arXiv v2, 2020). The journal version’s abstract reports that nnU-Net surpassed most existing approaches on 23 public datasets (Isensee et al., 2021); its tables could not be read for this article, so the counts above are those of arXiv v2.

nnU-Net Revisited (2024). In a benchmark by the nnU-Net developers, the original configuration and three new presets with residual encoders were compared with recent CNN, Transformer and Mamba-based networks and with the MONAI Auto3DSeg framework on six public datasets (BTCV, ACDC, LiTS, BraTS 2021, KiTS 2023 and AMOS 2022), all trained from scratch (except Auto3DSeg’s SwinUNETR, left at its default of loading pretrained weights) on one 40 GB A100 GPU and evaluated by five-fold cross-validation with mean Dice as the primary metric (Isensee et al., 2024). CNN-based U-Nets in the nnU-Net framework performed best overall; MedNeXt led on five of the six datasets, at a much higher training cost; none of the three Auto3DSeg models reached the original nnU-Net on any dataset. The text states that the Transformer-based models failed to match the original nnU-Net; in the results table they score below it on five datasets, but on ACDC nnFormer (92.40%) and SwinUNETR V2 (92.01%) score above it (91.54%). Larger models helped most on the harder datasets: on KiTS the Dice rose from 86.04% for the original configuration (7.7 GB of GPU memory, 9 GPU hours listed as runtime) to 88.17% for the ResEnc L preset (22.7 GB, 35 hours) and 88.67% for ResEnc XL (36.6 GB, 66 hours). The authors also rated how well each dataset separates methods, recommending KiTS, AMOS and ACDC for benchmarking and finding BTCV, BraTS and LiTS less suitable. These are cross-validation results on public training sets in the authors’ own framework, not a prospective or external evaluation.

Strengths

  • No manual tuning. One command sequence produces a complete pipeline for a new dataset, so a new method can be compared with the configuration a dataset receives by default rather than with a baseline tuned by its own authors.
  • Explicit, inspectable rules. The decisions are written down in the papers and stored per dataset in a JSON plans file, so they can be read, compared and overridden; planning needs no GPU.
  • Spacing-aware design. Target spacing, split resampling, pseudo-2D kernels, per-axis pooling and the 2D configuration all respond to anisotropic voxel spacing.

Limitations

  • Semantic segmentation only. nnU-Net labels voxels; separating touching instances, as in cell segmentation, or detecting objects needs other methods. The 2.8.1 documentation describes it as built for supervised semantic segmentation with labelled training data.
  • Rules from ten datasets. The heuristics were developed on the Decathlon’s ten training sets. The authors note that nnU-Net was developed with the Dice coefficient as target and that dataset properties not yet considered may lead to suboptimal pipelines; on the CREMI synaptic-cleft task in electron microscopy it ranked 6th of 39, and they expected that a task-specific loss and preprocessing would be needed to do better (Isensee et al., arXiv v2, 2020).
  • Compute. Training every configuration for 1000 epochs on five folds, and possibly a cascade, multiplies the cost of a single model (see the run times above).
  • Memory target. The default planner sizes patches for 8 GB of GPU memory, and nnU-Net Revisited argues that a large new model should not be compared with this small original configuration (Isensee et al., 2024).

Historical Importance

Before nnU-Net, according to its authors, papers on medical image segmentation often proposed an architectural change to the U-Net, evaluated it on no more than two datasets, and compared it with baselines that are hard to tune for a new dataset (Isensee et al., arXiv v2, 2020). After nnU-Net won the Decathlon with plain U-Nets, the organizers reported that it became a common starting point for other teams: eight nnU-Net derivatives ranked in the top 15 of the KiTS 2019 challenge, and nine of the top ten entries in the COVID-19 Lung CT Lesion Segmentation Challenge 2020 built on it (Antonelli et al., 2022). On the Decathlon’s open leaderboard nnU-Net held first place from 6 December 2019 for almost a year, until 30 October 2020, and the organizers named neural architecture search, which optimizes the network per task at a higher computational cost, as the other trend among top entries (Antonelli et al., 2022). nnU-Net Revisited took the methodological message further, attributing many reported gains of newer architectures to inadequate baselines, insufficient datasets and neglected computational resources (Isensee et al., 2024).

Variants

  • 2018, challenge entry. The arXiv preprint of 27 September 2018 describes three U-Nets (2D, 3D and the cascade) trained with the Adam optimizer at a learning rate of 3×10−43 \times 10^{-4}, ensembles of any two of the three and five-fold cross-validation (Isensee et al., 2018). The Decathlon paper describes the entry as trained with Adam and ensembling “four different architectures” (Antonelli et al., 2022), whereas arXiv v2 describes SGD with Nesterov momentum and three configurations. The 2018 preprint and arXiv v1 of 17 April 2019 both use Adam, and SGD with the poly schedule first appears in arXiv v2 of 2 April 2020. The Decathlon paper cites the 2021 journal paper for the method.
  • 2019–2021, nnU-Net v1. Packages named nnunet appeared on the Python Package Index from 28 August 2019; version 1.0 was uploaded on 31 March 2020 and 1.7.0 on 1 September 2021. The journal paper appeared online on 7 December 2020 in Nature Methods (volume 18, February 2021).
  • March 2023, nnU-Net v2. Version 2.0 (17 March 2023) is a rewrite that, according to its release notes, gives the same segmentation performance with better usability and extensibility: plans in JSON with named configurations that can inherit from each other and be chained into custom cascades, input formats beyond NIfTI through reader-writer classes, region-based training for hierarchical labels such as BraTS’s tumour regions, a single trainer class, and support for CPUs and Apple MPS devices besides CUDA GPUs. Datasets can be converted from v1, trained models cannot; v1 remains available (last version 1.7.1, uploaded to the package index on 16 March 2023).
  • September 2023, v2.2. The inference code was reworked (release notes).
  • April 2024, residual encoder presets. Version 2.4 (uploaded to the package index on 18 April 2024) added the ResEnc M, L and XL presets, announced with the GitHub release of 2.4.1 (21 April 2024) titled “Residual Encoder UNets released!”. The presets use a U-Net with residual blocks in the encoder, a network the repository has supported since 2019 (Isensee et al., 2024). In 2.8.1 their planners target 8, 24 and 40 GB of GPU memory and remove the 5% batch cap, the documentation recommends ResEnc L as the new default, and the default planner prints a notice pointing to the presets, though it remains the default of the commands.
  • 2025–2026. Release 2.8.1 (1 July 2026) is the current version as of October 2026; its documentation also describes Primus, a Transformer-centric architecture implemented inside the framework. Between the v2.0 and v2.8.1 tags the default planner kept the target-spacing rule, the starting patch, the cascade search and the 5% batch cap; later releases corrected the kernel-size test in the topology code, adjusted the memory test for the reference batch size and added the check that drops a low-resolution configuration.

Because nnU-Net separates planning, preprocessing, training and inference, many methods are built inside it by replacing the network or the trainer; nnU-Net Revisited lists MedNeXt, STU-Net, nnFormer, CoTr and U-Mamba as originally implemented in the framework (Isensee et al., 2024).

Implementations

The official implementation is the MIC-DKFZ/nnUNet repository, under the Apache 2.0 licence, installed as the nnunetv2 package; v1 is kept on a separate branch. It is written in PyTorch and uses the batchgenerators libraries for augmentation and dynamic_network_architectures for the networks. Datasets follow the fixed layout used in the example. The planner, preprocessor, trainer and network classes can be subclassed, and the plans file can be edited, or a configuration added that inherits from a default one, to change patch size, batch size or spacing for an experiment; the documentation advises a new plans identifier when planning with changed settings, so that the existing plans are not overwritten.

Related

  • Dice Coefficient

    Twice the overlap of a predicted and a ground-truth mask divided by their total size, equal to the F1 score over pixels; the standard overlap score of medical image segmentation and, in soft form, a training loss.

  • Computed Tomography (CT)

    An X-ray imaging method that measures attenuation along many lines through the body and reconstructs cross-sectional images from them, with each voxel calibrated in Hounsfield units.

  • Magnetic Resonance Imaging (MRI)

    A medical imaging method that uses a strong magnet, magnetic field gradients and radio waves to sample the spatial Fourier transform (k-space) of the body's hydrogen magnetization, producing cross-sectional images whose contrast is set by tissue relaxation times and the scanner's sequence parameters.

  • Cross-Validation

    How k-fold cross-validation and its variants (leave-one-out, repeated, stratified, grouped, time-ordered and nested) reuse a small labelled image set for both training and evaluation, what the estimate measures, how noisy it is, and why tuning and reporting on the same folds is optimistic.

  • Data Augmentation

    Training a network on randomly transformed copies of its training images, such as crops, flips, colour changes, erasing and mixing, so that it learns invariances the small training set cannot show, provided each transformation keeps the label correct.

  • Normalization Layers

    Layers that standardize a network's activations with a mean and variance computed over a chosen set of tensor axes, then apply a learned scale and shift; batch, layer, instance, group and RMS normalization differ only in those axes, and weight normalization rescales the weights instead.

References

  1. Isensee, F., Jaeger, P. F., Kohl, S. A. A., Petersen, J. & Maier-Hein, K. H. (2021). nnU-Net: A Self-Configuring Method for Deep Learning-Based Biomedical Image Segmentation. Nature Methods, 18(2), 203–211.
  2. Isensee, F., Jaeger, P. F., Kohl, S. A. A., Petersen, J. & Maier-Hein, K. H. (2020). Automated Design of Deep Learning Methods for Biomedical Image Segmentation. arXiv:1904.08128v2.
  3. Isensee, F., Petersen, J., Kohl, S. A. A., Jäger, P. F. & Maier-Hein, K. H. (2019). nnU-Net: Breaking the Spell on Successful Medical Image Segmentation. arXiv:1904.08128v1.
  4. Isensee, F., Petersen, J., Klein, A., Zimmerer, D., Jaeger, P. F., Kohl, S., Wasserthal, J., Köhler, G., Norajitra, T., Wirkert, S. & Maier-Hein, K. H. (2018). nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation. arXiv:1809.10486.
  5. Isensee, F., Wald, T., Ulrich, C., Baumgartner, M., Roy, S., Maier-Hein, K. & Jäger, P. F. (2024). nnU-Net Revisited: A Call for Rigorous Validation in 3D Medical Image Segmentation. Medical Image Computing and Computer-Assisted Intervention (MICCAI), Lecture Notes in Computer Science, 488–498.
  6. Antonelli, M., Reinke, A., Bakas, S., Farahani, K., Kopp-Schneider, A., Landman, B. A., Litjens, G., Menze, B., Ronneberger, O., Summers, R. M., et al. (2022). The Medical Segmentation Decathlon. Nature Communications, 13, 4128.
  7. MIC-DKFZ. nnU-Net source code and documentation, release 2.8.1 (tag v2.8.1, 1 July 2026): nnunetv2/experiment_planning/, nnunetv2/preprocessing/, nnunetv2/training/nnUNetTrainer/nnUNetTrainer.py, nnunetv2/inference/, nnunetv2/postprocessing/, nnunetv2/evaluation/find_best_configuration.py and documentation/ (accessed October 2026).
  8. MIC-DKFZ. nnU-Net release notes (GitHub releases v2.0 of 17 March 2023, v2.2 of 19 September 2023 and v2.4.1 of 21 April 2024) and the release history of the nnunet and nnunetv2 packages on the Python Package Index (accessed October 2026).