Using the Tiled Ensemble Pipeline
The tiled-ensemble pipeline splits each image into overlapping tiles, trains/evaluates a separate model instance per tile position, then merges tile predictions (with optional seam smoothing) back into a full-image anomaly map. Use it for high-resolution images where a single model can't see fine detail at a manageable input size.
Code locations
src/anomalib/pipelines/tiled_ensemble/train_pipeline.py—TrainTiledEnsemble: composes the job graph (per-tile training, per-tile prediction, merge, seam smoothing, statistics) and picksSerialRunnerorParallelRunnerbased on the configured accelerator and available CUDA devices.src/anomalib/pipelines/tiled_ensemble/test_pipeline.py—EvalTiledEnsemble: runs inference/evaluation for an already-trained ensemble.src/anomalib/pipelines/tiled_ensemble/components/— individual job implementations (model training, prediction, merging, smoothing, metrics).src/anomalib/pipelines/tiled_ensemble/components/utils/ensemble_engine.py—TiledEnsembleEngine, anEnginesubclass that customizes per-tile checkpoint/workspace naming.
Running it
python tools/tiled_ensemble/train.py --config tools/tiled_ensemble/ens_config.yaml
python tools/tiled_ensemble/eval.py --config tools/tiled_ensemble/ens_config.yaml \
--root results/Padim/MVTecAD/bottle/v0
train.py runs TrainTiledEnsemble().run() which includes evaluation after training;
eval.py runs EvalTiledEnsemble to re-run evaluation against an existing results directory
(--root) — use it only when you want to evaluate again without retraining.
Config structure
Start from tools/tiled_ensemble/ens_config.yaml and adjust the fields you need:
seed: 42
accelerator: "cuda" # or "cpu"
default_root_dir: "results"
tiling:
image_size: [256, 256] # size the full image is resized to before tiling
tile_size: [128, 128] # size of each tile
stride: 128 # tile stride; stride < tile_size gives overlapping tiles
normalization_stage: image
thresholding_stage: image
data:
class_path: anomalib.data.MVTecAD
init_args:
root: ./datasets/MVTecAD
category: bottle
train_batch_size: 32
eval_batch_size: 32
num_workers: 8
val_split_mode: from_test
test_split_mode: from_dir
SeamSmoothing:
apply: False
sigma: 2
width: 0.1
TrainModels:
model:
class_path: Padim
Key fields:
tiling.tile_size/tiling.stride— the core tiling geometry;stride < tile_sizeproduces overlap thatSeamSmoothingthen blends.data.class_path— any imageanomalib.data.*datamodule that yieldsImageBatch(seeanomalib-training/anomalib-adding-a-datamodule). Video and depth datamodules are not supported — the tiled collater usesImageBatch.collateinternally.TrainModels.model.class_path— the model class trained per tile; must be a standard image model that only requiresbatch.imageas input. Models requiring additional inputs (e.g. CFM which needspoint_cloud/depth_map) are not compatible with the tiled collater. Video models are also not compatible.SeamSmoothing.apply— whenTrue, applies Gaussian blending at tile boundaries. This is most useful when tiles overlap (stride < tile_size), but can also smooth hard boundaries between non-overlapping tiles. SetFalseto skip if seam artifacts are not visible.
For a worked reference invocation with a full config, see
tests/integration/pipelines/test_tiled_ensemble.py.
Gotchas
- The pipeline trains one model instance per tile position, not one shared model — total training
cost scales with the number of tiles, not just image count. Budget accordingly before scaling up
tile_size/stridecombinations. accelerator: cudawith multiple visible GPUs triggersParallelRunner, which trains multiple tile jobs concurrently across devices — setaccelerator: cpu(or restrict visible devices) for deterministic single-process runs while debugging a config.- Eval (
eval.py) needs--rootpointing at the exact output directory produced by the matching training run; it does not re-derive this automatically. data.init_argsmust includeval_split_modeandtest_split_mode— the pipeline reads these directly from the config before datamodule defaults are applied, and will raiseKeyErrorif missing.
Reviewer / self-check
-
tiling.tile_size/stridechosen relative totiling.image_size(stride ≤ tile_size). -
data.class_pathandTrainModels.model.class_pathboth resolve to real, exported classes. -
SeamSmoothing.applyis intentional given whether tiles overlap. - Training run completed and its
results/...path is used correctly aseval.py --root.