--- language: - en tags: - medical-imaging - segmentation - 3d-segmentation - monai - nnunet - ct - cbct - dental - alveolar-canal - toothfairy library_name: monai license: mit --- # 3D Alveolar Canal Segmentation — Multi-Model Benchmark Pretrained weights for six 3D segmentation models trained on the [ToothFairy2 dataset](https://toothfairy2.grand-challenge.org/) for alveolar canal segmentation from CBCT scans. ## Model Performance (Test Set, n=50) | Model | Dice ↑ | IoU ↑ | PPV ↑ | Recall ↑ | HD95 (mm) ↓ | MaxHD (mm) ↓ | |---|---|---|---|---|---|---| | **nnUNetv2** | **0.9163 ± 0.0119** | **0.8458 ± 0.0201** | 0.8898 ± 0.0326 | **0.9472 ± 0.0396** | **1.17 ± 0.31** | **5.87 ± 3.22** | | AttentionUnet | 0.8895 ± 0.0476 | 0.8037 ± 0.0659 | 0.8882 ± 0.0388 | 0.8980 ± 0.0844 | 4.93 ± 13.46 | 10.95 ± 17.03 | | SwinUNETR | 0.8859 ± 0.0495 | 0.7985 ± 0.0745 | **0.9021 ± 0.0329** | 0.8776 ± 0.0949 | 11.99 ± 22.04 | 19.97 ± 27.70 | | SegResNet | 0.8760 ± 0.0613 | 0.7839 ± 0.0843 | 0.8865 ± 0.0383 | 0.8755 ± 0.1057 | 9.71 ± 23.73 | 17.57 ± 27.08 | | 3D UNet | 0.8678 ± 0.0639 | 0.7713 ± 0.0885 | 0.8747 ± 0.0432 | 0.8705 ± 0.1065 | 12.38 ± 23.20 | 20.33 ± 27.67 | | DynUNet | 0.7129 ± 0.0515 | 0.5563 ± 0.0618 | 0.5607 ± 0.0618 | 0.9865 ± 0.0262 | 8.14 ± 8.06 | 21.33 ± 11.52 | All differences between models are statistically significant (Wilcoxon signed-rank, p<0.001) except AttentionUnet vs SwinUNETR (p=0.20, ns). ## Repository Structure ``` abhijithkj3690/alveolar-canal-segmentation/ ├── unet/ │ └── best_model.pth # 3D UNet (MONAI) ├── attention_unet/ │ └── best_model.pth # AttentionUnet (MONAI) ├── dynunet/ │ └── best_model.pth # DynUNet (MONAI) ├── swinunetr/ │ └── best_model.pth # SwinUNETR (MONAI) ├── segresnet/ │ └── best_model.pth # SegResNet (MONAI) └── nnunetv2/ ├── plans.json ├── dataset.json ├── dataset_fingerprint.json └── fold_0/ ├── checkpoint_best.pth └── checkpoint_final.pth ``` ## Usage ### Installation ```bash pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install monai nibabel scipy scikit-image tqdm pip install huggingface_hub ``` ### Load and run inference (MONAI models) ```python import torch from monai.networks.nets import AttentionUnet from huggingface_hub import hf_hub_download # Download weights weights_path = hf_hub_download( repo_id="abhijithkj3690/alveolar-canal-segmentation", filename="attention_unet/best_model.pth", ) # Build model — must match training architecture exactly model = AttentionUnet( spatial_dims=3, in_channels=1, out_channels=1, channels=(32, 64, 128, 256, 320), strides=(2, 2, 2, 2), dropout=0.1, ) model.load_state_dict( torch.load(weights_path, map_location="cpu", weights_only=True) ) model.eval() ``` ### Available model strings | Model | `filename` argument | |---|---| | 3D UNet | `"unet/best_model.pth"` | | AttentionUnet | `"attention_unet/best_model.pth"` | | DynUNet | `"dynunet/best_model.pth"` | | SwinUNETR | `"swinunetr/best_model.pth"` | | SegResNet | `"segresnet/best_model.pth"` | ### MONAI model constructors ```python from monai.networks.nets import UNet, AttentionUnet, DynUNet, SwinUNETR, SegResNet # 3D UNet UNet(spatial_dims=3, in_channels=1, out_channels=1, channels=(32,64,128,256,320), strides=(2,2,2,2), num_res_units=2) # AttentionUnet AttentionUnet(spatial_dims=3, in_channels=1, out_channels=1, channels=(32,64,128,256,320), strides=(2,2,2,2), dropout=0.1) # DynUNet DynUNet(spatial_dims=3, in_channels=1, out_channels=1, kernel_size=[[3,3,3]]*5, strides=[[1,1,1],[2,2,2],[2,2,2],[2,2,2],[2,2,2]], upsample_kernel_size=[[2,2,2]]*4, filters=(32,64,128,256,320), dropout=0.1, deep_supervision=False, res_block=True) # SwinUNETR SwinUNETR(in_channels=1, out_channels=1, feature_size=48, depths=(2,2,2,2), num_heads=(3,6,12,24), window_size=7, dropout_path_rate=0.1, spatial_dims=3) # SegResNet SegResNet(spatial_dims=3, in_channels=1, out_channels=1, init_filters=32, blocks_down=(1,2,2,4), blocks_up=(1,1,1), dropout_prob=0.1, use_conv_final=True) ``` ### Preprocessing All MONAI models use the following preprocessing (must be applied before inference): ```python from monai.transforms import Compose, LoadImaged, EnsureChannelFirstd, Orientationd, \ Spacingd, ScaleIntensityRanged, SpatialPadd, DivisiblePadd, EnsureTyped transforms = Compose([ LoadImaged(keys=["image"]), EnsureChannelFirstd(keys=["image"]), Orientationd(keys=["image"], axcodes="RAS", labels=None), Spacingd(keys=["image"], pixdim=(0.3, 0.3, 0.3), mode="bilinear"), ScaleIntensityRanged(keys=["image"], a_min=-167.8, a_max=1111.5, b_min=0.0, b_max=1.0, clip=True), SpatialPadd(keys=["image"], spatial_size=(128, 128, 128)), DivisiblePadd(keys=["image"], k=32), EnsureTyped(keys=["image"]), ]) ``` ## Training Details | Setting | Value | |---|---| | Dataset | ToothFairy2 (CBCT, alveolar canal) | | Train / Val / Test split | 296 / 86 / 50 | | Patch size | 128 × 128 × 128 | | Target spacing | 0.3 × 0.3 × 0.3 mm | | Loss | DiceFocalLoss (γ=2.0) | | Optimizer | SGD (lr=0.01, momentum=0.99, Nesterov) | | LR schedule | Polynomial decay (power=0.9) | | Epochs | 300 (scratch) | | Framework | MONAI 1.3.2 / PyTorch 2.2.2 | ## Code Full training, inference, and analysis scripts: 👉 [github.com/abhijithkj3690/alveolar-canal-segmentation](https://github.com/abhijithkj369/Alveolar_Canals_Segmentation) ## Dataset [ToothFairy2 Challenge](https://toothfairy2.grand-challenge.org/) — 3D CBCT scans with expert annotations of the alveolar canal (inferior alveolar nerve canal). ## License MIT — free to use for research and commercial purposes with attribution.