RibaDiba/tumor-segmentation

Detectron2 instance segmentation pipeline for subcutaneous mouse tumors, RGB, depth map, and RGD channel-fusion model variants trained on structured-light scanner data.

0

stars

247

commits

Jupyter Notebook

primary language

Jul 22, 2026

updated

README

Mouse Tumor Segmentation with Detectron2

Python PyTorch Detectron2 OpenCV Platform HPC

This repository contains the full pipeline for automated instance segmentation of subcutaneous mouse tumors using Detectron2 (Mask R-CNN). Data is sourced from Biopticon's TI-2 structured-light scanner. Three model variants are trained and evaluated: RGB, Depth, and RGD (Red-Green-Depth).

The RGD model replaces the blue channel of the texture image with a normalized depth map derived from the scanner's point cloud, producing the strongest overall segmentation results.


Repository Structure

PathDescription
configs/base.yamlShared Detectron2 hyperparameters (LR schedule, ROI heads, dataloader)
configs/{rgb,depth,rgd}.yamlPer-modality overrides, inherit from base.yaml via _BASE_
requirements.txtPython dependencies
data/huggingface-repo/useable_data/Cleaned raw data (scanner triplets)
data/processed_data/{rgb,depth,rgd}/Preprocessed, split, and cached images + COCO JSON
data/testing/pytest suite validating data integrity before training
src/util/preprocessing/PreprocessingFunctions/functions.pyAggregates all preprocessing functions (_io, _masks, _depth, _transforms, _splitting, _subset)
src/util/preprocessing/TumorDataset/tumor_dataset.pyDataset class — wraps preprocessing and Detectron2 dataset registration
src/util/preprocessing/process_coco_json.pyConverts binary masks to COCO-format JSON annotations
src/pipeline/trainer/trainer.pyCustom Trainer subclass with hooks injected
src/pipeline/training_scripts/train.pyMain training entry point
src/pipeline/training_scripts/train.shShell wrapper: runs pytest suite then train.py
src/pipeline/training_scripts/slurm/sbatch_scripts/SLURM job scripts for the Princeton Della cluster
src/pipeline/hooks/loss_hook.pyTrain + validation loss curves
src/pipeline/hooks/ap_hook.pyAP / AP50 / AP75 tracked over training (validation set)
src/pipeline/hooks/iou_hook.pyPer-image IoU counts tracked over training (validation set)
src/pipeline/hooks/iou_evaluator.pyCustom DatasetEvaluator for per-image IoU
src/pipeline/hooks/ap_final_hook.pyFinal AP + IoU results on the test set after training
src/pipeline/hooks/outputs_hook.pySaves all model predictions as JSON (RLE-encoded masks)
src/pipeline/evaluation/cross_comparison/Cross-model failure analysis (RGB vs. Depth vs. RGD)

Installation & Setup

git clone https://github.com/your-repository.git
cd tumor-segmentation
pip install -e .            # installs deps + makes `Detectron2` and `preprocessing` importable
pip install -e ".[dev]"     # plus pytest / black / ipykernel

The editable install is required: it adds src/pipeline/ and src/util/preprocessing/ to your import path so the training scripts run from anywhere without sys.path hacks.

Detectron2 (and SAM, if needed) are not on PyPI and must be installed from source separately:

pip install git+https://github.com/facebookresearch/detectron2.git
pip install git+https://github.com/facebookresearch/segment-anything.git

After pip install -e ., the training entry point is available as a console script:

tumor-segmentation-train --model-name <name> --model-type <group> --modality rgb

…which is equivalent to python3 src/pipeline/training_scripts/train.py ….

Training was run on the Princeton Della cluster using NVIDIA A100 GPUs. The SLURM scripts under src/pipeline/training_scripts/slurm/sbatch_scripts/ are configured for that environment — adjust --account and --partition as needed.


Running the Pipeline

The pipeline has a few prerequisites that must be satisfied before training. In particular, the processed_data/ directory — where cached, split data lives — is produced by the first training run with --split-cache true.

