{
  "id": 679259,
  "title": "12th place solution",
  "url": "/competitions/vesuvius-challenge-surface-detection/writeups/12th-place-solution",
  "author_name": "",
  "post_date": "2026-02-28T07:54:57.413Z",
  "votes": 19,
  "comment_count": 1,
  "views": 0,
  "content": "<p>Thank you for the organizers and Kaggle team for this great competition!</p>\n<h2>1. Summary</h2>\n<p>nnUNet-based 3D segmentation.\n4-model ensemble of 3d_lowres and 3d_fullres + opening/closing post-processing</p>\n<ul>\n<li>Public LB: 0.578</li>\n<li>Private LB: 0.613</li>\n</ul>\n<hr>\n<h2>2. Solution Overview</h2>\n<pre><code>[Pipeline]\n\nInput (3D CT volume)\n    ↓\nnnUNet preprocessing (normalization, resampling)\n    ↓\n4-model inference (2x T4 GPU parallel)\n  ├─ 3d_lowres fold_0 (2000ep) × 0.2\n  ├─ 3d_lowres fold_1 (4000ep) × 0.2\n  ├─ 3d_fullres fold_0 (4000ep) × 0.3\n  └─ 3d_fullres fold_1 (2000ep) × 0.3\n    ↓\nWeighted average of probability maps\n    ↓\nPost-processing\n  ├─ Hysteresis thresholding (t_low=0.3, t_high=0.85)\n  ├─ Opening (noise removal)\n  └─ Closing (hole filling)\n    ↓\nOutput (3D segmentation mask)\n</code></pre>\n<p><strong>Key Points</strong></p>\n<ul>\n<li>Used nnUNet with mostly default settings</li>\n<li>Combined lowres + fullres for different scales</li>\n<li>Post-processing significantly improved TopoScore (topology quality)</li>\n</ul>\n<hr>\n<h2>3. Model &amp; Training</h2>\n<p><strong>Configuration Comparison</strong></p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>3d_lowres</th>\n<th>3d_fullres</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Patch size</td>\n<td>128³</td>\n<td>128³</td>\n</tr>\n<tr>\n<td>Spacing</td>\n<td>1.56 mm</td>\n<td>1.0 mm</td>\n</tr>\n<tr>\n<td>Effective FOV</td>\n<td>~200 mm³</td>\n<td>~128 mm³</td>\n</tr>\n<tr>\n<td>Image size</td>\n<td>205³</td>\n<td>320³</td>\n</tr>\n</tbody>\n</table>\n<p>*Same patch size but different physical coverage due to spacing differences</p>\n<p><strong>Fold Strategy</strong></p>\n<ul>\n<li>Used only 2 folds from nnUNet's default 5-fold CV (fold_0, fold_1)</li>\n<li>Reason: Time constraints, and 2 folds provided sufficient diversity</li>\n<li>Training data: 628 cases, validation data: 157-158 cases/fold</li>\n</ul>\n<p><strong>Epochs</strong></p>\n<ul>\n<li>Base: 2000 epochs</li>\n<li>Some models extended to 4000 epochs</li>\n<li>Wanted to train all models to 4000 epochs but ran out of competition deadline</li>\n<li>Final 4 models used:</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>Config</th>\n<th>Fold</th>\n<th>Epochs</th>\n<th>CV (opening_closing)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>3d_lowres</td>\n<td>fold_0</td>\n<td>2000</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>3d_lowres</td>\n<td>fold_1</td>\n<td>4000</td>\n<td>0.603</td>\n</tr>\n<tr>\n<td>3d_fullres</td>\n<td>fold_0</td>\n<td>4000</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>3d_fullres</td>\n<td>fold_1</td>\n<td>2000</td>\n<td>0.603</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Effect of Epochs</strong></p>\n<ul>\n<li>1000ep → 2000ep:<ul>\n<li>3d_lowres fold_0: 0.601 → 0.605 (+0.004)</li></ul></li>\n<li>2000ep → 4000ep:<ul>\n<li>3d_fullres fold_0: 0.603 → 0.606 (+0.003)</li>\n<li>3d_lowres fold_1: 0.594 → 0.603 (+0.009)</li></ul></li>\n</ul>\n<hr>\n<h2>4. Inference &amp; Post-processing</h2>\n<p><strong>Sliding Window Settings</strong></p>\n<ul>\n<li>step_size = 0.3 (70% overlap)</li>\n</ul>\n<p><strong>TTA (Test Time Augmentation)</strong></p>\n<ul>\n<li>8-direction mirroring</li>\n<li>Used TTA for inference, switched to non-TTA when approaching 9-hour time limit</li>\n</ul>\n<p><strong>Post-processing Pipeline</strong></p>\n<pre><code>Probability map → Hysteresis → Opening → Closing → Dust Removal → Final mask\n</code></pre>\n<p><strong>Step 1: 3D Hysteresis Thresholding</strong></p>\n<ul>\n<li>t_high = 0.85: High confidence regions (seeds)</li>\n<li>t_low = 0.30: Wide coverage</li>\n<li>Structuring element: generate_binary_structure(3, 3) - 26-connectivity</li>\n<li>Process: binary_propagation from strong to weak regions</li>\n</ul>\n<p><strong>Step 2: Opening (Noise Removal)</strong></p>\n<ul>\n<li>Structuring element: generate_binary_structure(3, 1) - 6-connectivity</li>\n<li>Effect: Removes small protrusions and noise</li>\n</ul>\n<p><strong>Step 3: Anisotropic Closing (Hole Filling)</strong></p>\n<ul>\n<li>Structuring element: z_radius=2, xy_radius=1 (anisotropic)</li>\n<li>Larger z-direction to strengthen inter-slice connectivity</li>\n</ul>\n<p><strong>Step 4: Dust Removal</strong></p>\n<ul>\n<li>min_size = 100 voxels</li>\n<li>Effect: Removes small isolated regions</li>\n</ul>\n<p><strong>Post-processing Effect Comparison</strong> (2000ep fold_0)</p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Competition Score</th>\n<th>TopoScore</th>\n<th>Improvement</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>None (argmax)</td>\n<td>0.571</td>\n<td>0.246</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Hysteresis only</td>\n<td>0.592</td>\n<td>0.322</td>\n<td>+0.021</td>\n</tr>\n<tr>\n<td>+ Opening/Closing</td>\n<td>0.606</td>\n<td>0.342</td>\n<td>+0.035</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>5. Scores</h2>\n<p><strong>Score Progression</strong></p>\n<table>\n<thead>\n<tr>\n<th>Stage</th>\n<th>Changes</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline</td>\n<td>1000ep, 1 model, argmax</td>\n<td>0.530</td>\n<td>0.552</td>\n</tr>\n<tr>\n<td>+Post-processing</td>\n<td>hysteresis</td>\n<td>0.549</td>\n<td>0.570</td>\n</tr>\n<tr>\n<td>+2-fold</td>\n<td>fold_0+1 ensemble</td>\n<td>0.565</td>\n<td>0.590</td>\n</tr>\n<tr>\n<td>+opening_closing</td>\n<td>Improved post-processing</td>\n<td>0.565</td>\n<td>0.593</td>\n</tr>\n<tr>\n<td>+2000ep</td>\n<td>Increased epochs</td>\n<td>0.568</td>\n<td>0.593</td>\n</tr>\n<tr>\n<td>+fullres</td>\n<td>fullres 2 models only</td>\n<td>0.575</td>\n<td>0.598</td>\n</tr>\n<tr>\n<td>+4 models</td>\n<td>lowres+fullres ensemble</td>\n<td>0.582</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>+Weight tuning</td>\n<td>fullres 60%, lowres 40%</td>\n<td>0.583</td>\n<td>0.605</td>\n</tr>\n<tr>\n<td>+TTA</td>\n<td>8-direction mirroring</td>\n<td>0.584</td>\n<td>0.607</td>\n</tr>\n<tr>\n<td>+4000ep</td>\n<td>Final submission</td>\n<td>0.578</td>\n<td>0.613</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>6. What Worked / What Didn't Work</h2>\n<h3>What Worked</h3>\n<ul>\n<li>nnUNet default settings</li>\n<li>4-model ensemble (lowres + fullres fold0, 1)</li>\n<li>Post-processing (Hysteresis + Opening/Closing)</li>\n<li>Epoch increase (1000→2000→4000)</li>\n<li>TTA (Test Time Augmentation)</li>\n</ul>\n<h3>What Didn't Work</h3>\n<ul>\n<li>Increased inference parallelism (npp=2, nps=2): Counterproductive due to T4 memory constraints (+50min slower)</li>\n<li>step_size changes: 0.3 was best, 0.2 and 0.5 worsened Public score</li>\n</ul>",
  "messages": [
    {
      "id": "3415123",
      "postDate": "02/28/2026 07:50:29",
      "content": "<p>Thank you for the organizers and Kaggle team for this great competition!</p>\n<h2>1. Summary</h2>\n<p>nnUNet-based 3D segmentation.\n4-model ensemble of 3d_lowres and 3d_fullres + opening/closing post-processing</p>\n<ul>\n<li>Public LB: 0.578</li>\n<li>Private LB: 0.613</li>\n</ul>\n<hr>\n<h2>2. Solution Overview</h2>\n<pre><code>[Pipeline]\n\nInput (3D CT volume)\n    ↓\nnnUNet preprocessing (normalization, resampling)\n    ↓\n4-model inference (2x T4 GPU parallel)\n  ├─ 3d_lowres fold_0 (2000ep) × 0.2\n  ├─ 3d_lowres fold_1 (4000ep) × 0.2\n  ├─ 3d_fullres fold_0 (4000ep) × 0.3\n  └─ 3d_fullres fold_1 (2000ep) × 0.3\n    ↓\nWeighted average of probability maps\n    ↓\nPost-processing\n  ├─ Hysteresis thresholding (t_low=0.3, t_high=0.85)\n  ├─ Opening (noise removal)\n  └─ Closing (hole filling)\n    ↓\nOutput (3D segmentation mask)\n</code></pre>\n<p><strong>Key Points</strong></p>\n<ul>\n<li>Used nnUNet with mostly default settings</li>\n<li>Combined lowres + fullres for different scales</li>\n<li>Post-processing significantly improved TopoScore (topology quality)</li>\n</ul>\n<hr>\n<h2>3. Model &amp; Training</h2>\n<p><strong>Configuration Comparison</strong></p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>3d_lowres</th>\n<th>3d_fullres</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Patch size</td>\n<td>128³</td>\n<td>128³</td>\n</tr>\n<tr>\n<td>Spacing</td>\n<td>1.56 mm</td>\n<td>1.0 mm</td>\n</tr>\n<tr>\n<td>Effective FOV</td>\n<td>~200 mm³</td>\n<td>~128 mm³</td>\n</tr>\n<tr>\n<td>Image size</td>\n<td>205³</td>\n<td>320³</td>\n</tr>\n</tbody>\n</table>\n<p>*Same patch size but different physical coverage due to spacing differences</p>\n<p><strong>Fold Strategy</strong></p>\n<ul>\n<li>Used only 2 folds from nnUNet's default 5-fold CV (fold_0, fold_1)</li>\n<li>Reason: Time constraints, and 2 folds provided sufficient diversity</li>\n<li>Training data: 628 cases, validation data: 157-158 cases/fold</li>\n</ul>\n<p><strong>Epochs</strong></p>\n<ul>\n<li>Base: 2000 epochs</li>\n<li>Some models extended to 4000 epochs</li>\n<li>Wanted to train all models to 4000 epochs but ran out of competition deadline</li>\n<li>Final 4 models used:</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>Config</th>\n<th>Fold</th>\n<th>Epochs</th>\n<th>CV (opening_closing)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>3d_lowres</td>\n<td>fold_0</td>\n<td>2000</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>3d_lowres</td>\n<td>fold_1</td>\n<td>4000</td>\n<td>0.603</td>\n</tr>\n<tr>\n<td>3d_fullres</td>\n<td>fold_0</td>\n<td>4000</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>3d_fullres</td>\n<td>fold_1</td>\n<td>2000</td>\n<td>0.603</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Effect of Epochs</strong></p>\n<ul>\n<li>1000ep → 2000ep:<ul>\n<li>3d_lowres fold_0: 0.601 → 0.605 (+0.004)</li></ul></li>\n<li>2000ep → 4000ep:<ul>\n<li>3d_fullres fold_0: 0.603 → 0.606 (+0.003)</li>\n<li>3d_lowres fold_1: 0.594 → 0.603 (+0.009)</li></ul></li>\n</ul>\n<hr>\n<h2>4. Inference &amp; Post-processing</h2>\n<p><strong>Sliding Window Settings</strong></p>\n<ul>\n<li>step_size = 0.3 (70% overlap)</li>\n</ul>\n<p><strong>TTA (Test Time Augmentation)</strong></p>\n<ul>\n<li>8-direction mirroring</li>\n<li>Used TTA for inference, switched to non-TTA when approaching 9-hour time limit</li>\n</ul>\n<p><strong>Post-processing Pipeline</strong></p>\n<pre><code>Probability map → Hysteresis → Opening → Closing → Dust Removal → Final mask\n</code></pre>\n<p><strong>Step 1: 3D Hysteresis Thresholding</strong></p>\n<ul>\n<li>t_high = 0.85: High confidence regions (seeds)</li>\n<li>t_low = 0.30: Wide coverage</li>\n<li>Structuring element: generate_binary_structure(3, 3) - 26-connectivity</li>\n<li>Process: binary_propagation from strong to weak regions</li>\n</ul>\n<p><strong>Step 2: Opening (Noise Removal)</strong></p>\n<ul>\n<li>Structuring element: generate_binary_structure(3, 1) - 6-connectivity</li>\n<li>Effect: Removes small protrusions and noise</li>\n</ul>\n<p><strong>Step 3: Anisotropic Closing (Hole Filling)</strong></p>\n<ul>\n<li>Structuring element: z_radius=2, xy_radius=1 (anisotropic)</li>\n<li>Larger z-direction to strengthen inter-slice connectivity</li>\n</ul>\n<p><strong>Step 4: Dust Removal</strong></p>\n<ul>\n<li>min_size = 100 voxels</li>\n<li>Effect: Removes small isolated regions</li>\n</ul>\n<p><strong>Post-processing Effect Comparison</strong> (2000ep fold_0)</p>\n<table>\n<thead>\n<tr>\n<th>Method</th>\n<th>Competition Score</th>\n<th>TopoScore</th>\n<th>Improvement</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>None (argmax)</td>\n<td>0.571</td>\n<td>0.246</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Hysteresis only</td>\n<td>0.592</td>\n<td>0.322</td>\n<td>+0.021</td>\n</tr>\n<tr>\n<td>+ Opening/Closing</td>\n<td>0.606</td>\n<td>0.342</td>\n<td>+0.035</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>5. Scores</h2>\n<p><strong>Score Progression</strong></p>\n<table>\n<thead>\n<tr>\n<th>Stage</th>\n<th>Changes</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline</td>\n<td>1000ep, 1 model, argmax</td>\n<td>0.530</td>\n<td>0.552</td>\n</tr>\n<tr>\n<td>+Post-processing</td>\n<td>hysteresis</td>\n<td>0.549</td>\n<td>0.570</td>\n</tr>\n<tr>\n<td>+2-fold</td>\n<td>fold_0+1 ensemble</td>\n<td>0.565</td>\n<td>0.590</td>\n</tr>\n<tr>\n<td>+opening_closing</td>\n<td>Improved post-processing</td>\n<td>0.565</td>\n<td>0.593</td>\n</tr>\n<tr>\n<td>+2000ep</td>\n<td>Increased epochs</td>\n<td>0.568</td>\n<td>0.593</td>\n</tr>\n<tr>\n<td>+fullres</td>\n<td>fullres 2 models only</td>\n<td>0.575</td>\n<td>0.598</td>\n</tr>\n<tr>\n<td>+4 models</td>\n<td>lowres+fullres ensemble</td>\n<td>0.582</td>\n<td>0.606</td>\n</tr>\n<tr>\n<td>+Weight tuning</td>\n<td>fullres 60%, lowres 40%</td>\n<td>0.583</td>\n<td>0.605</td>\n</tr>\n<tr>\n<td>+TTA</td>\n<td>8-direction mirroring</td>\n<td>0.584</td>\n<td>0.607</td>\n</tr>\n<tr>\n<td>+4000ep</td>\n<td>Final submission</td>\n<td>0.578</td>\n<td>0.613</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>6. What Worked / What Didn't Work</h2>\n<h3>What Worked</h3>\n<ul>\n<li>nnUNet default settings</li>\n<li>4-model ensemble (lowres + fullres fold0, 1)</li>\n<li>Post-processing (Hysteresis + Opening/Closing)</li>\n<li>Epoch increase (1000→2000→4000)</li>\n<li>TTA (Test Time Augmentation)</li>\n</ul>\n<h3>What Didn't Work</h3>\n<ul>\n<li>Increased inference parallelism (npp=2, nps=2): Counterproductive due to T4 memory constraints (+50min slower)</li>\n<li>step_size changes: 0.3 was best, 0.2 and 0.5 worsened Public score</li>\n</ul>",
      "rawMarkdown": "Thank you for the organizers and Kaggle team for this great competition!\n\n## 1. Summary\n\nnnUNet-based 3D segmentation.\n4-model ensemble of 3d_lowres and 3d_fullres + opening/closing post-processing\n- Public LB: 0.578\n- Private LB: 0.613\n\n---\n\n## 2. Solution Overview\n\n```\n[Pipeline]\n\nInput (3D CT volume)\n    ↓\nnnUNet preprocessing (normalization, resampling)\n    ↓\n4-model inference (2x T4 GPU parallel)\n  ├─ 3d_lowres fold_0 (2000ep) × 0.2\n  ├─ 3d_lowres fold_1 (4000ep) × 0.2\n  ├─ 3d_fullres fold_0 (4000ep) × 0.3\n  └─ 3d_fullres fold_1 (2000ep) × 0.3\n    ↓\nWeighted average of probability maps\n    ↓\nPost-processing\n  ├─ Hysteresis thresholding (t_low=0.3, t_high=0.85)\n  ├─ Opening (noise removal)\n  └─ Closing (hole filling)\n    ↓\nOutput (3D segmentation mask)\n```\n\n**Key Points**\n- Used nnUNet with mostly default settings\n- Combined lowres + fullres for different scales\n- Post-processing significantly improved TopoScore (topology quality)\n\n---\n\n## 3. Model & Training\n\n**Configuration Comparison**\n\n|              | 3d_lowres | 3d_fullres |\n|--------------|-----------|------------|\n| Patch size   | 128³      | 128³       |\n| Spacing      | 1.56 mm   | 1.0 mm     |\n| Effective FOV| ~200 mm³  | ~128 mm³   |\n| Image size   | 205³      | 320³       |\n\n*Same patch size but different physical coverage due to spacing differences\n\n**Fold Strategy**\n- Used only 2 folds from nnUNet's default 5-fold CV (fold_0, fold_1)\n- Reason: Time constraints, and 2 folds provided sufficient diversity\n- Training data: 628 cases, validation data: 157-158 cases/fold\n\n**Epochs**\n- Base: 2000 epochs\n- Some models extended to 4000 epochs\n- Wanted to train all models to 4000 epochs but ran out of competition deadline\n- Final 4 models used:\n\n| Config     | Fold   | Epochs | CV (opening_closing) |\n|------------|--------|--------|----------------------|\n| 3d_lowres  | fold_0 | 2000   | 0.606                |\n| 3d_lowres  | fold_1 | 4000   | 0.603                |\n| 3d_fullres | fold_0 | 4000   | 0.606                |\n| 3d_fullres | fold_1 | 2000   | 0.603                |\n\n**Effect of Epochs**\n- 1000ep → 2000ep:\n  - 3d_lowres fold_0: 0.601 → 0.605 (+0.004)\n- 2000ep → 4000ep:\n  - 3d_fullres fold_0: 0.603 → 0.606 (+0.003)\n  - 3d_lowres fold_1: 0.594 → 0.603 (+0.009)\n\n---\n\n## 4. Inference & Post-processing\n\n**Sliding Window Settings**\n- step_size = 0.3 (70% overlap)\n\n**TTA (Test Time Augmentation)**\n- 8-direction mirroring\n- Used TTA for inference, switched to non-TTA when approaching 9-hour time limit\n\n**Post-processing Pipeline**\n```\nProbability map → Hysteresis → Opening → Closing → Dust Removal → Final mask\n```\n\n**Step 1: 3D Hysteresis Thresholding**\n- t_high = 0.85: High confidence regions (seeds)\n- t_low = 0.30: Wide coverage\n- Structuring element: generate_binary_structure(3, 3) - 26-connectivity\n- Process: binary_propagation from strong to weak regions\n\n**Step 2: Opening (Noise Removal)**\n- Structuring element: generate_binary_structure(3, 1) - 6-connectivity\n- Effect: Removes small protrusions and noise\n\n**Step 3: Anisotropic Closing (Hole Filling)**\n- Structuring element: z_radius=2, xy_radius=1 (anisotropic)\n- Larger z-direction to strengthen inter-slice connectivity\n\n**Step 4: Dust Removal**\n- min_size = 100 voxels\n- Effect: Removes small isolated regions\n\n**Post-processing Effect Comparison** (2000ep fold_0)\n\n| Method | Competition Score | TopoScore | Improvement |\n|--------|-------------------|-----------|-------------|\n| None (argmax) | 0.571 | 0.246 | - |\n| Hysteresis only | 0.592 | 0.322 | +0.021 |\n| + Opening/Closing | 0.606 | 0.342 | +0.035 |\n\n---\n\n## 5. Scores\n\n**Score Progression**\n\n| Stage | Changes | Public | Private |\n|-------|---------|--------|---------|\n| Baseline | 1000ep, 1 model, argmax | 0.530 | 0.552 |\n| +Post-processing | hysteresis | 0.549 | 0.570 |\n| +2-fold | fold_0+1 ensemble | 0.565 | 0.590 |\n| +opening_closing | Improved post-processing | 0.565 | 0.593 |\n| +2000ep | Increased epochs | 0.568 | 0.593 |\n| +fullres | fullres 2 models only | 0.575 | 0.598 |\n| +4 models | lowres+fullres ensemble | 0.582 | 0.606 |\n| +Weight tuning | fullres 60%, lowres 40% | 0.583 | 0.605 |\n| +TTA | 8-direction mirroring | 0.584 | 0.607 |\n| +4000ep | Final submission | 0.578 | 0.613 |\n\n\n---\n\n## 6. What Worked / What Didn't Work\n\n### What Worked\n\n- nnUNet default settings\n- 4-model ensemble (lowres + fullres fold0, 1)\n- Post-processing (Hysteresis + Opening/Closing)\n- Epoch increase (1000→2000→4000)\n- TTA (Test Time Augmentation)\n\n### What Didn't Work\n\n- Increased inference parallelism (npp=2, nps=2): Counterproductive due to T4 memory constraints (+50min slower)\n- step_size changes: 0.3 was best, 0.2 and 0.5 worsened Public score",
      "votes": null
    },
    {
      "id": "3415401",
      "postDate": "02/28/2026 20:51:36",
      "content": "<p>Congratulations, and thank you for your sharing. The ideas were presented very clearly, and I learned a lot.</p>",
      "rawMarkdown": "Congratulations, and thank you for your sharing. The ideas were presented very clearly, and I learned a lot.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3415401,
      "author_name": "potonglantie93",
      "author_url": "",
      "post_date": "02/28/2026 20:51:36",
      "content": "<p>Congratulations, and thank you for your sharing. The ideas were presented very clearly, and I learned a lot.</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3415123": "Thank you for the organizers and Kaggle team for this great competition!\n\n## 1. Summary\n\nnnUNet-based 3D segmentation.\n4-model ensemble of 3d_lowres and 3d_fullres + opening/closing post-processing\n- Public LB: 0.578\n- Private LB: 0.613\n\n---\n\n## 2. Solution Overview\n\n```\n[Pipeline]\n\nInput (3D CT volume)\n    ↓\nnnUNet preprocessing (normalization, resampling)\n    ↓\n4-model inference (2x T4 GPU parallel)\n  ├─ 3d_lowres fold_0 (2000ep) × 0.2\n  ├─ 3d_lowres fold_1 (4000ep) × 0.2\n  ├─ 3d_fullres fold_0 (4000ep) × 0.3\n  └─ 3d_fullres fold_1 (2000ep) × 0.3\n    ↓\nWeighted average of probability maps\n    ↓\nPost-processing\n  ├─ Hysteresis thresholding (t_low=0.3, t_high=0.85)\n  ├─ Opening (noise removal)\n  └─ Closing (hole filling)\n    ↓\nOutput (3D segmentation mask)\n```\n\n**Key Points**\n- Used nnUNet with mostly default settings\n- Combined lowres + fullres for different scales\n- Post-processing significantly improved TopoScore (topology quality)\n\n---\n\n## 3. Model & Training\n\n**Configuration Comparison**\n\n|              | 3d_lowres | 3d_fullres |\n|--------------|-----------|------------|\n| Patch size   | 128³      | 128³       |\n| Spacing      | 1.56 mm   | 1.0 mm     |\n| Effective FOV| ~200 mm³  | ~128 mm³   |\n| Image size   | 205³      | 320³       |\n\n*Same patch size but different physical coverage due to spacing differences\n\n**Fold Strategy**\n- Used only 2 folds from nnUNet's default 5-fold CV (fold_0, fold_1)\n- Reason: Time constraints, and 2 folds provided sufficient diversity\n- Training data: 628 cases, validation data: 157-158 cases/fold\n\n**Epochs**\n- Base: 2000 epochs\n- Some models extended to 4000 epochs\n- Wanted to train all models to 4000 epochs but ran out of competition deadline\n- Final 4 models used:\n\n| Config     | Fold   | Epochs | CV (opening_closing) |\n|------------|--------|--------|----------------------|\n| 3d_lowres  | fold_0 | 2000   | 0.606                |\n| 3d_lowres  | fold_1 | 4000   | 0.603                |\n| 3d_fullres | fold_0 | 4000   | 0.606                |\n| 3d_fullres | fold_1 | 2000   | 0.603                |\n\n**Effect of Epochs**\n- 1000ep → 2000ep:\n  - 3d_lowres fold_0: 0.601 → 0.605 (+0.004)\n- 2000ep → 4000ep:\n  - 3d_fullres fold_0: 0.603 → 0.606 (+0.003)\n  - 3d_lowres fold_1: 0.594 → 0.603 (+0.009)\n\n---\n\n## 4. Inference & Post-processing\n\n**Sliding Window Settings**\n- step_size = 0.3 (70% overlap)\n\n**TTA (Test Time Augmentation)**\n- 8-direction mirroring\n- Used TTA for inference, switched to non-TTA when approaching 9-hour time limit\n\n**Post-processing Pipeline**\n```\nProbability map → Hysteresis → Opening → Closing → Dust Removal → Final mask\n```\n\n**Step 1: 3D Hysteresis Thresholding**\n- t_high = 0.85: High confidence regions (seeds)\n- t_low = 0.30: Wide coverage\n- Structuring element: generate_binary_structure(3, 3) - 26-connectivity\n- Process: binary_propagation from strong to weak regions\n\n**Step 2: Opening (Noise Removal)**\n- Structuring element: generate_binary_structure(3, 1) - 6-connectivity\n- Effect: Removes small protrusions and noise\n\n**Step 3: Anisotropic Closing (Hole Filling)**\n- Structuring element: z_radius=2, xy_radius=1 (anisotropic)\n- Larger z-direction to strengthen inter-slice connectivity\n\n**Step 4: Dust Removal**\n- min_size = 100 voxels\n- Effect: Removes small isolated regions\n\n**Post-processing Effect Comparison** (2000ep fold_0)\n\n| Method | Competition Score | TopoScore | Improvement |\n|--------|-------------------|-----------|-------------|\n| None (argmax) | 0.571 | 0.246 | - |\n| Hysteresis only | 0.592 | 0.322 | +0.021 |\n| + Opening/Closing | 0.606 | 0.342 | +0.035 |\n\n---\n\n## 5. Scores\n\n**Score Progression**\n\n| Stage | Changes | Public | Private |\n|-------|---------|--------|---------|\n| Baseline | 1000ep, 1 model, argmax | 0.530 | 0.552 |\n| +Post-processing | hysteresis | 0.549 | 0.570 |\n| +2-fold | fold_0+1 ensemble | 0.565 | 0.590 |\n| +opening_closing | Improved post-processing | 0.565 | 0.593 |\n| +2000ep | Increased epochs | 0.568 | 0.593 |\n| +fullres | fullres 2 models only | 0.575 | 0.598 |\n| +4 models | lowres+fullres ensemble | 0.582 | 0.606 |\n| +Weight tuning | fullres 60%, lowres 40% | 0.583 | 0.605 |\n| +TTA | 8-direction mirroring | 0.584 | 0.607 |\n| +4000ep | Final submission | 0.578 | 0.613 |\n\n\n---\n\n## 6. What Worked / What Didn't Work\n\n### What Worked\n\n- nnUNet default settings\n- 4-model ensemble (lowres + fullres fold0, 1)\n- Post-processing (Hysteresis + Opening/Closing)\n- Epoch increase (1000→2000→4000)\n- TTA (Test Time Augmentation)\n\n### What Didn't Work\n\n- Increased inference parallelism (npp=2, nps=2): Counterproductive due to T4 memory constraints (+50min slower)\n- step_size changes: 0.3 was best, 0.2 and 0.5 worsened Public score",
    "3415401": "Congratulations, and thank you for your sharing. The ideas were presented very clearly, and I learned a lot."
  },
  "source": "meta"
}