{
  "id": 117330,
  "title": "11th place solution (with updated code on github)",
  "url": "/competitions/rsna-intracranial-hemorrhage-detection/discussion/117330",
  "author_name": "Appian",
  "post_date": "2019-11-14T18:03:47.680000",
  "votes": 55,
  "comment_count": 22,
  "views": 0,
  "content": "<p>Congratulations to all. \nThank you kaggle and the host team for organizing this interesting competition.</p>\n\n<p>The updated source code is available at <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage\">https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage</a>\nI will probably upload all trained models later.</p>\n\n<h3>Windowing</h3>\n\n<p>For this challenge, windowing is important to focus on the matter, in this case the brain and the blood. There are good kernels explaining how windowing works.</p>\n\n<ul>\n<li><a href=\"https://www.kaggle.com/dcstang/see-like-a-radiologist-with-systematic-windowing\">See like a Radiologist with Systematic Windowing</a> by <a href=\"https://www.kaggle.com/dcstang\">David Tang</a></li>\n<li><a href=\"https://www.kaggle.com/allunia/rsna-ih-detection-eda\">RSNA IH Detection - EDA</a> by <a href=\"https://www.kaggle.com/allunia\">Allunia</a></li>\n</ul>\n\n<p>We used three types of windows to focus and assigned them to each of the chennel to construct images on the fly for training.</p>\n\n<p>| Channel | Matter | Window Center | Window Width |\n----------|--------|---------------|---------------\n| 0 | Brain | 40 | 80 |\n| 1 | Blood/Subdural | 80 | 200 |\n| 2 | Soft tissues | 40 | 380 |</p>\n\n<p>Here is an example before and after applying the windowing. This image is labeled as <code>any intraparenchymal</code> and you can see that windowing helps focusing on the matter. Please check <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/dicom_windowing.ipynb\">windowing.ipynb</a> for the detail.</p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/windowing.png?raw=true\" alt=\"windowing.png\"></p>\n\n<h3>Classification</h3>\n\n<p>This step focuses on pixel data contained in DICOM file not meta data. But still four kind of meta data is used to apply windowing properly. <code>RescaleSlope</code> and <code>RescaleIntercept</code> are used for windowing. <code>BitsStored</code> and <code>PixelRepresentation</code> are used for fixing wrong intercept values which is mentioned in <a href=\"https://www.kaggle.com/jhoward/cleaning-the-data-for-rapid-prototyping-fastai\">Cleaning the data for rapid prototyping</a> written by <a href=\"https://www.kaggle.com/jhoward\">Jeremy Howard</a>. </p>\n\n<ul>\n<li>Two architectures are used. <code>se_resnext50_32x4d</code> and <code>se_resnext101_32x4d</code>. </li>\n<li>Imagenet pretrained weights from <a href=\"https://github.com/Cadene/pretrained-models.pytorch\">https://github.com/Cadene/pretrained-models.pytorch</a></li>\n<li>8 folds each. </li>\n<li>Adding a random number to windowed pixel data as augmentation led to a little better generalization performace. This idea is based on a hunch that CT scanners are probably not perfectly calibrated. </li>\n<li>Test time augmentations(n=5) are used for predictions.</li>\n<li>Checkpoints from 2nd and 3rd epochs are used for predictions and then averaged.</li>\n<li>Final predictions are obtained from simple average of <code>se_resnext50_32x4d</code> and <code>se_resnext101_32x4d</code>. </li>\n</ul>\n\n<p><strong>The training result of 0th fold of se_resnext50_32x4d (<a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model100.py\">model100.py</a>)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model100_fold0.png?raw=true\" alt=\"model100_fold0.png\"></p>\n\n<p><strong>The training result of 0th fold of se_resnext101_32x4d (<a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model110.py\">model110.py</a>)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model110_fold0.png?raw=true\" alt=\"model110_fold0.png\"></p>\n\n<p><strong>Logloss for each of the Hemorrhage Types after emsembling (oof)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/ensembled.png?raw=true\" alt=\"ensembled.png\"></p>\n\n<p>This ensembled score (0.0642) is similar to the score (0.065) we got on public LB in the first stage before introducing second level model.</p>\n\n<h3>Second Level Model</h3>\n\n<p>The second level model focuses on a series of CT scan unlike the classification model which focuses on a given image(slice). The main idea is that other slices of a certain slice within the same series can be useful to enhance the predictions of that slice. For example, if both of the adjacent slices of a certain slice are inferred as <code>epidural</code>, the middle of the slice is most likey <code>epidural</code>. This kind of relationships can trained using something like LightGBM. The train data can be constructed as follows,</p>\n\n<p>For example, in case of training <code>epidural</code> based on oof predictions, you can construct a record like this,</p>\n\n<p><code>\nprediction of the given slice, left1, right1, left2, right2, left3, right3, ...,\n</code></p>\n\n<ul>\n<li><code>left1</code> indicates the prediction of the first slice to the left from the given slice.</li>\n<li><code>right2</code> indicates the prediction of the second slice to the right from the given slice.</li>\n</ul>\n\n<p>We included <code>left1</code> to <code>left9</code> and <code>right1</code> to <code>right9</code> for each of the slice. <code>left1</code> and <code>right1</code> are unsurprisingly the most useful features among all other slices except the given slice based on feature importance(lightgbm gain). Some distant slices such as <code>left9</code> or <code>right9</code> are not as important as closer slices to the given slice but still somewhat useful.</p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/secondlevel.png?raw=true\" alt=\"secondlevel.png\"></p>\n\n<ul>\n<li>Final predictions are obtained by simply averaging predictions from LightGBM, Catboost and XGB.</li>\n<li>The 1st stage public LB score was improved from 0.65 to 0.57 by this.</li>\n</ul>\n\n<p>Thank you for reading!</p>",
  "messages": [
    {
      "id": 673247,
      "postDate": "2019-11-14T18:03:47.680Z",
      "content": "<p>Congratulations to all. \nThank you kaggle and the host team for organizing this interesting competition.</p>\n\n<p>The updated source code is available at <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage\">https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage</a>\nI will probably upload all trained models later.</p>\n\n<h3>Windowing</h3>\n\n<p>For this challenge, windowing is important to focus on the matter, in this case the brain and the blood. There are good kernels explaining how windowing works.</p>\n\n<ul>\n<li><a href=\"https://www.kaggle.com/dcstang/see-like-a-radiologist-with-systematic-windowing\">See like a Radiologist with Systematic Windowing</a> by <a href=\"https://www.kaggle.com/dcstang\">David Tang</a></li>\n<li><a href=\"https://www.kaggle.com/allunia/rsna-ih-detection-eda\">RSNA IH Detection - EDA</a> by <a href=\"https://www.kaggle.com/allunia\">Allunia</a></li>\n</ul>\n\n<p>We used three types of windows to focus and assigned them to each of the chennel to construct images on the fly for training.</p>\n\n<p>| Channel | Matter | Window Center | Window Width |\n----------|--------|---------------|---------------\n| 0 | Brain | 40 | 80 |\n| 1 | Blood/Subdural | 80 | 200 |\n| 2 | Soft tissues | 40 | 380 |</p>\n\n<p>Here is an example before and after applying the windowing. This image is labeled as <code>any intraparenchymal</code> and you can see that windowing helps focusing on the matter. Please check <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/dicom_windowing.ipynb\">windowing.ipynb</a> for the detail.</p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/windowing.png?raw=true\" alt=\"windowing.png\"></p>\n\n<h3>Classification</h3>\n\n<p>This step focuses on pixel data contained in DICOM file not meta data. But still four kind of meta data is used to apply windowing properly. <code>RescaleSlope</code> and <code>RescaleIntercept</code> are used for windowing. <code>BitsStored</code> and <code>PixelRepresentation</code> are used for fixing wrong intercept values which is mentioned in <a href=\"https://www.kaggle.com/jhoward/cleaning-the-data-for-rapid-prototyping-fastai\">Cleaning the data for rapid prototyping</a> written by <a href=\"https://www.kaggle.com/jhoward\">Jeremy Howard</a>. </p>\n\n<ul>\n<li>Two architectures are used. <code>se_resnext50_32x4d</code> and <code>se_resnext101_32x4d</code>. </li>\n<li>Imagenet pretrained weights from <a href=\"https://github.com/Cadene/pretrained-models.pytorch\">https://github.com/Cadene/pretrained-models.pytorch</a></li>\n<li>8 folds each. </li>\n<li>Adding a random number to windowed pixel data as augmentation led to a little better generalization performace. This idea is based on a hunch that CT scanners are probably not perfectly calibrated. </li>\n<li>Test time augmentations(n=5) are used for predictions.</li>\n<li>Checkpoints from 2nd and 3rd epochs are used for predictions and then averaged.</li>\n<li>Final predictions are obtained from simple average of <code>se_resnext50_32x4d</code> and <code>se_resnext101_32x4d</code>. </li>\n</ul>\n\n<p><strong>The training result of 0th fold of se_resnext50_32x4d (<a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model100.py\">model100.py</a>)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model100_fold0.png?raw=true\" alt=\"model100_fold0.png\"></p>\n\n<p><strong>The training result of 0th fold of se_resnext101_32x4d (<a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model110.py\">model110.py</a>)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model110_fold0.png?raw=true\" alt=\"model110_fold0.png\"></p>\n\n<p><strong>Logloss for each of the Hemorrhage Types after emsembling (oof)</strong></p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/ensembled.png?raw=true\" alt=\"ensembled.png\"></p>\n\n<p>This ensembled score (0.0642) is similar to the score (0.065) we got on public LB in the first stage before introducing second level model.</p>\n\n<h3>Second Level Model</h3>\n\n<p>The second level model focuses on a series of CT scan unlike the classification model which focuses on a given image(slice). The main idea is that other slices of a certain slice within the same series can be useful to enhance the predictions of that slice. For example, if both of the adjacent slices of a certain slice are inferred as <code>epidural</code>, the middle of the slice is most likey <code>epidural</code>. This kind of relationships can trained using something like LightGBM. The train data can be constructed as follows,</p>\n\n<p>For example, in case of training <code>epidural</code> based on oof predictions, you can construct a record like this,</p>\n\n<p><code>\nprediction of the given slice, left1, right1, left2, right2, left3, right3, ...,\n</code></p>\n\n<ul>\n<li><code>left1</code> indicates the prediction of the first slice to the left from the given slice.</li>\n<li><code>right2</code> indicates the prediction of the second slice to the right from the given slice.</li>\n</ul>\n\n<p>We included <code>left1</code> to <code>left9</code> and <code>right1</code> to <code>right9</code> for each of the slice. <code>left1</code> and <code>right1</code> are unsurprisingly the most useful features among all other slices except the given slice based on feature importance(lightgbm gain). Some distant slices such as <code>left9</code> or <code>right9</code> are not as important as closer slices to the given slice but still somewhat useful.</p>\n\n<p><img src=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/secondlevel.png?raw=true\" alt=\"secondlevel.png\"></p>\n\n<ul>\n<li>Final predictions are obtained by simply averaging predictions from LightGBM, Catboost and XGB.</li>\n<li>The 1st stage public LB score was improved from 0.65 to 0.57 by this.</li>\n</ul>\n\n<p>Thank you for reading!</p>",
      "rawMarkdown": "Congratulations to all. \nThank you kaggle and the host team for organizing this interesting competition.\n\nThe updated source code is available at https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage\nI will probably upload all trained models later.\n\n### Windowing\n\nFor this challenge, windowing is important to focus on the matter, in this case the brain and the blood. There are good kernels explaining how windowing works.\n\n- [See like a Radiologist with Systematic Windowing](https://www.kaggle.com/dcstang/see-like-a-radiologist-with-systematic-windowing) by [David Tang](https://www.kaggle.com/dcstang)\n- [RSNA IH Detection - EDA](https://www.kaggle.com/allunia/rsna-ih-detection-eda) by [Allunia](https://www.kaggle.com/allunia)\n\nWe used three types of windows to focus and assigned them to each of the chennel to construct images on the fly for training.\n\n| Channel | Matter | Window Center | Window Width |\n----------|--------|---------------|---------------\n| 0 | Brain | 40 | 80 |\n| 1 | Blood/Subdural | 80 | 200 |\n| 2 | Soft tissues | 40 | 380 |\n\nHere is an example before and after applying the windowing. This image is labeled as `any intraparenchymal` and you can see that windowing helps focusing on the matter. Please check [windowing.ipynb](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/dicom_windowing.ipynb) for the detail.\n\n![windowing.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/windowing.png?raw=true)\n\n\n### Classification\n\nThis step focuses on pixel data contained in DICOM file not meta data. But still four kind of meta data is used to apply windowing properly. `RescaleSlope` and `RescaleIntercept` are used for windowing. `BitsStored` and `PixelRepresentation` are used for fixing wrong intercept values which is mentioned in [Cleaning the data for rapid prototyping](https://www.kaggle.com/jhoward/cleaning-the-data-for-rapid-prototyping-fastai) written by [Jeremy Howard](https://www.kaggle.com/jhoward). \n\n- Two architectures are used. `se_resnext50_32x4d` and `se_resnext101_32x4d`. \n- Imagenet pretrained weights from https://github.com/Cadene/pretrained-models.pytorch\n- 8 folds each. \n- Adding a random number to windowed pixel data as augmentation led to a little better generalization performace. This idea is based on a hunch that CT scanners are probably not perfectly calibrated. \n- Test time augmentations(n=5) are used for predictions.\n- Checkpoints from 2nd and 3rd epochs are used for predictions and then averaged.\n- Final predictions are obtained from simple average of `se_resnext50_32x4d` and `se_resnext101_32x4d`. \n\n**The training result of 0th fold of se\\_resnext50\\_32x4d ([model100.py](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model100.py))**\n\n![model100_fold0.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model100_fold0.png?raw=true)\n\n**The training result of 0th fold of se\\_resnext101\\_32x4d ([model110.py](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model110.py))**\n\n![model110_fold0.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model110_fold0.png?raw=true)\n\n**Logloss for each of the Hemorrhage Types after emsembling (oof)**\n\n![ensembled.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/ensembled.png?raw=true)\n\nThis ensembled score (0.0642) is similar to the score (0.065) we got on public LB in the first stage before introducing second level model.\n\n\n### Second Level Model\n\nThe second level model focuses on a series of CT scan unlike the classification model which focuses on a given image(slice). The main idea is that other slices of a certain slice within the same series can be useful to enhance the predictions of that slice. For example, if both of the adjacent slices of a certain slice are inferred as `epidural`, the middle of the slice is most likey `epidural`. This kind of relationships can trained using something like LightGBM. The train data can be constructed as follows,\n\nFor example, in case of training `epidural` based on oof predictions, you can construct a record like this,\n\n```\nprediction of the given slice, left1, right1, left2, right2, left3, right3, ...,\n```\n\n- `left1` indicates the prediction of the first slice to the left from the given slice.\n- `right2` indicates the prediction of the second slice to the right from the given slice.\n\nWe included `left1` to `left9` and `right1` to `right9` for each of the slice. `left1` and `right1` are unsurprisingly the most useful features among all other slices except the given slice based on feature importance(lightgbm gain). Some distant slices such as `left9` or `right9` are not as important as closer slices to the given slice but still somewhat useful.\n\n![secondlevel.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/secondlevel.png?raw=true)\n\n- Final predictions are obtained by simply averaging predictions from LightGBM, Catboost and XGB.\n- The 1st stage public LB score was improved from 0.65 to 0.57 by this.\n\nThank you for reading!\n",
      "votes": 54
    },
    {
      "id": 680686,
      "postDate": "2019-11-25T04:17:50.897Z",
      "content": "<p>Thank you for sharing your full code. I learned a lot from your sharing - especially your code structure and attention on reproducibility. </p>\n\n<p>I have a couple of questions:\n- Any reason for you to choose n_fold to be 8? How did you come up with it as you were using 5 in your first shared version\n- Did you increase number of epoch to 4 as you see the validation loss was still decreasing?\n- For the second level model, how did you deal with empty values? You seem to assume that a series will have 19 images each (left 1 to 9 and right 1 to 9). How did you deal with the case when a series has only 2 images? I see the function to fill as nan in this <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/src/meta/trainer.py\">file</a>. Wouldn't there be a lot of nans in this case? </p>\n\n<p>Thanks again :)</p>",
      "rawMarkdown": "Thank you for sharing your full code. I learned a lot from your sharing - especially your code structure and attention on reproducibility. \n\nI have a couple of questions:\n- Any reason for you to choose n_fold to be 8? How did you come up with it as you were using 5 in your first shared version\n- Did you increase number of epoch to 4 as you see the validation loss was still decreasing?\n- For the second level model, how did you deal with empty values? You seem to assume that a series will have 19 images each (left 1 to 9 and right 1 to 9). How did you deal with the case when a series has only 2 images? I see the function to fill as nan in this [file](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/src/meta/trainer.py). Wouldn't there be a lot of nans in this case? \n\nThanks again :)",
      "votes": 1,
      "replies": [
        {
          "id": 681064,
          "postDate": "2019-11-25T16:03:29.567Z",
          "content": "<p>Thank you very much!</p>\n\n<ul>\n<li>I simply thought 8 is better than 5. Smoothing was important for this competition metric and I wanted to smooth by averaging many predictions.</li>\n<li>The last epoch actually overfits and cv got sligtly worse.  It's intentional because ensembling probably benefits from overfitted predictions along with less overfitted predictions. </li>\n<li>Each series has at least 20 images in 1st stage data. I didn't check 2nd stage test data but I suppose it's same.</li>\n</ul>\n\n<p>Hope this answers.</p>",
          "rawMarkdown": "Thank you very much!\n\n- I simply thought 8 is better than 5. Smoothing was important for this competition metric and I wanted to smooth by averaging many predictions.\n- The last epoch actually overfits and cv got sligtly worse.  It's intentional because ensembling probably benefits from overfitted predictions along with less overfitted predictions. \n- Each series has at least 20 images in 1st stage data. I didn't check 2nd stage test data but I suppose it's same.\n\nHope this answers.",
          "votes": 2
        }
      ]
    },
    {
      "id": 674528,
      "postDate": "2019-11-16T16:42:21.547Z",
      "content": "<p>Congratulation and many thanks for sharing great approach.</p>",
      "rawMarkdown": "Congratulation and many thanks for sharing great approach.",
      "votes": 1
    },
    {
      "id": 674137,
      "postDate": "2019-11-15T23:36:28.337Z",
      "content": "<p>Congratulation my friend <a href=\"/appian\">@appian</a> !  Looking forward to participating more with you!</p>",
      "rawMarkdown": "Congratulation my friend @appian !  Looking forward to participating more with you!",
      "votes": 1,
      "replies": [
        {
          "id": 674292,
          "postDate": "2019-11-16T07:22:19.597Z",
          "content": "<p>Thank you! Yes, it's nice competing and I'd like to read more of your insightful kernels!</p>",
          "rawMarkdown": "Thank you! Yes, it's nice competing and I'd like to read more of your insightful kernels!",
          "votes": 1
        }
      ]
    },
    {
      "id": 673800,
      "postDate": "2019-11-15T14:01:57.967Z",
      "content": "<p>Congrats! Your code helped me a lot, thank you;)</p>",
      "rawMarkdown": "Congrats! Your code helped me a lot, thank you;)",
      "votes": 1,
      "replies": [
        {
          "id": 674293,
          "postDate": "2019-11-16T07:23:33.037Z",
          "content": "<p>You are welcome!\nNow I'm reading your solution/code and nice to learn from it. </p>",
          "rawMarkdown": "You are welcome!\nNow I'm reading your solution/code and nice to learn from it. "
        }
      ]
    },
    {
      "id": 673798,
      "postDate": "2019-11-15T13:58:45.853Z",
      "content": "<p>I like your approach with LightGBM! Damn, it's so simple but I didn't think of it. :(\nThe only thing I did is the median filtration with the kernel size of 3 slices.</p>",
      "rawMarkdown": "I like your approach with LightGBM! Damn, it's so simple but I didn't think of it. :(\nThe only thing I did is the median filtration with the kernel size of 3 slices.\n ",
      "votes": 1,
      "replies": [
        {
          "id": 674294,
          "postDate": "2019-11-16T07:24:53.650Z",
          "content": "<p>Thank you! I like a simple approach too and satisfied that this turned out to work nicely.</p>",
          "rawMarkdown": "Thank you! I like a simple approach too and satisfied that this turned out to work nicely.",
          "votes": 1
        }
      ]
    },
    {
      "id": 673772,
      "postDate": "2019-11-15T13:23:45.817Z",
      "content": "<p>Congratulations  and thank you very much for sharing the approach and the solution .. </p>",
      "rawMarkdown": "Congratulations  and thank you very much for sharing the approach and the solution .. ",
      "votes": 1
    },
    {
      "id": 673510,
      "postDate": "2019-11-15T04:49:35.017Z",
      "content": "<p>Congratulations\nGreat Write-Up\nThanks for Sharing your Valuable Insights &amp; Approach <a href=\"/appian\">@appian</a> </p>",
      "rawMarkdown": "Congratulations\nGreat Write-Up\nThanks for Sharing your Valuable Insights &amp; Approach @appian ",
      "votes": 1
    },
    {
      "id": 673472,
      "postDate": "2019-11-15T02:40:55.317Z",
      "content": "<p>Congratulations on the gold and thank you for the write ups! Your code was a great input for me, and I really appreciate the share.</p>",
      "rawMarkdown": "Congratulations on the gold and thank you for the write ups! Your code was a great input for me, and I really appreciate the share.",
      "votes": 1
    },
    {
      "id": 673392,
      "postDate": "2019-11-14T23:17:37.697Z",
      "content": "<p>Thanks for explaining this simple yet great work! It looks like using neighboring slice features or sequence modeling seems to give major improvements in many top team solutions. Unfortunately it was too late for me to add that for before stage-1 model upload but still great to learn how effective it is even after the competition :)</p>",
      "rawMarkdown": "Thanks for explaining this simple yet great work! It looks like using neighboring slice features or sequence modeling seems to give major improvements in many top team solutions. Unfortunately it was too late for me to add that for before stage-1 model upload but still great to learn how effective it is even after the competition :)",
      "votes": 1,
      "replies": [
        {
          "id": 673514,
          "postDate": "2019-11-15T05:03:01.697Z",
          "content": "<p>Yes, making use of series information is very important. I didn't treat them as a sequence but the sequential model probably does a better job here. </p>",
          "rawMarkdown": "Yes, making use of series information is very important. I didn't treat them as a sequence but the sequential model probably does a better job here. ",
          "votes": 1
        }
      ]
    },
    {
      "id": 673377,
      "postDate": "2019-11-14T22:45:45.807Z",
      "content": "<p>Congrats and thanks for sharing. Your code is very well organised and a joy to read. Did your normalisation of </p>\n\n<p>{'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}</p>\n\n<p>have any impact vs. no normalisation or normalizing by ImageNet stats? </p>",
      "rawMarkdown": "Congrats and thanks for sharing. Your code is very well organised and a joy to read. Did your normalisation of \n\n {'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}\n\nhave any impact vs. no normalisation or normalizing by ImageNet stats? ",
      "votes": 1,
      "replies": [
        {
          "id": 673516,
          "postDate": "2019-11-15T05:05:32.437Z",
          "content": "<p>Thank you!\nI did not even try using ImageNet stats because it does not make sense considering dicom images are so much different from images from ImageNet. I was using min-max normalization before and <code>{'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}</code> works sligtly better than that.</p>",
          "rawMarkdown": "Thank you!\nI did not even try using ImageNet stats because it does not make sense considering dicom images are so much different from images from ImageNet. I was using min-max normalization before and `{'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}` works sligtly better than that.",
          "votes": 1
        }
      ]
    },
    {
      "id": 673483,
      "postDate": "2019-11-15T03:27:12.650Z",
      "content": "<p>Congratulations and thanks for the clear write up. Can I ask how many studies are there with the wrong intercept values?  </p>",
      "rawMarkdown": "Congratulations and thanks for the clear write up. Can I ask how many studies are there with the wrong intercept values?  ",
      "votes": 2,
      "replies": [
        {
          "id": 673513,
          "postDate": "2019-11-15T05:02:04.823Z",
          "content": "<p>Thank you!\nI'm afraid I didn't record the number but I guess it was less than 1% of train data. </p>",
          "rawMarkdown": "Thank you!\nI'm afraid I didn't record the number but I guess it was less than 1% of train data. "
        }
      ]
    },
    {
      "id": 673261,
      "postDate": "2019-11-14T18:21:10.720Z",
      "content": "<p>Thank you for sharing and Congrats!! You deserve an extra applause for your contribution in this competition. </p>",
      "rawMarkdown": "Thank you for sharing and Congrats!! You deserve an extra applause for your contribution in this competition. ",
      "votes": 2,
      "replies": [
        {
          "id": 673267,
          "postDate": "2019-11-14T18:30:19.567Z",
          "content": "<p>Thank you! I'm glad to hear that.</p>",
          "rawMarkdown": "Thank you! I'm glad to hear that.",
          "votes": 1
        }
      ]
    },
    {
      "id": 703672,
      "postDate": "2019-12-26T13:30:38.023Z",
      "rawMarkdown": "",
      "isDeleted": true
    },
    {
      "id": 673579,
      "postDate": "2019-11-15T07:26:24.590Z",
      "content": "<p>thank you for you kind sharing</p>",
      "rawMarkdown": "thank you for you kind sharing",
      "votes": 1
    }
  ],
  "comments": [
    {
      "id": 680686,
      "author_name": "ChinHuiC",
      "author_url": "",
      "post_date": "2019-11-25T04:17:50.897000",
      "content": "<p>Thank you for sharing your full code. I learned a lot from your sharing - especially your code structure and attention on reproducibility. </p>\n\n<p>I have a couple of questions:\n- Any reason for you to choose n_fold to be 8? How did you come up with it as you were using 5 in your first shared version\n- Did you increase number of epoch to 4 as you see the validation loss was still decreasing?\n- For the second level model, how did you deal with empty values? You seem to assume that a series will have 19 images each (left 1 to 9 and right 1 to 9). How did you deal with the case when a series has only 2 images? I see the function to fill as nan in this <a href=\"https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/src/meta/trainer.py\">file</a>. Wouldn't there be a lot of nans in this case? </p>\n\n<p>Thanks again :)</p>",
      "votes": 1,
      "replies": [
        {
          "id": 681064,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-25T16:03:29.567000",
          "content": "<p>Thank you very much!</p>\n\n<ul>\n<li>I simply thought 8 is better than 5. Smoothing was important for this competition metric and I wanted to smooth by averaging many predictions.</li>\n<li>The last epoch actually overfits and cv got sligtly worse.  It's intentional because ensembling probably benefits from overfitted predictions along with less overfitted predictions. </li>\n<li>Each series has at least 20 images in 1st stage data. I didn't check 2nd stage test data but I suppose it's same.</li>\n</ul>\n\n<p>Hope this answers.</p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 674528,
      "author_name": "sleepysleeping",
      "author_url": "",
      "post_date": "2019-11-16T16:42:21.547000",
      "content": "<p>Congratulation and many thanks for sharing great approach.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 674137,
      "author_name": "Neuron Engineer",
      "author_url": "",
      "post_date": "2019-11-15T23:36:28.337000",
      "content": "<p>Congratulation my friend <a href=\"/appian\">@appian</a> !  Looking forward to participating more with you!</p>",
      "votes": 1,
      "replies": [
        {
          "id": 674292,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-16T07:22:19.597000",
          "content": "<p>Thank you! Yes, it's nice competing and I'd like to read more of your insightful kernels!</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 673800,
      "author_name": "takuoko",
      "author_url": "",
      "post_date": "2019-11-15T14:01:57.967000",
      "content": "<p>Congrats! Your code helped me a lot, thank you;)</p>",
      "votes": 1,
      "replies": [
        {
          "id": 674293,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-16T07:23:33.037000",
          "content": "<p>You are welcome!\nNow I'm reading your solution/code and nice to learn from it. </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 673798,
      "author_name": "Sergey Zlobin",
      "author_url": "",
      "post_date": "2019-11-15T13:58:45.853000",
      "content": "<p>I like your approach with LightGBM! Damn, it's so simple but I didn't think of it. :(\nThe only thing I did is the median filtration with the kernel size of 3 slices.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 674294,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-16T07:24:53.650000",
          "content": "<p>Thank you! I like a simple approach too and satisfied that this turned out to work nicely.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 673772,
      "author_name": "Kishore M",
      "author_url": "",
      "post_date": "2019-11-15T13:23:45.817000",
      "content": "<p>Congratulations  and thank you very much for sharing the approach and the solution .. </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 673510,
      "author_name": "Ailurophile",
      "author_url": "",
      "post_date": "2019-11-15T04:49:35.017000",
      "content": "<p>Congratulations\nGreat Write-Up\nThanks for Sharing your Valuable Insights &amp; Approach <a href=\"/appian\">@appian</a> </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 673472,
      "author_name": "yukiya",
      "author_url": "",
      "post_date": "2019-11-15T02:40:55.317000",
      "content": "<p>Congratulations on the gold and thank you for the write ups! Your code was a great input for me, and I really appreciate the share.</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 673392,
      "author_name": "Kerem Turgutlu",
      "author_url": "",
      "post_date": "2019-11-14T23:17:37.697000",
      "content": "<p>Thanks for explaining this simple yet great work! It looks like using neighboring slice features or sequence modeling seems to give major improvements in many top team solutions. Unfortunately it was too late for me to add that for before stage-1 model upload but still great to learn how effective it is even after the competition :)</p>",
      "votes": 1,
      "replies": [
        {
          "id": 673514,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-15T05:03:01.697000",
          "content": "<p>Yes, making use of series information is very important. I didn't treat them as a sequence but the sequential model probably does a better job here. </p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 673377,
      "author_name": "David Ten",
      "author_url": "",
      "post_date": "2019-11-14T22:45:45.807000",
      "content": "<p>Congrats and thanks for sharing. Your code is very well organised and a joy to read. Did your normalisation of </p>\n\n<p>{'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}</p>\n\n<p>have any impact vs. no normalisation or normalizing by ImageNet stats? </p>",
      "votes": 1,
      "replies": [
        {
          "id": 673516,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-15T05:05:32.437000",
          "content": "<p>Thank you!\nI did not even try using ImageNet stats because it does not make sense considering dicom images are so much different from images from ImageNet. I was using min-max normalization before and <code>{'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}</code> works sligtly better than that.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 673483,
      "author_name": "Yee Ng",
      "author_url": "",
      "post_date": "2019-11-15T03:27:12.650000",
      "content": "<p>Congratulations and thanks for the clear write up. Can I ask how many studies are there with the wrong intercept values?  </p>",
      "votes": 2,
      "replies": [
        {
          "id": 673513,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-15T05:02:04.823000",
          "content": "<p>Thank you!\nI'm afraid I didn't record the number but I guess it was less than 1% of train data. </p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 673261,
      "author_name": "Bibek",
      "author_url": "",
      "post_date": "2019-11-14T18:21:10.720000",
      "content": "<p>Thank you for sharing and Congrats!! You deserve an extra applause for your contribution in this competition. </p>",
      "votes": 2,
      "replies": [
        {
          "id": 673267,
          "author_name": "Appian",
          "author_url": "",
          "post_date": "2019-11-14T18:30:19.567000",
          "content": "<p>Thank you! I'm glad to hear that.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 703672,
      "author_name": "",
      "author_url": "",
      "post_date": "2019-12-26T13:30:38.023000",
      "content": "",
      "votes": 0,
      "replies": []
    },
    {
      "id": 673579,
      "author_name": "yangDDD",
      "author_url": "",
      "post_date": "2019-11-15T07:26:24.590000",
      "content": "<p>thank you for you kind sharing</p>",
      "votes": 1,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "673247": "Congratulations to all. \nThank you kaggle and the host team for organizing this interesting competition.\n\nThe updated source code is available at https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage\nI will probably upload all trained models later.\n\n### Windowing\n\nFor this challenge, windowing is important to focus on the matter, in this case the brain and the blood. There are good kernels explaining how windowing works.\n\n- [See like a Radiologist with Systematic Windowing](https://www.kaggle.com/dcstang/see-like-a-radiologist-with-systematic-windowing) by [David Tang](https://www.kaggle.com/dcstang)\n- [RSNA IH Detection - EDA](https://www.kaggle.com/allunia/rsna-ih-detection-eda) by [Allunia](https://www.kaggle.com/allunia)\n\nWe used three types of windows to focus and assigned them to each of the chennel to construct images on the fly for training.\n\n| Channel | Matter | Window Center | Window Width |\n----------|--------|---------------|---------------\n| 0 | Brain | 40 | 80 |\n| 1 | Blood/Subdural | 80 | 200 |\n| 2 | Soft tissues | 40 | 380 |\n\nHere is an example before and after applying the windowing. This image is labeled as `any intraparenchymal` and you can see that windowing helps focusing on the matter. Please check [windowing.ipynb](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/dicom_windowing.ipynb) for the detail.\n\n![windowing.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/windowing.png?raw=true)\n\n\n### Classification\n\nThis step focuses on pixel data contained in DICOM file not meta data. But still four kind of meta data is used to apply windowing properly. `RescaleSlope` and `RescaleIntercept` are used for windowing. `BitsStored` and `PixelRepresentation` are used for fixing wrong intercept values which is mentioned in [Cleaning the data for rapid prototyping](https://www.kaggle.com/jhoward/cleaning-the-data-for-rapid-prototyping-fastai) written by [Jeremy Howard](https://www.kaggle.com/jhoward). \n\n- Two architectures are used. `se_resnext50_32x4d` and `se_resnext101_32x4d`. \n- Imagenet pretrained weights from https://github.com/Cadene/pretrained-models.pytorch\n- 8 folds each. \n- Adding a random number to windowed pixel data as augmentation led to a little better generalization performace. This idea is based on a hunch that CT scanners are probably not perfectly calibrated. \n- Test time augmentations(n=5) are used for predictions.\n- Checkpoints from 2nd and 3rd epochs are used for predictions and then averaged.\n- Final predictions are obtained from simple average of `se_resnext50_32x4d` and `se_resnext101_32x4d`. \n\n**The training result of 0th fold of se\\_resnext50\\_32x4d ([model100.py](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model100.py))**\n\n![model100_fold0.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model100_fold0.png?raw=true)\n\n**The training result of 0th fold of se\\_resnext101\\_32x4d ([model110.py](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/conf/model110.py))**\n\n![model110_fold0.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/model110_fold0.png?raw=true)\n\n**Logloss for each of the Hemorrhage Types after emsembling (oof)**\n\n![ensembled.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/ensembled.png?raw=true)\n\nThis ensembled score (0.0642) is similar to the score (0.065) we got on public LB in the first stage before introducing second level model.\n\n\n### Second Level Model\n\nThe second level model focuses on a series of CT scan unlike the classification model which focuses on a given image(slice). The main idea is that other slices of a certain slice within the same series can be useful to enhance the predictions of that slice. For example, if both of the adjacent slices of a certain slice are inferred as `epidural`, the middle of the slice is most likey `epidural`. This kind of relationships can trained using something like LightGBM. The train data can be constructed as follows,\n\nFor example, in case of training `epidural` based on oof predictions, you can construct a record like this,\n\n```\nprediction of the given slice, left1, right1, left2, right2, left3, right3, ...,\n```\n\n- `left1` indicates the prediction of the first slice to the left from the given slice.\n- `right2` indicates the prediction of the second slice to the right from the given slice.\n\nWe included `left1` to `left9` and `right1` to `right9` for each of the slice. `left1` and `right1` are unsurprisingly the most useful features among all other slices except the given slice based on feature importance(lightgbm gain). Some distant slices such as `left9` or `right9` are not as important as closer slices to the given slice but still somewhat useful.\n\n![secondlevel.png](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/demo/image/secondlevel.png?raw=true)\n\n- Final predictions are obtained by simply averaging predictions from LightGBM, Catboost and XGB.\n- The 1st stage public LB score was improved from 0.65 to 0.57 by this.\n\nThank you for reading!\n",
    "680686": "Thank you for sharing your full code. I learned a lot from your sharing - especially your code structure and attention on reproducibility. \n\nI have a couple of questions:\n- Any reason for you to choose n_fold to be 8? How did you come up with it as you were using 5 in your first shared version\n- Did you increase number of epoch to 4 as you see the validation loss was still decreasing?\n- For the second level model, how did you deal with empty values? You seem to assume that a series will have 19 images each (left 1 to 9 and right 1 to 9). How did you deal with the case when a series has only 2 images? I see the function to fill as nan in this [file](https://github.com/appian42/kaggle-rsna-intracranial-hemorrhage/blob/master/src/meta/trainer.py). Wouldn't there be a lot of nans in this case? \n\nThanks again :)",
    "674528": "Congratulation and many thanks for sharing great approach.",
    "674137": "Congratulation my friend @appian !  Looking forward to participating more with you!",
    "673800": "Congrats! Your code helped me a lot, thank you;)",
    "673798": "I like your approach with LightGBM! Damn, it's so simple but I didn't think of it. :(\nThe only thing I did is the median filtration with the kernel size of 3 slices.\n ",
    "673772": "Congratulations  and thank you very much for sharing the approach and the solution .. ",
    "673510": "Congratulations\nGreat Write-Up\nThanks for Sharing your Valuable Insights &amp; Approach @appian ",
    "673472": "Congratulations on the gold and thank you for the write ups! Your code was a great input for me, and I really appreciate the share.",
    "673392": "Thanks for explaining this simple yet great work! It looks like using neighboring slice features or sequence modeling seems to give major improvements in many top team solutions. Unfortunately it was too late for me to add that for before stage-1 model upload but still great to learn how effective it is even after the competition :)",
    "673377": "Congrats and thanks for sharing. Your code is very well organised and a joy to read. Did your normalisation of \n\n {'mean': [13.197, 7.179, -78.954,], 'std': [24.509, 55.063, 113.127,]}\n\nhave any impact vs. no normalisation or normalizing by ImageNet stats? ",
    "673483": "Congratulations and thanks for the clear write up. Can I ask how many studies are there with the wrong intercept values?  ",
    "673261": "Thank you for sharing and Congrats!! You deserve an extra applause for your contribution in this competition. ",
    "703672": "",
    "673579": "thank you for you kind sharing"
  }
}