Initial Setup

The dataset is hosted as a HuggingFace dataset repository and is included here as a git submodule. On initial clone of this repository it will not be populated. The guide below sets up the HuggingFace submodule.

Note on data access. The dataset is currently gated behind HuggingFace authentication. If you do not have access, contact the maintainers. A public release with an open license is planned — see the Data section.

1. Install git lfs

git lfs install

2. Authenticate with HuggingFace

Generate a private access token from your HuggingFace account (instructions), install the CLI, and log in:

pip install -U "huggingface_hub[cli]"
huggingface-cli login

3. Initialize the submodule

git submodule update --init --recursive

Launch Training

The recommended entry point is the train.sh wrapper, which runs the pytest data-validation suite and then calls train.py:

cd src/pipeline/training_scripts

./train.sh \
  --name <model-name> \
  --model_type <output-subdir> \
  --iter <num-iterations> \
  --modality rgb \      # one of: rgb | depth | rgd
  --split-cache         # pass on first run to preprocess and cache data

train.sh arguments

ArgumentDescription
--nameModel name, used for output directories
--model_typeSubdirectory label for saved outputs (e.g. rgb, depth, rgd)
--iterNumber of training iterations
--modalityImage modality to train on (rgb, depth, or rgd) — required
--split-cachePreprocess, split (70/10/20), and cache data before training (first run only)
--augmentationsEnable augmentation pipeline
--flip_probProbability of horizontal flip
--rotate-probProbability of rotation
--rotate-degreesMaximum +/- rotation angle in degrees
--targetTarget image count post-augmentation
--root-pathPath prefix prepended to train.py and the pytest suite (default: ./)
--skip-testsSkip the pytest validation suite

All boolean flags are bare switches — pass --split-cache to enable, omit it to disable. (The legacy --rgb true / --depth true / --rgd true triplet has been replaced by a single --modality choice.)

train.py CLI (direct invocation)

train.sh is a thin wrapper that translates its named flags into the keyword arguments expected by train.py. If you want to call the Python entry point directly, the signature is:

python3 train.py --model-name <name> --model-type <group> --modality {rgb,depth,rgd} [options] [-- KEY VALUE ...]
OptionDescription
--model-nameRequired. Written into cfg.MODELNAME and used in output paths.
--model-typeRequired. Experiment group / output subdirectory (cfg.MODELTYPE).
--modalityRequired. One of rgb, depth, rgd.
--config-dirDirectory containing base.yaml and <modality>.yaml. Defaults to configs/.
--split-cacheRun preprocess → split → cache before training
--augmentationsEnable augmentations during preprocessing
--flip_prob, --rotate_prob, --rotate_degrees, --targetAugmentation parameters

Any positional arguments after -- are passed straight to cfg.merge_from_list, so e.g. -- SOLVER.MAX_ITER 10000 SOLVER.BASE_LR 0.0001 overrides those fields. CLI overrides win over the YAML hierarchy.

Configuration

Configs are layered (later wins):

  1. Detectron2 model zoo defaults — Mask R-CNN R-101 FPN 3x
  2. configs/base.yaml — project-wide overrides (LR schedule, ROI heads, dataloader)
  3. configs/{rgb,depth,rgd}.yaml — per-modality overrides, chain via _BASE_: base.yaml
  4. CLI: ./train.sh ... -- SOLVER.BASE_LR 0.001

Every run snapshots its fully merged config to models/<model_type>/<model_name>/run_*/config_used.yaml — so a reviewer reading a checkpoint never has to guess what hyperparameters produced it.

Output layout

models/<model_type>/<model_name>/
  run_YYYYMMDD-HHMM/
    config_used.yaml         # fully merged config (every key)
    model_final.pth          # weights
    metrics.json             # Detectron2 default
    events.out.tfevents.*    # TensorBoard scalars
  latest -> run_YYYYMMDD-HHMM/   # symlink to the most recent run

