{
  "id": 48825,
  "title": "Idea for a solution: focus on boundaries",
  "url": "/competitions/data-science-bowl-2018/discussion/48825",
  "author_name": "Anne Carpenter",
  "post_date": "2018-02-02T17:19:26.181000",
  "votes": 17,
  "comment_count": 29,
  "views": 0,
  "content": "<p>Keeping in mind I'm not trained in deep learning myself - For what it's worth, I think this would be a great strategy for nucleus segmentation; it's something we haven't tried in my lab and it relies solely on pixel-level prediction for the deep learning steps:</p>\n\n<p>Step 1: Neural Network (NN) for foreground/background (nuclei vs non-nuclei). One could almost get away with adaptive thresholding here, but the potential for different color schemes makes it hard to know which channel (or combos of channels) to use for this so I assume NNs magically figure this out). This yields a foreground/background probability map.</p>\n\n<p>Step 2: NN for boundary pixels, but ONLY those boundaries between adjacent nuclei (it’s easy to create ground truth for this from any style of annotation). This makes a boundaries probability map.</p>\n\n<p>Step 3: “subtract” the boundaries probability map from the foreground/background probability map (so if the foreground is whitish, the boundaries are dark pixels imprinted onto the foreground image) </p>\n\n<p>Step 4: post-processing to turn into proper masks, maybe need to use something like CellProfiler's IdentifyPrimaryObjects module to find peaks and then proper boundaries.</p>\n\n<p>I'd love to see someone try this.</p>",
  "messages": [
    {
      "id": 277273,
      "postDate": "2018-02-02T17:19:26.180Z",
      "content": "<p>Keeping in mind I'm not trained in deep learning myself - For what it's worth, I think this would be a great strategy for nucleus segmentation; it's something we haven't tried in my lab and it relies solely on pixel-level prediction for the deep learning steps:</p>\n\n<p>Step 1: Neural Network (NN) for foreground/background (nuclei vs non-nuclei). One could almost get away with adaptive thresholding here, but the potential for different color schemes makes it hard to know which channel (or combos of channels) to use for this so I assume NNs magically figure this out). This yields a foreground/background probability map.</p>\n\n<p>Step 2: NN for boundary pixels, but ONLY those boundaries between adjacent nuclei (it’s easy to create ground truth for this from any style of annotation). This makes a boundaries probability map.</p>\n\n<p>Step 3: “subtract” the boundaries probability map from the foreground/background probability map (so if the foreground is whitish, the boundaries are dark pixels imprinted onto the foreground image) </p>\n\n<p>Step 4: post-processing to turn into proper masks, maybe need to use something like CellProfiler's IdentifyPrimaryObjects module to find peaks and then proper boundaries.</p>\n\n<p>I'd love to see someone try this.</p>",
      "rawMarkdown": "Keeping in mind I'm not trained in deep learning myself - For what it's worth, I think this would be a great strategy for nucleus segmentation; it's something we haven't tried in my lab and it relies solely on pixel-level prediction for the deep learning steps:\n\nStep 1: Neural Network (NN) for foreground/background (nuclei vs non-nuclei). One could almost get away with adaptive thresholding here, but the potential for different color schemes makes it hard to know which channel (or combos of channels) to use for this so I assume NNs magically figure this out). This yields a foreground/background probability map.\n\nStep 2: NN for boundary pixels, but ONLY those boundaries between adjacent nuclei (it’s easy to create ground truth for this from any style of annotation). This makes a boundaries probability map.\n\nStep 3: “subtract” the boundaries probability map from the foreground/background probability map (so if the foreground is whitish, the boundaries are dark pixels imprinted onto the foreground image) \n\nStep 4: post-processing to turn into proper masks, maybe need to use something like CellProfiler's IdentifyPrimaryObjects module to find peaks and then proper boundaries.\n\nI'd love to see someone try this.",
      "votes": 17
    },
    {
      "id": 277316,
      "postDate": "2018-02-02T19:21:25.390Z",
      "content": "<p>I'm pretty new at segmentation and just read the U-Net paper. They actually use a weighted loss that weights pixels on the boundaries between nuclei (cells in their case) much higher than other pixels. Apparently this encourages the NN to leave a gap between the cells so it can treat them as separate objects.</p>",
      "rawMarkdown": "I'm pretty new at segmentation and just read the U-Net paper. They actually use a weighted loss that weights pixels on the boundaries between nuclei (cells in their case) much higher than other pixels. Apparently this encourages the NN to leave a gap between the cells so it can treat them as separate objects.",
      "votes": 4
    },
    {
      "id": 277406,
      "postDate": "2018-02-03T01:58:13.523Z",
      "content": "<p>That was originally what I did. No matter what I tried, it never reached more than 0.35 score. There are multiple reasons for that. Overall, Nuclei are often very few - makes it hard to balance the loss - which results in not very consistent touch boundary prediction.</p>",
      "rawMarkdown": "That was originally what I did. No matter what I tried, it never reached more than 0.35 score. There are multiple reasons for that. Overall, Nuclei are often very few - makes it hard to balance the loss - which results in not very consistent touch boundary prediction.",
      "votes": 1
    },
    {
      "id": 277283,
      "postDate": "2018-02-02T17:42:51.193Z",
      "content": "<p>Hi!! </p>\n\n<p>I am implementing the step 1 and 3  in my method. I will post results here. I will to try step4 after.</p>",
      "rawMarkdown": "Hi!! \n\nI am implementing the step 1 and 3  in my method. I will post results here. I will to try step4 after.",
      "votes": 1
    },
    {
      "id": 277281,
      "postDate": "2018-02-02T17:37:52.847Z",
      "content": "<p>I'm up for the task. </p>",
      "rawMarkdown": "I'm up for the task. ",
      "votes": 1
    },
    {
      "id": 289906,
      "postDate": "2018-03-02T15:30:07.663Z",
      "content": "<p>Joining the crowd late as I started this week only.  Catching up on the forum, I see that my core idea is very close to what you describe, except I train only one NN (a modified unet) with 3 classes: background, boundary common to 2 masks, remainder of masks.</p>\n\n<p>As Heng noticed, this leads to some mask erosion, hence some post processing is required to expand the labeled regions predicted by the third class.  My first shot at it moved my LB score from 0.36x to 0.406 .   I'll focus on that for now.  Seems others get at least 0.42 with multi class unet, there is hope for improvement therefore!</p>",
      "rawMarkdown": "Joining the crowd late as I started this week only.  Catching up on the forum, I see that my core idea is very close to what you describe, except I train only one NN (a modified unet) with 3 classes: background, boundary common to 2 masks, remainder of masks.\n\nAs Heng noticed, this leads to some mask erosion, hence some post processing is required to expand the labeled regions predicted by the third class.  My first shot at it moved my LB score from 0.36x to 0.406 .   I'll focus on that for now.  Seems others get at least 0.42 with multi class unet, there is hope for improvement therefore!",
      "votes": 2,
      "replies": [
        {
          "id": 289910,
          "postDate": "2018-03-02T15:33:14.340Z",
          "content": "<p>The classes don't have to be mutually exclusive, so it's possible to avoid mask erosion. For me, predicting all boundaries works a bit better than predicting only overlapping boundaries, although still a far cry from top scores.</p>",
          "rawMarkdown": "The classes don't have to be mutually exclusive, so it's possible to avoid mask erosion. For me, predicting all boundaries works a bit better than predicting only overlapping boundaries, although still a far cry from top scores.",
          "votes": 2
        },
        {
          "id": 289914,
          "postDate": "2018-03-02T15:37:49.130Z",
          "content": "<p>Thanks, I agree with you that having overlapping classes is a good way to deal with the erosion, will try it.  However categorical cross entropy assumes the output comes form a softmax (in Keras).  I wonder if your approach will work with Keras.  I'll try it anyway and report outcome.</p>\n\n<p>I'll also have a try at predicting all boundaries.</p>\n\n<p>I don't expect top scores with that, I'm just learning as this is my first image competition ;)  Will move to mask rcnn after given this seems to be the way to go here.</p>",
          "rawMarkdown": "Thanks, I agree with you that having overlapping classes is a good way to deal with the erosion, will try it.  However categorical cross entropy assumes the output comes form a softmax (in Keras).  I wonder if your approach will work with Keras.  I'll try it anyway and report outcome.\n\nI'll also have a try at predicting all boundaries.\n\nI don't expect top scores with that, I'm just learning as this is my first image competition ;)  Will move to mask rcnn after given this seems to be the way to go here.",
          "votes": 1
        },
        {
          "id": 289922,
          "postDate": "2018-03-02T15:46:44.793Z",
          "content": "<blockquote>\n  <p>However categorical cross entropy assumes the output comes form a softmax</p>\n</blockquote>\n\n<p>Yes, in this case a binary cross-entropy would be better.</p>",
          "rawMarkdown": "&gt; However categorical cross entropy assumes the output comes form a softmax\n\nYes, in this case a binary cross-entropy would be better.",
          "votes": 2
        },
        {
          "id": 290250,
          "postDate": "2018-03-03T13:57:32.807Z",
          "content": "<p>Keeping the masks as original instead of removing their common boundaries improves my cv and lb score a bit.  Thanks for the tip!</p>",
          "rawMarkdown": "Keeping the masks as original instead of removing their common boundaries improves my cv and lb score a bit.  Thanks for the tip!",
          "votes": 2
        },
        {
          "id": 295594,
          "postDate": "2018-03-13T22:03:24.370Z",
          "content": "<p>@CPMP and @Konstantin, after having read this discussion, I added overlapping boundaries to one of the output classes and did a 6-fold CV (with 20 epochs for each model) and averaged the predictions, my LB got worse. It seems overlapping boundaries are not predicted too well when there are lots of cells in the image. In addition to remove noises (applying an area opening filter), I XORed the overlapping boundaries with the predicted boundaries. Any thoughts of how I can improve?</p>\n\n<p>And aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help? However, I'm going to try to predict all boundaries anyway. I'm getting desperate before moving on to the mask RCNN. </p>",
          "rawMarkdown": "@CPMP and @Konstantin, after having read this discussion, I added overlapping boundaries to one of the output classes and did a 6-fold CV (with 20 epochs for each model) and averaged the predictions, my LB got worse. It seems overlapping boundaries are not predicted too well when there are lots of cells in the image. In addition to remove noises (applying an area opening filter), I XORed the overlapping boundaries with the predicted boundaries. Any thoughts of how I can improve?\n\nAnd aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help? However, I'm going to try to predict all boundaries anyway. I'm getting desperate before moving on to the mask RCNN. "
        },
        {
          "id": 295597,
          "postDate": "2018-03-13T22:07:24.237Z",
          "content": "<blockquote>\n  <p>And aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help?</p>\n</blockquote>\n\n<p>Predicting boundaries helps with separation of touching nuclei during watershed postprocessing.</p>",
          "rawMarkdown": "&gt; And aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help?\n\nPredicting boundaries helps with separation of touching nuclei during watershed postprocessing."
        },
        {
          "id": 295602,
          "postDate": "2018-03-13T22:20:46.497Z",
          "content": "<p>@Konstantin, excellent, you're dead right on that. Thank you for the tip. </p>",
          "rawMarkdown": "@Konstantin, excellent, you're dead right on that. Thank you for the tip. "
        }
      ]
    },
    {
      "id": 278125,
      "postDate": "2018-02-05T12:40:01.400Z",
      "content": "<p>I tried the following</p>\n\n<ol>\n<li><p>from the train image and label, create foreground and background segmentation (i.e. discard object instance information )</p></li>\n<li><p>from the train image and label, create boundary (1 pixel thick)</p></li>\n<li><p>make prediction = (1)-(2)</p></li>\n<li><p>measure the metric score.</p></li>\n</ol>\n\n<p>This represents the best possible results for pipeline steps from 1 to 4. It seems that i can only get metric score about 0.5. This is because the boundary can \"erode about a pixel\" of the segmentation. This is not so important in real application. But for this competition, it is a disadvantage. The metric is average mean-precision.  \"Erosion about a pixel\" cause poor precision at IOU &gt;0.7.  precision=0 for IOU &gt;0.8 to 0.9, especially for small nuclei.</p>\n\n<hr>\n\n<p>Then, how about post-processing to bring back the eroded pixel?</p>\n\n<p>The heuristics methods are not reliable.  We may need to like a post-processing network. In that case i think mask-rcnn is an easier approach.</p>\n\n<p>Alternative, we can up-size the image so that the nuclei is \"big\" and boundary is small.</p>\n\n<p>Note that similar method has be described in <a href=\"https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690\">https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690</a>. especially: <a href=\"https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/\">https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/</a>\n(2015 Gland Segmentation Challenge solution)</p>\n\n<p>and</p>\n\n<p><a href=\"https://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/\">https://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/</a></p>",
      "rawMarkdown": "I tried the following\n\n1. from the train image and label, create foreground and background segmentation (i.e. discard object instance information )\n\n2. from the train image and label, create boundary (1 pixel thick)\n\n3. make prediction = (1)-(2)\n\n4. measure the metric score.\n\nThis represents the best possible results for pipeline steps from 1 to 4. It seems that i can only get metric score about 0.5. This is because the boundary can \"erode about a pixel\" of the segmentation. This is not so important in real application. But for this competition, it is a disadvantage. The metric is average mean-precision.  \"Erosion about a pixel\" cause poor precision at IOU &gt;0.7.  precision=0 for IOU &gt;0.8 to 0.9, especially for small nuclei.\n\n---\n\nThen, how about post-processing to bring back the eroded pixel?\n\nThe heuristics methods are not reliable.  We may need to like a post-processing network. In that case i think mask-rcnn is an easier approach.\n\n\nAlternative, we can up-size the image so that the nuclei is \"big\" and boundary is small.\n\nNote that similar method has be described in https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690. especially: https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/\n(2015 Gland Segmentation Challenge solution)\n\nand\n\nhttps://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/\n",
      "votes": 2,
      "replies": [
        {
          "id": 278139,
          "postDate": "2018-02-05T13:02:49.093Z",
          "content": "<p>some of my other results, see <a href=\"https://www.kaggle.com/c/data-science-bowl-2018/discussion/47686\">https://www.kaggle.com/c/data-science-bowl-2018/discussion/47686</a></p>\n\n<p><img src=\"https://storage.googleapis.com/kaggle-forum-message-attachments/271841/8332/post_process.png\" alt=\"enter image description here\"></p>",
          "rawMarkdown": "some of my other results, see https://www.kaggle.com/c/data-science-bowl-2018/discussion/47686\n\n ![enter image description here][1]\n\n\n  [1]: https://kaggle2.blob.core.windows.net/forum-message-attachments/271841/8332/post_process.png",
          "votes": 2
        },
        {
          "id": 295796,
          "postDate": "2018-03-14T07:43:56.327Z",
          "content": "<p>@Heng CherKeng   do you mean you discarded each individual mask and only used sure foreground (each mask may shrink a bit after threshold/distance transformation ), sure background and contours as your labelled data?</p>",
          "rawMarkdown": "@Heng CherKeng   do you mean you discarded each individual mask and only used sure foreground (each mask may shrink a bit after threshold/distance transformation ), sure background and contours as your labelled data?"
        },
        {
          "id": 296016,
          "postDate": "2018-03-14T15:40:18.390Z",
          "content": "<p>currently, i dropped this method  becuase i cannot find a good way to do the post processing. What i have shown the the pictures above is simply predicted_mask subtracted by predicted_contour.</p>\n\n<p>For training, we use the original mask as mask ground truth.\nIn additional, we extract the contour and use as contour ground truth. \nA pixel can be labelled as both mask and contour. It is a multi-lablel setup.</p>\n\n<p>(i.e. the probability computed as sigmoid output and not softmax, which is used for multi-class single-label problem)</p>\n\n<p>However, some kagglers can get quite good results (e.g. ~0.46)) with this kind of method. you  can check their posts</p>",
          "rawMarkdown": "currently, i dropped this method  becuase i cannot find a good way to do the post processing. What i have shown the the pictures above is simply predicted_mask subtracted by predicted_contour.\n\nFor training, we use the original mask as mask ground truth.\nIn additional, we extract the contour and use as contour ground truth. \nA pixel can be labelled as both mask and contour. It is a multi-lablel setup.\n\n(i.e. the probability computed as sigmoid output and not softmax, which is used for multi-class single-label problem)\n\nHowever, some kagglers can get quite good results (e.g. ~0.46)) with this kind of method. you  can check their posts",
          "votes": 2
        },
        {
          "id": 296033,
          "postDate": "2018-03-14T16:14:09.120Z",
          "content": "<p>@Heng CherKeng, Thanks. My approach was kind of similar. I did 2 output classes with the original masks and the boundaries of adjacent cells , and the output was sigmoid (U-net), however, the overlapping boundaries were not predicted well and ended up hurting the predicted masks. We were better off without. And I did find some top scorers using contours and they used watershed, masks and background as outputs and came across your post. Thanks for your contributions to the Kaggle community.</p>",
          "rawMarkdown": "@Heng CherKeng, Thanks. My approach was kind of similar. I did 2 output classes with the original masks and the boundaries of adjacent cells , and the output was sigmoid (U-net), however, the overlapping boundaries were not predicted well and ended up hurting the predicted masks. We were better off without. And I did find some top scorers using contours and they used watershed, masks and background as outputs and came across your post. Thanks for your contributions to the Kaggle community.",
          "votes": 1
        }
      ]
    },
    {
      "id": 281369,
      "postDate": "2018-02-12T16:55:06.227Z",
      "content": "<p>I think this is a good direction for the bottom-up method like u-net. And this is the way I'm doing now. I got 0.402 scores. As @Heng say, it really takes some post-processing.</p>",
      "rawMarkdown": "I think this is a good direction for the bottom-up method like u-net. And this is the way I'm doing now. I got 0.402 scores. As @Heng say, it really takes some post-processing."
    },
    {
      "id": 278057,
      "postDate": "2018-02-05T08:54:25.583Z",
      "content": "<p>For <em>Step1</em> and thresholding: <a href=\"https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation\">https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation</a></p>\n\n<p>Here we use HSV color space so it is easier to distinguish which channels are useful. The kernel is not complete but it is a good starting point.</p>",
      "rawMarkdown": "For *Step1* and thresholding: https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation\n\nHere we use HSV color space so it is easier to distinguish which channels are useful. The kernel is not complete but it is a good starting point."
    },
    {
      "id": 282066,
      "postDate": "2018-02-13T15:20:48.773Z",
      "rawMarkdown": "",
      "votes": 8,
      "isDeleted": true,
      "replies": [
        {
          "id": 282074,
          "postDate": "2018-02-13T15:36:56.877Z",
          "content": "<p>Hi, Tariq. Nice score! If you don’t mind sharing, are you using U-Net or another fully convolutional network? Are you using imregionalmax to find peaks to watershed?</p>",
          "rawMarkdown": "Hi, Tariq. Nice score! If you don’t mind sharing, are you using U-Net or another fully convolutional network? Are you using imregionalmax to find peaks to watershed?\n",
          "votes": 5
        },
        {
          "id": 282108,
          "postDate": "2018-02-13T16:40:23.870Z",
          "content": "<p>What model are you using?</p>",
          "rawMarkdown": "What model are you using?"
        },
        {
          "id": 283016,
          "postDate": "2018-02-14T21:08:33.813Z",
          "content": "<p>Did you use imregionalmax function with Matlab or Python? </p>",
          "rawMarkdown": "Did you use imregionalmax function with Matlab or Python? ",
          "votes": 1
        },
        {
          "id": 289901,
          "postDate": "2018-03-02T15:21:20.173Z",
          "content": "<p>Seems the GPU version is for Matlab.  I don't know if using Matlab is allowed by the rules, but you can get an equivalent result with Python, albeit on cpu, see <a href=\"https://stackoverflow.com/questions/27598103/what-is-the-difference-between-imregionalmax-of-matlab-and-scipy-ndimage-filte\">https://stackoverflow.com/questions/27598103/what-is-the-difference-between-imregionalmax-of-matlab-and-scipy-ndimage-filte</a></p>\n\n<p>I have not used it yet, will give it a try soon.</p>",
          "rawMarkdown": "Seems the GPU version is for Matlab.  I don't know if using Matlab is allowed by the rules, but you can get an equivalent result with Python, albeit on cpu, see https://stackoverflow.com/questions/27598103/what-is-the-difference-between-imregionalmax-of-matlab-and-scipy-ndimage-filte\n\nI have not used it yet, will give it a try soon."
        },
        {
          "id": 289962,
          "postDate": "2018-03-02T17:09:37.457Z",
          "content": "<p>I seen this a few weeks back. But, I didn't know how to implement it in my code.</p>",
          "rawMarkdown": "I seen this a few weeks back. But, I didn't know how to implement it in my code."
        },
        {
          "id": 290261,
          "postDate": "2018-03-03T14:34:25.180Z",
          "content": "<p>Seems there is a direct way to get it with skimage.feature.peak_local_max()</p>",
          "rawMarkdown": "Seems there is a direct way to get it with skimage.feature.peak_local_max()"
        },
        {
          "id": 290622,
          "postDate": "2018-03-04T15:16:42.020Z",
          "content": "<p>@CPMP: Given a binary mask (like Unet result), could you provide some codes to make  instance segmentations using <code>skimage.feature.peak_local_max()</code>. I am using the link but it does not work <a href=\"http://blog.wolfram.com/2012/01/04/how-to-count-cells-annihilate-sailboats-and-warp-the-mona-lisa/\">http://blog.wolfram.com/2012/01/04/how-to-count-cells-annihilate-sailboats-and-warp-the-mona-lisa/</a></p>",
          "rawMarkdown": "@CPMP: Given a binary mask (like Unet result), could you provide some codes to make  instance segmentations using `skimage.feature.peak_local_max()`. I am using the link but it does not work http://blog.wolfram.com/2012/01/04/how-to-count-cells-annihilate-sailboats-and-warp-the-mona-lisa/"
        },
        {
          "id": 290642,
          "postDate": "2018-03-04T16:14:37.220Z",
          "content": "<p>I am not using it ;)  I was just responding to the question about how to do it in Python.</p>\n\n<p>But this may be useful to you: <a href=\"http://www.scipy-lectures.org/packages/scikit-image/index.html#marker-based-methods\">http://www.scipy-lectures.org/packages/scikit-image/index.html#marker-based-methods</a></p>",
          "rawMarkdown": "I am not using it ;)  I was just responding to the question about how to do it in Python.\n\nBut this may be useful to you: http://www.scipy-lectures.org/packages/scikit-image/index.html#marker-based-methods"
        }
      ]
    },
    {
      "id": 277430,
      "postDate": "2018-02-03T05:29:08.027Z",
      "rawMarkdown": "",
      "votes": 2,
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 277316,
      "author_name": "Human Analog",
      "author_url": "",
      "post_date": "2018-02-02T19:21:25.390000",
      "content": "<p>I'm pretty new at segmentation and just read the U-Net paper. They actually use a weighted loss that weights pixels on the boundaries between nuclei (cells in their case) much higher than other pixels. Apparently this encourages the NN to leave a gap between the cells so it can treat them as separate objects.</p>",
      "votes": 4,
      "replies": []
    },
    {
      "id": 277406,
      "author_name": "Oleksandr Bailo",
      "author_url": "",
      "post_date": "2018-02-03T01:58:13.523000",
      "content": "<p>That was originally what I did. No matter what I tried, it never reached more than 0.35 score. There are multiple reasons for that. Overall, Nuclei are often very few - makes it hard to balance the loss - which results in not very consistent touch boundary prediction.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 277283,
      "author_name": "arigarcia",
      "author_url": "",
      "post_date": "2018-02-02T17:42:51.193000",
      "content": "<p>Hi!! </p>\n\n<p>I am implementing the step 1 and 3  in my method. I will post results here. I will to try step4 after.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 277281,
      "author_name": "William Green",
      "author_url": "",
      "post_date": "2018-02-02T17:37:52.847000",
      "content": "<p>I'm up for the task. </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 289906,
      "author_name": "CPMP",
      "author_url": "",
      "post_date": "2018-03-02T15:30:07.663000",
      "content": "<p>Joining the crowd late as I started this week only.  Catching up on the forum, I see that my core idea is very close to what you describe, except I train only one NN (a modified unet) with 3 classes: background, boundary common to 2 masks, remainder of masks.</p>\n\n<p>As Heng noticed, this leads to some mask erosion, hence some post processing is required to expand the labeled regions predicted by the third class.  My first shot at it moved my LB score from 0.36x to 0.406 .   I'll focus on that for now.  Seems others get at least 0.42 with multi class unet, there is hope for improvement therefore!</p>",
      "votes": 2,
      "replies": [
        {
          "id": 289910,
          "author_name": "Konstantin Lopukhin",
          "author_url": "",
          "post_date": "2018-03-02T15:33:14.340000",
          "content": "<p>The classes don't have to be mutually exclusive, so it's possible to avoid mask erosion. For me, predicting all boundaries works a bit better than predicting only overlapping boundaries, although still a far cry from top scores.</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 289914,
          "author_name": "CPMP",
          "author_url": "",
          "post_date": "2018-03-02T15:37:49.130000",
          "content": "<p>Thanks, I agree with you that having overlapping classes is a good way to deal with the erosion, will try it.  However categorical cross entropy assumes the output comes form a softmax (in Keras).  I wonder if your approach will work with Keras.  I'll try it anyway and report outcome.</p>\n\n<p>I'll also have a try at predicting all boundaries.</p>\n\n<p>I don't expect top scores with that, I'm just learning as this is my first image competition ;)  Will move to mask rcnn after given this seems to be the way to go here.</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 289922,
          "author_name": "Konstantin Lopukhin",
          "author_url": "",
          "post_date": "2018-03-02T15:46:44.793000",
          "content": "<blockquote>\n  <p>However categorical cross entropy assumes the output comes form a softmax</p>\n</blockquote>\n\n<p>Yes, in this case a binary cross-entropy would be better.</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 290250,
          "author_name": "CPMP",
          "author_url": "",
          "post_date": "2018-03-03T13:57:32.807000",
          "content": "<p>Keeping the masks as original instead of removing their common boundaries improves my cv and lb score a bit.  Thanks for the tip!</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 295594,
          "author_name": "Nicole Finnie",
          "author_url": "",
          "post_date": "2018-03-13T22:03:24.370000",
          "content": "<p>@CPMP and @Konstantin, after having read this discussion, I added overlapping boundaries to one of the output classes and did a 6-fold CV (with 20 epochs for each model) and averaged the predictions, my LB got worse. It seems overlapping boundaries are not predicted too well when there are lots of cells in the image. In addition to remove noises (applying an area opening filter), I XORed the overlapping boundaries with the predicted boundaries. Any thoughts of how I can improve?</p>\n\n<p>And aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help? However, I'm going to try to predict all boundaries anyway. I'm getting desperate before moving on to the mask RCNN. </p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 295597,
          "author_name": "Konstantin Lopukhin",
          "author_url": "",
          "post_date": "2018-03-13T22:07:24.237000",
          "content": "<blockquote>\n  <p>And aren't predicting masks and predicting boundaries the same thing? Would having both output classes really help?</p>\n</blockquote>\n\n<p>Predicting boundaries helps with separation of touching nuclei during watershed postprocessing.</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 295602,
          "author_name": "Nicole Finnie",
          "author_url": "",
          "post_date": "2018-03-13T22:20:46.497000",
          "content": "<p>@Konstantin, excellent, you're dead right on that. Thank you for the tip. </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 278125,
      "author_name": "hengck23",
      "author_url": "",
      "post_date": "2018-02-05T12:40:01.400000",
      "content": "<p>I tried the following</p>\n\n<ol>\n<li><p>from the train image and label, create foreground and background segmentation (i.e. discard object instance information )</p></li>\n<li><p>from the train image and label, create boundary (1 pixel thick)</p></li>\n<li><p>make prediction = (1)-(2)</p></li>\n<li><p>measure the metric score.</p></li>\n</ol>\n\n<p>This represents the best possible results for pipeline steps from 1 to 4. It seems that i can only get metric score about 0.5. This is because the boundary can \"erode about a pixel\" of the segmentation. This is not so important in real application. But for this competition, it is a disadvantage. The metric is average mean-precision.  \"Erosion about a pixel\" cause poor precision at IOU &gt;0.7.  precision=0 for IOU &gt;0.8 to 0.9, especially for small nuclei.</p>\n\n<hr>\n\n<p>Then, how about post-processing to bring back the eroded pixel?</p>\n\n<p>The heuristics methods are not reliable.  We may need to like a post-processing network. In that case i think mask-rcnn is an easier approach.</p>\n\n<p>Alternative, we can up-size the image so that the nuclei is \"big\" and boundary is small.</p>\n\n<p>Note that similar method has be described in <a href=\"https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690\">https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690</a>. especially: <a href=\"https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/\">https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/</a>\n(2015 Gland Segmentation Challenge solution)</p>\n\n<p>and</p>\n\n<p><a href=\"https://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/\">https://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/</a></p>",
      "votes": 2,
      "replies": [
        {
          "id": 278139,
          "author_name": "hengck23",
          "author_url": "",
          "post_date": "2018-02-05T13:02:49.093000",
          "content": "<p>some of my other results, see <a href=\"https://www.kaggle.com/c/data-science-bowl-2018/discussion/47686\">https://www.kaggle.com/c/data-science-bowl-2018/discussion/47686</a></p>\n\n<p><img src=\"https://storage.googleapis.com/kaggle-forum-message-attachments/271841/8332/post_process.png\" alt=\"enter image description here\"></p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 295796,
          "author_name": "Nicole Finnie",
          "author_url": "",
          "post_date": "2018-03-14T07:43:56.327000",
          "content": "<p>@Heng CherKeng   do you mean you discarded each individual mask and only used sure foreground (each mask may shrink a bit after threshold/distance transformation ), sure background and contours as your labelled data?</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 296016,
          "author_name": "hengck23",
          "author_url": "",
          "post_date": "2018-03-14T15:40:18.390000",
          "content": "<p>currently, i dropped this method  becuase i cannot find a good way to do the post processing. What i have shown the the pictures above is simply predicted_mask subtracted by predicted_contour.</p>\n\n<p>For training, we use the original mask as mask ground truth.\nIn additional, we extract the contour and use as contour ground truth. \nA pixel can be labelled as both mask and contour. It is a multi-lablel setup.</p>\n\n<p>(i.e. the probability computed as sigmoid output and not softmax, which is used for multi-class single-label problem)</p>\n\n<p>However, some kagglers can get quite good results (e.g. ~0.46)) with this kind of method. you  can check their posts</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 296033,
          "author_name": "Nicole Finnie",
          "author_url": "",
          "post_date": "2018-03-14T16:14:09.120000",
          "content": "<p>@Heng CherKeng, Thanks. My approach was kind of similar. I did 2 output classes with the original masks and the boundaries of adjacent cells , and the output was sigmoid (U-net), however, the overlapping boundaries were not predicted well and ended up hurting the predicted masks. We were better off without. And I did find some top scorers using contours and they used watershed, masks and background as outputs and came across your post. Thanks for your contributions to the Kaggle community.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 281369,
      "author_name": "Cheng, Hua",
      "author_url": "",
      "post_date": "2018-02-12T16:55:06.227000",
      "content": "<p>I think this is a good direction for the bottom-up method like u-net. And this is the way I'm doing now. I got 0.402 scores. As @Heng say, it really takes some post-processing.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 278057,
      "author_name": "Gábor Vecsei",
      "author_url": "",
      "post_date": "2018-02-05T08:54:25.583000",
      "content": "<p>For <em>Step1</em> and thresholding: <a href=\"https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation\">https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation</a></p>\n\n<p>Here we use HSV color space so it is easier to distinguish which channels are useful. The kernel is not complete but it is a good starting point.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 282066,
      "author_name": "",
      "author_url": "",
      "post_date": "2018-02-13T15:20:48.773000",
      "content": "",
      "votes": 8,
      "replies": [
        {
          "id": 282074,
          "author_name": "Allen Goodman",
          "author_url": "",
          "post_date": "2018-02-13T15:36:56.877000",
          "content": "<p>Hi, Tariq. Nice score! If you don’t mind sharing, are you using U-Net or another fully convolutional network? Are you using imregionalmax to find peaks to watershed?</p>",
          "votes": 5,
          "replies": []
        },
        {
          "id": 282108,
          "author_name": "William Green",
          "author_url": "",
          "post_date": "2018-02-13T16:40:23.870000",
          "content": "<p>What model are you using?</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 283016,
          "author_name": "William Green",
          "author_url": "",
          "post_date": "2018-02-14T21:08:33.813000",
          "content": "<p>Did you use imregionalmax function with Matlab or Python? </p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 289901,
          "author_name": "CPMP",
          "author_url": "",
          "post_date": "2018-03-02T15:21:20.173000",
          "content": "<p>Seems the GPU version is for Matlab.  I don't know if using Matlab is allowed by the rules, but you can get an equivalent result with Python, albeit on cpu, see <a href=\"https://stackoverflow.com/questions/27598103/what-is-the-difference-between-imregionalmax-of-matlab-and-scipy-ndimage-filte\">https://stackoverflow.com/questions/27598103/what-is-the-difference-between-imregionalmax-of-matlab-and-scipy-ndimage-filte</a></p>\n\n<p>I have not used it yet, will give it a try soon.</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 289962,
          "author_name": "William Green",
          "author_url": "",
          "post_date": "2018-03-02T17:09:37.457000",
          "content": "<p>I seen this a few weeks back. But, I didn't know how to implement it in my code.</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 290261,
          "author_name": "CPMP",
          "author_url": "",
          "post_date": "2018-03-03T14:34:25.180000",
          "content": "<p>Seems there is a direct way to get it with skimage.feature.peak_local_max()</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 290622,
          "author_name": "john1231983",
          "author_url": "",
          "post_date": "2018-03-04T15:16:42.020000",
          "content": "<p>@CPMP: Given a binary mask (like Unet result), could you provide some codes to make  instance segmentations using <code>skimage.feature.peak_local_max()</code>. I am using the link but it does not work <a href=\"http://blog.wolfram.com/2012/01/04/how-to-count-cells-annihilate-sailboats-and-warp-the-mona-lisa/\">http://blog.wolfram.com/2012/01/04/how-to-count-cells-annihilate-sailboats-and-warp-the-mona-lisa/</a></p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 290642,
          "author_name": "CPMP",
          "author_url": "",
          "post_date": "2018-03-04T16:14:37.220000",
          "content": "<p>I am not using it ;)  I was just responding to the question about how to do it in Python.</p>\n\n<p>But this may be useful to you: <a href=\"http://www.scipy-lectures.org/packages/scikit-image/index.html#marker-based-methods\">http://www.scipy-lectures.org/packages/scikit-image/index.html#marker-based-methods</a></p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 277430,
      "author_name": "",
      "author_url": "",
      "post_date": "2018-02-03T05:29:08.027000",
      "content": "",
      "votes": 2,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "277273": "Keeping in mind I'm not trained in deep learning myself - For what it's worth, I think this would be a great strategy for nucleus segmentation; it's something we haven't tried in my lab and it relies solely on pixel-level prediction for the deep learning steps:\n\nStep 1: Neural Network (NN) for foreground/background (nuclei vs non-nuclei). One could almost get away with adaptive thresholding here, but the potential for different color schemes makes it hard to know which channel (or combos of channels) to use for this so I assume NNs magically figure this out). This yields a foreground/background probability map.\n\nStep 2: NN for boundary pixels, but ONLY those boundaries between adjacent nuclei (it’s easy to create ground truth for this from any style of annotation). This makes a boundaries probability map.\n\nStep 3: “subtract” the boundaries probability map from the foreground/background probability map (so if the foreground is whitish, the boundaries are dark pixels imprinted onto the foreground image) \n\nStep 4: post-processing to turn into proper masks, maybe need to use something like CellProfiler's IdentifyPrimaryObjects module to find peaks and then proper boundaries.\n\nI'd love to see someone try this.",
    "277316": "I'm pretty new at segmentation and just read the U-Net paper. They actually use a weighted loss that weights pixels on the boundaries between nuclei (cells in their case) much higher than other pixels. Apparently this encourages the NN to leave a gap between the cells so it can treat them as separate objects.",
    "277406": "That was originally what I did. No matter what I tried, it never reached more than 0.35 score. There are multiple reasons for that. Overall, Nuclei are often very few - makes it hard to balance the loss - which results in not very consistent touch boundary prediction.",
    "277283": "Hi!! \n\nI am implementing the step 1 and 3  in my method. I will post results here. I will to try step4 after.",
    "277281": "I'm up for the task. ",
    "289906": "Joining the crowd late as I started this week only.  Catching up on the forum, I see that my core idea is very close to what you describe, except I train only one NN (a modified unet) with 3 classes: background, boundary common to 2 masks, remainder of masks.\n\nAs Heng noticed, this leads to some mask erosion, hence some post processing is required to expand the labeled regions predicted by the third class.  My first shot at it moved my LB score from 0.36x to 0.406 .   I'll focus on that for now.  Seems others get at least 0.42 with multi class unet, there is hope for improvement therefore!",
    "278125": "I tried the following\n\n1. from the train image and label, create foreground and background segmentation (i.e. discard object instance information )\n\n2. from the train image and label, create boundary (1 pixel thick)\n\n3. make prediction = (1)-(2)\n\n4. measure the metric score.\n\nThis represents the best possible results for pipeline steps from 1 to 4. It seems that i can only get metric score about 0.5. This is because the boundary can \"erode about a pixel\" of the segmentation. This is not so important in real application. But for this competition, it is a disadvantage. The metric is average mean-precision.  \"Erosion about a pixel\" cause poor precision at IOU &gt;0.7.  precision=0 for IOU &gt;0.8 to 0.9, especially for small nuclei.\n\n---\n\nThen, how about post-processing to bring back the eroded pixel?\n\nThe heuristics methods are not reliable.  We may need to like a post-processing network. In that case i think mask-rcnn is an easier approach.\n\n\nAlternative, we can up-size the image so that the nuclei is \"big\" and boundary is small.\n\nNote that similar method has be described in https://www.kaggle.com/c/data-science-bowl-2018/discussion/47690. especially: https://news.developer.nvidia.com/diagnosing-cancer-with-deep-learning-and-gpus/\n(2015 Gland Segmentation Challenge solution)\n\nand\n\nhttps://surabhibhargava.github.io/Detection-and-Segmentation-of-Nuclei-in-Computational-Pathology/\n",
    "281369": "I think this is a good direction for the bottom-up method like u-net. And this is the way I'm doing now. I got 0.402 scores. As @Heng say, it really takes some post-processing.",
    "278057": "For *Step1* and thresholding: https://www.kaggle.com/gaborvecsei/unsupervised-segmentation-with-type-separation\n\nHere we use HSV color space so it is easier to distinguish which channels are useful. The kernel is not complete but it is a good starting point.",
    "282066": "",
    "277430": ""
  }
}