{ "model_name": "Pulmo", "description": "Two-stage explainable lung-nodule analysis pipeline on LUNA16/LIDC-IDRI: a 3D detector finds nodule centres, a 2.5D concept-bottleneck model characterises each candidate (detection, malignancy, 8 radiological concepts, segmentation).", "pipeline": ["stage1_detector", "stage2_characteriser"], "stage1_detector": { "architecture": "HeatmapUNet3D", "weights": "stage1_detector_v2.pth", "role": "Locate nodule centres in a full CT volume (3D sliding window -> centre heatmap -> peaks).", "base_channels": 16, "patch_zyx": [64, 128, 128], "input": "(B, 1, 64, 128, 128) float32 in [0, 1] (native resolution, no downsampling)", "output": "(B, 1, 64, 128, 128) per-voxel nodule-centre probability heatmap", "loss": "CenterNet penalty-reduced focal loss", "metrics_scan_level": { "CPM_at_8FP": 0.629, "sensitivity_at_16FP_per_scan": 0.956, "mean_centre_distance_mm": 1.85, "note": "FROC on held-out internal val split. Operating point is tunable via peak_thresh; Stage 2 filters false positives." } }, "stage2_characteriser": { "architecture": "Student2p5D", "weights": "student_2p5d_best.pth", "role": "Per-candidate diagnosis + explanation from a 64^3 patch (its 7 central axial slices).", "input": { "n_slices": 7, "slice_size": [64, 64], "tensor_shape": "(B, 7, 64, 64)", "dtype": "float32", "value_range": [0.0, 1.0] }, "backbone": {"type": "UNet2D", "base_channels": 24, "trunk_dim": 384}, "heads": { "detection": "2 (nodule vs non-nodule)", "concepts": "8 (LIDC radiological concepts, regression)", "malignancy": "Linear(8 -> 2), concept bottleneck", "segmentation": "(B, 1, 64, 64), middle axial slice" }, "n_concepts": 8, "concept_names": [ "subtlety", "internalStructure", "calcification", "sphericity", "margin", "lobulation", "spiculation", "texture" ], "test_metrics_patch_level": { "detection_auc": 0.997, "malignancy_auc": 0.986, "segmentation_dice": 0.859, "note": "Held-out internal test split (patient-level split of LUNA16). Not externally validated." }, "teacher_reference_3d": { "detection_auc": 0.998, "malignancy_auc": 0.986, "segmentation_dice": 0.857 } }, "preprocessing": { "hu_clip": [-1000, 1000], "normalize": "(x - hu_min) / (hu_max - hu_min) -> [0, 1] (identical for both stages)", "stage1_input": "raw (Z, Y, X) HU volume; sliding-window 3D patches of [64, 128, 128]", "stage2_input": "7 central axial slices of a 64^3 patch centred on a Stage-1 candidate", "spacing_order": "[z, y, x] in mm" }, "training_data": "LUNA16 (subset of LIDC-IDRI), 888 scans, patient-level 80/10/10 split", "license": "cc-by-4.0", "intended_use": "research only; not a medical device" }