src/pipeline/slurm_output/<model_type>/<model_name>/run_YYYYMMDD-HHMM/
  loss_plots/  AP_Fig/  IoU_fig/  outputs/  IoU_AP_Final/

Each invocation creates a fresh run_<timestamp>/ directory, so reruns never silently overwrite earlier weights.

Experiment tracking

TensorBoard is wired in by default — total_loss, loss_mask, AP, AP50, AP75, and the IoU buckets are written by Detectron2's event storage:

tensorboard --logdir models/

Weights & Biases is opt-in. Set WANDB_PROJECT before launching and a WandbWriter is appended to the writer list automatically:

pip install wandb && wandb login
WANDB_PROJECT=tumor-seg ./train.sh --name foo --model_type rgb --iter 5000 --modality rgb

Reproducing the Paper

Status: results in this README are produced by the commands below. Update the seed, model checkpoints, and runtime numbers if you change the recipe.

The published numbers were produced with:

ArtifactCommandNotes
Table 1 (RGB / Depth / RGD AP, AP50, AP75, IoU)./train.sh --name rgb_final --model_type rgb --iter <N> --modality rgb --split-cache (and analogously --modality depth / --modality rgd)Final metrics are logged by ap_final_hook under src/pipeline/slurm_output/<model_type>/<model_name>/run_*/IoU_AP_Final/.
Figure 3 (training curves)Loss / AP / IoU curves are written by LossHook, APHook, IoUHook during the same runs above.Plots are produced by the notebooks under src/util/plotting/ (or equivalent) — see commit history (ef7bbf7, de2dc51) for the most recent plot recipe.
Cross-model failure analysissrc/pipeline/evaluation/cross_comparison/Run after all three models are trained.

Compute. All training runs were performed on a single NVIDIA A100 (40 GB) on the Princeton Della cluster.

Seed. Seeds are currently inherited from Detectron2's defaults — exact reproduction of paper numbers requires fixing the seed in cfg before broad release (tracked as TODO).

Expected runtime. TBD — fill in once a clean run has been timed end-to-end.


Results

Numbers below are placeholders. Replace with the final published values and link to the paper / preprint once available.

ModelAPAP50AP75Mean per-image IoU
RGB
Depth
RGD

Paper / preprint: TBD.


Data

The dataset is hosted on HuggingFace at data/huggingface-repo/ (added as a git submodule). See data/README.md for the per-directory breakdown.

FieldValue
SubjectsMice (subcutaneous tumor model)
Acquisition deviceBiopticon TI-2 structured-light scanner (RGB texture + depth from point cloud)
ModalitiesRGB, depth, RGD (red+green from texture, blue replaced by normalized depth)
Splits70 / 10 / 20 train / val / test, produced by Dataset.split_train_val_test
Source datasetsMC_Data (600 pairs, point-cloud .bin files missing for some pairs and are excluded), Invotive Data (35 pairs), usable_data (the merged set actually used for training)
Ethics / IACUCTBD — add IACUC protocol number and approving institution.
LicenseTBD — confirm before public release.
AccessCurrently gated by HuggingFace authentication.

Known Issues

  • correct_binary_masks() uses the wrong OpenCV color-conversion flag. Location: src/util/preprocessing/PreprocessingFunctions/_masks.py:87. The call passes cv2.COLOR_BAYER_BG2GRAY where cv2.COLOR_BGR2GRAY is intended. This treats the input as a Bayer-pattern raw image rather than a BGR image, so the resulting grayscale (and the binary mask derived from it) is incorrect.
    • Impact on published results: the function is invoked from src/util/preprocessing/TumorDataset/_preprocessing.py (_preprocessing.py:46, :111, :122, :135) and runs on every preprocessing pass. All currently published numbers were produced with this bug present.
    • Fix: swap the flag to cv2.COLOR_BGR2GRAY and re-run --split-cache true to regenerate the cached splits before retraining.

Contributors

RibaDiba

237 commits

riyajain2025

10 commits

RibaDiba/tumor-segmentation

