{
  "id": 354851,
  "title": "4th place solution: Stain Normalization is all you need",
  "url": "/competitions/hubmap-organ-segmentation/writeups/rock-4th-place-solution-stain-normalization-is-all",
  "author_name": "",
  "post_date": "2022-09-25T03:23:05.487Z",
  "votes": 50,
  "comment_count": 12,
  "views": 0,
  "content": "<p>First, we'll thank organizers for their effort in this amazing competation. And then, we will thank <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> , we learnt a lot from your code and notebook.</p>\n<p>This is my second competation in kaggle, and my first competation on image segmentation, I learnt a lot from this, thanks all of you.</p>\n<p>In this competation, we mainly rely on two-stream model and some tricks on models ensemble and stain normalization at infernce, without using any pseudo label or ext data, maybe that's why we missed prize hahaha :)</p>\n<h2>Models</h2>\n<p>At first, we followed the code share by <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> that's an amazing baseline code. Besides, in our experience, we found that the knowledge learned from other organs may influence the performance in lung images, so we proposed two-stream model, one stream for lung images and the other model for other organs. And then we tried some other encoders and decoders, and the final ensemble models are shown as follows:</p>\n<ul>\n<li>Encoder: Coat-lite-medium; Decoder: daformer+unet</li>\n<li>Encoder: mit (Segformer); Decoder: daformer+unet</li>\n<li>Encoder: mpvit; Decoder: daformer+unet</li>\n</ul>\n<h2>Stain Normalization</h2>\n<p>That's the most import part in our training and inference step, for we think the biggest challenge in this competation is how to bridge the gap between HPA and HuBMAP images. The methods we used for stain normalization are from Staintools.</p>\n<h3>Train</h3>\n<p>First, in training step, we normalize the HPA image to the only one HuBMAP test image by using reinhard and vahadane normalization randomly. So that the model can study both features in HPA feature space and HuBMAP feature space.</p>\n<h3>Inference</h3>\n<p>However, just using stain normalization in training step is not enough, for stain normalization still can't transfer feature space perfectly, we also need using stain normalization in inference step for better bridging the gap between two datasets.</p>\n<p>In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to HPA images according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.</p>\n<p>The final codes will be released after a few days, thanks for reading!</p>",
  "messages": [
    {
      "id": "1953143",
      "postDate": "09/24/2022 08:36:23",
      "content": "<p>First, we'll thank organizers for their effort in this amazing competation. And then, we will thank <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> , we learnt a lot from your code and notebook.</p>\n<p>This is my second competation in kaggle, and my first competation on image segmentation, I learnt a lot from this, thanks all of you.</p>\n<p>In this competation, we mainly rely on two-stream model and some tricks on models ensemble and stain normalization at infernce, without using any pseudo label or ext data, maybe that's why we missed prize hahaha :)</p>\n<h2>Models</h2>\n<p>At first, we followed the code share by <a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> that's an amazing baseline code. Besides, in our experience, we found that the knowledge learned from other organs may influence the performance in lung images, so we proposed two-stream model, one stream for lung images and the other model for other organs. And then we tried some other encoders and decoders, and the final ensemble models are shown as follows:</p>\n<ul>\n<li>Encoder: Coat-lite-medium; Decoder: daformer+unet</li>\n<li>Encoder: mit (Segformer); Decoder: daformer+unet</li>\n<li>Encoder: mpvit; Decoder: daformer+unet</li>\n</ul>\n<h2>Stain Normalization</h2>\n<p>That's the most import part in our training and inference step, for we think the biggest challenge in this competation is how to bridge the gap between HPA and HuBMAP images. The methods we used for stain normalization are from Staintools.</p>\n<h3>Train</h3>\n<p>First, in training step, we normalize the HPA image to the only one HuBMAP test image by using reinhard and vahadane normalization randomly. So that the model can study both features in HPA feature space and HuBMAP feature space.</p>\n<h3>Inference</h3>\n<p>However, just using stain normalization in training step is not enough, for stain normalization still can't transfer feature space perfectly, we also need using stain normalization in inference step for better bridging the gap between two datasets.</p>\n<p>In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to HPA images according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.</p>\n<p>The final codes will be released after a few days, thanks for reading!</p>",
      "rawMarkdown": "First, we'll thank organizers for their effort in this amazing competation. And then, we will thank @hengck23 , we learnt a lot from your code and notebook.\n\nThis is my second competation in kaggle, and my first competation on image segmentation, I learnt a lot from this, thanks all of you.\n\nIn this competation, we mainly rely on two-stream model and some tricks on models ensemble and stain normalization at infernce, without using any pseudo label or ext data, maybe that's why we missed prize hahaha :)\n\n## Models\n\nAt first, we followed the code share by @hengck23 that's an amazing baseline code. Besides, in our experience, we found that the knowledge learned from other organs may influence the performance in lung images, so we proposed two-stream model, one stream for lung images and the other model for other organs. And then we tried some other encoders and decoders, and the final ensemble models are shown as follows:\n\n- Encoder: Coat-lite-medium; Decoder: daformer+unet\n- Encoder: mit (Segformer); Decoder: daformer+unet\n- Encoder: mpvit; Decoder: daformer+unet\n\n## Stain Normalization\n\nThat's the most import part in our training and inference step, for we think the biggest challenge in this competation is how to bridge the gap between HPA and HuBMAP images. The methods we used for stain normalization are from Staintools.\n\n### Train\n\nFirst, in training step, we normalize the HPA image to the only one HuBMAP test image by using reinhard and vahadane normalization randomly. So that the model can study both features in HPA feature space and HuBMAP feature space.\n\n### Inference\n\nHowever, just using stain normalization in training step is not enough, for stain normalization still can't transfer feature space perfectly, we also need using stain normalization in inference step for better bridging the gap between two datasets.\n\nIn inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to HPA images according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.\n\nThe final codes will be released after a few days, thanks for reading!",
      "votes": null
    },
    {
      "id": "1953173",
      "postDate": "09/24/2022 09:20:11",
      "content": "<p>Congrats! I also did something similar. At test time, I was selecting a random HPA image with same organ type and normalizing HuBMAP image using that randomly selected image. This was implemented as a test-time augmentation and it gave me 0.01 boost on public leaderboard.</p>",
      "rawMarkdown": "Congrats! I also did something similar. At test time, I was selecting a random HPA image with same organ type and normalizing HuBMAP image using that randomly selected image. This was implemented as a test-time augmentation and it gave me 0.01 boost on public leaderboard.",
      "votes": null
    },
    {
      "id": "1953913",
      "postDate": "09/24/2022 20:56:59",
      "content": "<p>Curious if there are 5 people in your team, why is it all <strong>I</strong> and <strong>my</strong>?</p>",
      "rawMarkdown": "Curious if there are 5 people in your team, why is it all **I** and **my**?",
      "votes": null
    },
    {
      "id": "1954080",
      "postDate": "09/25/2022 02:21:28",
      "content": "<p>Sorry for the clerical error, I wrote it too hasty and didn't notice it, thanks for pointing.</p>",
      "rawMarkdown": "Sorry for the clerical error, I wrote it too hasty and didn't notice it, thanks for pointing.",
      "votes": null
    },
    {
      "id": "1954102",
      "postDate": "09/25/2022 03:03:52",
      "content": "<p>The trick is you can register new kaggle accounts and add up submission times</p>",
      "rawMarkdown": "The trick is you can register new kaggle accounts and add up submission times",
      "votes": null
    },
    {
      "id": "1954109",
      "postDate": "09/25/2022 03:17:26",
      "content": "<p>My teammates are all my classmates who want to take participate in deep learning competation and learn knowledge from it, I cannot achieve this without them, and you can see that our submission times is not too much :)</p>",
      "rawMarkdown": "My teammates are all my classmates who want to take participate in deep learning competation and learn knowledge from it, I cannot achieve this without them, and you can see that our submission times is not too much :)",
      "votes": null
    },
    {
      "id": "1956431",
      "postDate": "09/26/2022 13:02:59",
      "content": "<p>How did you perform Stain Normalization?</p>",
      "rawMarkdown": "How did you perform Stain Normalization?",
      "votes": null
    },
    {
      "id": "1957492",
      "postDate": "09/27/2022 02:43:31",
      "content": "<p>I just use staintools.<a href=\"url\" target=\"_blank\">https://github.com/Peter554/StainTools</a></p>",
      "rawMarkdown": "I just use staintools.[https://github.com/Peter554/StainTools](url)",
      "votes": null
    },
    {
      "id": "1961041",
      "postDate": "09/29/2022 01:00:49",
      "content": "<p>Congratulations! Amazing that you could achieve all this without external data.</p>",
      "rawMarkdown": "Congratulations! Amazing that you could achieve all this without external data.",
      "votes": null
    },
    {
      "id": "1961072",
      "postDate": "09/29/2022 01:55:22",
      "content": "<p>Thank you!</p>",
      "rawMarkdown": "Thank you!",
      "votes": null
    },
    {
      "id": "1972178",
      "postDate": "10/05/2022 03:30:50",
      "content": "<p>Thank you for sharing your wonderful solution!!</p>\n<p>you mentioned that you normalized all HubMAP images to training HPA images for five organs respectively at inference step.<br>\nAre these HPA images processed with reinhard and vahadane normalization by using the only one HubMAP test image?</p>\n<blockquote>\n  <p>In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to <strong>HPA images</strong> according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.</p>\n</blockquote>\n<p>And how did you handle with resolution problem?<br>\nResolution are also different in HPA and HubMAP.</p>",
      "rawMarkdown": "Thank you for sharing your wonderful solution!!\n\nyou mentioned that you normalized all HubMAP images to training HPA images for five organs respectively at inference step.\nAre these HPA images processed with reinhard and vahadane normalization by using the only one HubMAP test image?\n\n> In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to **HPA images** according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.\n\nAnd how did you handle with resolution problem?\nResolution are also different in HPA and HubMAP.",
      "votes": null
    },
    {
      "id": "1977568",
      "postDate": "10/08/2022 05:19:30",
      "content": "<p>Yes, I just use the only one HuBMAP test image for normalization.<br>\nFor resolution, I just resize these images to a fixed size, for example 1024x1024.</p>",
      "rawMarkdown": "Yes, I just use the only one HuBMAP test image for normalization.\nFor resolution, I just resize these images to a fixed size, for example 1024x1024.",
      "votes": null
    },
    {
      "id": "2016365",
      "postDate": "11/04/2022 00:20:38",
      "content": "<p>Thanks for sharing that! <br>\nAny refernces for explaining?</p>",
      "rawMarkdown": "Thanks for sharing that! \nAny refernces for explaining?",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 1953173,
      "author_name": "gunesevitan",
      "author_url": "",
      "post_date": "09/24/2022 09:20:11",
      "content": "<p>Congrats! I also did something similar. At test time, I was selecting a random HPA image with same organ type and normalizing HuBMAP image using that randomly selected image. This was implemented as a test-time augmentation and it gave me 0.01 boost on public leaderboard.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 1953913,
      "author_name": "julianmukaj",
      "author_url": "",
      "post_date": "09/24/2022 20:56:59",
      "content": "<p>Curious if there are 5 people in your team, why is it all <strong>I</strong> and <strong>my</strong>?</p>",
      "votes": null,
      "replies": [
        {
          "id": 1954080,
          "author_name": "rock139",
          "author_url": "",
          "post_date": "09/25/2022 02:21:28",
          "content": "<p>Sorry for the clerical error, I wrote it too hasty and didn't notice it, thanks for pointing.</p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 1954102,
          "author_name": "lililycai",
          "author_url": "",
          "post_date": "09/25/2022 03:03:52",
          "content": "<p>The trick is you can register new kaggle accounts and add up submission times</p>",
          "votes": null,
          "replies": []
        },
        {
          "id": 1954109,
          "author_name": "rock139",
          "author_url": "",
          "post_date": "09/25/2022 03:17:26",
          "content": "<p>My teammates are all my classmates who want to take participate in deep learning competation and learn knowledge from it, I cannot achieve this without them, and you can see that our submission times is not too much :)</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 1956431,
      "author_name": "salmanahmedtamu",
      "author_url": "",
      "post_date": "09/26/2022 13:02:59",
      "content": "<p>How did you perform Stain Normalization?</p>",
      "votes": null,
      "replies": [
        {
          "id": 1957492,
          "author_name": "rock139",
          "author_url": "",
          "post_date": "09/27/2022 02:43:31",
          "content": "<p>I just use staintools.<a href=\"url\" target=\"_blank\">https://github.com/Peter554/StainTools</a></p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 1961041,
      "author_name": "miroslavln",
      "author_url": "",
      "post_date": "09/29/2022 01:00:49",
      "content": "<p>Congratulations! Amazing that you could achieve all this without external data.</p>",
      "votes": null,
      "replies": [
        {
          "id": 1961072,
          "author_name": "rock139",
          "author_url": "",
          "post_date": "09/29/2022 01:55:22",
          "content": "<p>Thank you!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 1972178,
      "author_name": "yoshoo",
      "author_url": "",
      "post_date": "10/05/2022 03:30:50",
      "content": "<p>Thank you for sharing your wonderful solution!!</p>\n<p>you mentioned that you normalized all HubMAP images to training HPA images for five organs respectively at inference step.<br>\nAre these HPA images processed with reinhard and vahadane normalization by using the only one HubMAP test image?</p>\n<blockquote>\n  <p>In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to <strong>HPA images</strong> according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.</p>\n</blockquote>\n<p>And how did you handle with resolution problem?<br>\nResolution are also different in HPA and HubMAP.</p>",
      "votes": null,
      "replies": [
        {
          "id": 1977568,
          "author_name": "rock139",
          "author_url": "",
          "post_date": "10/08/2022 05:19:30",
          "content": "<p>Yes, I just use the only one HuBMAP test image for normalization.<br>\nFor resolution, I just resize these images to a fixed size, for example 1024x1024.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2016365,
      "author_name": "rahmasamy",
      "author_url": "",
      "post_date": "11/04/2022 00:20:38",
      "content": "<p>Thanks for sharing that! <br>\nAny refernces for explaining?</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1953143": "First, we'll thank organizers for their effort in this amazing competation. And then, we will thank @hengck23 , we learnt a lot from your code and notebook.\n\nThis is my second competation in kaggle, and my first competation on image segmentation, I learnt a lot from this, thanks all of you.\n\nIn this competation, we mainly rely on two-stream model and some tricks on models ensemble and stain normalization at infernce, without using any pseudo label or ext data, maybe that's why we missed prize hahaha :)\n\n## Models\n\nAt first, we followed the code share by @hengck23 that's an amazing baseline code. Besides, in our experience, we found that the knowledge learned from other organs may influence the performance in lung images, so we proposed two-stream model, one stream for lung images and the other model for other organs. And then we tried some other encoders and decoders, and the final ensemble models are shown as follows:\n\n- Encoder: Coat-lite-medium; Decoder: daformer+unet\n- Encoder: mit (Segformer); Decoder: daformer+unet\n- Encoder: mpvit; Decoder: daformer+unet\n\n## Stain Normalization\n\nThat's the most import part in our training and inference step, for we think the biggest challenge in this competation is how to bridge the gap between HPA and HuBMAP images. The methods we used for stain normalization are from Staintools.\n\n### Train\n\nFirst, in training step, we normalize the HPA image to the only one HuBMAP test image by using reinhard and vahadane normalization randomly. So that the model can study both features in HPA feature space and HuBMAP feature space.\n\n### Inference\n\nHowever, just using stain normalization in training step is not enough, for stain normalization still can't transfer feature space perfectly, we also need using stain normalization in inference step for better bridging the gap between two datasets.\n\nIn inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to HPA images according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.\n\nThe final codes will be released after a few days, thanks for reading!",
    "1953173": "Congrats! I also did something similar. At test time, I was selecting a random HPA image with same organ type and normalizing HuBMAP image using that randomly selected image. This was implemented as a test-time augmentation and it gave me 0.01 boost on public leaderboard.",
    "1953913": "Curious if there are 5 people in your team, why is it all **I** and **my**?",
    "1954080": "Sorry for the clerical error, I wrote it too hasty and didn't notice it, thanks for pointing.",
    "1954102": "The trick is you can register new kaggle accounts and add up submission times",
    "1954109": "My teammates are all my classmates who want to take participate in deep learning competation and learn knowledge from it, I cannot achieve this without them, and you can see that our submission times is not too much :)",
    "1956431": "How did you perform Stain Normalization?",
    "1957492": "I just use staintools.[https://github.com/Peter554/StainTools](url)",
    "1961041": "Congratulations! Amazing that you could achieve all this without external data.",
    "1961072": "Thank you!",
    "1972178": "Thank you for sharing your wonderful solution!!\n\nyou mentioned that you normalized all HubMAP images to training HPA images for five organs respectively at inference step.\nAre these HPA images processed with reinhard and vahadane normalization by using the only one HubMAP test image?\n\n> In inference step, we select a representive image from training images for five organs respectively. And for all of HuBMAP images, we normalized them to **HPA images** according to their organ labels by using vahadane and reinhard methods, and then average their predictions to get the final predicted mask.\n\nAnd how did you handle with resolution problem?\nResolution are also different in HPA and HubMAP.",
    "1977568": "Yes, I just use the only one HuBMAP test image for normalization.\nFor resolution, I just resize these images to a fixed size, for example 1024x1024.",
    "2016365": "Thanks for sharing that! \nAny refernces for explaining?"
  },
  "source": "meta"
}