{
  "id": 679301,
  "title": "24th Place Solution - Vesuvius Challenge ",
  "url": "/competitions/vesuvius-challenge-surface-detection/writeups/24th-place-solution",
  "author_name": "",
  "post_date": "2026-02-28T13:47:05.247Z",
  "votes": 14,
  "comment_count": 7,
  "views": 0,
  "content": "<p>Thank you to the organisers and other participants for providing such a challenge. I could not participate in previous Vesuvius Challenge competitions due to other commitments so it was amazing to finally have that change and learn so much about it, as well as 3D data in general. </p>\n<p><strong>A single model solution</strong></p>\n<p>Before the test data got corrected, my strategy was to focus on precision rather than recall as I could not figure out how to make the topo score improve on LB.\nOne thing that helped a little to experiment faster was to use the weights from the nnUNet trained on the \"old\" dataset as pretrained weights to all my models (though it was a bit of a headache when dealing with folds and ensuring there is no data leakage). I had a nnUNet with Tversky loss (alpha=0.7, beta=0.3 to focus on precision) and 160x160x160 patches.\nAfter the test set correction, I had to retrain my model using the Skeleton-Recall loss and it gave a +0.004 boost. It took more time than I expected as the threshold and the outputs were so different that it then behaved differently with the post-processing functions I had designed.\nAll models were first trained on a few folds to better assess hyperparameters and number of epochs, before training the final model on the full dataset.</p>\n<p><strong>Post-processing</strong></p>\n<p>I spent a lot of time designing methods that would remove incomplete sheets. These incomplete sheets were often the verso of a sheet, so there was no interest in keeping them. I removed any connected components below 5000 pixels unless the connected components where close to the edges or corners. I analysed the training data and it appeared that some sheets could be as small as 300-400 pixels when located in a corner and I defined threshold based on this.\nI developed a method to detect whether a sheet was small due to it being in a corner (by touching both sides of a corner) or just incomplete. I also checked the main direction of the sheets to then remove incomplete sheets by looking at the size of their bounding boxes and if it goes to whole length of the image.\nI used the hysteresis post-processing function shared on a public notebook and changed the z-radius from 3 to 2 and the xy-radius from 2 to 1.</p>\n<table>\n<thead>\n<tr>\n<th>Methods</th>\n<th>Performance Boost</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Advanced object removal</td>\n<td>+0.002</td>\n</tr>\n<tr>\n<td>Incomplete sheet filtering</td>\n<td>+0.001</td>\n</tr>\n<tr>\n<td>Hysteresis radius 2-to-1</td>\n<td>+0.004</td>\n</tr>\n</tbody>\n</table>\n<p><strong>What did not work (for me)</strong></p>\n<ul>\n<li>I tried ensembling models relatively early and it did not seem to work well. Though it seems to give a boost when looking at my private leaderboard scores and other solutions. Probably my biggest regret there as I had several models to ensemble at the end!</li>\n<li>To my surprise, lower step size with the nnUNet did not work and seemed to detect more verso sheets.</li>\n<li>Apply move conservative threshold close to areas where 2 sheets merge. The merges were detected by detecting bifurcations in 2D (on all 3 axes).</li>\n<li>Vary the thresholds based on the Betti numbers, I only started playing with this idea in the last 2-3 days.</li>\n<li>Hole filling in individual connected components or with 2D approaches.</li>\n<li>Distance transform thinning.</li>\n<li>3D cascade nnUNet: I had actually trained a 3D cascade model but simply did not have time to create the inference pipeline, also because it was trained with my high-precision approach that did not work after the test set was fixed and the topo score was really taken into account.</li>\n</ul>\n<p><strong>Conclusion</strong></p>\n<p>It was a difficult competition due to the many changes and my teammate, Jirka, stopped contributing soon after the first dataset change. This was extremely unfortunate as I believe his notebooks had a great impact on the competition and I really wanted to work on this competition as a team. I am overall extremely happy with my final result and to see the wide variety in post-processing solutions and tricks used by everyone. Thank you for these crazy 3 (and a bonus half) months!</p>",
  "messages": [
    {
      "id": "3415237",
      "postDate": "02/28/2026 13:46:21",
      "content": "<p>Thank you to the organisers and other participants for providing such a challenge. I could not participate in previous Vesuvius Challenge competitions due to other commitments so it was amazing to finally have that change and learn so much about it, as well as 3D data in general. </p>\n<p><strong>A single model solution</strong></p>\n<p>Before the test data got corrected, my strategy was to focus on precision rather than recall as I could not figure out how to make the topo score improve on LB.\nOne thing that helped a little to experiment faster was to use the weights from the nnUNet trained on the \"old\" dataset as pretrained weights to all my models (though it was a bit of a headache when dealing with folds and ensuring there is no data leakage). I had a nnUNet with Tversky loss (alpha=0.7, beta=0.3 to focus on precision) and 160x160x160 patches.\nAfter the test set correction, I had to retrain my model using the Skeleton-Recall loss and it gave a +0.004 boost. It took more time than I expected as the threshold and the outputs were so different that it then behaved differently with the post-processing functions I had designed.\nAll models were first trained on a few folds to better assess hyperparameters and number of epochs, before training the final model on the full dataset.</p>\n<p><strong>Post-processing</strong></p>\n<p>I spent a lot of time designing methods that would remove incomplete sheets. These incomplete sheets were often the verso of a sheet, so there was no interest in keeping them. I removed any connected components below 5000 pixels unless the connected components where close to the edges or corners. I analysed the training data and it appeared that some sheets could be as small as 300-400 pixels when located in a corner and I defined threshold based on this.\nI developed a method to detect whether a sheet was small due to it being in a corner (by touching both sides of a corner) or just incomplete. I also checked the main direction of the sheets to then remove incomplete sheets by looking at the size of their bounding boxes and if it goes to whole length of the image.\nI used the hysteresis post-processing function shared on a public notebook and changed the z-radius from 3 to 2 and the xy-radius from 2 to 1.</p>\n<table>\n<thead>\n<tr>\n<th>Methods</th>\n<th>Performance Boost</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Advanced object removal</td>\n<td>+0.002</td>\n</tr>\n<tr>\n<td>Incomplete sheet filtering</td>\n<td>+0.001</td>\n</tr>\n<tr>\n<td>Hysteresis radius 2-to-1</td>\n<td>+0.004</td>\n</tr>\n</tbody>\n</table>\n<p><strong>What did not work (for me)</strong></p>\n<ul>\n<li>I tried ensembling models relatively early and it did not seem to work well. Though it seems to give a boost when looking at my private leaderboard scores and other solutions. Probably my biggest regret there as I had several models to ensemble at the end!</li>\n<li>To my surprise, lower step size with the nnUNet did not work and seemed to detect more verso sheets.</li>\n<li>Apply move conservative threshold close to areas where 2 sheets merge. The merges were detected by detecting bifurcations in 2D (on all 3 axes).</li>\n<li>Vary the thresholds based on the Betti numbers, I only started playing with this idea in the last 2-3 days.</li>\n<li>Hole filling in individual connected components or with 2D approaches.</li>\n<li>Distance transform thinning.</li>\n<li>3D cascade nnUNet: I had actually trained a 3D cascade model but simply did not have time to create the inference pipeline, also because it was trained with my high-precision approach that did not work after the test set was fixed and the topo score was really taken into account.</li>\n</ul>\n<p><strong>Conclusion</strong></p>\n<p>It was a difficult competition due to the many changes and my teammate, Jirka, stopped contributing soon after the first dataset change. This was extremely unfortunate as I believe his notebooks had a great impact on the competition and I really wanted to work on this competition as a team. I am overall extremely happy with my final result and to see the wide variety in post-processing solutions and tricks used by everyone. Thank you for these crazy 3 (and a bonus half) months!</p>",
      "rawMarkdown": "Thank you to the organisers and other participants for providing such a challenge. I could not participate in previous Vesuvius Challenge competitions due to other commitments so it was amazing to finally have that change and learn so much about it, as well as 3D data in general. \n\n\n**A single model solution**\n\nBefore the test data got corrected, my strategy was to focus on precision rather than recall as I could not figure out how to make the topo score improve on LB.\nOne thing that helped a little to experiment faster was to use the weights from the nnUNet trained on the \"old\" dataset as pretrained weights to all my models (though it was a bit of a headache when dealing with folds and ensuring there is no data leakage). I had a nnUNet with Tversky loss (alpha=0.7, beta=0.3 to focus on precision) and 160x160x160 patches.\nAfter the test set correction, I had to retrain my model using the Skeleton-Recall loss and it gave a +0.004 boost. It took more time than I expected as the threshold and the outputs were so different that it then behaved differently with the post-processing functions I had designed.\nAll models were first trained on a few folds to better assess hyperparameters and number of epochs, before training the final model on the full dataset.\n\n\n\n**Post-processing**\n\nI spent a lot of time designing methods that would remove incomplete sheets. These incomplete sheets were often the verso of a sheet, so there was no interest in keeping them. I removed any connected components below 5000 pixels unless the connected components where close to the edges or corners. I analysed the training data and it appeared that some sheets could be as small as 300-400 pixels when located in a corner and I defined threshold based on this.\nI developed a method to detect whether a sheet was small due to it being in a corner (by touching both sides of a corner) or just incomplete. I also checked the main direction of the sheets to then remove incomplete sheets by looking at the size of their bounding boxes and if it goes to whole length of the image.\nI used the hysteresis post-processing function shared on a public notebook and changed the z-radius from 3 to 2 and the xy-radius from 2 to 1.\n\n| Methods | Performance Boost |\n| --- | --- |\n| Advanced object removal | +0.002 |\n| Incomplete sheet filtering | +0.001 |\n| Hysteresis radius 2-to-1 | +0.004 |\n\n\n\n\n\n\n**What did not work (for me)**\n\n\n- I tried ensembling models relatively early and it did not seem to work well. Though it seems to give a boost when looking at my private leaderboard scores and other solutions. Probably my biggest regret there as I had several models to ensemble at the end!\n- To my surprise, lower step size with the nnUNet did not work and seemed to detect more verso sheets.\n- Apply move conservative threshold close to areas where 2 sheets merge. The merges were detected by detecting bifurcations in 2D (on all 3 axes).\n- Vary the thresholds based on the Betti numbers, I only started playing with this idea in the last 2-3 days.\n- Hole filling in individual connected components or with 2D approaches.\n- Distance transform thinning.\n- 3D cascade nnUNet: I had actually trained a 3D cascade model but simply did not have time to create the inference pipeline, also because it was trained with my high-precision approach that did not work after the test set was fixed and the topo score was really taken into account.\n\n\n**Conclusion**\n\n\nIt was a difficult competition due to the many changes and my teammate, Jirka, stopped contributing soon after the first dataset change. This was extremely unfortunate as I believe his notebooks had a great impact on the competition and I really wanted to work on this competition as a team. I am overall extremely happy with my final result and to see the wide variety in post-processing solutions and tricks used by everyone. Thank you for these crazy 3 (and a bonus half) months!",
      "votes": null
    },
    {
      "id": "3415271",
      "postDate": "02/28/2026 15:09:49",
      "content": "<p>Congrats on the result. It hard to do well when sharing everything as you (@jirkaborovec ) did. Your notebooks were a great starting point for someone like me who never did 3D segmentation (not even 2D segmentation really).</p>",
      "rawMarkdown": "Congrats on the result. It hard to do well when sharing everything as you (@jirkaborovec ) did. Your notebooks were a great starting point for someone like me who never did 3D segmentation (not even 2D segmentation really).",
      "votes": null
    },
    {
      "id": "3415308",
      "postDate": "02/28/2026 16:52:21",
      "content": "<p>I am really happy we could team up and hoped for top10, however my work and personal situation changed which made following contributions very challenging… So huge shutout to <a href=\"https://www.kaggle.com/frlemarchand\" target=\"_blank\">@frlemarchand</a>!</p>",
      "rawMarkdown": "I am really happy we could team up and hoped for top10, however my work and personal situation changed which made following contributions very challenging... So huge shutout to @frlemarchand!",
      "votes": null
    },
    {
      "id": "3415314",
      "postDate": "02/28/2026 17:05:17",
      "content": "<p>Thank you Jirka! \nLife always takes priority! You definitely should be proud to have made such a strong contribution early in this competition! </p>",
      "rawMarkdown": "Thank you Jirka! \nLife always takes priority! You definitely should be proud to have made such a strong contribution early in this competition!",
      "votes": null
    },
    {
      "id": "3415317",
      "postDate": "02/28/2026 17:09:47",
      "content": "<p>I truly admire the effort you put into the competition. Competing for a top spot while sharing a public solution isn’t easy, it takes real dedication and hard work. Wishing all the best to you and <a href=\"https://www.kaggle.com/frlemarchand\" target=\"_blank\">@frlemarchand</a> for next challenge.  </p>",
      "rawMarkdown": "I truly admire the effort you put into the competition. Competing for a top spot while sharing a public solution isn’t easy, it takes real dedication and hard work. Wishing all the best to you and @frlemarchand for next challenge.",
      "votes": null
    },
    {
      "id": "3415391",
      "postDate": "02/28/2026 20:32:42",
      "content": "<p>Congratulations Jirka and team. Thank you <a href=\"https://www.kaggle.com/jirkaborovec\" target=\"_blank\">@jirkaborovec</a> and <a href=\"https://www.kaggle.com/ipythonx\" target=\"_blank\">@ipythonx</a> for sharing great pipelines to help other kagglers get started. </p>",
      "rawMarkdown": "Congratulations Jirka and team. Thank you @jirkaborovec and @ipythonx for sharing great pipelines to help other kagglers get started.",
      "votes": null
    },
    {
      "id": "3415790",
      "postDate": "03/01/2026 10:52:11",
      "content": "<p><a href=\"https://www.kaggle.com/jirkaborovec\" target=\"_blank\">@jirkaborovec</a> this was my first time working on 3D segmentation, especially for a problem as complex as this one. Your notebooks were a huge help in getting started. Learnt a lot from all the detailed notebooks and the datasets that you shared throughout the competition. Thank you! Congratulations on your result!</p>",
      "rawMarkdown": "jirkaborovec this was my first time working on 3D segmentation, especially for a problem as complex as this one. Your notebooks were a huge help in getting started. Learnt a lot from all the detailed notebooks and the datasets that you shared throughout the competition. Thank you! Congratulations on your result!",
      "votes": null
    },
    {
      "id": "3416022",
      "postDate": "03/01/2026 21:03:51",
      "content": "<p>Congrats guys, very impressive work regardless of the dataset changes. I know you guys felt the pain of the changes as we did. Really sorry to see you guys slip out of gold with the final 2 weeks. The efforts you made no doubt made the competition more competitive. </p>",
      "rawMarkdown": "Congrats guys, very impressive work regardless of the dataset changes. I know you guys felt the pain of the changes as we did. Really sorry to see you guys slip out of gold with the final 2 weeks. The efforts you made no doubt made the competition more competitive.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3415271,
      "author_name": "cpmpml",
      "author_url": "",
      "post_date": "02/28/2026 15:09:49",
      "content": "<p>Congrats on the result. It hard to do well when sharing everything as you (@jirkaborovec ) did. Your notebooks were a great starting point for someone like me who never did 3D segmentation (not even 2D segmentation really).</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 3415308,
      "author_name": "jirkaborovec",
      "author_url": "",
      "post_date": "02/28/2026 16:52:21",
      "content": "<p>I am really happy we could team up and hoped for top10, however my work and personal situation changed which made following contributions very challenging… So huge shutout to <a href=\"https://www.kaggle.com/frlemarchand\" target=\"_blank\">@frlemarchand</a>!</p>",
      "votes": null,
      "replies": [
        {
          "id": 3415314,
          "author_name": "frlemarchand",
          "author_url": "",
          "post_date": "02/28/2026 17:05:17",
          "content": "<p>Thank you Jirka! \nLife always takes priority! You definitely should be proud to have made such a strong contribution early in this competition! </p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 3415317,
          "author_name": "ipythonx",
          "author_url": "",
          "post_date": "02/28/2026 17:09:47",
          "content": "<p>I truly admire the effort you put into the competition. Competing for a top spot while sharing a public solution isn’t easy, it takes real dedication and hard work. Wishing all the best to you and <a href=\"https://www.kaggle.com/frlemarchand\" target=\"_blank\">@frlemarchand</a> for next challenge.  </p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 3415391,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "02/28/2026 20:32:42",
          "content": "<p>Congratulations Jirka and team. Thank you <a href=\"https://www.kaggle.com/jirkaborovec\" target=\"_blank\">@jirkaborovec</a> and <a href=\"https://www.kaggle.com/ipythonx\" target=\"_blank\">@ipythonx</a> for sharing great pipelines to help other kagglers get started. </p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 3415790,
          "author_name": "mohanarc",
          "author_url": "",
          "post_date": "03/01/2026 10:52:11",
          "content": "<p><a href=\"https://www.kaggle.com/jirkaborovec\" target=\"_blank\">@jirkaborovec</a> this was my first time working on 3D segmentation, especially for a problem as complex as this one. Your notebooks were a huge help in getting started. Learnt a lot from all the detailed notebooks and the datasets that you shared throughout the competition. Thank you! Congratulations on your result!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 3416022,
      "author_name": "cody11null",
      "author_url": "",
      "post_date": "03/01/2026 21:03:51",
      "content": "<p>Congrats guys, very impressive work regardless of the dataset changes. I know you guys felt the pain of the changes as we did. Really sorry to see you guys slip out of gold with the final 2 weeks. The efforts you made no doubt made the competition more competitive. </p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3415237": "Thank you to the organisers and other participants for providing such a challenge. I could not participate in previous Vesuvius Challenge competitions due to other commitments so it was amazing to finally have that change and learn so much about it, as well as 3D data in general. \n\n\n**A single model solution**\n\nBefore the test data got corrected, my strategy was to focus on precision rather than recall as I could not figure out how to make the topo score improve on LB.\nOne thing that helped a little to experiment faster was to use the weights from the nnUNet trained on the \"old\" dataset as pretrained weights to all my models (though it was a bit of a headache when dealing with folds and ensuring there is no data leakage). I had a nnUNet with Tversky loss (alpha=0.7, beta=0.3 to focus on precision) and 160x160x160 patches.\nAfter the test set correction, I had to retrain my model using the Skeleton-Recall loss and it gave a +0.004 boost. It took more time than I expected as the threshold and the outputs were so different that it then behaved differently with the post-processing functions I had designed.\nAll models were first trained on a few folds to better assess hyperparameters and number of epochs, before training the final model on the full dataset.\n\n\n\n**Post-processing**\n\nI spent a lot of time designing methods that would remove incomplete sheets. These incomplete sheets were often the verso of a sheet, so there was no interest in keeping them. I removed any connected components below 5000 pixels unless the connected components where close to the edges or corners. I analysed the training data and it appeared that some sheets could be as small as 300-400 pixels when located in a corner and I defined threshold based on this.\nI developed a method to detect whether a sheet was small due to it being in a corner (by touching both sides of a corner) or just incomplete. I also checked the main direction of the sheets to then remove incomplete sheets by looking at the size of their bounding boxes and if it goes to whole length of the image.\nI used the hysteresis post-processing function shared on a public notebook and changed the z-radius from 3 to 2 and the xy-radius from 2 to 1.\n\n| Methods | Performance Boost |\n| --- | --- |\n| Advanced object removal | +0.002 |\n| Incomplete sheet filtering | +0.001 |\n| Hysteresis radius 2-to-1 | +0.004 |\n\n\n\n\n\n\n**What did not work (for me)**\n\n\n- I tried ensembling models relatively early and it did not seem to work well. Though it seems to give a boost when looking at my private leaderboard scores and other solutions. Probably my biggest regret there as I had several models to ensemble at the end!\n- To my surprise, lower step size with the nnUNet did not work and seemed to detect more verso sheets.\n- Apply move conservative threshold close to areas where 2 sheets merge. The merges were detected by detecting bifurcations in 2D (on all 3 axes).\n- Vary the thresholds based on the Betti numbers, I only started playing with this idea in the last 2-3 days.\n- Hole filling in individual connected components or with 2D approaches.\n- Distance transform thinning.\n- 3D cascade nnUNet: I had actually trained a 3D cascade model but simply did not have time to create the inference pipeline, also because it was trained with my high-precision approach that did not work after the test set was fixed and the topo score was really taken into account.\n\n\n**Conclusion**\n\n\nIt was a difficult competition due to the many changes and my teammate, Jirka, stopped contributing soon after the first dataset change. This was extremely unfortunate as I believe his notebooks had a great impact on the competition and I really wanted to work on this competition as a team. I am overall extremely happy with my final result and to see the wide variety in post-processing solutions and tricks used by everyone. Thank you for these crazy 3 (and a bonus half) months!",
    "3415271": "Congrats on the result. It hard to do well when sharing everything as you (@jirkaborovec ) did. Your notebooks were a great starting point for someone like me who never did 3D segmentation (not even 2D segmentation really).",
    "3415308": "I am really happy we could team up and hoped for top10, however my work and personal situation changed which made following contributions very challenging... So huge shutout to @frlemarchand!",
    "3415314": "Thank you Jirka! \nLife always takes priority! You definitely should be proud to have made such a strong contribution early in this competition!",
    "3415317": "I truly admire the effort you put into the competition. Competing for a top spot while sharing a public solution isn’t easy, it takes real dedication and hard work. Wishing all the best to you and @frlemarchand for next challenge.",
    "3415391": "Congratulations Jirka and team. Thank you @jirkaborovec and @ipythonx for sharing great pipelines to help other kagglers get started.",
    "3415790": "jirkaborovec this was my first time working on 3D segmentation, especially for a problem as complex as this one. Your notebooks were a huge help in getting started. Learnt a lot from all the detailed notebooks and the datasets that you shared throughout the competition. Thank you! Congratulations on your result!",
    "3416022": "Congrats guys, very impressive work regardless of the dataset changes. I know you guys felt the pain of the changes as we did. Really sorry to see you guys slip out of gold with the final 2 weeks. The efforts you made no doubt made the competition more competitive."
  },
  "source": "meta"
}