Detectron2 instance segmentation pipeline for subcutaneous mouse tumors, RGB, depth map, and RGD channel-fusion model variants trained on structured-light scanner data.

0

stars

247

commits

Jupyter Notebook

primary language

Jul 22, 2026

updated

README

Mouse Tumor Segmentation with Detectron2

Python PyTorch Detectron2 OpenCV Platform HPC

This repository contains the full pipeline for automated instance segmentation of subcutaneous mouse tumors using Detectron2 (Mask R-CNN). Data is sourced from Biopticon's TI-2 structured-light scanner. Three model variants are trained and evaluated: RGB, Depth, and RGD (Red-Green-Depth).

The RGD model replaces the blue channel of the texture image with a normalized depth map derived from the scanner's point cloud, producing the strongest overall segmentation results.


Repository Structure

PathDescription
configs/base.yamlShared Detectron2 hyperparameters (LR schedule, ROI heads, dataloader)
configs/{rgb,depth,rgd}.yamlPer-modality overrides, inherit from base.yaml via _BASE_
requirements.txtPython dependencies
data/huggingface-repo/useable_data/Cleaned raw data (scanner triplets)
data/processed_data/{rgb,depth,rgd}/Preprocessed, split, and cached images + COCO JSON
data/testing/pytest suite validating data integrity before training
src/util/preprocessing/PreprocessingFunctions/functions.pyAggregates all preprocessing functions (_io, _masks, _depth, _transforms, _splitting, _subset)
src/util/preprocessing/TumorDataset/tumor_dataset.pyDataset class — wraps preprocessing and Detectron2 dataset registration
src/util/preprocessing/process_coco_json.pyConverts binary masks to COCO-format JSON annotations
src/pipeline/trainer/trainer.pyCustom Trainer subclass with hooks injected
src/pipeline/training_scripts/train.pyMain training entry point
src/pipeline/training_scripts/train.shShell wrapper: runs pytest suite then train.py
src/pipeline/training_scripts/slurm/sbatch_scripts/SLURM job scripts for the Princeton Della cluster
src/pipeline/hooks/loss_hook.pyTrain + validation loss curves
src/pipeline/hooks/ap_hook.pyAP / AP50 / AP75 tracked over training (validation set)
src/pipeline/hooks/iou_hook.pyPer-image IoU counts tracked over training (validation set)
src/pipeline/hooks/iou_evaluator.pyCustom DatasetEvaluator for per-image IoU
src/pipeline/hooks/ap_final_hook.pyFinal AP + IoU results on the test set after training
src/pipeline/hooks/outputs_hook.pySaves all model predictions as JSON (RLE-encoded masks)
src/pipeline/evaluation/cross_comparison/Cross-model failure analysis (RGB vs. Depth vs. RGD)

Installation & Setup

git clone https://github.com/your-repository.git
cd tumor-segmentation
pip install -e .            # installs deps + makes `Detectron2` and `preprocessing` importable
pip install -e ".[dev]"     # plus pytest / black / ipykernel

The editable install is required: it adds src/pipeline/ and src/util/preprocessing/ to your import path so the training scripts run from anywhere without sys.path hacks.

Detectron2 (and SAM, if needed) are not on PyPI and must be installed from source separately:

pip install git+https://github.com/facebookresearch/detectron2.git
pip install git+https://github.com/facebookresearch/segment-anything.git

After pip install -e ., the training entry point is available as a console script:

tumor-segmentation-train --model-name <name> --model-type <group> --modality rgb

…which is equivalent to python3 src/pipeline/training_scripts/train.py ….

Training was run on the Princeton Della cluster using NVIDIA A100 GPUs. The SLURM scripts under src/pipeline/training_scripts/slurm/sbatch_scripts/ are configured for that environment — adjust --account and --partition as needed.


Running the Pipeline

The pipeline has a few prerequisites that must be satisfied before training. In particular, the processed_data/ directory — where cached, split data lives — is produced by the first training run with --split-cache true.

