{
  "id": 333389,
  "title": "Some Insights",
  "url": "/competitions/hubmap-organ-segmentation/discussion/333389",
  "author_name": "Yassine Alouini",
  "post_date": "2022-06-26T09:53:42.822000",
  "votes": 89,
  "comment_count": 34,
  "views": 0,
  "content": "<p>New competition, new insights post, let's go.</p>\n<h2>Task</h2>\n<p>This is a <strong>medical</strong> (semantic) <strong>segmentation</strong> competition focusing on <strong>locating</strong> <strong>functional tissue units</strong> (shortened as FTU) from <strong>various organs</strong> biopsies.</p>\n<p>For each input image, the task is to predict a binary mask of wheter there is an FTU (predict 1) or not (predict 0).</p>\n<h2>Metric and Loss</h2>\n<h3>Metric</h3>\n<p>Dice (also known as <a href=\"https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\" target=\"_blank\">Sørensen-Dice</a>), dice coefficient, or dice similarity, (shortened as DSC) is a metric used to measure the similarity between two samples.</p>\n<p>It is a popular semantic segmentation metric and has the following equation for a two sets of pixels 𝐴  and  𝐵, where 𝐴 is the set of true (mask) pixels and  𝐵  the set of predicted (mask) ones:</p>\n<p>$$𝐷𝑆𝐶(𝐴,𝐵):=2|𝐴∩𝐵|/(|𝐴|+|𝐵|)$$</p>\n<p>You can use the following implementation from <a href=\"https://torchmetrics.readthedocs.io/en/stable/classification/dice.html#\" target=\"_blank\">torchmetrics</a> (or implement your own if you prefer):</p>\n<pre><code>from torchmetrics.functional import dice\npreds = torch.tensor([1, 0, 0, 0])\ntarget = torch.tensor([1, 1, 0, 1])\nprint(\"Dice: \", dice(preds, target, average='micro'))\n</code></pre>\n<h3>Loss</h3>\n<p>One simple way to derive a loss from the competition's metric, is to set:</p>\n<p><code>loss = 1 - metric</code></p>\n<p>This isn't however the best loss to use since it isn't differentiable so harder to optimize. Notice that we can make it differentiable by replacing the non-differentiable intersection with a differentiable element-wise product (as discussed <a href=\"https://stackoverflow.com/questions/51973856/how-is-the-smooth-dice-loss-differentiable\" target=\"_blank\">here</a>) and letting the predictions be continuous (a probability instead of binary labels).</p>\n<p>Another \"classic\" loss (that is differentiable this time) that we can try is the <strong>binary <a href=\"https://en.wikipedia.org/wiki/Cross_entropy\" target=\"_blank\">cross entropy</a></strong> (shortened often as BCE). </p>\n<p>You can use the <a href=\"https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html\" target=\"_blank\"><code>BCELoss</code></a> implementation from PyTorch.</p>\n<p>However, as you might have guessed similarly to <a href=\"https://www.kaggle.com/nishantbhansali\" target=\"_blank\">@nishantbhansali</a>, this still isn't the best loss since we have a lof of background pixels (0 pixels) in comparison with FTU pixels. Thus, we need a solution to fix this imbalance (otherwise the model will predict 0 all the time). </p>\n<p>One possible solution is to add the <a href=\"https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf\" target=\"_blank\">Lovasz</a> loss (as done in this top <a href=\"https://www.kaggle.com/competitions/hubmap-kidney-segmentation/discussion/238198\" target=\"_blank\">solution</a>) to BCE. This implements a differentiable IoU (also known as <a href=\"https://torchmetrics.readthedocs.io/en/stable/classification/jaccard_index.html\" target=\"_blank\">Jaccard index</a> and which is directly linked to Dice). Bingo!</p>\n<p>One Lovasz implementation can be found <a href=\"https://github.com/bermanmaxim/LovaszSoftmax\" target=\"_blank\">here</a>. There is also one <a href=\"https://github.com/bermanmaxim/LovaszSoftmax/blob/master/pytorch/demo_binary.ipynb\" target=\"_blank\">notebook</a> example.</p>\n<h3>&nbsp;Data</h3>\n<p>Notice that all images contain at least one FTU (so no empty images but haven't yet check this claim) and<br>\nthey come from healthy donors.</p>\n<p>One particularity of this competition is that training data comes from one source (HPA), the<br>\npublic testing is a mix of two sources (HPA and HubMAP), and the private testing is only the second source (HubMAP). </p>\n<p>This is an interesting generalization challenge.</p>\n<h3>Training</h3>\n<p>Here are some insights from the <code>train.csv</code> file:</p>\n<ul>\n<li>The train metadata has <code>351</code> rows and <code>10</code> columns.</li>\n<li><code>id</code>: this is the image id. There are <code>351</code> unique image id, the same number of rows so<br>\nthis isn't very useful.</li>\n<li><code>organ</code>: this is the organ for which the biopsy was done. There are <code>5</code> unique organs:<br>\n<code>['prostate', 'spleen', 'lung', 'kidney', 'largeintestine']</code> with the following distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F6fc2f9537a5ef427f906ae2395d66efc%2Forgan_value_counts.png?generation=1656236866064299&amp;alt=media\" alt=\"organ_distribution\"></p>\n<ul>\n<li><code>data_source</code>: from where the data comes from. There is only one data source for the training: <code>HPA</code>.</li>\n<li><code>img_width</code>: the width of the image in pixels. Here is the list of the different possible values:<br>\n<code>[3000, 2867, 2654, 2727, 2680, 2539, 2631, 2790, 2942, 2308, 2764, 2783, 2869, 2760, 2630, 2511, 2416, 2593, 2675, 3070]</code>. The <code>3000</code> is the dominant (326 out of 351), here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F0ca15f350b45010e20d710025cb1986d%2Fimg_width_distribution.png?generation=1656236933358972&amp;alt=media\" alt=\"img_width_distribution\"></p>\n<ul>\n<li><code>img_height</code>: the height of the image in pixels. Similar to <code>img_height</code>, the <code>3000</code> value is the dominant one and we have a similar distribution.</li>\n<li><code>pixel_size</code>: the height/width of a single pixel from this image in micrometers. There is only one value: <code>0.4</code> (in μm).</li>\n<li><code>tissue_thickness</code>: the thickness of the biopsy sample in micrometers. Similar to the pixel size, there is only one value: <code>4</code> (in μm).</li>\n<li><code>rle</code>: this is the target we want to predict. It is the run-length encoded mask.</li>\n<li><code>age</code>: this is the patient's age in years. Notice that this won't be available for the testing dataset, so use with caution. Here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F860a37ca1322c723990fe33ccd79b1a0%2Fage_distribution.png?generation=1656236813000062&amp;alt=media\" alt=\"age_distribution\"></p>\n<ul>\n<li><code>sex</code>: the sex of the patient. Two-thirds of males, on-third of females. Again, this is only provided for the training dataset. Here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F4882956a95234db73cc83b378b9cbde5%2Fsex_distribution.png?generation=1656236788652037&amp;alt=media\" alt=\"sex_distribution\"></p>\n<p>Here is how to get the RLE into a mask and plot it:</p>\n<pre><code>from PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n</code></pre>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F3a8f66b8c8490c5e381d6f90b5d7feef%2Fmask.jpg?generation=1656360389223797&amp;alt=media\" alt=\"\"></p>\n<h3>Testing</h3>\n<p>Only a fraction of the testing images are provided of course.<br>\nHere are some insights:</p>\n<ul>\n<li>Public dataset: mix of <code>HAP</code> and HubMAP data.</li>\n<li>Private dataset: only <code>HubMAP</code> data.</li>\n</ul>\n<h3>Sources</h3>\n<p>Data comes from these two sources:</p>\n<ul>\n<li>The Human BioMolecular Atlas Program data (shortened as HubMAP) comes from here: <a href=\"https://hubmapconsortium.org/\" target=\"_blank\">https://hubmapconsortium.org/</a></li>\n<li>The Human Protein Atlas (shortened as HPA) data comes from here: <a href=\"https://www.proteinatlas.org/\" target=\"_blank\">https://www.proteinatlas.org/</a></li>\n</ul>\n<h2>Keywords</h2>\n<p>Lots of medical and segmentation jargon here as you would expect:</p>\n<ul>\n<li>FTU: functional tissue unit.</li>\n<li>RLE: run-length encoding.</li>\n<li>DSC: dice similarity coefficient.</li>\n<li>HubMAP: BioMolecular Atlas.</li>\n<li>HPA: Human Protein Atlas.</li>\n</ul>\n<h2>Modeling</h2>\n<p>Here are some modeling ideas:</p>\n<ul>\n<li>One model for everything</li>\n<li>One model per organ type</li>\n</ul>\n<h2>Validation</h2>\n<p>Some ideas:</p>\n<ul>\n<li>Random split validation</li>\n<li>Validation that takes into account the distribution of the organs</li>\n</ul>\n<h2>Misc</h2>\n<p>While researching things for this post, I have discovered the following topics:</p>\n<ul>\n<li><a href=\"https://en.wikipedia.org/wiki/Tissue_engineering\" target=\"_blank\">https://en.wikipedia.org/wiki/Tissue_engineering</a></li>\n</ul>\n<h2>Useful Notebooks</h2>\n<p>Here are some useful notebooks to get you started:</p>\n<ul>\n<li>A great EDA: <a href=\"https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b\" target=\"_blank\">https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b</a></li>\n<li>Another great EDA: <a href=\"https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking\" target=\"_blank\">https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking</a></li>\n<li>A great notebook about the Dice metric: <a href=\"https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient\" target=\"_blank\">https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient</a></li>\n<li>A great baseline model (can be improved a lot of course): <a href=\"https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet\" target=\"_blank\">https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet</a></li>\n<li>Run-length encoding and decoding: <a href=\"https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\" target=\"_blank\">https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script</a></li>\n<li>Same as above but more efficient: <a href=\"https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook\" target=\"_blank\">https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook</a></li>\n<li>How to work with TIFF files (warning, my own work): <a href=\"https://www.kaggle.com/code/yassinealouini/working-with-tiff-files\" target=\"_blank\">https://www.kaggle.com/code/yassinealouini/working-with-tiff-files</a></li>\n<li>Various segmentation metrics detailed (warning, my own work again): <a href=\"https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics\" target=\"_blank\">https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics</a>.</li>\n</ul>",
  "messages": [
    {
      "id": 1833749,
      "postDate": "2022-06-26T09:53:42.823Z",
      "content": "<p>New competition, new insights post, let's go.</p>\n<h2>Task</h2>\n<p>This is a <strong>medical</strong> (semantic) <strong>segmentation</strong> competition focusing on <strong>locating</strong> <strong>functional tissue units</strong> (shortened as FTU) from <strong>various organs</strong> biopsies.</p>\n<p>For each input image, the task is to predict a binary mask of wheter there is an FTU (predict 1) or not (predict 0).</p>\n<h2>Metric and Loss</h2>\n<h3>Metric</h3>\n<p>Dice (also known as <a href=\"https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\" target=\"_blank\">Sørensen-Dice</a>), dice coefficient, or dice similarity, (shortened as DSC) is a metric used to measure the similarity between two samples.</p>\n<p>It is a popular semantic segmentation metric and has the following equation for a two sets of pixels 𝐴  and  𝐵, where 𝐴 is the set of true (mask) pixels and  𝐵  the set of predicted (mask) ones:</p>\n<p>$$𝐷𝑆𝐶(𝐴,𝐵):=2|𝐴∩𝐵|/(|𝐴|+|𝐵|)$$</p>\n<p>You can use the following implementation from <a href=\"https://torchmetrics.readthedocs.io/en/stable/classification/dice.html#\" target=\"_blank\">torchmetrics</a> (or implement your own if you prefer):</p>\n<pre><code>from torchmetrics.functional import dice\npreds = torch.tensor([1, 0, 0, 0])\ntarget = torch.tensor([1, 1, 0, 1])\nprint(\"Dice: \", dice(preds, target, average='micro'))\n</code></pre>\n<h3>Loss</h3>\n<p>One simple way to derive a loss from the competition's metric, is to set:</p>\n<p><code>loss = 1 - metric</code></p>\n<p>This isn't however the best loss to use since it isn't differentiable so harder to optimize. Notice that we can make it differentiable by replacing the non-differentiable intersection with a differentiable element-wise product (as discussed <a href=\"https://stackoverflow.com/questions/51973856/how-is-the-smooth-dice-loss-differentiable\" target=\"_blank\">here</a>) and letting the predictions be continuous (a probability instead of binary labels).</p>\n<p>Another \"classic\" loss (that is differentiable this time) that we can try is the <strong>binary <a href=\"https://en.wikipedia.org/wiki/Cross_entropy\" target=\"_blank\">cross entropy</a></strong> (shortened often as BCE). </p>\n<p>You can use the <a href=\"https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html\" target=\"_blank\"><code>BCELoss</code></a> implementation from PyTorch.</p>\n<p>However, as you might have guessed similarly to <a href=\"https://www.kaggle.com/nishantbhansali\" target=\"_blank\">@nishantbhansali</a>, this still isn't the best loss since we have a lof of background pixels (0 pixels) in comparison with FTU pixels. Thus, we need a solution to fix this imbalance (otherwise the model will predict 0 all the time). </p>\n<p>One possible solution is to add the <a href=\"https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf\" target=\"_blank\">Lovasz</a> loss (as done in this top <a href=\"https://www.kaggle.com/competitions/hubmap-kidney-segmentation/discussion/238198\" target=\"_blank\">solution</a>) to BCE. This implements a differentiable IoU (also known as <a href=\"https://torchmetrics.readthedocs.io/en/stable/classification/jaccard_index.html\" target=\"_blank\">Jaccard index</a> and which is directly linked to Dice). Bingo!</p>\n<p>One Lovasz implementation can be found <a href=\"https://github.com/bermanmaxim/LovaszSoftmax\" target=\"_blank\">here</a>. There is also one <a href=\"https://github.com/bermanmaxim/LovaszSoftmax/blob/master/pytorch/demo_binary.ipynb\" target=\"_blank\">notebook</a> example.</p>\n<h3>&nbsp;Data</h3>\n<p>Notice that all images contain at least one FTU (so no empty images but haven't yet check this claim) and<br>\nthey come from healthy donors.</p>\n<p>One particularity of this competition is that training data comes from one source (HPA), the<br>\npublic testing is a mix of two sources (HPA and HubMAP), and the private testing is only the second source (HubMAP). </p>\n<p>This is an interesting generalization challenge.</p>\n<h3>Training</h3>\n<p>Here are some insights from the <code>train.csv</code> file:</p>\n<ul>\n<li>The train metadata has <code>351</code> rows and <code>10</code> columns.</li>\n<li><code>id</code>: this is the image id. There are <code>351</code> unique image id, the same number of rows so<br>\nthis isn't very useful.</li>\n<li><code>organ</code>: this is the organ for which the biopsy was done. There are <code>5</code> unique organs:<br>\n<code>['prostate', 'spleen', 'lung', 'kidney', 'largeintestine']</code> with the following distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F6fc2f9537a5ef427f906ae2395d66efc%2Forgan_value_counts.png?generation=1656236866064299&amp;alt=media\" alt=\"organ_distribution\"></p>\n<ul>\n<li><code>data_source</code>: from where the data comes from. There is only one data source for the training: <code>HPA</code>.</li>\n<li><code>img_width</code>: the width of the image in pixels. Here is the list of the different possible values:<br>\n<code>[3000, 2867, 2654, 2727, 2680, 2539, 2631, 2790, 2942, 2308, 2764, 2783, 2869, 2760, 2630, 2511, 2416, 2593, 2675, 3070]</code>. The <code>3000</code> is the dominant (326 out of 351), here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F0ca15f350b45010e20d710025cb1986d%2Fimg_width_distribution.png?generation=1656236933358972&amp;alt=media\" alt=\"img_width_distribution\"></p>\n<ul>\n<li><code>img_height</code>: the height of the image in pixels. Similar to <code>img_height</code>, the <code>3000</code> value is the dominant one and we have a similar distribution.</li>\n<li><code>pixel_size</code>: the height/width of a single pixel from this image in micrometers. There is only one value: <code>0.4</code> (in μm).</li>\n<li><code>tissue_thickness</code>: the thickness of the biopsy sample in micrometers. Similar to the pixel size, there is only one value: <code>4</code> (in μm).</li>\n<li><code>rle</code>: this is the target we want to predict. It is the run-length encoded mask.</li>\n<li><code>age</code>: this is the patient's age in years. Notice that this won't be available for the testing dataset, so use with caution. Here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F860a37ca1322c723990fe33ccd79b1a0%2Fage_distribution.png?generation=1656236813000062&amp;alt=media\" alt=\"age_distribution\"></p>\n<ul>\n<li><code>sex</code>: the sex of the patient. Two-thirds of males, on-third of females. Again, this is only provided for the training dataset. Here is the distribution:</li>\n</ul>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F4882956a95234db73cc83b378b9cbde5%2Fsex_distribution.png?generation=1656236788652037&amp;alt=media\" alt=\"sex_distribution\"></p>\n<p>Here is how to get the RLE into a mask and plot it:</p>\n<pre><code>from PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n</code></pre>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F3a8f66b8c8490c5e381d6f90b5d7feef%2Fmask.jpg?generation=1656360389223797&amp;alt=media\" alt=\"\"></p>\n<h3>Testing</h3>\n<p>Only a fraction of the testing images are provided of course.<br>\nHere are some insights:</p>\n<ul>\n<li>Public dataset: mix of <code>HAP</code> and HubMAP data.</li>\n<li>Private dataset: only <code>HubMAP</code> data.</li>\n</ul>\n<h3>Sources</h3>\n<p>Data comes from these two sources:</p>\n<ul>\n<li>The Human BioMolecular Atlas Program data (shortened as HubMAP) comes from here: <a href=\"https://hubmapconsortium.org/\" target=\"_blank\">https://hubmapconsortium.org/</a></li>\n<li>The Human Protein Atlas (shortened as HPA) data comes from here: <a href=\"https://www.proteinatlas.org/\" target=\"_blank\">https://www.proteinatlas.org/</a></li>\n</ul>\n<h2>Keywords</h2>\n<p>Lots of medical and segmentation jargon here as you would expect:</p>\n<ul>\n<li>FTU: functional tissue unit.</li>\n<li>RLE: run-length encoding.</li>\n<li>DSC: dice similarity coefficient.</li>\n<li>HubMAP: BioMolecular Atlas.</li>\n<li>HPA: Human Protein Atlas.</li>\n</ul>\n<h2>Modeling</h2>\n<p>Here are some modeling ideas:</p>\n<ul>\n<li>One model for everything</li>\n<li>One model per organ type</li>\n</ul>\n<h2>Validation</h2>\n<p>Some ideas:</p>\n<ul>\n<li>Random split validation</li>\n<li>Validation that takes into account the distribution of the organs</li>\n</ul>\n<h2>Misc</h2>\n<p>While researching things for this post, I have discovered the following topics:</p>\n<ul>\n<li><a href=\"https://en.wikipedia.org/wiki/Tissue_engineering\" target=\"_blank\">https://en.wikipedia.org/wiki/Tissue_engineering</a></li>\n</ul>\n<h2>Useful Notebooks</h2>\n<p>Here are some useful notebooks to get you started:</p>\n<ul>\n<li>A great EDA: <a href=\"https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b\" target=\"_blank\">https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b</a></li>\n<li>Another great EDA: <a href=\"https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking\" target=\"_blank\">https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking</a></li>\n<li>A great notebook about the Dice metric: <a href=\"https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient\" target=\"_blank\">https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient</a></li>\n<li>A great baseline model (can be improved a lot of course): <a href=\"https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet\" target=\"_blank\">https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet</a></li>\n<li>Run-length encoding and decoding: <a href=\"https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\" target=\"_blank\">https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script</a></li>\n<li>Same as above but more efficient: <a href=\"https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook\" target=\"_blank\">https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook</a></li>\n<li>How to work with TIFF files (warning, my own work): <a href=\"https://www.kaggle.com/code/yassinealouini/working-with-tiff-files\" target=\"_blank\">https://www.kaggle.com/code/yassinealouini/working-with-tiff-files</a></li>\n<li>Various segmentation metrics detailed (warning, my own work again): <a href=\"https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics\" target=\"_blank\">https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics</a>.</li>\n</ul>",
      "rawMarkdown": "New competition, new insights post, let's go.\n\n## Task\n\nThis is a **medical** (semantic) **segmentation** competition focusing on **locating** **functional tissue units** (shortened as FTU) from **various organs** biopsies.\n\nFor each input image, the task is to predict a binary mask of wheter there is an FTU (predict 1) or not (predict 0).\n\n## Metric and Loss\n\n### Metric\n\nDice (also known as [Sørensen-Dice](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient)), dice coefficient, or dice similarity, (shortened as DSC) is a metric used to measure the similarity between two samples.\n\nIt is a popular semantic segmentation metric and has the following equation for a two sets of pixels 𝐴  and  𝐵, where 𝐴 is the set of true (mask) pixels and  𝐵  the set of predicted (mask) ones:\n\n$$𝐷𝑆𝐶(𝐴,𝐵):=2|𝐴∩𝐵|/(|𝐴|+|𝐵|)$$\n\nYou can use the following implementation from [torchmetrics](https://torchmetrics.readthedocs.io/en/stable/classification/dice.html#) (or implement your own if you prefer):\n\n``` python\n\nfrom torchmetrics.functional import dice\npreds = torch.tensor([1, 0, 0, 0])\ntarget = torch.tensor([1, 1, 0, 1])\nprint(\"Dice: \", dice(preds, target, average='micro'))\n\n```\n\n### Loss\n\nOne simple way to derive a loss from the competition's metric, is to set:\n\n`loss = 1 - metric`\n\nThis isn't however the best loss to use since it isn't differentiable so harder to optimize. Notice that we can make it differentiable by replacing the non-differentiable intersection with a differentiable element-wise product (as discussed [here](https://stackoverflow.com/questions/51973856/how-is-the-smooth-dice-loss-differentiable)) and letting the predictions be continuous (a probability instead of binary labels).\n\nAnother \"classic\" loss (that is differentiable this time) that we can try is the **binary [cross entropy](https://en.wikipedia.org/wiki/Cross_entropy)** (shortened often as BCE). \n\nYou can use the [`BCELoss`](https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html) implementation from PyTorch.\n\nHowever, as you might have guessed similarly to @nishantbhansali, this still isn't the best loss since we have a lof of background pixels (0 pixels) in comparison with FTU pixels. Thus, we need a solution to fix this imbalance (otherwise the model will predict 0 all the time). \n\nOne possible solution is to add the [Lovasz](https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf) loss (as done in this top [solution](https://www.kaggle.com/competitions/hubmap-kidney-segmentation/discussion/238198)) to BCE. This implements a differentiable IoU (also known as [Jaccard index](https://torchmetrics.readthedocs.io/en/stable/classification/jaccard_index.html) and which is directly linked to Dice). Bingo!\n\nOne Lovasz implementation can be found [here](https://github.com/bermanmaxim/LovaszSoftmax). There is also one [notebook](https://github.com/bermanmaxim/LovaszSoftmax/blob/master/pytorch/demo_binary.ipynb) example.\n\n### Data\n\nNotice that all images contain at least one FTU (so no empty images but haven't yet check this claim) and\nthey come from healthy donors.\n\nOne particularity of this competition is that training data comes from one source (HPA), the\npublic testing is a mix of two sources (HPA and HubMAP), and the private testing is only the second source (HubMAP). \n\nThis is an interesting generalization challenge.\n\n### Training\n\nHere are some insights from the `train.csv` file:\n\n* The train metadata has `351` rows and `10` columns.\n* `id`: this is the image id. There are `351` unique image id, the same number of rows so\nthis isn't very useful.\n* `organ`: this is the organ for which the biopsy was done. There are `5` unique organs:\n`['prostate', 'spleen', 'lung', 'kidney', 'largeintestine']` with the following distribution:\n\n![organ_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F6fc2f9537a5ef427f906ae2395d66efc%2Forgan_value_counts.png?generation=1656236866064299&alt=media)\n\n* `data_source`: from where the data comes from. There is only one data source for the training: `HPA`.\n* `img_width`: the width of the image in pixels. Here is the list of the different possible values:\n`[3000, 2867, 2654, 2727, 2680, 2539, 2631, 2790, 2942, 2308, 2764, 2783, 2869, 2760, 2630, 2511, 2416, 2593, 2675, 3070]`. The `3000` is the dominant (326 out of 351), here is the distribution:\n\n![img_width_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F0ca15f350b45010e20d710025cb1986d%2Fimg_width_distribution.png?generation=1656236933358972&alt=media)\n\n* `img_height`: the height of the image in pixels. Similar to `img_height`, the `3000` value is the dominant one and we have a similar distribution.\n* `pixel_size`: the height/width of a single pixel from this image in micrometers. There is only one value: `0.4` (in μm).\n* `tissue_thickness`: the thickness of the biopsy sample in micrometers. Similar to the pixel size, there is only one value: `4` (in μm).\n* `rle`: this is the target we want to predict. It is the run-length encoded mask.\n* `age`: this is the patient's age in years. Notice that this won't be available for the testing dataset, so use with caution. Here is the distribution:\n\n![age_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F860a37ca1322c723990fe33ccd79b1a0%2Fage_distribution.png?generation=1656236813000062&alt=media)\n\n* `sex`: the sex of the patient. Two-thirds of males, on-third of females. Again, this is only provided for the training dataset. Here is the distribution:\n\n![sex_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F4882956a95234db73cc83b378b9cbde5%2Fsex_distribution.png?generation=1656236788652037&alt=media)\n\n\nHere is how to get the RLE into a mask and plot it:\n\n```\nfrom PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n```\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F3a8f66b8c8490c5e381d6f90b5d7feef%2Fmask.jpg?generation=1656360389223797&alt=media)\n\n### Testing\n\nOnly a fraction of the testing images are provided of course.\nHere are some insights:\n\n* Public dataset: mix of `HAP` and HubMAP data.\n* Private dataset: only `HubMAP` data.\n\n### Sources\n\nData comes from these two sources:\n\n* The Human BioMolecular Atlas Program data (shortened as HubMAP) comes from here: https://hubmapconsortium.org/\n* The Human Protein Atlas (shortened as HPA) data comes from here: https://www.proteinatlas.org/\n\n## Keywords\n\nLots of medical and segmentation jargon here as you would expect:\n\n* FTU: functional tissue unit.\n* RLE: run-length encoding.\n* DSC: dice similarity coefficient.\n* HubMAP: BioMolecular Atlas.\n* HPA: Human Protein Atlas.\n\n## Modeling\n\nHere are some modeling ideas:\n\n* One model for everything\n* One model per organ type\n\n## Validation\n\nSome ideas:\n\n* Random split validation\n* Validation that takes into account the distribution of the organs\n\n## Misc\n\nWhile researching things for this post, I have discovered the following topics:\n\n* https://en.wikipedia.org/wiki/Tissue_engineering\n\n## Useful Notebooks\n\nHere are some useful notebooks to get you started:\n\n* A great EDA: https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b\n* Another great EDA: https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking\n* A great notebook about the Dice metric: https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient\n* A great baseline model (can be improved a lot of course): https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet\n* Run-length encoding and decoding: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\n* Same as above but more efficient: https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook\n* How to work with TIFF files (warning, my own work): https://www.kaggle.com/code/yassinealouini/working-with-tiff-files\n* Various segmentation metrics detailed (warning, my own work again): https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics.\n\n\n",
      "votes": 86
    },
    {
      "id": 1838823,
      "postDate": "2022-06-30T21:14:25.757Z",
      "content": "<p>I did a quick benchmark of various TIFF reading methods (I hope I am not doing anything stupid here):</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2Fb5532315d6b9ba3a0eb803d07f90bb21%2Ftiff_reading_methods.jpg?generation=1656623639333000&amp;alt=media\" alt=\"tiff_reading_methods_benchmark\"></p>\n<p>It looks like PIL is the fastest method.</p>",
      "rawMarkdown": "I did a quick benchmark of various TIFF reading methods (I hope I am not doing anything stupid here):\n\n![tiff_reading_methods_benchmark](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2Fb5532315d6b9ba3a0eb803d07f90bb21%2Ftiff_reading_methods.jpg?generation=1656623639333000&alt=media)\n\n\nIt looks like PIL is the fastest method.",
      "votes": 3,
      "replies": [
        {
          "id": 1838828,
          "postDate": "2022-06-30T21:36:31.213Z",
          "content": "<p>But you will have to convert both the rasterio object as well as the PIL object to numpy/tf to work with them.</p>\n<p>If you benchmark with numpy as the final desirable state, you can see that rasterio is the fastest.</p>\n<hr>\n<p>EDIT: See below, <strong><code>tifffile</code></strong> is actually the fastest library because rasterio objects require a <code>.read()</code> call which slows things down.</p>\n<hr>\n<p>Also, side note: most libraries cache a file that's been opened already. For different libraries you will see different speedups for opening the same file multiple times. So it's best to benchmark on a new sequence each time.</p>\n<p><img src=\"https://i.ibb.co/HnwqyCH/Screen-Shot-2022-06-30-at-5-34-25-PM.png\" alt=\"Screen-Shot-2022-06-30-at-5-34-25-PM\"></p>",
          "rawMarkdown": "But you will have to convert both the rasterio object as well as the PIL object to numpy/tf to work with them.\n\nIf you benchmark with numpy as the final desirable state, you can see that rasterio is the fastest.\n\n---\n\nEDIT: See below, **`tifffile`** is actually the fastest library because rasterio objects require a `.read()` call which slows things down.\n\n---\n\nAlso, side note: most libraries cache a file that's been opened already. For different libraries you will see different speedups for opening the same file multiple times. So it's best to benchmark on a new sequence each time.\n\n<img src=\"https://i.ibb.co/HnwqyCH/Screen-Shot-2022-06-30-at-5-34-25-PM.png\" alt=\"Screen-Shot-2022-06-30-at-5-34-25-PM\" border=\"0\">",
          "votes": 6
        },
        {
          "id": 1838832,
          "postDate": "2022-06-30T21:42:20.757Z",
          "content": "<p>I made a mistake in the above calculation.</p>\n<p>rasterio.open() needs to have .read() called before the array is accessible… as such the timing is:</p>\n<pre><code>%%timeit\nrasterio.open(demo_path).read()\n\n32.4 ms ± 916 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n</code></pre>\n<p>This means that <strong><code>tifffile</code></strong> is the fastest library.</p>",
          "rawMarkdown": "I made a mistake in the above calculation.\n\nrasterio.open() needs to have .read() called before the array is accessible... as such the timing is:\n\n```\n%%timeit\nrasterio.open(demo_path).read()\n\n32.4 ms ± 916 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n```\n\nThis means that **`tifffile`** is the fastest library.",
          "votes": 3
        },
        {
          "id": 1838845,
          "postDate": "2022-06-30T22:01:34.003Z",
          "content": "<p>I knew I was missing something and doing these experiments late is never a good idea, thanks <a href=\"https://www.kaggle.com/dschettler8845\" target=\"_blank\">@dschettler8845</a> for these. 👍</p>",
          "rawMarkdown": "I knew I was missing something and doing these experiments late is never a good idea, thanks @dschettler8845 for these. 👍",
          "votes": 1
        }
      ]
    },
    {
      "id": 1889568,
      "postDate": "2022-08-08T09:21:36.700Z",
      "content": "<p>thanks for sharing. However if i want to process the images into several patches, do i need to take the 'pixel_size' into consideration?🙌</p>",
      "rawMarkdown": "thanks for sharing. However if i want to process the images into several patches, do i need to take the 'pixel_size' into consideration?🙌",
      "votes": 1,
      "replies": [
        {
          "id": 1889994,
          "postDate": "2022-08-08T13:46:57.873Z",
          "content": "<p><code>pixel_size</code>is a mapping between pixel dimensions and real dimensions as measured using the microscope. So you probably won't need this information.</p>",
          "rawMarkdown": "`pixel_size `is a mapping between pixel dimensions and real dimensions as measured using the microscope. So you probably won't need this information."
        }
      ]
    },
    {
      "id": 1857588,
      "postDate": "2022-07-16T08:27:58.303Z",
      "content": "<p>Nice discussion, a good guideline for the competition starter👍</p>",
      "rawMarkdown": "Nice discussion, a good guideline for the competition starter👍",
      "votes": 1,
      "replies": [
        {
          "id": 1857845,
          "postDate": "2022-07-16T12:52:16.303Z",
          "content": "<p>Glad you find it useful. Please ask further questions so that I can add details. 👌 </p>",
          "rawMarkdown": "Glad you find it useful. Please ask further questions so that I can add details. 👌 "
        }
      ]
    },
    {
      "id": 1842891,
      "postDate": "2022-07-04T11:22:30.407Z",
      "content": "<p>although it is currently above my level. but still it's informative for me. sometimes I feel hesitant to write comments on a post. the author of that post may get the feeling that I am writing just to get upvoted. which is not at all a reason for my comments. I just wanted to appreciate that work.</p>",
      "rawMarkdown": "although it is currently above my level. but still it's informative for me. sometimes I feel hesitant to write comments on a post. the author of that post may get the feeling that I am writing just to get upvoted. which is not at all a reason for my comments. I just wanted to appreciate that work.",
      "votes": 1,
      "replies": [
        {
          "id": 1843122,
          "postDate": "2022-07-04T15:01:36.417Z",
          "content": "<p>Very appreciated <a href=\"https://www.kaggle.com/sohailds\" target=\"_blank\">@sohailds</a>, thanks. Also, feel free to ask any question about the content: that's how you learn and it may help me learn as well. 👍</p>",
          "rawMarkdown": "Very appreciated @sohailds, thanks. Also, feel free to ask any question about the content: that's how you learn and it may help me learn as well. 👍",
          "votes": 1
        }
      ]
    },
    {
      "id": 1837892,
      "postDate": "2022-06-30T03:06:07.667Z",
      "content": "<p>This is an extremely useful thread, thanks for sharing <a href=\"https://www.kaggle.com/yassinealouini\" target=\"_blank\">@yassinealouini</a> !</p>",
      "rawMarkdown": "This is an extremely useful thread, thanks for sharing @yassinealouini !",
      "votes": 1,
      "replies": [
        {
          "id": 1838019,
          "postDate": "2022-06-30T06:09:18.977Z",
          "content": "<p>You are welcome <a href=\"https://www.kaggle.com/saurabhbagchi\" target=\"_blank\">@saurabhbagchi</a>. Glad if it helps. </p>",
          "rawMarkdown": "You are welcome @saurabhbagchi. Glad if it helps. ",
          "votes": 1
        }
      ]
    },
    {
      "id": 1837890,
      "postDate": "2022-06-30T03:03:40.610Z",
      "content": "<p>thanks for sharing. However, I don't think It is a good metric.</p>",
      "rawMarkdown": "thanks for sharing. However, I don't think It is a good metric.",
      "votes": 1,
      "replies": [
        {
          "id": 1838321,
          "postDate": "2022-06-30T12:09:32.917Z",
          "content": "<p>Thanks. Which metric are you talking about, Dice? If so, it is the competition's metric, so you should at least keep in eye on it. </p>\n<p>If you are talking about the loss, BCE + Lovasz might be not the best option. What do you propose instead? 👀</p>",
          "rawMarkdown": "Thanks. Which metric are you talking about, Dice? If so, it is the competition's metric, so you should at least keep in eye on it. \n\nIf you are talking about the loss, BCE + Lovasz might be not the best option. What do you propose instead? 👀"
        },
        {
          "id": 1839009,
          "postDate": "2022-07-01T03:50:53.027Z",
          "content": "<p>competition metric.</p>\n<p>I would suggest that a combined metric with bbox and dice/iou</p>",
          "rawMarkdown": "competition metric.\n\nI would suggest that a combined metric with bbox and dice/iou",
          "votes": 2
        },
        {
          "id": 1841555,
          "postDate": "2022-07-03T08:32:45.850Z",
          "content": "<p>That's an interesting idea. How would adding the bbox help? Do you use this as a first stage evaluation, i.e. find the bbox of the FTU and then get the mask?</p>",
          "rawMarkdown": "That's an interesting idea. How would adding the bbox help? Do you use this as a first stage evaluation, i.e. find the bbox of the FTU and then get the mask?"
        },
        {
          "id": 1842094,
          "postDate": "2022-07-03T17:39:54Z",
          "content": "<p>The issue with dice is, that it puts an emphasis on large objects, while smaller objects (fewer pixel) are less important. By normalizing for instances, we can partially get around that issue. </p>",
          "rawMarkdown": "The issue with dice is, that it puts an emphasis on large objects, while smaller objects (fewer pixel) are less important. By normalizing for instances, we can partially get around that issue. ",
          "votes": 1
        },
        {
          "id": 1842132,
          "postDate": "2022-07-03T18:21:12.207Z",
          "content": "<p>That's a good point <a href=\"https://www.kaggle.com/theudas\" target=\"_blank\">@theudas</a>. Thanks for sharing.</p>",
          "rawMarkdown": "That's a good point @theudas. Thanks for sharing."
        }
      ]
    },
    {
      "id": 1836043,
      "postDate": "2022-06-28T10:03:22.117Z",
      "content": "<p>Well, that was a good post. Thanks for sharing👍</p>",
      "rawMarkdown": "Well, that was a good post. Thanks for sharing👍",
      "votes": 1,
      "replies": [
        {
          "id": 1836054,
          "postDate": "2022-06-28T10:17:11.520Z",
          "content": "<p>You are welcome. Glad you find it useful. </p>",
          "rawMarkdown": "You are welcome. Glad you find it useful. "
        }
      ]
    },
    {
      "id": 1834577,
      "postDate": "2022-06-27T04:10:38.967Z",
      "content": "<p>Thanks for putting this together. Appreciated!</p>",
      "rawMarkdown": "Thanks for putting this together. Appreciated!",
      "votes": 1,
      "replies": [
        {
          "id": 1834874,
          "postDate": "2022-06-27T09:11:06.083Z",
          "content": "<p>You are welcome! Please share any insights you have and/or comments. </p>",
          "rawMarkdown": "You are welcome! Please share any insights you have and/or comments. ",
          "votes": 1
        }
      ]
    },
    {
      "id": 1833765,
      "postDate": "2022-06-26T10:14:09.173Z",
      "content": "<p>Why isn't the dice loss the best loss to use? as per my understanding if we use per pixel BCE loss would'nt that introduce a bias as most pixels are <strong>0</strong>.  Hence even predicting the entire mask as empty should give a good score, and this can be misleading. <br>\nPlease let me know if I'm wrong in thinking so</p>\n<p>Thanks for the useful insights!</p>",
      "rawMarkdown": "Why isn't the dice loss the best loss to use? as per my understanding if we use per pixel BCE loss would'nt that introduce a bias as most pixels are **0**.  Hence even predicting the entire mask as empty should give a good score, and this can be misleading. \nPlease let me know if I'm wrong in thinking so\n\nThanks for the useful insights!\n",
      "votes": 2,
      "replies": [
        {
          "id": 1833768,
          "postDate": "2022-06-26T10:18:47.460Z",
          "content": "<p>That's a good comment. I was planning to add more losses later but I will have to do it sooner. 😉 </p>",
          "rawMarkdown": "That's a good comment. I was planning to add more losses later but I will have to do it sooner. 😉 ",
          "votes": 1
        },
        {
          "id": 1833774,
          "postDate": "2022-06-26T10:36:57.347Z",
          "content": "<p>Here is one solution: the Lovasz loss =&gt; <a href=\"https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf\" target=\"_blank\">https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf</a></p>",
          "rawMarkdown": "Here is one solution: the Lovasz loss => https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf",
          "votes": 1
        },
        {
          "id": 1833775,
          "postDate": "2022-06-26T10:40:43.487Z",
          "content": "<p>Notice that we can make the Dice loss (1 - Dice) differentiable by replacing the non-differentiable intersection with an element-wise product.</p>",
          "rawMarkdown": "Notice that we can make the Dice loss (1 - Dice) differentiable by replacing the non-differentiable intersection with an element-wise product.",
          "votes": 2
        }
      ]
    },
    {
      "id": 1855178,
      "postDate": "2022-07-14T10:50:44.577Z",
      "content": "<p>Interesting RLE function: <a href=\"https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook\" target=\"_blank\">https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook</a><br>\nThanks to <a href=\"https://www.kaggle.com/bguberfain\" target=\"_blank\">https://www.kaggle.com/bguberfain</a>.</p>",
      "rawMarkdown": "Interesting RLE function: https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook\nThanks to https://www.kaggle.com/bguberfain."
    },
    {
      "id": 1836576,
      "postDate": "2022-06-28T20:04:37.497Z",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F584e44c0d3a744c65d9adf478717d953%2Fdeep_supervision_unet_paper.jpg?generation=1656446664887118&amp;alt=media\" alt=\"deep_supervision_unet\"></p>\n<p>Interesting paper: <a href=\"https://arxiv.org/pdf/2103.03759.pdf\" target=\"_blank\">https://arxiv.org/pdf/2103.03759.pdf</a></p>",
      "rawMarkdown": "![deep_supervision_unet](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F584e44c0d3a744c65d9adf478717d953%2Fdeep_supervision_unet_paper.jpg?generation=1656446664887118&alt=media)\n\n\nInteresting paper: https://arxiv.org/pdf/2103.03759.pdf\n\n"
    },
    {
      "id": 1835538,
      "postDate": "2022-06-27T20:04:01.153Z",
      "content": "<p>Here is an update to get RLE into a mask and then plot it:</p>\n<pre><code>from PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\n# Source: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n</code></pre>",
      "rawMarkdown": "Here is an update to get RLE into a mask and then plot it:\n\n```\nfrom PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\n# Source: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n```\n\n",
      "replies": [
        {
          "id": 1855442,
          "postDate": "2022-07-14T15:22:38.880Z",
          "content": "<p>Thank you for the great insights!</p>\n<p>I was wondering why you are transposing the mask in the end in <code>rle2mask</code>? Shouldn't it be just <code>return img.reshape(shape)</code>?</p>",
          "rawMarkdown": "Thank you for the great insights!\n\nI was wondering why you are transposing the mask in the end in `rle2mask`? Shouldn't it be just `return img.reshape(shape)`?",
          "votes": 1
        },
        {
          "id": 1855471,
          "postDate": "2022-07-14T16:01:28.850Z",
          "content": "<p>This is a usual confusing thing about the different image and mask formats. </p>\n<p>To have the usual array format, we put the height as the first dimension (x) and the width as the second (y). That's why we transpose at the end. </p>",
          "rawMarkdown": "This is a usual confusing thing about the different image and mask formats. \n\nTo have the usual array format, we put the height as the first dimension (x) and the width as the second (y). That's why we transpose at the end. ",
          "votes": 1
        }
      ]
    },
    {
      "id": 1833752,
      "postDate": "2022-06-26T09:54:45.833Z",
      "content": "<p>As usual, I will keep updating this post as I go and if you have comments/suggestions. Thanks.</p>",
      "rawMarkdown": "As usual, I will keep updating this post as I go and if you have comments/suggestions. Thanks."
    },
    {
      "id": 1923380,
      "postDate": "2022-09-02T07:15:51.350Z",
      "rawMarkdown": "",
      "votes": 1,
      "isDeleted": true,
      "replies": [
        {
          "id": 1923424,
          "postDate": "2022-09-02T08:12:21.817Z",
          "content": "<p>Glad it helps, please let me know if you need more details!</p>",
          "rawMarkdown": "Glad it helps, please let me know if you need more details!"
        }
      ]
    }
  ],
  "comments": [
    {
      "id": 1838823,
      "author_name": "Yassine Alouini",
      "author_url": "",
      "post_date": "2022-06-30T21:14:25.757000",
      "content": "<p>I did a quick benchmark of various TIFF reading methods (I hope I am not doing anything stupid here):</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2Fb5532315d6b9ba3a0eb803d07f90bb21%2Ftiff_reading_methods.jpg?generation=1656623639333000&amp;alt=media\" alt=\"tiff_reading_methods_benchmark\"></p>\n<p>It looks like PIL is the fastest method.</p>",
      "votes": 3,
      "replies": [
        {
          "id": 1838828,
          "author_name": "Darien Schettler",
          "author_url": "",
          "post_date": "2022-06-30T21:36:31.213000",
          "content": "<p>But you will have to convert both the rasterio object as well as the PIL object to numpy/tf to work with them.</p>\n<p>If you benchmark with numpy as the final desirable state, you can see that rasterio is the fastest.</p>\n<hr>\n<p>EDIT: See below, <strong><code>tifffile</code></strong> is actually the fastest library because rasterio objects require a <code>.read()</code> call which slows things down.</p>\n<hr>\n<p>Also, side note: most libraries cache a file that's been opened already. For different libraries you will see different speedups for opening the same file multiple times. So it's best to benchmark on a new sequence each time.</p>\n<p><img src=\"https://i.ibb.co/HnwqyCH/Screen-Shot-2022-06-30-at-5-34-25-PM.png\" alt=\"Screen-Shot-2022-06-30-at-5-34-25-PM\"></p>",
          "votes": 6,
          "replies": []
        },
        {
          "id": 1838832,
          "author_name": "Darien Schettler",
          "author_url": "",
          "post_date": "2022-06-30T21:42:20.757000",
          "content": "<p>I made a mistake in the above calculation.</p>\n<p>rasterio.open() needs to have .read() called before the array is accessible… as such the timing is:</p>\n<pre><code>%%timeit\nrasterio.open(demo_path).read()\n\n32.4 ms ± 916 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n</code></pre>\n<p>This means that <strong><code>tifffile</code></strong> is the fastest library.</p>",
          "votes": 3,
          "replies": []
        },
        {
          "id": 1838845,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-30T22:01:34.003000",
          "content": "<p>I knew I was missing something and doing these experiments late is never a good idea, thanks <a href=\"https://www.kaggle.com/dschettler8845\" target=\"_blank\">@dschettler8845</a> for these. 👍</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1889568,
      "author_name": "tanxxx",
      "author_url": "",
      "post_date": "2022-08-08T09:21:36.700000",
      "content": "<p>thanks for sharing. However if i want to process the images into several patches, do i need to take the 'pixel_size' into consideration?🙌</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1889994,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-08-08T13:46:57.873000",
          "content": "<p><code>pixel_size</code>is a mapping between pixel dimensions and real dimensions as measured using the microscope. So you probably won't need this information.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1857588,
      "author_name": "Manyu Li",
      "author_url": "",
      "post_date": "2022-07-16T08:27:58.303000",
      "content": "<p>Nice discussion, a good guideline for the competition starter👍</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1857845,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-07-16T12:52:16.303000",
          "content": "<p>Glad you find it useful. Please ask further questions so that I can add details. 👌 </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1842891,
      "author_name": "Sohail Ahmed",
      "author_url": "",
      "post_date": "2022-07-04T11:22:30.407000",
      "content": "<p>although it is currently above my level. but still it's informative for me. sometimes I feel hesitant to write comments on a post. the author of that post may get the feeling that I am writing just to get upvoted. which is not at all a reason for my comments. I just wanted to appreciate that work.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1843122,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-07-04T15:01:36.417000",
          "content": "<p>Very appreciated <a href=\"https://www.kaggle.com/sohailds\" target=\"_blank\">@sohailds</a>, thanks. Also, feel free to ask any question about the content: that's how you learn and it may help me learn as well. 👍</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1837892,
      "author_name": "Old Monk",
      "author_url": "",
      "post_date": "2022-06-30T03:06:07.667000",
      "content": "<p>This is an extremely useful thread, thanks for sharing <a href=\"https://www.kaggle.com/yassinealouini\" target=\"_blank\">@yassinealouini</a> !</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1838019,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-30T06:09:18.977000",
          "content": "<p>You are welcome <a href=\"https://www.kaggle.com/saurabhbagchi\" target=\"_blank\">@saurabhbagchi</a>. Glad if it helps. </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1837890,
      "author_name": "dragon zhang",
      "author_url": "",
      "post_date": "2022-06-30T03:03:40.610000",
      "content": "<p>thanks for sharing. However, I don't think It is a good metric.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1838321,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-30T12:09:32.917000",
          "content": "<p>Thanks. Which metric are you talking about, Dice? If so, it is the competition's metric, so you should at least keep in eye on it. </p>\n<p>If you are talking about the loss, BCE + Lovasz might be not the best option. What do you propose instead? 👀</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1839009,
          "author_name": "dragon zhang",
          "author_url": "",
          "post_date": "2022-07-01T03:50:53.027000",
          "content": "<p>competition metric.</p>\n<p>I would suggest that a combined metric with bbox and dice/iou</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 1841555,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-07-03T08:32:45.850000",
          "content": "<p>That's an interesting idea. How would adding the bbox help? Do you use this as a first stage evaluation, i.e. find the bbox of the FTU and then get the mask?</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1842094,
          "author_name": "Philipp Sodmann",
          "author_url": "",
          "post_date": "2022-07-03T17:39:54",
          "content": "<p>The issue with dice is, that it puts an emphasis on large objects, while smaller objects (fewer pixel) are less important. By normalizing for instances, we can partially get around that issue. </p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1842132,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-07-03T18:21:12.207000",
          "content": "<p>That's a good point <a href=\"https://www.kaggle.com/theudas\" target=\"_blank\">@theudas</a>. Thanks for sharing.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1836043,
      "author_name": "Omkar Gowda",
      "author_url": "",
      "post_date": "2022-06-28T10:03:22.117000",
      "content": "<p>Well, that was a good post. Thanks for sharing👍</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1836054,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-28T10:17:11.520000",
          "content": "<p>You are welcome. Glad you find it useful. </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1834577,
      "author_name": "Darien Schettler",
      "author_url": "",
      "post_date": "2022-06-27T04:10:38.967000",
      "content": "<p>Thanks for putting this together. Appreciated!</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1834874,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-27T09:11:06.083000",
          "content": "<p>You are welcome! Please share any insights you have and/or comments. </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1833765,
      "author_name": "Nishant Bhansali",
      "author_url": "",
      "post_date": "2022-06-26T10:14:09.173000",
      "content": "<p>Why isn't the dice loss the best loss to use? as per my understanding if we use per pixel BCE loss would'nt that introduce a bias as most pixels are <strong>0</strong>.  Hence even predicting the entire mask as empty should give a good score, and this can be misleading. <br>\nPlease let me know if I'm wrong in thinking so</p>\n<p>Thanks for the useful insights!</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1833768,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-26T10:18:47.460000",
          "content": "<p>That's a good comment. I was planning to add more losses later but I will have to do it sooner. 😉 </p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1833774,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-26T10:36:57.347000",
          "content": "<p>Here is one solution: the Lovasz loss =&gt; <a href=\"https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf\" target=\"_blank\">https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf</a></p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1833775,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-06-26T10:40:43.487000",
          "content": "<p>Notice that we can make the Dice loss (1 - Dice) differentiable by replacing the non-differentiable intersection with an element-wise product.</p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 1855178,
      "author_name": "Yassine Alouini",
      "author_url": "",
      "post_date": "2022-07-14T10:50:44.577000",
      "content": "<p>Interesting RLE function: <a href=\"https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook\" target=\"_blank\">https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook</a><br>\nThanks to <a href=\"https://www.kaggle.com/bguberfain\" target=\"_blank\">https://www.kaggle.com/bguberfain</a>.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1836576,
      "author_name": "Yassine Alouini",
      "author_url": "",
      "post_date": "2022-06-28T20:04:37.497000",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F584e44c0d3a744c65d9adf478717d953%2Fdeep_supervision_unet_paper.jpg?generation=1656446664887118&amp;alt=media\" alt=\"deep_supervision_unet\"></p>\n<p>Interesting paper: <a href=\"https://arxiv.org/pdf/2103.03759.pdf\" target=\"_blank\">https://arxiv.org/pdf/2103.03759.pdf</a></p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1835538,
      "author_name": "Yassine Alouini",
      "author_url": "",
      "post_date": "2022-06-27T20:04:01.153000",
      "content": "<p>Here is an update to get RLE into a mask and then plot it:</p>\n<pre><code>from PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\n# Source: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n</code></pre>",
      "votes": 0,
      "replies": [
        {
          "id": 1855442,
          "author_name": "clem-chris",
          "author_url": "",
          "post_date": "2022-07-14T15:22:38.880000",
          "content": "<p>Thank you for the great insights!</p>\n<p>I was wondering why you are transposing the mask in the end in <code>rle2mask</code>? Shouldn't it be just <code>return img.reshape(shape)</code>?</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1855471,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-07-14T16:01:28.850000",
          "content": "<p>This is a usual confusing thing about the different image and mask formats. </p>\n<p>To have the usual array format, we put the height as the first dimension (x) and the width as the second (y). That's why we transpose at the end. </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1833752,
      "author_name": "Yassine Alouini",
      "author_url": "",
      "post_date": "2022-06-26T09:54:45.833000",
      "content": "<p>As usual, I will keep updating this post as I go and if you have comments/suggestions. Thanks.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1923380,
      "author_name": "",
      "author_url": "",
      "post_date": "2022-09-02T07:15:51.350000",
      "content": "",
      "votes": 1,
      "replies": [
        {
          "id": 1923424,
          "author_name": "Yassine Alouini",
          "author_url": "",
          "post_date": "2022-09-02T08:12:21.817000",
          "content": "<p>Glad it helps, please let me know if you need more details!</p>",
          "votes": 0,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "1833749": "New competition, new insights post, let's go.\n\n## Task\n\nThis is a **medical** (semantic) **segmentation** competition focusing on **locating** **functional tissue units** (shortened as FTU) from **various organs** biopsies.\n\nFor each input image, the task is to predict a binary mask of wheter there is an FTU (predict 1) or not (predict 0).\n\n## Metric and Loss\n\n### Metric\n\nDice (also known as [Sørensen-Dice](https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient)), dice coefficient, or dice similarity, (shortened as DSC) is a metric used to measure the similarity between two samples.\n\nIt is a popular semantic segmentation metric and has the following equation for a two sets of pixels 𝐴  and  𝐵, where 𝐴 is the set of true (mask) pixels and  𝐵  the set of predicted (mask) ones:\n\n$$𝐷𝑆𝐶(𝐴,𝐵):=2|𝐴∩𝐵|/(|𝐴|+|𝐵|)$$\n\nYou can use the following implementation from [torchmetrics](https://torchmetrics.readthedocs.io/en/stable/classification/dice.html#) (or implement your own if you prefer):\n\n``` python\n\nfrom torchmetrics.functional import dice\npreds = torch.tensor([1, 0, 0, 0])\ntarget = torch.tensor([1, 1, 0, 1])\nprint(\"Dice: \", dice(preds, target, average='micro'))\n\n```\n\n### Loss\n\nOne simple way to derive a loss from the competition's metric, is to set:\n\n`loss = 1 - metric`\n\nThis isn't however the best loss to use since it isn't differentiable so harder to optimize. Notice that we can make it differentiable by replacing the non-differentiable intersection with a differentiable element-wise product (as discussed [here](https://stackoverflow.com/questions/51973856/how-is-the-smooth-dice-loss-differentiable)) and letting the predictions be continuous (a probability instead of binary labels).\n\nAnother \"classic\" loss (that is differentiable this time) that we can try is the **binary [cross entropy](https://en.wikipedia.org/wiki/Cross_entropy)** (shortened often as BCE). \n\nYou can use the [`BCELoss`](https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html) implementation from PyTorch.\n\nHowever, as you might have guessed similarly to @nishantbhansali, this still isn't the best loss since we have a lof of background pixels (0 pixels) in comparison with FTU pixels. Thus, we need a solution to fix this imbalance (otherwise the model will predict 0 all the time). \n\nOne possible solution is to add the [Lovasz](https://openaccess.thecvf.com/content_cvpr_2018/papers/Berman_The_LovaSz-Softmax_Loss_CVPR_2018_paper.pdf) loss (as done in this top [solution](https://www.kaggle.com/competitions/hubmap-kidney-segmentation/discussion/238198)) to BCE. This implements a differentiable IoU (also known as [Jaccard index](https://torchmetrics.readthedocs.io/en/stable/classification/jaccard_index.html) and which is directly linked to Dice). Bingo!\n\nOne Lovasz implementation can be found [here](https://github.com/bermanmaxim/LovaszSoftmax). There is also one [notebook](https://github.com/bermanmaxim/LovaszSoftmax/blob/master/pytorch/demo_binary.ipynb) example.\n\n### Data\n\nNotice that all images contain at least one FTU (so no empty images but haven't yet check this claim) and\nthey come from healthy donors.\n\nOne particularity of this competition is that training data comes from one source (HPA), the\npublic testing is a mix of two sources (HPA and HubMAP), and the private testing is only the second source (HubMAP). \n\nThis is an interesting generalization challenge.\n\n### Training\n\nHere are some insights from the `train.csv` file:\n\n* The train metadata has `351` rows and `10` columns.\n* `id`: this is the image id. There are `351` unique image id, the same number of rows so\nthis isn't very useful.\n* `organ`: this is the organ for which the biopsy was done. There are `5` unique organs:\n`['prostate', 'spleen', 'lung', 'kidney', 'largeintestine']` with the following distribution:\n\n![organ_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F6fc2f9537a5ef427f906ae2395d66efc%2Forgan_value_counts.png?generation=1656236866064299&alt=media)\n\n* `data_source`: from where the data comes from. There is only one data source for the training: `HPA`.\n* `img_width`: the width of the image in pixels. Here is the list of the different possible values:\n`[3000, 2867, 2654, 2727, 2680, 2539, 2631, 2790, 2942, 2308, 2764, 2783, 2869, 2760, 2630, 2511, 2416, 2593, 2675, 3070]`. The `3000` is the dominant (326 out of 351), here is the distribution:\n\n![img_width_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F0ca15f350b45010e20d710025cb1986d%2Fimg_width_distribution.png?generation=1656236933358972&alt=media)\n\n* `img_height`: the height of the image in pixels. Similar to `img_height`, the `3000` value is the dominant one and we have a similar distribution.\n* `pixel_size`: the height/width of a single pixel from this image in micrometers. There is only one value: `0.4` (in μm).\n* `tissue_thickness`: the thickness of the biopsy sample in micrometers. Similar to the pixel size, there is only one value: `4` (in μm).\n* `rle`: this is the target we want to predict. It is the run-length encoded mask.\n* `age`: this is the patient's age in years. Notice that this won't be available for the testing dataset, so use with caution. Here is the distribution:\n\n![age_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F860a37ca1322c723990fe33ccd79b1a0%2Fage_distribution.png?generation=1656236813000062&alt=media)\n\n* `sex`: the sex of the patient. Two-thirds of males, on-third of females. Again, this is only provided for the training dataset. Here is the distribution:\n\n![sex_distribution](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F4882956a95234db73cc83b378b9cbde5%2Fsex_distribution.png?generation=1656236788652037&alt=media)\n\n\nHere is how to get the RLE into a mask and plot it:\n\n```\nfrom PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n```\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F3a8f66b8c8490c5e381d6f90b5d7feef%2Fmask.jpg?generation=1656360389223797&alt=media)\n\n### Testing\n\nOnly a fraction of the testing images are provided of course.\nHere are some insights:\n\n* Public dataset: mix of `HAP` and HubMAP data.\n* Private dataset: only `HubMAP` data.\n\n### Sources\n\nData comes from these two sources:\n\n* The Human BioMolecular Atlas Program data (shortened as HubMAP) comes from here: https://hubmapconsortium.org/\n* The Human Protein Atlas (shortened as HPA) data comes from here: https://www.proteinatlas.org/\n\n## Keywords\n\nLots of medical and segmentation jargon here as you would expect:\n\n* FTU: functional tissue unit.\n* RLE: run-length encoding.\n* DSC: dice similarity coefficient.\n* HubMAP: BioMolecular Atlas.\n* HPA: Human Protein Atlas.\n\n## Modeling\n\nHere are some modeling ideas:\n\n* One model for everything\n* One model per organ type\n\n## Validation\n\nSome ideas:\n\n* Random split validation\n* Validation that takes into account the distribution of the organs\n\n## Misc\n\nWhile researching things for this post, I have discovered the following topics:\n\n* https://en.wikipedia.org/wiki/Tissue_engineering\n\n## Useful Notebooks\n\nHere are some useful notebooks to get you started:\n\n* A great EDA: https://www.kaggle.com/code/ishandutta/hubmap-complete-understanding-and-eda-w-b\n* Another great EDA: https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking\n* A great notebook about the Dice metric: https://www.kaggle.com/code/arnavr10880/all-about-dice-coefficient\n* A great baseline model (can be improved a lot of course): https://www.kaggle.com/code/jirkaborovec/ftus-segm-eda-baseline-flash-deeplab-effnet\n* Run-length encoding and decoding: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\n* Same as above but more efficient: https://www.kaggle.com/code/xhlulu/efficient-mask2rle/notebook\n* How to work with TIFF files (warning, my own work): https://www.kaggle.com/code/yassinealouini/working-with-tiff-files\n* Various segmentation metrics detailed (warning, my own work again): https://www.kaggle.com/code/yassinealouini/all-the-segmentation-metrics.\n\n\n",
    "1838823": "I did a quick benchmark of various TIFF reading methods (I hope I am not doing anything stupid here):\n\n![tiff_reading_methods_benchmark](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2Fb5532315d6b9ba3a0eb803d07f90bb21%2Ftiff_reading_methods.jpg?generation=1656623639333000&alt=media)\n\n\nIt looks like PIL is the fastest method.",
    "1889568": "thanks for sharing. However if i want to process the images into several patches, do i need to take the 'pixel_size' into consideration?🙌",
    "1857588": "Nice discussion, a good guideline for the competition starter👍",
    "1842891": "although it is currently above my level. but still it's informative for me. sometimes I feel hesitant to write comments on a post. the author of that post may get the feeling that I am writing just to get upvoted. which is not at all a reason for my comments. I just wanted to appreciate that work.",
    "1837892": "This is an extremely useful thread, thanks for sharing @yassinealouini !",
    "1837890": "thanks for sharing. However, I don't think It is a good metric.",
    "1836043": "Well, that was a good post. Thanks for sharing👍",
    "1834577": "Thanks for putting this together. Appreciated!",
    "1833765": "Why isn't the dice loss the best loss to use? as per my understanding if we use per pixel BCE loss would'nt that introduce a bias as most pixels are **0**.  Hence even predicting the entire mask as empty should give a good score, and this can be misleading. \nPlease let me know if I'm wrong in thinking so\n\nThanks for the useful insights!\n",
    "1855178": "Interesting RLE function: https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook\nThanks to https://www.kaggle.com/bguberfain.",
    "1836576": "![deep_supervision_unet](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F172860%2F584e44c0d3a744c65d9adf478717d953%2Fdeep_supervision_unet_paper.jpg?generation=1656446664887118&alt=media)\n\n\nInteresting paper: https://arxiv.org/pdf/2103.03759.pdf\n\n",
    "1835538": "Here is an update to get RLE into a mask and then plot it:\n\n```\nfrom PIL import Image\nimport matplotlib.pylab as plt\nimport numpy as np\n\n\n# Source: https://www.kaggle.com/code/paulorzp/run-length-encode-and-decode/script\ndef rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    Source: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\n\n\nrle = train_df.loc[0, \"rle\"]\nimg_size = (int(train_df.loc[0, \"img_width\"]), \n            int(train_df.loc[0, \"img_height\"]))\n\nmask = rle2mask(rle, shape=img_size)\n\nprint(mask.shape)\n\nplt.imshow(mask)\n```\n\n",
    "1833752": "As usual, I will keep updating this post as I go and if you have comments/suggestions. Thanks.",
    "1923380": ""
  }
}