Getting Started
Prerequisites, environment setup, the one external dependency, the expected data layout, and the commands for training, inference, scoring and the nnU-Net baseline.
1. Prerequisites
| Requirement | Notes |
|---|---|
| Python 3.11+ | The project targets 3.11 or newer. |
uv |
Used for environment creation and dependency resolution against the committed lockfile. |
| NVIDIA GPU with CUDA | Training and inference both require a GPU. Multi-GPU is supported and is the default training path. |
| Fast local storage | Converted volumes, checkpoints and prediction volumes are all large, and none of them belong inside the repository. |
| Competition data | CT volumes and labels, converted to the array layout the dataset expects. |
| The external metrics package | See the callout below — required for any scoring pass. |
2. Install
git clone <repository>
cd vesuvius
uv sync
uv sync creates the virtual environment and installs exactly the versions recorded in
the lockfile. Use it in preference to a bare pip install: the lockfile is what makes an
environment reproducible across machines.
Install the metrics package separately
The competition metric is supplied as an external, separately versioned package rather than as a
declared dependency of this project, so it is not installed by uv sync. Install it into
the same environment before running anything that imports the metrics module — typically as an
editable install pointing at a local checkout of the metrics implementation. If a scoring run fails
immediately with an unresolved import for the topological metrics package, this is the cause. The
requirement is described in
Dependencies.
3. Environment variables
Runtime paths and tracking settings are supplied through the environment. The conventional pattern
in this repository is to keep them in a .env file at the repository root and export the
whole file before invoking a command, which is exactly what the Makefile does:
set -a && . .env && set +a
| Variable | Purpose | Required |
|---|---|---|
BASE_DIR |
Root directory used to locate the shared configuration files and, from there, the data and output directories. Defaults to the repository root when unset, so it only needs setting if configuration lives elsewhere. | Optional |
NVME_DIR |
Fast-storage root used by the data conversion and synthetic-data generation scripts. | For those scripts |
WANDB_* |
Tracking project, entity, run name, directory and mode. Normally set programmatically from the resolved configuration rather than by hand, but they can be exported to override it. | Optional |
CUDA_VISIBLE_DEVICES |
Restricts which devices a process may use. Essential for the partitioned nnU-Net prediction path, where each worker is pinned to a single GPU. | For multi-GPU work |
NNUNET_* |
The nnU-Net raw, preprocessed and results directories. The nnU-Net driver sets these itself from its own configuration, so they rarely need setting by hand. | Set by the driver |
Note the interaction between the distributed launcher and CUDA_VISIBLE_DEVICES: the
launcher sets a local rank per process, and the code uses that rank to select a device. Setting
CUDA_VISIBLE_DEVICES on top of that renumbers the visible devices, so the two are best
used separately — launcher-driven for training, explicit pinning for the partitioned
prediction path.
4. Data layout
Scans arrive as TIFF and are converted once to NumPy arrays. Training reads the converted form, so the conversion step is a one-time preparation rather than part of the training loop:
<data_dir>/
├── train_images/<case_id>.npy input volumes
└── train_labels/<case_id>.npy label volumes (0 / 1 / 2)
<base_dir>/
├── configs/ shared configuration
└── data/raw/kaggle_converted/ where scoring expects to find labels
The case identifier is the filename stem, and the same identifier appears in prediction filenames and score reports. Keeping that naming convention intact is what makes a case traceable from a metric back to the volume that produced it.
5. Run training
Every run is identified by an approach and an experiment. The multi-GPU entry point is the
Makefile target, which is the most complete example of the expected invocation:
make unetbasic-train
# equivalently, spelled out:
set -a && . .env && set +a
PYTHONPATH=$(pwd)/src uv run torchrun \
--nproc_per_node=2 \
src/approach/unetbasic/train.py \
--experiment exp_v0
Points to be aware of when adapting this:
-
PYTHONPATHmust includesrc/, because the approach packages live undersrc/approach/rather than at the top level. -
--nproc_per_nodeshould match the number of GPUs you want to use; the code derives rank and world size from the launcher’s environment. -
The experiment name selects the YAML under the approach’s
configs/experiments/directory. Switching experiments is switching a name, not editing code. -
For a single-GPU run, invoke
train.pydirectly instead of under the distributed launcher.
A run writes everything into outputs/<approach>/<experiment>/ —
checkpoints, the resolved configuration, and tracking logs. The layout is documented in
Deployment.
6. Run inference
Inference is a separate entry point that loads a checkpoint and writes predictions for a directory of images:
make dynclassreg-infer # single-GPU example, edit CHECKPOINT first
# equivalently:
PYTHONPATH=$(pwd)/src uv run python \
src/approach/unetbasic/inference.py \
--experiment exp_v0 \
--checkpoint <checkpoint_dir> \
--images_dir <input_images_dir> \
--output_dir <output_dir> \
--batch_size 1 \
--num_workers 4
The output directory receives one probability array and one distance array per case, plus the metadata that ties each prediction to its source case. Both arrays are written in half precision to keep whole-volume artifacts a manageable size.
Check the defaults before you rely on them
Several inference arguments have absolute default paths baked in from the machine the pipeline was
developed on. Always pass --checkpoint, --images_dir and
--output_dir explicitly rather than depending on the defaults.
7. Score a prediction
Scoring consumes a directory of predictions and reports the four numbers that matter: SurfaceDice, TopoScore, VoiScore and the composite score. Two entry points exist:
| Entry point | Use it for |
|---|---|
src/approach/unetbasic/metrics/kaggle_metrics.py
|
The scoring path used during development: threshold, apply a post-processing configuration, and average the component metrics over cases. |
exploration/scoring/
|
Comparing post-processing strategies. This is where you sweep approaches rather than accept one, and where new strategies are registered. |
A scoring pass is CPU-bound and parallelises across cases, so it benefits from a large core count. Both entry points accept a sequential mode, which is much easier to debug when a single case produces an unexpected number.
8. Run the nnU-Net baseline
The nnU-Net pipeline is a self-contained driver that can run end to end or stage by stage:
PYTHONPATH=$(pwd)/src uv run python scripts/nnunetbaseline/train_nnunetv2.py
Its stages are dataset preparation, preprocessing, training, prediction and TIFF export. Run the stages individually while iterating: preprocessing is the slowest step and there is rarely a reason to repeat it because a training setting changed.
9. First things to check
| Symptom | Likely cause |
|---|---|
| Import error for the topological metrics package | The external metrics package has not been installed into this environment. |
ModuleNotFoundError for approach.* |
PYTHONPATH does not include src/. |
| Training starts but data is not found | The data directory in the resolved configuration does not match where the converted arrays live. |
| Out-of-memory error on the GPU | Patch size, batch size and gradient accumulation in the experiment configuration. |
| Checkpoints written to an unexpected place | Absolute defaults in the inference or training arguments; pass explicit paths. |
| Scoring reports zeros | No prediction files were found in the directory passed to the scorer, or the patch metadata does not match the predictions. |