Initial Setup

The dataset is hosted as a HuggingFace dataset repository and is included here as a git submodule. On initial clone of this repository it will not be populated. The guide below sets up the HuggingFace submodule.

Note on data access. The dataset is currently gated behind HuggingFace authentication. If you do not have access, contact the maintainers. A public release with an open license is planned — see the Data section.

1. Install git lfs

git lfs install

2. Authenticate with HuggingFace

Generate a private access token from your HuggingFace account (instructions), install the CLI, and log in:

pip install -U "huggingface_hub[cli]"
huggingface-cli login

3. Initialize the submodule

git submodule update --init --recursive

Launch Training

The recommended entry point is the train.sh wrapper, which runs the pytest data-validation suite and then calls train.py:

cd src/pipeline/training_scripts

./train.sh \
  --name <model-name> \
  --model_type <output-subdir> \
  --iter <num-iterations> \
  --modality rgb \      # one of: rgb | depth | rgd
  --split-cache         # pass on first run to preprocess and cache data

train.sh arguments

ArgumentDescription
--nameModel name, used for output directories
--model_typeSubdirectory label for saved outputs (e.g. rgb, depth, rgd)
--iterNumber of training iterations
--modalityImage modality to train on (rgb, depth, or rgd) — required
--split-cachePreprocess, split (70/10/20), and cache data before training (first run only)
--augmentationsEnable augmentation pipeline
--flip_probProbability of horizontal flip
--rotate-probProbability of rotation
--rotate-degreesMaximum +/- rotation angle in degrees
--targetTarget image count post-augmentation
--root-pathPath prefix prepended to train.py and the pytest suite (default: ./)
--skip-testsSkip the pytest validation suite

All boolean flags are bare switches — pass --split-cache to enable, omit it to disable. (The legacy --rgb true / --depth true / --rgd true triplet has been replaced by a single --modality choice.)

train.py CLI (direct invocation)

train.sh is a thin wrapper that translates its named flags into the keyword arguments expected by train.py. If you want to call the Python entry point directly, the signature is:

python3 train.py --model-name <name> --model-type <group> --modality {rgb,depth,rgd} [options] [-- KEY VALUE ...]
OptionDescription
--model-nameRequired. Written into cfg.MODELNAME and used in output paths.
--model-typeRequired. Experiment group / output subdirectory (cfg.MODELTYPE).
--modalityRequired. One of rgb, depth, rgd.
--config-dirDirectory containing base.yaml and <modality>.yaml. Defaults to configs/.
--split-cacheRun preprocess → split → cache before training
--augmentationsEnable augmentations during preprocessing
--flip_prob, --rotate_prob, --rotate_degrees, --targetAugmentation parameters

Any positional arguments after -- are passed straight to cfg.merge_from_list, so e.g. -- SOLVER.MAX_ITER 10000 SOLVER.BASE_LR 0.0001 overrides those fields. CLI overrides win over the YAML hierarchy.

Configuration

Configs are layered (later wins):

  1. Detectron2 model zoo defaults — Mask R-CNN R-101 FPN 3x
  2. configs/base.yaml — project-wide overrides (LR schedule, ROI heads, dataloader)
  3. configs/{rgb,depth,rgd}.yaml — per-modality overrides, chain via _BASE_: base.yaml
  4. CLI: ./train.sh ... -- SOLVER.BASE_LR 0.001

Every run snapshots its fully merged config to models/<model_type>/<model_name>/run_*/config_used.yaml — so a reviewer reading a checkpoint never has to guess what hyperparameters produced it.

Output layout

models/<model_type>/<model_name>/
  run_YYYYMMDD-HHMM/
    config_used.yaml         # fully merged config (every key)
    model_final.pth          # weights
    metrics.json             # Detectron2 default
    events.out.tfevents.*    # TensorBoard scalars
  latest -> run_YYYYMMDD-HHMM/   # symlink to the most recent run

