{
  "id": 354701,
  "title": "11th place solution",
  "url": "/competitions/hubmap-organ-segmentation/discussion/354701",
  "author_name": "D.Imanishi",
  "post_date": "2022-09-23T11:51:08.766000",
  "votes": 36,
  "comment_count": 7,
  "views": 0,
  "content": "<p>Thanks to the organizers and congrats to all the winners!</p>\n<h3>Overview</h3>\n<p>In this competition, since CV based on the HPA labelled data is not reliable for the private LB score improvement, I made as many submissions as possible to confirm the effectiveness of my experiments by the Hubmap only LB score. Finally, the following three points were the key item of my solution.</p>\n<ul>\n<li>Use GTEx data</li>\n<li>Ensemble and TTA as many as possible (12 models x 20 TTAs)</li>\n<li>Post-process</li>\n</ul>\n<h3>Models</h3>\n<p>Total 12 models were used for ensemble.</p>\n<ul>\n<li>EfficientNet B4/B5/B6/B7 - Unet</li>\n<li>EfficientNetV2 S/M/L - Unet</li>\n<li>ConvNeXt T/S/B - DeeplabV3+</li>\n<li>Swin B/L - Unet</li>\n</ul>\n<h3>Training</h3>\n<ul>\n<li>Data were resized to x0.25 scale (for GTEx data, after rescaled to 0.4 um pixel size) and random cropped to 512x512 size</li>\n<li>120 epochs</li>\n<li>Loss: BCE loss + Dice loss</li>\n<li>Optimizer: Adam</li>\n<li>LR schedule: Cosine decay with warmup</li>\n<li>Augmentation stronger than usual competitons was used</li>\n<li>ImageNet pretrained backbone</li>\n<li>Trained on TPU of Kaggle kernel or Colab Pro</li>\n<li>All models were trained with TensorFlow</li>\n<li>All data were used for training (Not using kFold-CV)</li>\n</ul>\n<h3>External data</h3>\n<p>I downloaded external data from GTEx Portal, and made the pseudo labels of them. Since the GTEx .svs images have too large resolution, they were cropped as tile before making the pseudo labels. If the pseudo label's mask area was too small or there was no mask, this tile was excluded. The pseudo labels were manually checked and modified or removed if it was obviously wrong. These data were used for training by mixing with the original labeled data. Finally, total 650 tiles from 40 samples were used for training. It improved my Hubmap only LB score ~0.02.</p>\n<h3>TTA</h3>\n<p>Although I could use maximum 8 combination patterns, I reduced them to four because of the 9 hours run-time limitation. The scales were chosen based on x0.25 training scale.</p>\n<ul>\n<li>5 scales x 4 patterns = 20 TTAs per model</li>\n<li>5 scales: 0.19, 0.21, 0.23, 0.25, 0.28</li>\n<li>4 patterns: original, lr-flip, ud-flip, rot90</li>\n</ul>\n<h3>Post-process</h3>\n<p>Although there is no clear evidence, especially for \"spleen\" and \"lung\", the boundary of the masks is fuzzy, so I tried to enlarge or shrink the masks and confirmed the effect in LB score. As a result, shrinking spleen and lung prediction masks improved my LB score. I did not include post-processing in one of the final submissions because I thought there was a possibility of overfitting to the public data. However, the resulting private LB score was better if I include the post-processing. The post-processing was impremented as following code.</p>\n<pre><code>SHRINK = {'spleen': 10, 'lung': 10}\n\ndef post_proc(preds, organ):\n    # preds: predicted mask after binarization\n\n    if organ in SHRINK.keys():\n        contours, _ = cv2.findContours(preds, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n        preds = preds.astype(np.int8)\n        preds_cont = np.zeros_like(preds)\n        preds_cont = cv2.drawContours(preds_cont, contours, -1, 1, SHRINK[organ]*2)\n        preds = (preds - preds_cont).clip(0, 1).astype(np.uint8)\n    return preds\n</code></pre>",
  "messages": [
    {
      "id": 1952033,
      "postDate": "2022-09-23T11:51:08.767Z",
      "content": "<p>Thanks to the organizers and congrats to all the winners!</p>\n<h3>Overview</h3>\n<p>In this competition, since CV based on the HPA labelled data is not reliable for the private LB score improvement, I made as many submissions as possible to confirm the effectiveness of my experiments by the Hubmap only LB score. Finally, the following three points were the key item of my solution.</p>\n<ul>\n<li>Use GTEx data</li>\n<li>Ensemble and TTA as many as possible (12 models x 20 TTAs)</li>\n<li>Post-process</li>\n</ul>\n<h3>Models</h3>\n<p>Total 12 models were used for ensemble.</p>\n<ul>\n<li>EfficientNet B4/B5/B6/B7 - Unet</li>\n<li>EfficientNetV2 S/M/L - Unet</li>\n<li>ConvNeXt T/S/B - DeeplabV3+</li>\n<li>Swin B/L - Unet</li>\n</ul>\n<h3>Training</h3>\n<ul>\n<li>Data were resized to x0.25 scale (for GTEx data, after rescaled to 0.4 um pixel size) and random cropped to 512x512 size</li>\n<li>120 epochs</li>\n<li>Loss: BCE loss + Dice loss</li>\n<li>Optimizer: Adam</li>\n<li>LR schedule: Cosine decay with warmup</li>\n<li>Augmentation stronger than usual competitons was used</li>\n<li>ImageNet pretrained backbone</li>\n<li>Trained on TPU of Kaggle kernel or Colab Pro</li>\n<li>All models were trained with TensorFlow</li>\n<li>All data were used for training (Not using kFold-CV)</li>\n</ul>\n<h3>External data</h3>\n<p>I downloaded external data from GTEx Portal, and made the pseudo labels of them. Since the GTEx .svs images have too large resolution, they were cropped as tile before making the pseudo labels. If the pseudo label's mask area was too small or there was no mask, this tile was excluded. The pseudo labels were manually checked and modified or removed if it was obviously wrong. These data were used for training by mixing with the original labeled data. Finally, total 650 tiles from 40 samples were used for training. It improved my Hubmap only LB score ~0.02.</p>\n<h3>TTA</h3>\n<p>Although I could use maximum 8 combination patterns, I reduced them to four because of the 9 hours run-time limitation. The scales were chosen based on x0.25 training scale.</p>\n<ul>\n<li>5 scales x 4 patterns = 20 TTAs per model</li>\n<li>5 scales: 0.19, 0.21, 0.23, 0.25, 0.28</li>\n<li>4 patterns: original, lr-flip, ud-flip, rot90</li>\n</ul>\n<h3>Post-process</h3>\n<p>Although there is no clear evidence, especially for \"spleen\" and \"lung\", the boundary of the masks is fuzzy, so I tried to enlarge or shrink the masks and confirmed the effect in LB score. As a result, shrinking spleen and lung prediction masks improved my LB score. I did not include post-processing in one of the final submissions because I thought there was a possibility of overfitting to the public data. However, the resulting private LB score was better if I include the post-processing. The post-processing was impremented as following code.</p>\n<pre><code>SHRINK = {'spleen': 10, 'lung': 10}\n\ndef post_proc(preds, organ):\n    # preds: predicted mask after binarization\n\n    if organ in SHRINK.keys():\n        contours, _ = cv2.findContours(preds, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n        preds = preds.astype(np.int8)\n        preds_cont = np.zeros_like(preds)\n        preds_cont = cv2.drawContours(preds_cont, contours, -1, 1, SHRINK[organ]*2)\n        preds = (preds - preds_cont).clip(0, 1).astype(np.uint8)\n    return preds\n</code></pre>",
      "rawMarkdown": "Thanks to the organizers and congrats to all the winners!\n\n### Overview\nIn this competition, since CV based on the HPA labelled data is not reliable for the private LB score improvement, I made as many submissions as possible to confirm the effectiveness of my experiments by the Hubmap only LB score. Finally, the following three points were the key item of my solution.\n- Use GTEx data\n- Ensemble and TTA as many as possible (12 models x 20 TTAs)\n- Post-process\n\n### Models\nTotal 12 models were used for ensemble.\n- EfficientNet B4/B5/B6/B7 - Unet\n- EfficientNetV2 S/M/L - Unet\n- ConvNeXt T/S/B - DeeplabV3+\n- Swin B/L - Unet\n\n### Training\n- Data were resized to x0.25 scale (for GTEx data, after rescaled to 0.4 um pixel size) and random cropped to 512x512 size\n- 120 epochs\n- Loss: BCE loss + Dice loss\n- Optimizer: Adam\n- LR schedule: Cosine decay with warmup\n- Augmentation stronger than usual competitons was used\n- ImageNet pretrained backbone\n- Trained on TPU of Kaggle kernel or Colab Pro\n- All models were trained with TensorFlow\n- All data were used for training (Not using kFold-CV)\n\n### External data\nI downloaded external data from GTEx Portal, and made the pseudo labels of them. Since the GTEx .svs images have too large resolution, they were cropped as tile before making the pseudo labels. If the pseudo label's mask area was too small or there was no mask, this tile was excluded. The pseudo labels were manually checked and modified or removed if it was obviously wrong. These data were used for training by mixing with the original labeled data. Finally, total 650 tiles from 40 samples were used for training. It improved my Hubmap only LB score ~0.02.\n\n### TTA\nAlthough I could use maximum 8 combination patterns, I reduced them to four because of the 9 hours run-time limitation. The scales were chosen based on x0.25 training scale.\n- 5 scales x 4 patterns = 20 TTAs per model\n- 5 scales: 0.19, 0.21, 0.23, 0.25, 0.28\n- 4 patterns: original, lr-flip, ud-flip, rot90\n\n### Post-process\nAlthough there is no clear evidence, especially for \"spleen\" and \"lung\", the boundary of the masks is fuzzy, so I tried to enlarge or shrink the masks and confirmed the effect in LB score. As a result, shrinking spleen and lung prediction masks improved my LB score. I did not include post-processing in one of the final submissions because I thought there was a possibility of overfitting to the public data. However, the resulting private LB score was better if I include the post-processing. The post-processing was impremented as following code.\n\n```\nSHRINK = {'spleen': 10, 'lung': 10}\n\ndef post_proc(preds, organ):\n    # preds: predicted mask after binarization\n    \n    if organ in SHRINK.keys():\n        contours, _ = cv2.findContours(preds, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n        preds = preds.astype(np.int8)\n        preds_cont = np.zeros_like(preds)\n        preds_cont = cv2.drawContours(preds_cont, contours, -1, 1, SHRINK[organ]*2)\n        preds = (preds - preds_cont).clip(0, 1).astype(np.uint8)\n    return preds\n```\n",
      "votes": 36
    },
    {
      "id": 1954184,
      "postDate": "2022-09-25T04:43:47.663Z",
      "content": "<p>This is really helpful.</p>",
      "rawMarkdown": "This is really helpful.",
      "votes": 1
    },
    {
      "id": 1952439,
      "postDate": "2022-09-23T17:04:20.157Z",
      "content": "<p>congo keep it</p>",
      "rawMarkdown": "congo keep it",
      "votes": 1
    },
    {
      "id": 1952177,
      "postDate": "2022-09-23T13:37:33.840Z",
      "content": "<p>Hearty congratulations for the result, this is a great approach and a good learning for me <a href=\"https://www.kaggle.com/dimanishi\" target=\"_blank\">@dimanishi</a>!<br>\nThanks for sharing the approach!</p>",
      "rawMarkdown": "Hearty congratulations for the result, this is a great approach and a good learning for me @dimanishi!\nThanks for sharing the approach!",
      "votes": 1
    },
    {
      "id": 1972207,
      "postDate": "2022-10-05T04:00:05.003Z",
      "content": "<p>Conguraturation!</p>\n<p>How did you handle with resolution difference between HPA and HubMAP?<br>\nDid you get this result without caring about the resolution domain gap?</p>",
      "rawMarkdown": "Conguraturation!\n\nHow did you handle with resolution difference between HPA and HubMAP?\nDid you get this result without caring about the resolution domain gap?"
    },
    {
      "id": 1952412,
      "postDate": "2022-09-23T16:45:23.523Z",
      "content": "<p>How to use different loss? On differnet models?  </p>",
      "rawMarkdown": "How to use different loss? On differnet models?  ",
      "replies": [
        {
          "id": 1952831,
          "postDate": "2022-09-24T01:35:46.230Z",
          "content": "<p>I used <a href=\"https://github.com/qubvel/segmentation_models\" target=\"_blank\">this repository</a> and all the model's loss were configured like the following code (TensorFlow code).</p>\n<pre><code>model.compile(\n    loss=sm.losses.bce_dice_loss,\n)\n</code></pre>",
          "rawMarkdown": "I used [this repository](https://github.com/qubvel/segmentation_models) and all the model's loss were configured like the following code (TensorFlow code).\n```\nmodel.compile(\n    loss=sm.losses.bce_dice_loss,\n)\n```"
        }
      ]
    },
    {
      "id": 1952320,
      "postDate": "2022-09-23T15:08:33.803Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 1954184,
      "author_name": "Muhammad Abdullah",
      "author_url": "",
      "post_date": "2022-09-25T04:43:47.663000",
      "content": "<p>This is really helpful.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1952439,
      "author_name": "Rahul Prasad M.",
      "author_url": "",
      "post_date": "2022-09-23T17:04:20.157000",
      "content": "<p>congo keep it</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1952177,
      "author_name": "Ravi Ramakrishnan",
      "author_url": "",
      "post_date": "2022-09-23T13:37:33.840000",
      "content": "<p>Hearty congratulations for the result, this is a great approach and a good learning for me <a href=\"https://www.kaggle.com/dimanishi\" target=\"_blank\">@dimanishi</a>!<br>\nThanks for sharing the approach!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1972207,
      "author_name": "yoshoo",
      "author_url": "",
      "post_date": "2022-10-05T04:00:05.003000",
      "content": "<p>Conguraturation!</p>\n<p>How did you handle with resolution difference between HPA and HubMAP?<br>\nDid you get this result without caring about the resolution domain gap?</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1952412,
      "author_name": "Chinartist",
      "author_url": "",
      "post_date": "2022-09-23T16:45:23.523000",
      "content": "<p>How to use different loss? On differnet models?  </p>",
      "votes": 0,
      "replies": [
        {
          "id": 1952831,
          "author_name": "D.Imanishi",
          "author_url": "",
          "post_date": "2022-09-24T01:35:46.230000",
          "content": "<p>I used <a href=\"https://github.com/qubvel/segmentation_models\" target=\"_blank\">this repository</a> and all the model's loss were configured like the following code (TensorFlow code).</p>\n<pre><code>model.compile(\n    loss=sm.losses.bce_dice_loss,\n)\n</code></pre>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1952320,
      "author_name": "",
      "author_url": "",
      "post_date": "2022-09-23T15:08:33.803000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1952033": "Thanks to the organizers and congrats to all the winners!\n\n### Overview\nIn this competition, since CV based on the HPA labelled data is not reliable for the private LB score improvement, I made as many submissions as possible to confirm the effectiveness of my experiments by the Hubmap only LB score. Finally, the following three points were the key item of my solution.\n- Use GTEx data\n- Ensemble and TTA as many as possible (12 models x 20 TTAs)\n- Post-process\n\n### Models\nTotal 12 models were used for ensemble.\n- EfficientNet B4/B5/B6/B7 - Unet\n- EfficientNetV2 S/M/L - Unet\n- ConvNeXt T/S/B - DeeplabV3+\n- Swin B/L - Unet\n\n### Training\n- Data were resized to x0.25 scale (for GTEx data, after rescaled to 0.4 um pixel size) and random cropped to 512x512 size\n- 120 epochs\n- Loss: BCE loss + Dice loss\n- Optimizer: Adam\n- LR schedule: Cosine decay with warmup\n- Augmentation stronger than usual competitons was used\n- ImageNet pretrained backbone\n- Trained on TPU of Kaggle kernel or Colab Pro\n- All models were trained with TensorFlow\n- All data were used for training (Not using kFold-CV)\n\n### External data\nI downloaded external data from GTEx Portal, and made the pseudo labels of them. Since the GTEx .svs images have too large resolution, they were cropped as tile before making the pseudo labels. If the pseudo label's mask area was too small or there was no mask, this tile was excluded. The pseudo labels were manually checked and modified or removed if it was obviously wrong. These data were used for training by mixing with the original labeled data. Finally, total 650 tiles from 40 samples were used for training. It improved my Hubmap only LB score ~0.02.\n\n### TTA\nAlthough I could use maximum 8 combination patterns, I reduced them to four because of the 9 hours run-time limitation. The scales were chosen based on x0.25 training scale.\n- 5 scales x 4 patterns = 20 TTAs per model\n- 5 scales: 0.19, 0.21, 0.23, 0.25, 0.28\n- 4 patterns: original, lr-flip, ud-flip, rot90\n\n### Post-process\nAlthough there is no clear evidence, especially for \"spleen\" and \"lung\", the boundary of the masks is fuzzy, so I tried to enlarge or shrink the masks and confirmed the effect in LB score. As a result, shrinking spleen and lung prediction masks improved my LB score. I did not include post-processing in one of the final submissions because I thought there was a possibility of overfitting to the public data. However, the resulting private LB score was better if I include the post-processing. The post-processing was impremented as following code.\n\n```\nSHRINK = {'spleen': 10, 'lung': 10}\n\ndef post_proc(preds, organ):\n    # preds: predicted mask after binarization\n    \n    if organ in SHRINK.keys():\n        contours, _ = cv2.findContours(preds, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n        preds = preds.astype(np.int8)\n        preds_cont = np.zeros_like(preds)\n        preds_cont = cv2.drawContours(preds_cont, contours, -1, 1, SHRINK[organ]*2)\n        preds = (preds - preds_cont).clip(0, 1).astype(np.uint8)\n    return preds\n```\n",
    "1954184": "This is really helpful.",
    "1952439": "congo keep it",
    "1952177": "Hearty congratulations for the result, this is a great approach and a good learning for me @dimanishi!\nThanks for sharing the approach!",
    "1972207": "Conguraturation!\n\nHow did you handle with resolution difference between HPA and HubMAP?\nDid you get this result without caring about the resolution domain gap?",
    "1952412": "How to use different loss? On differnet models?  ",
    "1952320": ""
  }
}