{
  "id": 561878,
  "title": "98th place solution",
  "url": "/competitions/czii-cryo-et-object-identification/discussion/561878",
  "author_name": "Buse",
  "post_date": "2025-02-08T13:09:21.505000",
  "votes": 5,
  "comment_count": 0,
  "views": 0,
  "content": "<h1>Approach: Single 3D-UNet to detect segmentation masks &amp; run connected-components-3d to localize detections</h1>\n<p>Full code: <a href=\"https://github.com/Oliver-Busemann/CryoET/tree/main\" target=\"_blank\">https://github.com/Oliver-Busemann/CryoET/tree/main</a><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8876667%2F9e8f3d93e5bc4779f812616ecdb1ff8e%2F75.png?generation=1739019029401530&amp;alt=media\" alt=\"\"></p>\n<ul>\n<li>7-fold-CV: Train on patches from 6 samples</li>\n<li>Validate on patches from hold-out sample</li>\n<li>Save predictions from hold-out fold to disc</li>\n<li>After 7-folds run connected-components-3D &amp; competition metric on all predictions at once to get final score</li>\n</ul>\n<h3>CV-score: 0.7781; Public-LB: 0.72782; Private-LB: 0.71783</h3>\n<h3>What improved CV:</h3>\n<ul>\n<li>Larger patches (128 &gt; 96 &gt; 48)  </li>\n<li>Loss: 0.75 cross-entropy (without weights) + 0.25 dice loss (excluding background)  </li>\n<li>Masked loss: use only the inner (96, 96, 96) for loss as partially visible targets at the border lack context  </li>\n<li>Use the same mask for assigning predictions to reduce border artifacts  </li>\n<li>WeightedRandomSampler: upsample patches with targets such that each target is present in patches as many times as patches with only background (most)  </li>\n<li>Augmentations: RandFlipd (x, y, z), RandRotated (only z), RandGaussianNoised (mean=0.0, std=0.075), RandAdjustContrastd (gamma=(0.9, 1.1))  </li>\n<li>Lower train stride to get more patches to sample from (32)</li>\n<li>Individual radius for creating segmentation masks (apo-ferritin: 5, beta-galactosidase: 6, ribosome: 10, thyroglobulin: 6, virus-like-particle: 12)  </li>\n<li>Simple UNet: channels=(32, 64, 128, 256, 512), strides=(2, 2, 1, 1), dropout=0.2, num_res_units=1)  </li>\n<li>Adam optimizer; 40 epochs; learning rate 5e-4, 1215 (1456) training (full-training) samples per epoch</li>\n<li>LR-Scheduler: OneCycleLR  </li>\n</ul>\n<h3>What did not work:</h3>\n<ul>\n<li>TverskyLoss, DiceFocalLoss, weights in dice loss  </li>\n<li>Other models like AttentionUnet</li>\n<li>RandCoarseDropoutd, RandAdjustContrastd with lower/higher values, RandRotated around x/y</li>\n<li>Removing smaller or larger connected-components based on threshold  </li>\n</ul>",
  "messages": [
    {
      "id": 3118753,
      "postDate": "2025-02-08T13:09:21.507Z",
      "content": "<h1>Approach: Single 3D-UNet to detect segmentation masks &amp; run connected-components-3d to localize detections</h1>\n<p>Full code: <a href=\"https://github.com/Oliver-Busemann/CryoET/tree/main\" target=\"_blank\">https://github.com/Oliver-Busemann/CryoET/tree/main</a><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8876667%2F9e8f3d93e5bc4779f812616ecdb1ff8e%2F75.png?generation=1739019029401530&amp;alt=media\" alt=\"\"></p>\n<ul>\n<li>7-fold-CV: Train on patches from 6 samples</li>\n<li>Validate on patches from hold-out sample</li>\n<li>Save predictions from hold-out fold to disc</li>\n<li>After 7-folds run connected-components-3D &amp; competition metric on all predictions at once to get final score</li>\n</ul>\n<h3>CV-score: 0.7781; Public-LB: 0.72782; Private-LB: 0.71783</h3>\n<h3>What improved CV:</h3>\n<ul>\n<li>Larger patches (128 &gt; 96 &gt; 48)  </li>\n<li>Loss: 0.75 cross-entropy (without weights) + 0.25 dice loss (excluding background)  </li>\n<li>Masked loss: use only the inner (96, 96, 96) for loss as partially visible targets at the border lack context  </li>\n<li>Use the same mask for assigning predictions to reduce border artifacts  </li>\n<li>WeightedRandomSampler: upsample patches with targets such that each target is present in patches as many times as patches with only background (most)  </li>\n<li>Augmentations: RandFlipd (x, y, z), RandRotated (only z), RandGaussianNoised (mean=0.0, std=0.075), RandAdjustContrastd (gamma=(0.9, 1.1))  </li>\n<li>Lower train stride to get more patches to sample from (32)</li>\n<li>Individual radius for creating segmentation masks (apo-ferritin: 5, beta-galactosidase: 6, ribosome: 10, thyroglobulin: 6, virus-like-particle: 12)  </li>\n<li>Simple UNet: channels=(32, 64, 128, 256, 512), strides=(2, 2, 1, 1), dropout=0.2, num_res_units=1)  </li>\n<li>Adam optimizer; 40 epochs; learning rate 5e-4, 1215 (1456) training (full-training) samples per epoch</li>\n<li>LR-Scheduler: OneCycleLR  </li>\n</ul>\n<h3>What did not work:</h3>\n<ul>\n<li>TverskyLoss, DiceFocalLoss, weights in dice loss  </li>\n<li>Other models like AttentionUnet</li>\n<li>RandCoarseDropoutd, RandAdjustContrastd with lower/higher values, RandRotated around x/y</li>\n<li>Removing smaller or larger connected-components based on threshold  </li>\n</ul>",
      "rawMarkdown": "# Approach: Single 3D-UNet to detect segmentation masks & run connected-components-3d to localize detections\nFull code: https://github.com/Oliver-Busemann/CryoET/tree/main\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8876667%2F9e8f3d93e5bc4779f812616ecdb1ff8e%2F75.png?generation=1739019029401530&alt=media)\n- 7-fold-CV: Train on patches from 6 samples\n- Validate on patches from hold-out sample\n- Save predictions from hold-out fold to disc\n- After 7-folds run connected-components-3D & competition metric on all predictions at once to get final score\n\n### CV-score: 0.7781; Public-LB: 0.72782; Private-LB: 0.71783  \n\n### What improved CV:  \n\n- Larger patches (128 > 96 > 48)  \n- Loss: 0.75 cross-entropy (without weights) + 0.25 dice loss (excluding background)  \n- Masked loss: use only the inner (96, 96, 96) for loss as partially visible targets at the border lack context  \n- Use the same mask for assigning predictions to reduce border artifacts  \n- WeightedRandomSampler: upsample patches with targets such that each target is present in patches as many times as patches with only background (most)  \n- Augmentations: RandFlipd (x, y, z), RandRotated (only z), RandGaussianNoised (mean=0.0, std=0.075), RandAdjustContrastd (gamma=(0.9, 1.1))  \n- Lower train stride to get more patches to sample from (32)\n- Individual radius for creating segmentation masks (apo-ferritin: 5, beta-galactosidase: 6, ribosome: 10, thyroglobulin: 6, virus-like-particle: 12)  \n- Simple UNet: channels=(32, 64, 128, 256, 512), strides=(2, 2, 1, 1), dropout=0.2, num_res_units=1)  \n- Adam optimizer; 40 epochs; learning rate 5e-4, 1215 (1456) training (full-training) samples per epoch\n- LR-Scheduler: OneCycleLR  \n\n### What did not work:  \n\n- TverskyLoss, DiceFocalLoss, weights in dice loss  \n- Other models like AttentionUnet\n- RandCoarseDropoutd, RandAdjustContrastd with lower/higher values, RandRotated around x/y\n- Removing smaller or larger connected-components based on threshold  \n",
      "votes": 5
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "3118753": "# Approach: Single 3D-UNet to detect segmentation masks & run connected-components-3d to localize detections\nFull code: https://github.com/Oliver-Busemann/CryoET/tree/main\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F8876667%2F9e8f3d93e5bc4779f812616ecdb1ff8e%2F75.png?generation=1739019029401530&alt=media)\n- 7-fold-CV: Train on patches from 6 samples\n- Validate on patches from hold-out sample\n- Save predictions from hold-out fold to disc\n- After 7-folds run connected-components-3D & competition metric on all predictions at once to get final score\n\n### CV-score: 0.7781; Public-LB: 0.72782; Private-LB: 0.71783  \n\n### What improved CV:  \n\n- Larger patches (128 > 96 > 48)  \n- Loss: 0.75 cross-entropy (without weights) + 0.25 dice loss (excluding background)  \n- Masked loss: use only the inner (96, 96, 96) for loss as partially visible targets at the border lack context  \n- Use the same mask for assigning predictions to reduce border artifacts  \n- WeightedRandomSampler: upsample patches with targets such that each target is present in patches as many times as patches with only background (most)  \n- Augmentations: RandFlipd (x, y, z), RandRotated (only z), RandGaussianNoised (mean=0.0, std=0.075), RandAdjustContrastd (gamma=(0.9, 1.1))  \n- Lower train stride to get more patches to sample from (32)\n- Individual radius for creating segmentation masks (apo-ferritin: 5, beta-galactosidase: 6, ribosome: 10, thyroglobulin: 6, virus-like-particle: 12)  \n- Simple UNet: channels=(32, 64, 128, 256, 512), strides=(2, 2, 1, 1), dropout=0.2, num_res_units=1)  \n- Adam optimizer; 40 epochs; learning rate 5e-4, 1215 (1456) training (full-training) samples per epoch\n- LR-Scheduler: OneCycleLR  \n\n### What did not work:  \n\n- TverskyLoss, DiceFocalLoss, weights in dice loss  \n- Other models like AttentionUnet\n- RandCoarseDropoutd, RandAdjustContrastd with lower/higher values, RandRotated around x/y\n- Removing smaller or larger connected-components based on threshold  \n"
  }
}