src/pipeline/slurm_output/<model_type>/<model_name>/run_YYYYMMDD-HHMM/
  loss_plots/  AP_Fig/  IoU_fig/  outputs/  IoU_AP_Final/

Each invocation creates a fresh run_<timestamp>/ directory, so reruns never silently overwrite earlier weights.

Experiment tracking

TensorBoard is wired in by default — total_loss, loss_mask, AP, AP50, AP75, and the IoU buckets are written by Detectron2's event storage:

tensorboard --logdir models/

Weights & Biases is opt-in. Set WANDB_PROJECT before launching and a WandbWriter is appended to the writer list automatically:

pip install wandb && wandb login
WANDB_PROJECT=tumor-seg ./train.sh --name foo --model_type rgb --iter 5000 --modality rgb

Reproducing the Paper

Status: results in this README are produced by the commands below. Update the seed, model checkpoints, and runtime numbers if you change the recipe.

The published numbers were produced with:

ArtifactCommandNotes
Table 1 (RGB / Depth / RGD AP, AP50, AP75, IoU)./train.sh --name rgb_final --model_type rgb --iter <N> --modality rgb --split-cache (and analogously --modality depth / --modality rgd)Final metrics are logged by ap_final_hook under src/pipeline/slurm_output/<model_type>/<model_name>/run_*/IoU_AP_Final/.
Figure 3 (training curves)Loss / AP / IoU curves are written by LossHook, APHook, IoUHook during the same runs above.Plots are produced by the notebooks under src/util/plotting/ (or equivalent) — see commit history (ef7bbf7, de2dc51) for the most recent plot recipe.
Cross-model failure analysissrc/pipeline/evaluation/cross_comparison/Run after all three models are trained.

Compute. All training runs were performed on a single NVIDIA A100 (40 GB) on the Princeton Della cluster.

Seed. Seeds are currently inherited from Detectron2's defaults — exact reproduction of paper numbers requires fixing the seed in cfg before broad release (tracked as TODO).

Expected runtime. TBD — fill in once a clean run has been timed end-to-end.


Results

Numbers below are placeholders. Replace with the final published values and link to the paper / preprint once available.

ModelAPAP50AP75Mean per-image IoU
RGB
Depth
RGD

Paper / preprint: TBD.


Data

The dataset is hosted on HuggingFace at data/huggingface-repo/ (added as a git submodule). See data/README.md for the per-directory breakdown.

FieldValue
SubjectsMice (subcutaneous tumor model)
Acquisition deviceBiopticon TI-2 structured-light scanner (RGB texture + depth from point cloud)
ModalitiesRGB, depth, RGD (red+green from texture, blue replaced by normalized depth)
Splits70 / 10 / 20 train / val / test, produced by Dataset.split_train_val_test
Source datasetsMC_Data (600 pairs, point-cloud .bin files missing for some pairs and are excluded), Invotive Data (35 pairs), usable_data (the merged set actually used for training)
Ethics / IACUCTBD — add IACUC protocol number and approving institution.
LicenseTBD — confirm before public release.
AccessCurrently gated by HuggingFace authentication.

Known Issues

  • correct_binary_masks() uses the wrong OpenCV color-conversion flag. Location: src/util/preprocessing/PreprocessingFunctions/_masks.py:87. The call passes cv2.COLOR_BAYER_BG2GRAY where cv2.COLOR_BGR2GRAY is intended. This treats the input as a Bayer-pattern raw image rather than a BGR image, so the resulting grayscale (and the binary mask derived from it) is incorrect.
    • Impact on published results: the function is invoked from src/util/preprocessing/TumorDataset/_preprocessing.py (_preprocessing.py:46, :111, :122, :135) and runs on every preprocessing pass. All currently published numbers were produced with this bug present.
    • Fix: swap the flag to cv2.COLOR_BGR2GRAY and re-run --split-cache true to regenerate the cached splits before retraining.

Contributors

RibaDiba

237 commits

riyajain2025

10 commits

Languages

Jupyter Notebook

85.1%

Python

14.3%