{
  "id": 459596,
  "title": "11th Place - GRU, CNN, Transformer - GPU Deep Learning!",
  "url": "/competitions/child-mind-institute-detect-sleep-states/writeups/chris-deotte-11th-place-gru-cnn-transformer-gpu-de",
  "author_name": "",
  "post_date": "2023-12-09T21:31:23.193Z",
  "votes": 186,
  "comment_count": 59,
  "views": 0,
  "content": "<p>What a fun competition! I enjoyed this competition! Thank you Kaggle and host.</p>\n<h1>Building Blocks of GPU Deep Learning!</h1>\n<p>Below are 3 building blocks of deep learning. By creating different sequences of these building blocks, we can build powerful models! Each block takes an input shape of <code>(batch_size, sequence_length, features)</code> and outputs the same. The RNN \"block\" uses <strong>bidirectional</strong> (example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). The CNN \"block\" uses sums and products of multiple <strong>dilated convolutions</strong> (from WaveNet paper <a href=\"https://arxiv.org/abs/1609.03499\" target=\"_blank\">here</a> and example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). And the Transformer blocks uses <strong>self attention</strong> (example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). These 3 \"blocks\" can create features from signals without needing feature engineering!</p>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/blocks.png\" alt=\"\"></p>\n<h1>Data Loader - Cut Data into Daily Chunks</h1>\n<p>Our data loader will randomly give us 24 hour windows that <strong>always contain both one onset and one wakeup</strong>. During each epoch, we will get different cuts. This serves as crop data augmentation.<br>\n <img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/dataloader.png\" alt=\"\"></p>\n<h1>Model Head is NLP QA Softmax (not NLP NER)</h1>\n<p>For the head of our model, we use an architecture that is <strong>not</strong> in any public discussion <strong>nor</strong> public notebook. We use a technique from NLP called QuestionAnswering (i.e. <code>BertForQuestionAnswering</code>). This is analogous to Computer Vision's <code>object detection</code>. All public discussions and notebooks use NLP NER (i.e. <code>BertForTokenClassification</code>) which is analogous to Computer Vision <code>segmentation</code>. </p>\n<p>The way to implement QA is for our data loader to always include one onset and one wakeup in every train sequence. Then we apply 1440 multiclass softmax loss to pick the correct minute of target. Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa-head2.png\" alt=\"\"></p>\n<h1>My CNN-Transformer-GRU, 80 features</h1>\n<p><strong>Approximately CV 0.800 LB 0.750</strong><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model2b.png\" alt=\"\"></p>\n<h1>My Deep-GRU, 2 features</h1>\n<p><strong>Approximately CV 0.805 LB 0.755</strong><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model1c.png\" alt=\"\"></p>\n<h1>Extra Predictions Trick</h1>\n<p><strong>Approximately CV +0.050 LB 0.050 Wow!</strong><br>\nA huge trick in this competition is to make multiple onset and wakeup predictions per night. First we make a first choice for every user every night. With 200 test users and approximately 30 nights per user and 2 targets, this is about 12000 predictions. Next we make a second guess (i.e. the second max probability) for each night and divide it by <code>2^1</code>. This is 12000 more guesses. Next we made a 3rd guess (i.e. 3rd max prob) and divide it by <code>2^2</code>. We continue this for 30 guesses per night where the last guesses are divided by <code>2^29</code>. This boost CV by about +0.050 wow 😀! </p>\n<p>This works because Average Precision metric is <strong>always improved</strong> when adding more predictions if the new predictions have a lower score than all previous predictions. (More explanation <a href=\"https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\" target=\"_blank\">here</a>)</p>\n<h1>Rerank Scores</h1>\n<p><strong>Approximately CV +0.020 LB 0.020</strong><br>\nFor the metric Average Precision, the score we assign to each prediction is very important. First we use the probability from our above models as the starting score. Next we use CatBoost with handmade convolution features (<strong>CatBoost achieves LB 0.705</strong> by itself wow!), 1D-Unet, 2D-Unet, Mel Spectrograms, ResNet34, EfficientNetB5, and Audio WaveNet to rerank the scores. This is accomplished by predicting a new score for each prediction and then averaging all the scores.</p>\n<h1>Ensemble with NMS and WBF</h1>\n<p><strong>Approximately CV +0.010 LB 0.010</strong><br>\nMy CNN-Transformer-GRU and  Deep-GRU are very diverse. First I apply NMS (non maximum supression) to each model individually. Whenever two predictions are within 5 minutes of each other, we keep only the prediction which largest probability. Afterward we ensemble the two single models with WBF (weighted box fusion). Whenever two predictions are within 5 minutes of each other (and are the same level 1 thru 30 explained above in \"extra scores trick\"), then we replace the two with the average step position.</p>\n<h1>Solution Code</h1>\n<p>I published the code for these two TensorFlow models <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a></p>",
  "messages": [
    {
      "id": "2550266",
      "postDate": "12/06/2023 00:10:37",
      "content": "<p>What a fun competition! I enjoyed this competition! Thank you Kaggle and host.</p>\n<h1>Building Blocks of GPU Deep Learning!</h1>\n<p>Below are 3 building blocks of deep learning. By creating different sequences of these building blocks, we can build powerful models! Each block takes an input shape of <code>(batch_size, sequence_length, features)</code> and outputs the same. The RNN \"block\" uses <strong>bidirectional</strong> (example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). The CNN \"block\" uses sums and products of multiple <strong>dilated convolutions</strong> (from WaveNet paper <a href=\"https://arxiv.org/abs/1609.03499\" target=\"_blank\">here</a> and example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). And the Transformer blocks uses <strong>self attention</strong> (example code <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>). These 3 \"blocks\" can create features from signals without needing feature engineering!</p>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/blocks.png\" alt=\"\"></p>\n<h1>Data Loader - Cut Data into Daily Chunks</h1>\n<p>Our data loader will randomly give us 24 hour windows that <strong>always contain both one onset and one wakeup</strong>. During each epoch, we will get different cuts. This serves as crop data augmentation.<br>\n <img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/dataloader.png\" alt=\"\"></p>\n<h1>Model Head is NLP QA Softmax (not NLP NER)</h1>\n<p>For the head of our model, we use an architecture that is <strong>not</strong> in any public discussion <strong>nor</strong> public notebook. We use a technique from NLP called QuestionAnswering (i.e. <code>BertForQuestionAnswering</code>). This is analogous to Computer Vision's <code>object detection</code>. All public discussions and notebooks use NLP NER (i.e. <code>BertForTokenClassification</code>) which is analogous to Computer Vision <code>segmentation</code>. </p>\n<p>The way to implement QA is for our data loader to always include one onset and one wakeup in every train sequence. Then we apply 1440 multiclass softmax loss to pick the correct minute of target. Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa-head2.png\" alt=\"\"></p>\n<h1>My CNN-Transformer-GRU, 80 features</h1>\n<p><strong>Approximately CV 0.800 LB 0.750</strong><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model2b.png\" alt=\"\"></p>\n<h1>My Deep-GRU, 2 features</h1>\n<p><strong>Approximately CV 0.805 LB 0.755</strong><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model1c.png\" alt=\"\"></p>\n<h1>Extra Predictions Trick</h1>\n<p><strong>Approximately CV +0.050 LB 0.050 Wow!</strong><br>\nA huge trick in this competition is to make multiple onset and wakeup predictions per night. First we make a first choice for every user every night. With 200 test users and approximately 30 nights per user and 2 targets, this is about 12000 predictions. Next we make a second guess (i.e. the second max probability) for each night and divide it by <code>2^1</code>. This is 12000 more guesses. Next we made a 3rd guess (i.e. 3rd max prob) and divide it by <code>2^2</code>. We continue this for 30 guesses per night where the last guesses are divided by <code>2^29</code>. This boost CV by about +0.050 wow 😀! </p>\n<p>This works because Average Precision metric is <strong>always improved</strong> when adding more predictions if the new predictions have a lower score than all previous predictions. (More explanation <a href=\"https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\" target=\"_blank\">here</a>)</p>\n<h1>Rerank Scores</h1>\n<p><strong>Approximately CV +0.020 LB 0.020</strong><br>\nFor the metric Average Precision, the score we assign to each prediction is very important. First we use the probability from our above models as the starting score. Next we use CatBoost with handmade convolution features (<strong>CatBoost achieves LB 0.705</strong> by itself wow!), 1D-Unet, 2D-Unet, Mel Spectrograms, ResNet34, EfficientNetB5, and Audio WaveNet to rerank the scores. This is accomplished by predicting a new score for each prediction and then averaging all the scores.</p>\n<h1>Ensemble with NMS and WBF</h1>\n<p><strong>Approximately CV +0.010 LB 0.010</strong><br>\nMy CNN-Transformer-GRU and  Deep-GRU are very diverse. First I apply NMS (non maximum supression) to each model individually. Whenever two predictions are within 5 minutes of each other, we keep only the prediction which largest probability. Afterward we ensemble the two single models with WBF (weighted box fusion). Whenever two predictions are within 5 minutes of each other (and are the same level 1 thru 30 explained above in \"extra scores trick\"), then we replace the two with the average step position.</p>\n<h1>Solution Code</h1>\n<p>I published the code for these two TensorFlow models <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a></p>",
      "rawMarkdown": "What a fun competition! I enjoyed this competition! Thank you Kaggle and host.\n\n# Building Blocks of GPU Deep Learning!\nBelow are 3 building blocks of deep learning. By creating different sequences of these building blocks, we can build powerful models! Each block takes an input shape of `(batch_size, sequence_length, features)` and outputs the same. The RNN \"block\" uses **bidirectional** (example code [here][6]). The CNN \"block\" uses sums and products of multiple **dilated convolutions** (from WaveNet paper [here][5] and example code [here][6]). And the Transformer blocks uses **self attention** (example code [here][6]). These 3 \"blocks\" can create features from signals without needing feature engineering!\n\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/blocks.png)\n\n# Data Loader - Cut Data into Daily Chunks\nOur data loader will randomly give us 24 hour windows that **always contain both one onset and one wakeup**. During each epoch, we will get different cuts. This serves as crop data augmentation.\n ![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/dataloader.png)\n\n# Model Head is NLP QA Softmax (not NLP NER)\nFor the head of our model, we use an architecture that is **not** in any public discussion **nor** public notebook. We use a technique from NLP called QuestionAnswering (i.e. `BertForQuestionAnswering`). This is analogous to Computer Vision's `object detection`. All public discussions and notebooks use NLP NER (i.e. `BertForTokenClassification`) which is analogous to Computer Vision `segmentation`. \n\nThe way to implement QA is for our data loader to always include one onset and one wakeup in every train sequence. Then we apply 1440 multiclass softmax loss to pick the correct minute of target. Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa-head2.png)\n\n# My CNN-Transformer-GRU, 80 features\n**Approximately CV 0.800 LB 0.750**\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model2b.png)\n\n# My Deep-GRU, 2 features\n**Approximately CV 0.805 LB 0.755**\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model1c.png)\n\n# Extra Predictions Trick\n**Approximately CV +0.050 LB 0.050 Wow!**\nA huge trick in this competition is to make multiple onset and wakeup predictions per night. First we make a first choice for every user every night. With 200 test users and approximately 30 nights per user and 2 targets, this is about 12000 predictions. Next we make a second guess (i.e. the second max probability) for each night and divide it by `2^1`. This is 12000 more guesses. Next we made a 3rd guess (i.e. 3rd max prob) and divide it by `2^2`. We continue this for 30 guesses per night where the last guesses are divided by `2^29`. This boost CV by about +0.050 wow 😀! \n\nThis works because Average Precision metric is **always improved** when adding more predictions if the new predictions have a lower score than all previous predictions. (More explanation [here][1])\n\n# Rerank Scores\n**Approximately CV +0.020 LB 0.020**\nFor the metric Average Precision, the score we assign to each prediction is very important. First we use the probability from our above models as the starting score. Next we use CatBoost with handmade convolution features (**CatBoost achieves LB 0.705** by itself wow!), 1D-Unet, 2D-Unet, Mel Spectrograms, ResNet34, EfficientNetB5, and Audio WaveNet to rerank the scores. This is accomplished by predicting a new score for each prediction and then averaging all the scores.\n\n# Ensemble with NMS and WBF\n**Approximately CV +0.010 LB 0.010**\nMy CNN-Transformer-GRU and  Deep-GRU are very diverse. First I apply NMS (non maximum supression) to each model individually. Whenever two predictions are within 5 minutes of each other, we keep only the prediction which largest probability. Afterward we ensemble the two single models with WBF (weighted box fusion). Whenever two predictions are within 5 minutes of each other (and are the same level 1 thru 30 explained above in \"extra scores trick\"), then we replace the two with the average step position.\n\n# Solution Code\nI published the code for these two TensorFlow models [here][6]\n\n[1]: https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\n[2]: https://www.kaggle.com/code/ragnar123/wavenet-with-1-more-feature\n[3]: https://www.kaggle.com/code/cdeotte/tensorflow-transformer-0-112\n[4]: https://www.tensorflow.org/text/tutorials/transformer\n[5]: https://arxiv.org/abs/1609.03499\n[6]: https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788",
      "votes": null
    },
    {
      "id": "2550270",
      "postDate": "12/06/2023 00:19:53",
      "content": "<p>Learning from you yet again, a pleasure to watch you work. Congrats Chris!</p>",
      "rawMarkdown": "Learning from you yet again, a pleasure to watch you work. Congrats Chris!",
      "votes": null
    },
    {
      "id": "2550274",
      "postDate": "12/06/2023 00:22:31",
      "content": "<p>Great solution as always Chris. Very well done!! You were in the top for a very long time and I was like, okay Chris is for sure doing something with the post-processing again 😅 </p>\n<p>And I was wondering which features did you generate for <code>80 features</code> part?</p>",
      "rawMarkdown": "Great solution as always Chris. Very well done!! You were in the top for a very long time and I was like, okay Chris is for sure doing something with the post-processing again 😅 \n\nAnd I was wondering which features did you generate for `80 features` part?",
      "votes": null
    },
    {
      "id": "2550276",
      "postDate": "12/06/2023 00:23:19",
      "content": "<p>Congratulations with one more solo gold. Was rooting for you all the time and so sad you got hit by shakeup.</p>\n<p>Was a fun ride. <br>\nReally enjoyed the competition.</p>\n<p>Ruby K_mat and you always pushed us to try harder.</p>\n<p>Our solution is 100% result of the Francisco (Fnoa) hard work and he will write a review (my lgmb single model is 0.757 public / 0.82 private)</p>",
      "rawMarkdown": "Congratulations with one more solo gold. Was rooting for you all the time and so sad you got hit by shakeup.\n\nWas a fun ride. \nReally enjoyed the competition.\n\nRuby K_mat and you always pushed us to try harder.\n\nOur solution is 100% result of the Francisco (Fnoa) hard work and he will write a review (my lgmb single model is 0.757 public / 0.82 private)",
      "votes": null
    },
    {
      "id": "2550278",
      "postDate": "12/06/2023 00:26:29",
      "content": "<p>Wow that's an amazing LGBM model. I'm looking forward to your writeup.</p>\n<p>I was always watching your team and trying to stay ahead of you haha 😀 . You pushed me to work harder 😀 We were tied with same public LB score on many days. Congratulations building a strong generalizing model and jumping upward on private LB!</p>",
      "rawMarkdown": "Wow that's an amazing LGBM model. I'm looking forward to your writeup.\n\nI was always watching your team and trying to stay ahead of you haha 😀 . You pushed me to work harder 😀 We were tied with same public LB score on many days. Congratulations building a strong generalizing model and jumping upward on private LB!",
      "votes": null
    },
    {
      "id": "2550284",
      "postDate": "12/06/2023 00:30:14",
      "content": "<p><a href=\"https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201\" target=\"_blank\">https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201</a><br>\nlgbm - I'll clean private dataset and publish run with train also</p>",
      "rawMarkdown": "https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201\nlgbm - I'll clean private dataset and publish run with train also",
      "votes": null
    },
    {
      "id": "2550285",
      "postDate": "12/06/2023 00:32:37",
      "content": "<p>Thanks Sinan. The Average Precision metric has lots of way to exploit. The main ones are \"making more predictions which have a lower score than every other previous prediction\" will always increase the Average Precision metric. You can read about is <a href=\"https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\" target=\"_blank\">here</a> That is the idea behind the 30 levels of predictions each night where each new set gets divided by 2. The second way to exploit AP is to rerank/modify the scores. We want all false positives to have lower score than true positives for boost in metric.</p>\n<p>Another PP trick that I used (and did not write about above) was to add or subtract 1 to any prediction which was exactly a multiple of 12. This gave a nice boost. (Because of the metric, we do not want to predict perfect multiples of 12). </p>",
      "rawMarkdown": "Thanks Sinan. The Average Precision metric has lots of way to exploit. The main ones are \"making more predictions which have a lower score than every other previous prediction\" will always increase the Average Precision metric. You can read about is [here][1] That is the idea behind the 30 levels of predictions each night where each new set gets divided by 2. The second way to exploit AP is to rerank/modify the scores. We want all false positives to have lower score than true positives for boost in metric.\n\nAnother PP trick that I used (and did not write about above) was to add or subtract 1 to any prediction which was exactly a multiple of 12. This gave a nice boost. (Because of the metric, we do not want to predict perfect multiples of 12). \n\n[1]: https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637",
      "votes": null
    },
    {
      "id": "2550292",
      "postDate": "12/06/2023 00:41:35",
      "content": "<p>Thank you so much Chris. These are all great gems to have in the arsenal. Will keep coming to this post probably multiple times again in the future!</p>",
      "rawMarkdown": "Thank you so much Chris. These are all great gems to have in the arsenal. Will keep coming to this post probably multiple times again in the future!",
      "votes": null
    },
    {
      "id": "2550300",
      "postDate": "12/06/2023 00:52:06",
      "content": "<p>Congratulations once again <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>! It was a fun battle for days 😀</p>",
      "rawMarkdown": "Congratulations once again @cdeotte! It was a fun battle for days 😀",
      "votes": null
    },
    {
      "id": "2550302",
      "postDate": "12/06/2023 00:57:50",
      "content": "<p>Absolutely was fun! I knew your team was working hard every day and that encouraged me to work hard every day!</p>\n<p>Congratulations on an awesome 3rd place cash gold finish!</p>",
      "rawMarkdown": "Absolutely was fun! I knew your team was working hard every day and that encouraged me to work hard every day!\n\nCongratulations on an awesome 3rd place cash gold finish!",
      "votes": null
    },
    {
      "id": "2550311",
      "postDate": "12/06/2023 01:05:05",
      "content": "<p>Congrats Chris on the gold!</p>\n<p>And thanks for the clearly written writeup. Your solution is so sophisticated, yet easy to understand 🙂</p>\n<p>I found this idea very clever:</p>\n<p>\"Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\"</p>\n<p>I have one question:</p>\n<p>You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?</p>",
      "rawMarkdown": "Congrats Chris on the gold!\n\nAnd thanks for the clearly written writeup. Your solution is so sophisticated, yet easy to understand 🙂\n\nI found this idea very clever:\n\n\"Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\"\n\nI have one question:\n\nYou are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?",
      "votes": null
    },
    {
      "id": "2550312",
      "postDate": "12/06/2023 01:08:59",
      "content": "<p>Interesting solution! My solution is quite similar to yours - I used a window of 2 days and a custom defined self attention module instead of the usual transformer block. </p>\n<p>I didn't do extra postprocessing for the scores, I guess reranking with GB methods was what I needed for better calibrated probabilities.</p>\n<p>The postprocessing I did is to align the predictions to the nearest .25 or .75 second, augmenting the predictions by +-1 second (+0.005 CV), and removing repeated signals by matrix profile (+0.001 CV and private LB)</p>",
      "rawMarkdown": "Interesting solution! My solution is quite similar to yours - I used a window of 2 days and a custom defined self attention module instead of the usual transformer block. \n\nI didn't do extra postprocessing for the scores, I guess reranking with GB methods was what I needed for better calibrated probabilities.\n\nThe postprocessing I did is to align the predictions to the nearest .25 or .75 second, augmenting the predictions by +-1 second (+0.005 CV), and removing repeated signals by matrix profile (+0.001 CV and private LB)",
      "votes": null
    },
    {
      "id": "2550313",
      "postDate": "12/06/2023 01:09:20",
      "content": "<p>I’m impressed to see GRU having such a high score! 🚀</p>",
      "rawMarkdown": "I’m impressed to see GRU having such a high score! 🚀",
      "votes": null
    },
    {
      "id": "2550317",
      "postDate": "12/06/2023 01:13:22",
      "content": "<blockquote>\n  <p>You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?</p>\n</blockquote>\n<p>The first thing to realize is that we cannot start making second predictions for one night before we make first predictions for every user every night. (Because when we make second predictions then <strong>certainly</strong> either the first or second prediction will be a false positive and hurt metric). The Average Precision metric will rank every user every night <strong>all together</strong> and we want all false positives to have a lower score than true positives to optimize Average Precision. So the majority of our second predictions need to have a lower score than the majority of our first predictions.</p>\n<p>The exact division value is a hyperparameter that I determined from CV. First I used 10 because we want the second set of predictions to be \"an order of magnitude\" lower than the first set of predictions. The hyperparameter was <code>exponent</code> in <code>DIVIDE_CONSTANT = 10**exponent</code>. It turned out that <code>exponent = 1/5</code> was best which makes <code>DIVIDE CONSTANT</code> approximately 2.</p>",
      "rawMarkdown": ">You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?\n\nThe first thing to realize is that we cannot start making second predictions for one night before we make first predictions for every user every night. (Because when we make second predictions then **certainly** either the first or second prediction will be a false positive and hurt metric). The Average Precision metric will rank every user every night **all together** and we want all false positives to have a lower score than true positives to optimize Average Precision. So the majority of our second predictions need to have a lower score than the majority of our first predictions.\n\nThe exact division value is a hyperparameter that I determined from CV. First I used 10 because we want the second set of predictions to be \"an order of magnitude\" lower than the first set of predictions. The hyperparameter was `exponent` in `DIVIDE_CONSTANT = 10**exponent`. It turned out that `exponent = 1/5` was best which makes `DIVIDE CONSTANT` approximately 2.",
      "votes": null
    },
    {
      "id": "2550323",
      "postDate": "12/06/2023 01:20:01",
      "content": "<p>Amazing solution as always, Chris. Congrats on one more gold</p>",
      "rawMarkdown": "Amazing solution as always, Chris. Congrats on one more gold",
      "votes": null
    },
    {
      "id": "2550332",
      "postDate": "12/06/2023 01:29:51",
      "content": "<p>Awesome job! Congratulations <a href=\"https://www.kaggle.com/chauyh\" target=\"_blank\">@chauyh</a> on solo gold finish.</p>\n<p>I'm curious did you build features and/or post process information from the fact that sometimes the host make fake anglez enmo? For example, you could make a new feature \"has this anglez value at this daily timestep been seen before\" boolean feature. Or you could post process remove predictions from time windows that had fake data?</p>\n<p>I'm curious if there was helpful information here. I think my models naturally removed this stuff.</p>",
      "rawMarkdown": "Awesome job! Congratulations @chauyh on solo gold finish.\n\nI'm curious did you build features and/or post process information from the fact that sometimes the host make fake anglez enmo? For example, you could make a new feature \"has this anglez value at this daily timestep been seen before\" boolean feature. Or you could post process remove predictions from time windows that had fake data?\n\nI'm curious if there was helpful information here. I think my models naturally removed this stuff.",
      "votes": null
    },
    {
      "id": "2550343",
      "postDate": "12/06/2023 01:41:01",
      "content": "<p>A lot of great ideas! If some of the top ranks on the LB combined their ideas, 0.88 might be possible!</p>",
      "rawMarkdown": "A lot of great ideas! If some of the top ranks on the LB combined their ideas, 0.88 might be possible!",
      "votes": null
    },
    {
      "id": "2550349",
      "postDate": "12/06/2023 01:48:40",
      "content": "<p>Thanks <a href=\"https://www.kaggle.com/fritzcremer\" target=\"_blank\">@fritzcremer</a> . Congratulations on amazing cash solo gold !!</p>",
      "rawMarkdown": "Thanks @fritzcremer . Congratulations on amazing cash solo gold !!",
      "votes": null
    },
    {
      "id": "2550437",
      "postDate": "12/06/2023 03:15:13",
      "content": "<p>Yes it is impressive how well GRU can do with only input the two features <code>anglez</code> and <code>enmo</code>. Note I did post process the prediction logits for all <code>minute % 15</code> which equaled one of the values that did not occur in the train data. (There were 4 rare values for <code>onset</code> and 4 rare values for <code>wakeup</code>). For these rare logits, I divided their logit prediction by 2 before performing softmax. This boosted CV about approximately <code>+0.010</code> or <code>+0.020</code> (if i remember correctly)</p>\n<p>I also tried adding <code>minute % 15</code> as a feature for the GRU. It boosted the CV score, but it was better to not include this feature and post process. This is probably because the model will overfit when the feature <code>minute % 15</code> is present.</p>",
      "rawMarkdown": "Yes it is impressive how well GRU can do with only input the two features `anglez` and `enmo`. Note I did post process the prediction logits for all `minute % 15` which equaled one of the values that did not occur in the train data. (There were 4 rare values for `onset` and 4 rare values for `wakeup`). For these rare logits, I divided their logit prediction by 2 before performing softmax. This boosted CV about approximately `+0.010` or `+0.020` (if i remember correctly)\n\nI also tried adding `minute % 15` as a feature for the GRU. It boosted the CV score, but it was better to not include this feature and post process. This is probably because the model will overfit when the feature `minute % 15` is present.",
      "votes": null
    },
    {
      "id": "2550496",
      "postDate": "12/06/2023 04:42:19",
      "content": "<p>What a unique solution. Congratulations <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> on just another brilliant performance. We all learn from you everytime</p>",
      "rawMarkdown": "What a unique solution. Congratulations @cdeotte on just another brilliant performance. We all learn from you everytime",
      "votes": null
    },
    {
      "id": "2550503",
      "postDate": "12/06/2023 04:49:30",
      "content": "<p>Thanks <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and congrats on solo gold too!</p>\n<p>My approach is to train a DL model end to end and use as little manual processing /postprocessing as possible. I only applied a box-cox transform to enmo, and used the raw anglez as input to the DL model.</p>\n<p>At the last stages of the competition (~1 week), I found out that postprocessing to calibrate probabilities is quite important. I focused on the missing labels problem but the gains were trivial (+0.0004 CV, compared to approach already with matrix profile pruning).</p>\n<p>I tried very hard to find patterns leading to missing labels but I couldn't find any. The only consistent pattern was repeated data, which is could easily be pruned away with matrix profile. Interestingly, there are some labels in the training set for the repeated data.</p>\n<p>Let me first try some of your postprocessing methods and I'll post a detailed writeup of my methods and findings during the weekend!</p>",
      "rawMarkdown": "Thanks @cdeotte and congrats on solo gold too!\n\nMy approach is to train a DL model end to end and use as little manual processing /postprocessing as possible. I only applied a box-cox transform to enmo, and used the raw anglez as input to the DL model.\n\nAt the last stages of the competition (~1 week), I found out that postprocessing to calibrate probabilities is quite important. I focused on the missing labels problem but the gains were trivial (+0.0004 CV, compared to approach already with matrix profile pruning).\n\nI tried very hard to find patterns leading to missing labels but I couldn't find any. The only consistent pattern was repeated data, which is could easily be pruned away with matrix profile. Interestingly, there are some labels in the training set for the repeated data.\n\nLet me first try some of your postprocessing methods and I'll post a detailed writeup of my methods and findings during the weekend!",
      "votes": null
    },
    {
      "id": "2550628",
      "postDate": "12/06/2023 06:48:10",
      "content": "<p>There is always something to learn from you <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>. Thanks for the nice writeup. Congratulations on one more gold </p>",
      "rawMarkdown": "There is always something to learn from you @cdeotte. Thanks for the nice writeup. Congratulations on one more gold",
      "votes": null
    },
    {
      "id": "2550695",
      "postDate": "12/06/2023 08:16:43",
      "content": "<p>Amazing solution. Can you please share an inference code ?)</p>",
      "rawMarkdown": "Amazing solution. Can you please share an inference code ?)",
      "votes": null
    },
    {
      "id": "2550761",
      "postDate": "12/06/2023 08:54:42",
      "content": "<p>Despite not participating in the competition, I learned a lot about it just by reading this.</p>\n<p>Impressive solution as always, congrats Chris.</p>",
      "rawMarkdown": "Despite not participating in the competition, I learned a lot about it just by reading this.\n\nImpressive solution as always, congrats Chris.",
      "votes": null
    },
    {
      "id": "2550824",
      "postDate": "12/06/2023 10:01:22",
      "content": "<p>Well done on the solo gold ! <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> . we missed out on these metric specific tricks which turned out to be a huge deal, will make sure to study the metric more carefully next time. Really appreciate you sharing this!</p>",
      "rawMarkdown": "Well done on the solo gold ! @cdeotte . we missed out on these metric specific tricks which turned out to be a huge deal, will make sure to study the metric more carefully next time. Really appreciate you sharing this!",
      "votes": null
    },
    {
      "id": "2550916",
      "postDate": "12/06/2023 11:54:44",
      "content": "<p>Hi,Congrats Chris on the gold!  I have a question I would like to ask. Is BertForTokenClassification much worse than BertForQuestionAnswering? Why did you choose BertForQuestionAnswering? I  understand that BertForTokenClassification can also be used for subsequent post-processing processes. </p>",
      "rawMarkdown": "Hi,Congrats Chris on the gold!  I have a question I would like to ask. Is BertForTokenClassification much worse than BertForQuestionAnswering? Why did you choose BertForQuestionAnswering? I  understand that BertForTokenClassification can also be used for subsequent post-processing processes.",
      "votes": null
    },
    {
      "id": "2551066",
      "postDate": "12/06/2023 13:42:20",
      "content": "<p>Well Done Chris! Impressive solution.</p>",
      "rawMarkdown": "Well Done Chris! Impressive solution.",
      "votes": null
    },
    {
      "id": "2551434",
      "postDate": "12/06/2023 17:37:51",
      "content": "<p>Thanks Ertugrul </p>",
      "rawMarkdown": "Thanks Ertugrul",
      "votes": null
    },
    {
      "id": "2551520",
      "postDate": "12/06/2023 18:16:42",
      "content": "<p>Thanks, 3 more to go for Grandmaster 😁 Congrats to your 22nd Gold haha</p>",
      "rawMarkdown": "Thanks, 3 more to go for Grandmaster 😁 Congrats to your 22nd Gold haha",
      "votes": null
    },
    {
      "id": "2551630",
      "postDate": "12/06/2023 20:41:04",
      "content": "<p>Hi <a href=\"https://www.kaggle.com/sayoulala\" target=\"_blank\">@sayoulala</a> I think both methods work well. To me the task seemed like QA so I went QA from the beginning. Below are predictions from each technique. I think we need different post process for NER vs. QA. For my QA pipeline, I could simply find the top30 maxes to be my top30 predictions per night since QA makes peaks on single minute values. With NER, I think we would need to use a different way to find additional predictions.</p>\n<p>For diversity, i also trained NER models and used them to improve the <code>score</code> value for each QA prediction.</p>\n<h1>NLP QA Predictions</h1>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa.png\" alt=\"\"></p>\n<h1>NLP NER Predictions</h1>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/ner.png\" alt=\"\"></p>",
      "rawMarkdown": "Hi @sayoulala I think both methods work well. To me the task seemed like QA so I went QA from the beginning. Below are predictions from each technique. I think we need different post process for NER vs. QA. For my QA pipeline, I could simply find the top30 maxes to be my top30 predictions per night since QA makes peaks on single minute values. With NER, I think we would need to use a different way to find additional predictions.\n\nFor diversity, i also trained NER models and used them to improve the `score` value for each QA prediction.\n\n# NLP QA Predictions\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa.png)\n\n#NLP NER Predictions\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/ner.png)",
      "votes": null
    },
    {
      "id": "2551698",
      "postDate": "12/06/2023 22:05:38",
      "content": "<p>Fabulous sharing on GPU deep learning. Learnt a lot from u.</p>",
      "rawMarkdown": "Fabulous sharing on GPU deep learning. Learnt a lot from u.",
      "votes": null
    },
    {
      "id": "2551816",
      "postDate": "12/07/2023 02:04:37",
      "content": "<p>Do you mind sharing the pseudo code you used to automatically generate features?</p>",
      "rawMarkdown": "Do you mind sharing the pseudo code you used to automatically generate features?",
      "votes": null
    },
    {
      "id": "2551940",
      "postDate": "12/07/2023 04:38:26",
      "content": "<p>ResNet50 GPU deep learning</p>",
      "rawMarkdown": "ResNet50 GPU deep learning",
      "votes": null
    },
    {
      "id": "2552021",
      "postDate": "12/07/2023 06:02:52",
      "content": "<p>The observations on the evaluation metrics are most impressive to me so I will implement such technique in late submissions. Thank you!</p>",
      "rawMarkdown": "The observations on the evaluation metrics are most impressive to me so I will implement such technique in late submissions. Thank you!",
      "votes": null
    },
    {
      "id": "2552201",
      "postDate": "12/07/2023 09:33:38",
      "content": "<p>Congratulations. Thanks for sharing your solution details. Very interesting approach indeed. </p>",
      "rawMarkdown": "Congratulations. Thanks for sharing your solution details. Very interesting approach indeed.",
      "votes": null
    },
    {
      "id": "2552957",
      "postDate": "12/07/2023 22:35:39",
      "content": "<p>Thanks NikhilMishra. Congratulations to you and penguin46. Great job achieving cash gold !!</p>",
      "rawMarkdown": "Thanks NikhilMishra. Congratulations to you and penguin46. Great job achieving cash gold !!",
      "votes": null
    },
    {
      "id": "2553212",
      "postDate": "12/08/2023 04:54:59",
      "content": "<p>I have no word. It's a great post processing!</p>",
      "rawMarkdown": "I have no word. It's a great post processing!",
      "votes": null
    },
    {
      "id": "2553215",
      "postDate": "12/08/2023 04:57:52",
      "content": "<p>I have a problem to come up with what the right way to build input data is.<br>\nCould you explain why you selected the input data with both an onset and a wakeup?</p>",
      "rawMarkdown": "I have a problem to come up with what the right way to build input data is.\nCould you explain why you selected the input data with both an onset and a wakeup?",
      "votes": null
    },
    {
      "id": "2553543",
      "postDate": "12/08/2023 10:46:13",
      "content": "<p>This is a powerful technique to achieve top results in object detection and object segmentation Kaggle competitions! </p>\n<p>We want the model to <strong>locate</strong> where <code>onset</code> and <code>wakeup</code> is. So every train sample contains an <code>onset</code> and <code>wakeup</code>. (We cannot learn location if there is no onset wakeup). Therefore our dataloader, provides random 24 hour crops and <strong>every crop contains</strong> both <code>onset</code> and <code>wakeup</code>.</p>\n<p>This model will beat other models and techniques for <strong>locating</strong> <code>onset</code> and <code>wakeup</code>. However this model can not determine existence. This model will think that every day contains an onset and wakeup. So we also need to build a second model (not described in my solution post). The second model job is a classifier that outputs 0 or 1 predicting when a 24 window has an onset and wakeup.</p>\n<p>We train the second model with a different data loader. The data loader for the second model provides <strong>all types of random 24 hour crops</strong>. Some crops have onset wakeup, and some crops do not have onset wakeup. The second model is binary classifier that learns when onset wakeup is present or not.</p>\n<p>Then our inference pipeline uses both models, our first model predicts onset wakeup for <strong>every night, i.e. 24 hours</strong>. And our second model removes false positives. Whenever our second model outputs <code>prob &lt; 0.2</code> for a night (i.e. 24 hour window), then we <strong>remove</strong> the first model prediction from <code>submission.csv</code>.</p>",
      "rawMarkdown": "This is a powerful technique to achieve top results in object detection and object segmentation Kaggle competitions! \n\nWe want the model to **locate** where `onset` and `wakeup` is. So every train sample contains an `onset` and `wakeup`. (We cannot learn location if there is no onset wakeup). Therefore our dataloader, provides random 24 hour crops and **every crop contains** both `onset` and `wakeup`.\n\nThis model will beat other models and techniques for **locating** `onset` and `wakeup`. However this model can not determine existence. This model will think that every day contains an onset and wakeup. So we also need to build a second model (not described in my solution post). The second model job is a classifier that outputs 0 or 1 predicting when a 24 window has an onset and wakeup.\n\nWe train the second model with a different data loader. The data loader for the second model provides **all types of random 24 hour crops**. Some crops have onset wakeup, and some crops do not have onset wakeup. The second model is binary classifier that learns when onset wakeup is present or not.\n\nThen our inference pipeline uses both models, our first model predicts onset wakeup for **every night, i.e. 24 hours**. And our second model removes false positives. Whenever our second model outputs `prob < 0.2` for a night (i.e. 24 hour window), then we **remove** the first model prediction from `submission.csv`.",
      "votes": null
    },
    {
      "id": "2553796",
      "postDate": "12/08/2023 14:13:15",
      "content": "<p>That's very logical approach.<br>\nAnd I really appreciate your long and detail answer. I'm so touched. :)</p>",
      "rawMarkdown": "That's very logical approach.\nAnd I really appreciate your long and detail answer. I'm so touched. :)",
      "votes": null
    },
    {
      "id": "2554261",
      "postDate": "12/09/2023 01:22:19",
      "content": "<p><strong>UPDATE</strong> I published the code for these two TensorFlow models <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a></p>",
      "rawMarkdown": "**UPDATE** I published the code for these two TensorFlow models [here][1]\n\n[1]: https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788",
      "votes": null
    },
    {
      "id": "2554642",
      "postDate": "12/09/2023 09:17:28",
      "content": "<p>Excellent work! Really learnt a lot from this. I should have stuck with my keras framework rather than going to learn pytorch. Now I know…</p>",
      "rawMarkdown": "Excellent work! Really learnt a lot from this. I should have stuck with my keras framework rather than going to learn pytorch. Now I know...",
      "votes": null
    },
    {
      "id": "2554711",
      "postDate": "12/09/2023 10:44:28",
      "content": "<p>Thanks for Sharing</p>",
      "rawMarkdown": "Thanks for Sharing",
      "votes": null
    },
    {
      "id": "2555388",
      "postDate": "12/09/2023 21:32:46",
      "content": "<p>The RNN, CNN, and Transformer blocks generate features for us. Code is shown <a href=\"https://www.kaggle.com/code/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>. Then the model heads makes the prediction using features from the proceeding blocks.</p>",
      "rawMarkdown": "The RNN, CNN, and Transformer blocks generate features for us. Code is shown [here][1]. Then the model heads makes the prediction using features from the proceeding blocks.\n\n[1]: https://www.kaggle.com/code/cdeotte/11th-place-gold-cv-835-public-lb-788",
      "votes": null
    },
    {
      "id": "2558156",
      "postDate": "12/12/2023 00:24:35",
      "content": "<p>For reference, here are the 3 popular ways to create a target in this competition. All three performed well. From all three, we can compute a <code>step</code> and <code>score</code> for <code>submission.csv</code>:<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/targets2.png\" alt=\"\"></p>",
      "rawMarkdown": "For reference, here are the 3 popular ways to create a target in this competition. All three performed well. From all three, we can compute a `step` and `score` for `submission.csv`:\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/targets2.png)",
      "votes": null
    },
    {
      "id": "2558157",
      "postDate": "12/12/2023 00:30:36",
      "content": "<p>For reference, here are two Mel Spectrograms with 1D prediction and 2D prediction and ground truth:<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel1.png\" alt=\"\"><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel2.png\" alt=\"\"></p>",
      "rawMarkdown": "For reference, here are two Mel Spectrograms with 1D prediction and 2D prediction and ground truth:\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel1.png)\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel2.png)",
      "votes": null
    },
    {
      "id": "2559343",
      "postDate": "12/12/2023 18:48:35",
      "content": "<p>Congratulations! Such an excellent work. As a beginner I have really learned a lot from your solution. I am still a little bit confused about two details of your approach. </p>\n<p>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440. So I'm wondering whether you are using the mean of 12 steps as one data point as input. May I also asked about the 80 features you used?</p>\n<p>And the second one is about  labels. It is a great idea to seperate \"onset\" and \"awake\" as two different labels and I noticed that some competitors applied a gaussian window around the event step.  So did you use the same solution or just use original \"0\" and \"1\" labels?</p>\n<p>Thank you so much if you can reply to my comment.</p>",
      "rawMarkdown": "Congratulations! Such an excellent work. As a beginner I have really learned a lot from your solution. I am still a little bit confused about two details of your approach. \n\nOne is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440. So I'm wondering whether you are using the mean of 12 steps as one data point as input. May I also asked about the 80 features you used?\n\nAnd the second one is about  labels. It is a great idea to seperate \"onset\" and \"awake\" as two different labels and I noticed that some competitors applied a gaussian window around the event step.  So did you use the same solution or just use original \"0\" and \"1\" labels?\n\nThank you so much if you can reply to my comment.",
      "votes": null
    },
    {
      "id": "2559395",
      "postDate": "12/12/2023 19:32:07",
      "content": "<p>Thank you</p>\n<blockquote>\n  <p>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440</p>\n</blockquote>\n<p>My <code>CNN-Transformer-GRU</code> uses an input of 1440. The data loader output just skips every 12th using the following Python indexing <code>X_train[:,::12,:]</code>.</p>\n<blockquote>\n  <p>May I also asked about the 80 features you used?</p>\n</blockquote>\n<p>I used the 79 features from this popular LGBM notebook <a href=\"https://www.kaggle.com/code/renatoreggiani/lightgbm-starter-cmi\" target=\"_blank\">here</a>. And I added the additional feature <code>minute%15</code> to learn the weird labeler bias. (I also built my own CatBoost with my own 200 features and my CatBoost scored LB 0.705 but my Transformer used those public notebook features). </p>\n<blockquote>\n  <p>So did you use the same solution or just use original \"0\" and \"1\" labels?</p>\n</blockquote>\n<p>I used the original \"0\" and \"1\". Each of my two models here has output sequence length 1440 which is the number of minutes per day. The target for each day crop were 1439 zeros with 1 one where the actual target is. My loss is softmax multi-class crossentropy, so the model had no trouble learning the unique target \"1\" out of \"1440\" different classes. (I.e. the multiclass is the 1440 different minutes each day and the model finds the correct minute each day)</p>",
      "rawMarkdown": "Thank you\n\n>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440\n\nMy `CNN-Transformer-GRU` uses an input of 1440. The data loader output just skips every 12th using the following Python indexing `X_train[:,::12,:]`.\n\n>May I also asked about the 80 features you used?\n\nI used the 79 features from this popular LGBM notebook [here][1]. And I added the additional feature `minute%15` to learn the weird labeler bias. (I also built my own CatBoost with my own 200 features and my CatBoost scored LB 0.705 but my Transformer used those public notebook features). \n\n>So did you use the same solution or just use original \"0\" and \"1\" labels?\n\nI used the original \"0\" and \"1\". Each of my two models here has output sequence length 1440 which is the number of minutes per day. The target for each day crop were 1439 zeros with 1 one where the actual target is. My loss is softmax multi-class crossentropy, so the model had no trouble learning the unique target \"1\" out of \"1440\" different classes. (I.e. the multiclass is the 1440 different minutes each day and the model finds the correct minute each day)\n\n[1]: https://www.kaggle.com/code/renatoreggiani/lightgbm-starter-cmi",
      "votes": null
    },
    {
      "id": "2559403",
      "postDate": "12/12/2023 19:42:58",
      "content": "<p>Got it. Thank you so much!</p>",
      "rawMarkdown": "Got it. Thank you so much!",
      "votes": null
    },
    {
      "id": "2559919",
      "postDate": "12/13/2023 06:29:30",
      "content": "<p>Congratulations! Always can  learn a lot from your work. Especially the Deep GRU model that only use 2 original features. Really impressive!</p>\n<p>I'm trying to train your Deep GRU model, but I got gradient vanishing problem. I use exactly your 'build_model_2()' code, but If I call the \"build_model_2()\" function 5 times, maybe got gradient vanishing for 3 or 4 times.<br>\nI guess I must miss something somewhere, such as some special initializer? or some kind of random seed setting? Or other stuffs.<br>\nSo, will you public all your code? Then I can check where I'm going wrong. </p>\n<p>Again, thanks a lot for the sharing of your excellent work!</p>",
      "rawMarkdown": "Congratulations! Always can  learn a lot from your work. Especially the Deep GRU model that only use 2 original features. Really impressive!\n\nI'm trying to train your Deep GRU model, but I got gradient vanishing problem. I use exactly your 'build_model_2()' code, but If I call the \"build_model_2()\" function 5 times, maybe got gradient vanishing for 3 or 4 times.\nI guess I must miss something somewhere, such as some special initializer? or some kind of random seed setting? Or other stuffs.\nSo, will you public all your code? Then I can check where I'm going wrong. \n\nAgain, thanks a lot for the sharing of your excellent work!",
      "votes": null
    },
    {
      "id": "2560579",
      "postDate": "12/13/2023 19:41:21",
      "content": "<p>Wanted to perform this data transformation but implementation and computational bottleneck was a problem. Had wanted to use the sleeping and waking data spectrograms as images to a 2D CNN but kept crashing. Was this ever feasible given the constraints of the competition? Still would like to implement it fully and compare.</p>",
      "rawMarkdown": "Wanted to perform this data transformation but implementation and computational bottleneck was a problem. Had wanted to use the sleeping and waking data spectrograms as images to a 2D CNN but kept crashing. Was this ever feasible given the constraints of the competition? Still would like to implement it fully and compare.",
      "votes": null
    },
    {
      "id": "2560603",
      "postDate": "12/13/2023 20:13:27",
      "content": "<p>Yes this was feasible. My final solution used this model to predict a <code>score</code> for each <code>onset</code> and <code>wakeup</code> and I added the <code>score</code> to the <code>score</code> from my Transformer and GRU to improve CV and LB. Also by itself, this model achieved good results.</p>\n<p>An easy way to avoid memory error is to process data in chunks and save intermediate data to disk. We can do this both for train and infer.</p>\n<p>First read Kaggle's train parquet in chunks and we iterate through every user and write each user to disk as a NumPy file. So for each user we have data shape <code>(days, 17280, 4)</code> where <code>days</code> is the number of 24 hour periods (per user), and 17280 is the number of steps in 24 hours. And <code>4</code> is anglez, enmo, and the two targets. (Also we begin each user at 3pm and end at 3pm and add padding to beginning and ending if necessary. That makes all the 24 hour windows the same).</p>\n<p>Next we iterate through each of these NumPys. We load from disk then convert to image. Then save images to disk. The code below creates 2 channel images of size 256x1536 for each day for each user:</p>\n<pre><code>import librosa\nCROP = 17_280; SRR = 17_280; HL = 12; HH = 256\n\n j,u  enumerate(USERS):\n    data = np.nan_to_num( np.load(f) )\n    jj = []\n     r  range(len(data)):\n        ii = []\n        mel_spec = librosa.feature.melspectrogram(=data[r,:,0], =SRR, =2048, =HL, \n              =HH, =0, =SRR//2, =2048//4)\n        mel_spec_db = librosa.power_to_db(mel_spec, =np.max).astype(np.float32)\n        ii.append(mel_spec_db)\n\n        mel_spec = librosa.feature.melspectrogram(=data[r,:,1], =SRR, =2048, =HL, \n              =HH, =0, =SRR//2, =2048//4)\n        mel_spec_db = librosa.power_to_db(mel_spec, =np.max).astype(np.float32)\n        ii.append(mel_spec_db)\n\n        img2 = np.transpose( np.stack(ii), [1,2,0])\n        jj.append(img2)\n\n    jj = np.stack(jj)\n    np.save(f,jj)\n</code></pre>",
      "rawMarkdown": "Yes this was feasible. My final solution used this model to predict a `score` for each `onset` and `wakeup` and I added the `score` to the `score` from my Transformer and GRU to improve CV and LB. Also by itself, this model achieved good results.\n\nAn easy way to avoid memory error is to process data in chunks and save intermediate data to disk. We can do this both for train and infer.\n\nFirst read Kaggle's train parquet in chunks and we iterate through every user and write each user to disk as a NumPy file. So for each user we have data shape `(days, 17280, 4)` where `days` is the number of 24 hour periods (per user), and 17280 is the number of steps in 24 hours. And `4` is anglez, enmo, and the two targets. (Also we begin each user at 3pm and end at 3pm and add padding to beginning and ending if necessary. That makes all the 24 hour windows the same).\n\nNext we iterate through each of these NumPys. We load from disk then convert to image. Then save images to disk. The code below creates 2 channel images of size 256x1536 for each day for each user:\n\n    import librosa\n    CROP = 17_280; SRR = 17_280; HL = 12; HH = 256\n\n    for j,u in enumerate(USERS):\n        data = np.nan_to_num( np.load(f'numpys/{u}.npy') )\n        jj = []\n        for r in range(len(data)):\n            ii = []\n            mel_spec = librosa.feature.melspectrogram(y=data[r,:,0], sr=SRR, n_fft=2048, hop_length=HL, \n                  n_mels=HH, fmin=0, fmax=SRR//2, win_length=2048//4)\n            mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max).astype(np.float32)\n            ii.append(mel_spec_db)\n        \n            mel_spec = librosa.feature.melspectrogram(y=data[r,:,1], sr=SRR, n_fft=2048, hop_length=HL, \n                  n_mels=HH, fmin=0, fmax=SRR//2, win_length=2048//4)\n            mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max).astype(np.float32)\n            ii.append(mel_spec_db)\n        \n            img2 = np.transpose( np.stack(ii), [1,2,0])\n            jj.append(img2)\n        \n        jj = np.stack(jj)\n        np.save(f'images/{u}.npy',jj)",
      "votes": null
    },
    {
      "id": "2560605",
      "postDate": "12/13/2023 20:14:39",
      "content": "<p>Also note that the highest scoring public notebook uses Mel Spectrograms (created by PyTorch) and provides code on GitHub. Discussion <a href=\"https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/452940\" target=\"_blank\">here</a></p>",
      "rawMarkdown": "Also note that the highest scoring public notebook uses Mel Spectrograms (created by PyTorch) and provides code on GitHub. Discussion [here][1]\n\n[1]: https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/452940",
      "votes": null
    },
    {
      "id": "2560620",
      "postDate": "12/13/2023 20:26:47",
      "content": "<p>Thank you Chris. Wish I had had this earlier on. Gave up due to memory lags and crashes. I will work with this for future similar competitions. Once more, I really appreciate your hard work and taking the time to explain the secret dark arts of ML and DL in a succinct manner to us lost-in-the-woods folks. </p>",
      "rawMarkdown": "Thank you Chris. Wish I had had this earlier on. Gave up due to memory lags and crashes. I will work with this for future similar competitions. Once more, I really appreciate your hard work and taking the time to explain the secret dark arts of ML and DL in a succinct manner to us lost-in-the-woods folks.",
      "votes": null
    },
    {
      "id": "2560622",
      "postDate": "12/13/2023 20:29:07",
      "content": "<p>Ok Chris. Will check it out. I wonder if I doing this on TPUs would make that much difference in training and inference speed? Its the scoring time that gives me ulcers.</p>",
      "rawMarkdown": "Ok Chris. Will check it out. I wonder if I doing this on TPUs would make that much difference in training and inference speed? Its the scoring time that gives me ulcers.",
      "votes": null
    },
    {
      "id": "2560626",
      "postDate": "12/13/2023 20:32:44",
      "content": "<p>Oh I see. The librosa library makes it easier. Was trying to do it from scratch but never got a spectrogram plot good enough as yours. Must be some bug in my code.</p>",
      "rawMarkdown": "Oh I see. The librosa library makes it easier. Was trying to do it from scratch but never got a spectrogram plot good enough as yours. Must be some bug in my code.",
      "votes": null
    },
    {
      "id": "2560778",
      "postDate": "12/14/2023 02:00:58",
      "content": "<p>Congratulations! Very interesting approach indeed </p>",
      "rawMarkdown": "Congratulations! Very interesting approach indeed",
      "votes": null
    },
    {
      "id": "2561855",
      "postDate": "12/14/2023 22:02:57",
      "content": "<p>Do you mean that you get gradient vanishing during training? If so, does your data loader output the correct train data? Every train sample must have <code>X_train</code> with shape <code>(batch, 17280, 2)</code> where the 2 features are anglez and enmo standardized (i.e minus mean divide by std using the mean and std of the entire train data). And the target is list of length two <code>[y_train_1, y_train_2]</code> where each are shape <code>(batch, 1440)</code> and each have exactly 1439 zeros and 1 one? (i.e. there is exactly 1 target in every sample. We do not use 24 hour windows that are missing target).</p>",
      "rawMarkdown": "Do you mean that you get gradient vanishing during training? If so, does your data loader output the correct train data? Every train sample must have `X_train` with shape `(batch, 17280, 2)` where the 2 features are anglez and enmo standardized (i.e minus mean divide by std using the mean and std of the entire train data). And the target is list of length two `[y_train_1, y_train_2]` where each are shape `(batch, 1440)` and each have exactly 1439 zeros and 1 one? (i.e. there is exactly 1 target in every sample. We do not use 24 hour windows that are missing target).",
      "votes": null
    },
    {
      "id": "2562037",
      "postDate": "12/15/2023 03:56:08",
      "content": "<p>Thanks for your reply.<br>\nYes, I get gradient vanishing when I train the Deep-GRU model.<br>\nI checked many times, it seems my data loader satisfies all the demands that you described.  But gradient vanishing still happens from time to time.<br>\nToday, I set global seed using \"tf.random.set_seed()\", and set  the operation seeds of initializers for the Conv1d, GRU, Dense layers in the model. so that the initial weights in the model will be the same every time the model is built.<br>\nLuckily, it works. Gradient vanishing won't happen.<br>\nMaybe there is still something wrong in my data loader, so that  it demand some special initial weights in the model.<br>\nAnyway, I can avoid gradient vanishing for now. Hope the unknown bug doesn't affect the training result.<br>\n😅😅😅</p>",
      "rawMarkdown": "Thanks for your reply.\nYes, I get gradient vanishing when I train the Deep-GRU model.\nI checked many times, it seems my data loader satisfies all the demands that you described.  But gradient vanishing still happens from time to time.\nToday, I set global seed using \"tf.random.set_seed()\", and set  the operation seeds of initializers for the Conv1d, GRU, Dense layers in the model. so that the initial weights in the model will be the same every time the model is built.\nLuckily, it works. Gradient vanishing won't happen.\nMaybe there is still something wrong in my data loader, so that  it demand some special initial weights in the model.\nAnyway, I can avoid gradient vanishing for now. Hope the unknown bug doesn't affect the training result.\n😅😅😅",
      "votes": null
    },
    {
      "id": "2568995",
      "postDate": "12/21/2023 02:43:34",
      "content": "<p>Really interesting approach. Your solution was like a Random Forrest, implemented each ML-Code separatelly, instead decision trees.. Haha! <br>\nI'm completing this challenge (late submission), but in another way! Congrats bro!</p>",
      "rawMarkdown": "Really interesting approach. Your solution was like a Random Forrest, implemented each ML-Code separatelly, instead decision trees.. Haha! \nI'm completing this challenge (late submission), but in another way! Congrats bro!",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2550270,
      "author_name": "cody11null",
      "author_url": "",
      "post_date": "12/06/2023 00:19:53",
      "content": "<p>Learning from you yet again, a pleasure to watch you work. Congrats Chris!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2550274,
      "author_name": "snnclsr",
      "author_url": "",
      "post_date": "12/06/2023 00:22:31",
      "content": "<p>Great solution as always Chris. Very well done!! You were in the top for a very long time and I was like, okay Chris is for sure doing something with the post-processing again 😅 </p>\n<p>And I was wondering which features did you generate for <code>80 features</code> part?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550285,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 00:32:37",
          "content": "<p>Thanks Sinan. The Average Precision metric has lots of way to exploit. The main ones are \"making more predictions which have a lower score than every other previous prediction\" will always increase the Average Precision metric. You can read about is <a href=\"https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\" target=\"_blank\">here</a> That is the idea behind the 30 levels of predictions each night where each new set gets divided by 2. The second way to exploit AP is to rerank/modify the scores. We want all false positives to have lower score than true positives for boost in metric.</p>\n<p>Another PP trick that I used (and did not write about above) was to add or subtract 1 to any prediction which was exactly a multiple of 12. This gave a nice boost. (Because of the metric, we do not want to predict perfect multiples of 12). </p>",
          "votes": null,
          "replies": [
            {
              "id": 2550292,
              "author_name": "snnclsr",
              "author_url": "",
              "post_date": "12/06/2023 00:41:35",
              "content": "<p>Thank you so much Chris. These are all great gems to have in the arsenal. Will keep coming to this post probably multiple times again in the future!</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2550276,
      "author_name": "kyakovlev",
      "author_url": "",
      "post_date": "12/06/2023 00:23:19",
      "content": "<p>Congratulations with one more solo gold. Was rooting for you all the time and so sad you got hit by shakeup.</p>\n<p>Was a fun ride. <br>\nReally enjoyed the competition.</p>\n<p>Ruby K_mat and you always pushed us to try harder.</p>\n<p>Our solution is 100% result of the Francisco (Fnoa) hard work and he will write a review (my lgmb single model is 0.757 public / 0.82 private)</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550278,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 00:26:29",
          "content": "<p>Wow that's an amazing LGBM model. I'm looking forward to your writeup.</p>\n<p>I was always watching your team and trying to stay ahead of you haha 😀 . You pushed me to work harder 😀 We were tied with same public LB score on many days. Congratulations building a strong generalizing model and jumping upward on private LB!</p>",
          "votes": null,
          "replies": [
            {
              "id": 2550284,
              "author_name": "kyakovlev",
              "author_url": "",
              "post_date": "12/06/2023 00:30:14",
              "content": "<p><a href=\"https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201\" target=\"_blank\">https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201</a><br>\nlgbm - I'll clean private dataset and publish run with train also</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2550300,
      "author_name": "trasibulo",
      "author_url": "",
      "post_date": "12/06/2023 00:52:06",
      "content": "<p>Congratulations once again <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>! It was a fun battle for days 😀</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550302,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 00:57:50",
          "content": "<p>Absolutely was fun! I knew your team was working hard every day and that encouraged me to work hard every day!</p>\n<p>Congratulations on an awesome 3rd place cash gold finish!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2550311,
      "author_name": "sambitmukherjee",
      "author_url": "",
      "post_date": "12/06/2023 01:05:05",
      "content": "<p>Congrats Chris on the gold!</p>\n<p>And thanks for the clearly written writeup. Your solution is so sophisticated, yet easy to understand 🙂</p>\n<p>I found this idea very clever:</p>\n<p>\"Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\"</p>\n<p>I have one question:</p>\n<p>You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550317,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 01:13:22",
          "content": "<blockquote>\n  <p>You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?</p>\n</blockquote>\n<p>The first thing to realize is that we cannot start making second predictions for one night before we make first predictions for every user every night. (Because when we make second predictions then <strong>certainly</strong> either the first or second prediction will be a false positive and hurt metric). The Average Precision metric will rank every user every night <strong>all together</strong> and we want all false positives to have a lower score than true positives to optimize Average Precision. So the majority of our second predictions need to have a lower score than the majority of our first predictions.</p>\n<p>The exact division value is a hyperparameter that I determined from CV. First I used 10 because we want the second set of predictions to be \"an order of magnitude\" lower than the first set of predictions. The hyperparameter was <code>exponent</code> in <code>DIVIDE_CONSTANT = 10**exponent</code>. It turned out that <code>exponent = 1/5</code> was best which makes <code>DIVIDE CONSTANT</code> approximately 2.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2550312,
      "author_name": "chauyh",
      "author_url": "",
      "post_date": "12/06/2023 01:08:59",
      "content": "<p>Interesting solution! My solution is quite similar to yours - I used a window of 2 days and a custom defined self attention module instead of the usual transformer block. </p>\n<p>I didn't do extra postprocessing for the scores, I guess reranking with GB methods was what I needed for better calibrated probabilities.</p>\n<p>The postprocessing I did is to align the predictions to the nearest .25 or .75 second, augmenting the predictions by +-1 second (+0.005 CV), and removing repeated signals by matrix profile (+0.001 CV and private LB)</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550332,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 01:29:51",
          "content": "<p>Awesome job! Congratulations <a href=\"https://www.kaggle.com/chauyh\" target=\"_blank\">@chauyh</a> on solo gold finish.</p>\n<p>I'm curious did you build features and/or post process information from the fact that sometimes the host make fake anglez enmo? For example, you could make a new feature \"has this anglez value at this daily timestep been seen before\" boolean feature. Or you could post process remove predictions from time windows that had fake data?</p>\n<p>I'm curious if there was helpful information here. I think my models naturally removed this stuff.</p>",
          "votes": null,
          "replies": [
            {
              "id": 2550503,
              "author_name": "chauyh",
              "author_url": "",
              "post_date": "12/06/2023 04:49:30",
              "content": "<p>Thanks <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> and congrats on solo gold too!</p>\n<p>My approach is to train a DL model end to end and use as little manual processing /postprocessing as possible. I only applied a box-cox transform to enmo, and used the raw anglez as input to the DL model.</p>\n<p>At the last stages of the competition (~1 week), I found out that postprocessing to calibrate probabilities is quite important. I focused on the missing labels problem but the gains were trivial (+0.0004 CV, compared to approach already with matrix profile pruning).</p>\n<p>I tried very hard to find patterns leading to missing labels but I couldn't find any. The only consistent pattern was repeated data, which is could easily be pruned away with matrix profile. Interestingly, there are some labels in the training set for the repeated data.</p>\n<p>Let me first try some of your postprocessing methods and I'll post a detailed writeup of my methods and findings during the weekend!</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2550313,
      "author_name": "anthonytherrien",
      "author_url": "",
      "post_date": "12/06/2023 01:09:20",
      "content": "<p>I’m impressed to see GRU having such a high score! 🚀</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550437,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 03:15:13",
          "content": "<p>Yes it is impressive how well GRU can do with only input the two features <code>anglez</code> and <code>enmo</code>. Note I did post process the prediction logits for all <code>minute % 15</code> which equaled one of the values that did not occur in the train data. (There were 4 rare values for <code>onset</code> and 4 rare values for <code>wakeup</code>). For these rare logits, I divided their logit prediction by 2 before performing softmax. This boosted CV about approximately <code>+0.010</code> or <code>+0.020</code> (if i remember correctly)</p>\n<p>I also tried adding <code>minute % 15</code> as a feature for the GRU. It boosted the CV score, but it was better to not include this feature and post process. This is probably because the model will overfit when the feature <code>minute % 15</code> is present.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2550323,
      "author_name": "hinepo",
      "author_url": "",
      "post_date": "12/06/2023 01:20:01",
      "content": "<p>Amazing solution as always, Chris. Congrats on one more gold</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2550343,
      "author_name": "fritzcremer",
      "author_url": "",
      "post_date": "12/06/2023 01:41:01",
      "content": "<p>A lot of great ideas! If some of the top ranks on the LB combined their ideas, 0.88 might be possible!</p>",
      "votes": null,
      "replies": [
        {
          "id": 2550349,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 01:48:40",
          "content": "<p>Thanks <a href=\"https://www.kaggle.com/fritzcremer\" target=\"_blank\">@fritzcremer</a> . Congratulations on amazing cash solo gold !!</p>",
          "votes": null,
          "replies": [
            {
              "id": 2551520,
              "author_name": "fritzcremer",
              "author_url": "",
              "post_date": "12/06/2023 18:16:42",
              "content": "<p>Thanks, 3 more to go for Grandmaster 😁 Congrats to your 22nd Gold haha</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2550496,
      "author_name": "nikhilmishradev",
      "author_url": "",
      "post_date": "12/06/2023 04:42:19",
      "content": "<p>What a unique solution. Congratulations <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> on just another brilliant performance. We all learn from you everytime</p>",
      "votes": null,
      "replies": [
        {
          "id": 2552957,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/07/2023 22:35:39",
          "content": "<p>Thanks NikhilMishra. Congratulations to you and penguin46. Great job achieving cash gold !!</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2550628,
      "author_name": "anilreddyvv",
      "author_url": "",
      "post_date": "12/06/2023 06:48:10",
      "content": "<p>There is always something to learn from you <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>. Thanks for the nice writeup. Congratulations on one more gold </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2550695,
      "author_name": "nazarko99",
      "author_url": "",
      "post_date": "12/06/2023 08:16:43",
      "content": "<p>Amazing solution. Can you please share an inference code ?)</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2550761,
      "author_name": "datafan07",
      "author_url": "",
      "post_date": "12/06/2023 08:54:42",
      "content": "<p>Despite not participating in the competition, I learned a lot about it just by reading this.</p>\n<p>Impressive solution as always, congrats Chris.</p>",
      "votes": null,
      "replies": [
        {
          "id": 2551434,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 17:37:51",
          "content": "<p>Thanks Ertugrul </p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2550824,
      "author_name": "fahmiayari",
      "author_url": "",
      "post_date": "12/06/2023 10:01:22",
      "content": "<p>Well done on the solo gold ! <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a> . we missed out on these metric specific tricks which turned out to be a huge deal, will make sure to study the metric more carefully next time. Really appreciate you sharing this!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2550916,
      "author_name": "sayoulala",
      "author_url": "",
      "post_date": "12/06/2023 11:54:44",
      "content": "<p>Hi,Congrats Chris on the gold!  I have a question I would like to ask. Is BertForTokenClassification much worse than BertForQuestionAnswering? Why did you choose BertForQuestionAnswering? I  understand that BertForTokenClassification can also be used for subsequent post-processing processes. </p>",
      "votes": null,
      "replies": [
        {
          "id": 2551630,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/06/2023 20:41:04",
          "content": "<p>Hi <a href=\"https://www.kaggle.com/sayoulala\" target=\"_blank\">@sayoulala</a> I think both methods work well. To me the task seemed like QA so I went QA from the beginning. Below are predictions from each technique. I think we need different post process for NER vs. QA. For my QA pipeline, I could simply find the top30 maxes to be my top30 predictions per night since QA makes peaks on single minute values. With NER, I think we would need to use a different way to find additional predictions.</p>\n<p>For diversity, i also trained NER models and used them to improve the <code>score</code> value for each QA prediction.</p>\n<h1>NLP QA Predictions</h1>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa.png\" alt=\"\"></p>\n<h1>NLP NER Predictions</h1>\n<p><img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/ner.png\" alt=\"\"></p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2551066,
      "author_name": "adithyakolluru",
      "author_url": "",
      "post_date": "12/06/2023 13:42:20",
      "content": "<p>Well Done Chris! Impressive solution.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2551698,
      "author_name": "lizzyshi2003",
      "author_url": "",
      "post_date": "12/06/2023 22:05:38",
      "content": "<p>Fabulous sharing on GPU deep learning. Learnt a lot from u.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2551816,
      "author_name": "samu2505",
      "author_url": "",
      "post_date": "12/07/2023 02:04:37",
      "content": "<p>Do you mind sharing the pseudo code you used to automatically generate features?</p>",
      "votes": null,
      "replies": [
        {
          "id": 2555388,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/09/2023 21:32:46",
          "content": "<p>The RNN, CNN, and Transformer blocks generate features for us. Code is shown <a href=\"https://www.kaggle.com/code/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a>. Then the model heads makes the prediction using features from the proceeding blocks.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 2551940,
      "author_name": "pytorchnuruzzaman",
      "author_url": "",
      "post_date": "12/07/2023 04:38:26",
      "content": "<p>ResNet50 GPU deep learning</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2552021,
      "author_name": "coyamax",
      "author_url": "",
      "post_date": "12/07/2023 06:02:52",
      "content": "<p>The observations on the evaluation metrics are most impressive to me so I will implement such technique in late submissions. Thank you!</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2552201,
      "author_name": "crsuthikshnkumar",
      "author_url": "",
      "post_date": "12/07/2023 09:33:38",
      "content": "<p>Congratulations. Thanks for sharing your solution details. Very interesting approach indeed. </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2553212,
      "author_name": "dongyk",
      "author_url": "",
      "post_date": "12/08/2023 04:54:59",
      "content": "<p>I have no word. It's a great post processing!</p>",
      "votes": null,
      "replies": [
        {
          "id": 2553215,
          "author_name": "dongyk",
          "author_url": "",
          "post_date": "12/08/2023 04:57:52",
          "content": "<p>I have a problem to come up with what the right way to build input data is.<br>\nCould you explain why you selected the input data with both an onset and a wakeup?</p>",
          "votes": null,
          "replies": [
            {
              "id": 2553543,
              "author_name": "cdeotte",
              "author_url": "",
              "post_date": "12/08/2023 10:46:13",
              "content": "<p>This is a powerful technique to achieve top results in object detection and object segmentation Kaggle competitions! </p>\n<p>We want the model to <strong>locate</strong> where <code>onset</code> and <code>wakeup</code> is. So every train sample contains an <code>onset</code> and <code>wakeup</code>. (We cannot learn location if there is no onset wakeup). Therefore our dataloader, provides random 24 hour crops and <strong>every crop contains</strong> both <code>onset</code> and <code>wakeup</code>.</p>\n<p>This model will beat other models and techniques for <strong>locating</strong> <code>onset</code> and <code>wakeup</code>. However this model can not determine existence. This model will think that every day contains an onset and wakeup. So we also need to build a second model (not described in my solution post). The second model job is a classifier that outputs 0 or 1 predicting when a 24 window has an onset and wakeup.</p>\n<p>We train the second model with a different data loader. The data loader for the second model provides <strong>all types of random 24 hour crops</strong>. Some crops have onset wakeup, and some crops do not have onset wakeup. The second model is binary classifier that learns when onset wakeup is present or not.</p>\n<p>Then our inference pipeline uses both models, our first model predicts onset wakeup for <strong>every night, i.e. 24 hours</strong>. And our second model removes false positives. Whenever our second model outputs <code>prob &lt; 0.2</code> for a night (i.e. 24 hour window), then we <strong>remove</strong> the first model prediction from <code>submission.csv</code>.</p>",
              "votes": null,
              "replies": [
                {
                  "id": 2553796,
                  "author_name": "dongyk",
                  "author_url": "",
                  "post_date": "12/08/2023 14:13:15",
                  "content": "<p>That's very logical approach.<br>\nAnd I really appreciate your long and detail answer. I'm so touched. :)</p>",
                  "votes": null,
                  "replies": []
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2554261,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/09/2023 01:22:19",
      "content": "<p><strong>UPDATE</strong> I published the code for these two TensorFlow models <a href=\"https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788\" target=\"_blank\">here</a></p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2554642,
      "author_name": "aidlre001",
      "author_url": "",
      "post_date": "12/09/2023 09:17:28",
      "content": "<p>Excellent work! Really learnt a lot from this. I should have stuck with my keras framework rather than going to learn pytorch. Now I know…</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2554711,
      "author_name": "raihan150146",
      "author_url": "",
      "post_date": "12/09/2023 10:44:28",
      "content": "<p>Thanks for Sharing</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2558156,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/12/2023 00:24:35",
      "content": "<p>For reference, here are the 3 popular ways to create a target in this competition. All three performed well. From all three, we can compute a <code>step</code> and <code>score</code> for <code>submission.csv</code>:<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/targets2.png\" alt=\"\"></p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2558157,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/12/2023 00:30:36",
      "content": "<p>For reference, here are two Mel Spectrograms with 1D prediction and 2D prediction and ground truth:<br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel1.png\" alt=\"\"><br>\n<img src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel2.png\" alt=\"\"></p>",
      "votes": null,
      "replies": [
        {
          "id": 2560579,
          "author_name": "aidlre001",
          "author_url": "",
          "post_date": "12/13/2023 19:41:21",
          "content": "<p>Wanted to perform this data transformation but implementation and computational bottleneck was a problem. Had wanted to use the sleeping and waking data spectrograms as images to a 2D CNN but kept crashing. Was this ever feasible given the constraints of the competition? Still would like to implement it fully and compare.</p>",
          "votes": null,
          "replies": [
            {
              "id": 2560603,
              "author_name": "cdeotte",
              "author_url": "",
              "post_date": "12/13/2023 20:13:27",
              "content": "<p>Yes this was feasible. My final solution used this model to predict a <code>score</code> for each <code>onset</code> and <code>wakeup</code> and I added the <code>score</code> to the <code>score</code> from my Transformer and GRU to improve CV and LB. Also by itself, this model achieved good results.</p>\n<p>An easy way to avoid memory error is to process data in chunks and save intermediate data to disk. We can do this both for train and infer.</p>\n<p>First read Kaggle's train parquet in chunks and we iterate through every user and write each user to disk as a NumPy file. So for each user we have data shape <code>(days, 17280, 4)</code> where <code>days</code> is the number of 24 hour periods (per user), and 17280 is the number of steps in 24 hours. And <code>4</code> is anglez, enmo, and the two targets. (Also we begin each user at 3pm and end at 3pm and add padding to beginning and ending if necessary. That makes all the 24 hour windows the same).</p>\n<p>Next we iterate through each of these NumPys. We load from disk then convert to image. Then save images to disk. The code below creates 2 channel images of size 256x1536 for each day for each user:</p>\n<pre><code>import librosa\nCROP = 17_280; SRR = 17_280; HL = 12; HH = 256\n\n j,u  enumerate(USERS):\n    data = np.nan_to_num( np.load(f) )\n    jj = []\n     r  range(len(data)):\n        ii = []\n        mel_spec = librosa.feature.melspectrogram(=data[r,:,0], =SRR, =2048, =HL, \n              =HH, =0, =SRR//2, =2048//4)\n        mel_spec_db = librosa.power_to_db(mel_spec, =np.max).astype(np.float32)\n        ii.append(mel_spec_db)\n\n        mel_spec = librosa.feature.melspectrogram(=data[r,:,1], =SRR, =2048, =HL, \n              =HH, =0, =SRR//2, =2048//4)\n        mel_spec_db = librosa.power_to_db(mel_spec, =np.max).astype(np.float32)\n        ii.append(mel_spec_db)\n\n        img2 = np.transpose( np.stack(ii), [1,2,0])\n        jj.append(img2)\n\n    jj = np.stack(jj)\n    np.save(f,jj)\n</code></pre>",
              "votes": null,
              "replies": [
                {
                  "id": 2560620,
                  "author_name": "aidlre001",
                  "author_url": "",
                  "post_date": "12/13/2023 20:26:47",
                  "content": "<p>Thank you Chris. Wish I had had this earlier on. Gave up due to memory lags and crashes. I will work with this for future similar competitions. Once more, I really appreciate your hard work and taking the time to explain the secret dark arts of ML and DL in a succinct manner to us lost-in-the-woods folks. </p>",
                  "votes": null,
                  "replies": []
                }
              ]
            },
            {
              "id": 2560605,
              "author_name": "cdeotte",
              "author_url": "",
              "post_date": "12/13/2023 20:14:39",
              "content": "<p>Also note that the highest scoring public notebook uses Mel Spectrograms (created by PyTorch) and provides code on GitHub. Discussion <a href=\"https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/452940\" target=\"_blank\">here</a></p>",
              "votes": null,
              "replies": [
                {
                  "id": 2560622,
                  "author_name": "aidlre001",
                  "author_url": "",
                  "post_date": "12/13/2023 20:29:07",
                  "content": "<p>Ok Chris. Will check it out. I wonder if I doing this on TPUs would make that much difference in training and inference speed? Its the scoring time that gives me ulcers.</p>",
                  "votes": null,
                  "replies": [
                    {
                      "id": 2560626,
                      "author_name": "aidlre001",
                      "author_url": "",
                      "post_date": "12/13/2023 20:32:44",
                      "content": "<p>Oh I see. The librosa library makes it easier. Was trying to do it from scratch but never got a spectrogram plot good enough as yours. Must be some bug in my code.</p>",
                      "votes": null,
                      "replies": []
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "id": 2559343,
      "author_name": "miraclejy",
      "author_url": "",
      "post_date": "12/12/2023 18:48:35",
      "content": "<p>Congratulations! Such an excellent work. As a beginner I have really learned a lot from your solution. I am still a little bit confused about two details of your approach. </p>\n<p>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440. So I'm wondering whether you are using the mean of 12 steps as one data point as input. May I also asked about the 80 features you used?</p>\n<p>And the second one is about  labels. It is a great idea to seperate \"onset\" and \"awake\" as two different labels and I noticed that some competitors applied a gaussian window around the event step.  So did you use the same solution or just use original \"0\" and \"1\" labels?</p>\n<p>Thank you so much if you can reply to my comment.</p>",
      "votes": null,
      "replies": [
        {
          "id": 2559395,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/12/2023 19:32:07",
          "content": "<p>Thank you</p>\n<blockquote>\n  <p>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440</p>\n</blockquote>\n<p>My <code>CNN-Transformer-GRU</code> uses an input of 1440. The data loader output just skips every 12th using the following Python indexing <code>X_train[:,::12,:]</code>.</p>\n<blockquote>\n  <p>May I also asked about the 80 features you used?</p>\n</blockquote>\n<p>I used the 79 features from this popular LGBM notebook <a href=\"https://www.kaggle.com/code/renatoreggiani/lightgbm-starter-cmi\" target=\"_blank\">here</a>. And I added the additional feature <code>minute%15</code> to learn the weird labeler bias. (I also built my own CatBoost with my own 200 features and my CatBoost scored LB 0.705 but my Transformer used those public notebook features). </p>\n<blockquote>\n  <p>So did you use the same solution or just use original \"0\" and \"1\" labels?</p>\n</blockquote>\n<p>I used the original \"0\" and \"1\". Each of my two models here has output sequence length 1440 which is the number of minutes per day. The target for each day crop were 1439 zeros with 1 one where the actual target is. My loss is softmax multi-class crossentropy, so the model had no trouble learning the unique target \"1\" out of \"1440\" different classes. (I.e. the multiclass is the 1440 different minutes each day and the model finds the correct minute each day)</p>",
          "votes": null,
          "replies": [
            {
              "id": 2559403,
              "author_name": "miraclejy",
              "author_url": "",
              "post_date": "12/12/2023 19:42:58",
              "content": "<p>Got it. Thank you so much!</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2559919,
      "author_name": "huoyeqianxun",
      "author_url": "",
      "post_date": "12/13/2023 06:29:30",
      "content": "<p>Congratulations! Always can  learn a lot from your work. Especially the Deep GRU model that only use 2 original features. Really impressive!</p>\n<p>I'm trying to train your Deep GRU model, but I got gradient vanishing problem. I use exactly your 'build_model_2()' code, but If I call the \"build_model_2()\" function 5 times, maybe got gradient vanishing for 3 or 4 times.<br>\nI guess I must miss something somewhere, such as some special initializer? or some kind of random seed setting? Or other stuffs.<br>\nSo, will you public all your code? Then I can check where I'm going wrong. </p>\n<p>Again, thanks a lot for the sharing of your excellent work!</p>",
      "votes": null,
      "replies": [
        {
          "id": 2561855,
          "author_name": "cdeotte",
          "author_url": "",
          "post_date": "12/14/2023 22:02:57",
          "content": "<p>Do you mean that you get gradient vanishing during training? If so, does your data loader output the correct train data? Every train sample must have <code>X_train</code> with shape <code>(batch, 17280, 2)</code> where the 2 features are anglez and enmo standardized (i.e minus mean divide by std using the mean and std of the entire train data). And the target is list of length two <code>[y_train_1, y_train_2]</code> where each are shape <code>(batch, 1440)</code> and each have exactly 1439 zeros and 1 one? (i.e. there is exactly 1 target in every sample. We do not use 24 hour windows that are missing target).</p>",
          "votes": null,
          "replies": [
            {
              "id": 2562037,
              "author_name": "huoyeqianxun",
              "author_url": "",
              "post_date": "12/15/2023 03:56:08",
              "content": "<p>Thanks for your reply.<br>\nYes, I get gradient vanishing when I train the Deep-GRU model.<br>\nI checked many times, it seems my data loader satisfies all the demands that you described.  But gradient vanishing still happens from time to time.<br>\nToday, I set global seed using \"tf.random.set_seed()\", and set  the operation seeds of initializers for the Conv1d, GRU, Dense layers in the model. so that the initial weights in the model will be the same every time the model is built.<br>\nLuckily, it works. Gradient vanishing won't happen.<br>\nMaybe there is still something wrong in my data loader, so that  it demand some special initial weights in the model.<br>\nAnyway, I can avoid gradient vanishing for now. Hope the unknown bug doesn't affect the training result.<br>\n😅😅😅</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2560778,
      "author_name": "shangweichen",
      "author_url": "",
      "post_date": "12/14/2023 02:00:58",
      "content": "<p>Congratulations! Very interesting approach indeed </p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 2568995,
      "author_name": "valbercesar1",
      "author_url": "",
      "post_date": "12/21/2023 02:43:34",
      "content": "<p>Really interesting approach. Your solution was like a Random Forrest, implemented each ML-Code separatelly, instead decision trees.. Haha! <br>\nI'm completing this challenge (late submission), but in another way! Congrats bro!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2550266": "What a fun competition! I enjoyed this competition! Thank you Kaggle and host.\n\n# Building Blocks of GPU Deep Learning!\nBelow are 3 building blocks of deep learning. By creating different sequences of these building blocks, we can build powerful models! Each block takes an input shape of `(batch_size, sequence_length, features)` and outputs the same. The RNN \"block\" uses **bidirectional** (example code [here][6]). The CNN \"block\" uses sums and products of multiple **dilated convolutions** (from WaveNet paper [here][5] and example code [here][6]). And the Transformer blocks uses **self attention** (example code [here][6]). These 3 \"blocks\" can create features from signals without needing feature engineering!\n\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/blocks.png)\n\n# Data Loader - Cut Data into Daily Chunks\nOur data loader will randomly give us 24 hour windows that **always contain both one onset and one wakeup**. During each epoch, we will get different cuts. This serves as crop data augmentation.\n ![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/dataloader.png)\n\n# Model Head is NLP QA Softmax (not NLP NER)\nFor the head of our model, we use an architecture that is **not** in any public discussion **nor** public notebook. We use a technique from NLP called QuestionAnswering (i.e. `BertForQuestionAnswering`). This is analogous to Computer Vision's `object detection`. All public discussions and notebooks use NLP NER (i.e. `BertForTokenClassification`) which is analogous to Computer Vision `segmentation`. \n\nThe way to implement QA is for our data loader to always include one onset and one wakeup in every train sequence. Then we apply 1440 multiclass softmax loss to pick the correct minute of target. Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa-head2.png)\n\n# My CNN-Transformer-GRU, 80 features\n**Approximately CV 0.800 LB 0.750**\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model2b.png)\n\n# My Deep-GRU, 2 features\n**Approximately CV 0.805 LB 0.755**\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/model1c.png)\n\n# Extra Predictions Trick\n**Approximately CV +0.050 LB 0.050 Wow!**\nA huge trick in this competition is to make multiple onset and wakeup predictions per night. First we make a first choice for every user every night. With 200 test users and approximately 30 nights per user and 2 targets, this is about 12000 predictions. Next we make a second guess (i.e. the second max probability) for each night and divide it by `2^1`. This is 12000 more guesses. Next we made a 3rd guess (i.e. 3rd max prob) and divide it by `2^2`. We continue this for 30 guesses per night where the last guesses are divided by `2^29`. This boost CV by about +0.050 wow 😀! \n\nThis works because Average Precision metric is **always improved** when adding more predictions if the new predictions have a lower score than all previous predictions. (More explanation [here][1])\n\n# Rerank Scores\n**Approximately CV +0.020 LB 0.020**\nFor the metric Average Precision, the score we assign to each prediction is very important. First we use the probability from our above models as the starting score. Next we use CatBoost with handmade convolution features (**CatBoost achieves LB 0.705** by itself wow!), 1D-Unet, 2D-Unet, Mel Spectrograms, ResNet34, EfficientNetB5, and Audio WaveNet to rerank the scores. This is accomplished by predicting a new score for each prediction and then averaging all the scores.\n\n# Ensemble with NMS and WBF\n**Approximately CV +0.010 LB 0.010**\nMy CNN-Transformer-GRU and  Deep-GRU are very diverse. First I apply NMS (non maximum supression) to each model individually. Whenever two predictions are within 5 minutes of each other, we keep only the prediction which largest probability. Afterward we ensemble the two single models with WBF (weighted box fusion). Whenever two predictions are within 5 minutes of each other (and are the same level 1 thru 30 explained above in \"extra scores trick\"), then we replace the two with the average step position.\n\n# Solution Code\nI published the code for these two TensorFlow models [here][6]\n\n[1]: https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637\n[2]: https://www.kaggle.com/code/ragnar123/wavenet-with-1-more-feature\n[3]: https://www.kaggle.com/code/cdeotte/tensorflow-transformer-0-112\n[4]: https://www.tensorflow.org/text/tutorials/transformer\n[5]: https://arxiv.org/abs/1609.03499\n[6]: https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788",
    "2550270": "Learning from you yet again, a pleasure to watch you work. Congrats Chris!",
    "2550274": "Great solution as always Chris. Very well done!! You were in the top for a very long time and I was like, okay Chris is for sure doing something with the post-processing again 😅 \n\nAnd I was wondering which features did you generate for `80 features` part?",
    "2550276": "Congratulations with one more solo gold. Was rooting for you all the time and so sad you got hit by shakeup.\n\nWas a fun ride. \nReally enjoyed the competition.\n\nRuby K_mat and you always pushed us to try harder.\n\nOur solution is 100% result of the Francisco (Fnoa) hard work and he will write a review (my lgmb single model is 0.757 public / 0.82 private)",
    "2550278": "Wow that's an amazing LGBM model. I'm looking forward to your writeup.\n\nI was always watching your team and trying to stay ahead of you haha 😀 . You pushed me to work harder 😀 We were tied with same public LB score on many days. Congratulations building a strong generalizing model and jumping upward on private LB!",
    "2550284": "https://www.kaggle.com/kyakovlev/cmi-baseline-lgbm-v201\nlgbm - I'll clean private dataset and publish run with train also",
    "2550285": "Thanks Sinan. The Average Precision metric has lots of way to exploit. The main ones are \"making more predictions which have a lower score than every other previous prediction\" will always increase the Average Precision metric. You can read about is [here][1] That is the idea behind the 30 levels of predictions each night where each new set gets divided by 2. The second way to exploit AP is to rerank/modify the scores. We want all false positives to have lower score than true positives for boost in metric.\n\nAnother PP trick that I used (and did not write about above) was to add or subtract 1 to any prediction which was exactly a multiple of 12. This gave a nice boost. (Because of the metric, we do not want to predict perfect multiples of 12). \n\n[1]: https://www.kaggle.com/competitions/vinbigdata-chest-xray-abnormalities-detection/discussion/229637",
    "2550292": "Thank you so much Chris. These are all great gems to have in the arsenal. Will keep coming to this post probably multiple times again in the future!",
    "2550300": "Congratulations once again @cdeotte! It was a fun battle for days 😀",
    "2550302": "Absolutely was fun! I knew your team was working hard every day and that encouraged me to work hard every day!\n\nCongratulations on an awesome 3rd place cash gold finish!",
    "2550311": "Congrats Chris on the gold!\n\nAnd thanks for the clearly written writeup. Your solution is so sophisticated, yet easy to understand 🙂\n\nI found this idea very clever:\n\n\"Later we will use a separately trained classification model to remove false positives (since our QA model was trained on 100% positives and doesn't locate negatives well).\"\n\nI have one question:\n\nYou are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?",
    "2550312": "Interesting solution! My solution is quite similar to yours - I used a window of 2 days and a custom defined self attention module instead of the usual transformer block. \n\nI didn't do extra postprocessing for the scores, I guess reranking with GB methods was what I needed for better calibrated probabilities.\n\nThe postprocessing I did is to align the predictions to the nearest .25 or .75 second, augmenting the predictions by +-1 second (+0.005 CV), and removing repeated signals by matrix profile (+0.001 CV and private LB)",
    "2550313": "I’m impressed to see GRU having such a high score! 🚀",
    "2550317": ">You are dividing the second best prediction's probability by 2^2, the third best predictions's by 2^3, etc. How did you realise that this is the right way to 'adjust' the probabilities?\n\nThe first thing to realize is that we cannot start making second predictions for one night before we make first predictions for every user every night. (Because when we make second predictions then **certainly** either the first or second prediction will be a false positive and hurt metric). The Average Precision metric will rank every user every night **all together** and we want all false positives to have a lower score than true positives to optimize Average Precision. So the majority of our second predictions need to have a lower score than the majority of our first predictions.\n\nThe exact division value is a hyperparameter that I determined from CV. First I used 10 because we want the second set of predictions to be \"an order of magnitude\" lower than the first set of predictions. The hyperparameter was `exponent` in `DIVIDE_CONSTANT = 10**exponent`. It turned out that `exponent = 1/5` was best which makes `DIVIDE CONSTANT` approximately 2.",
    "2550323": "Amazing solution as always, Chris. Congrats on one more gold",
    "2550332": "Awesome job! Congratulations @chauyh on solo gold finish.\n\nI'm curious did you build features and/or post process information from the fact that sometimes the host make fake anglez enmo? For example, you could make a new feature \"has this anglez value at this daily timestep been seen before\" boolean feature. Or you could post process remove predictions from time windows that had fake data?\n\nI'm curious if there was helpful information here. I think my models naturally removed this stuff.",
    "2550343": "A lot of great ideas! If some of the top ranks on the LB combined their ideas, 0.88 might be possible!",
    "2550349": "Thanks @fritzcremer . Congratulations on amazing cash solo gold !!",
    "2550437": "Yes it is impressive how well GRU can do with only input the two features `anglez` and `enmo`. Note I did post process the prediction logits for all `minute % 15` which equaled one of the values that did not occur in the train data. (There were 4 rare values for `onset` and 4 rare values for `wakeup`). For these rare logits, I divided their logit prediction by 2 before performing softmax. This boosted CV about approximately `+0.010` or `+0.020` (if i remember correctly)\n\nI also tried adding `minute % 15` as a feature for the GRU. It boosted the CV score, but it was better to not include this feature and post process. This is probably because the model will overfit when the feature `minute % 15` is present.",
    "2550496": "What a unique solution. Congratulations @cdeotte on just another brilliant performance. We all learn from you everytime",
    "2550503": "Thanks @cdeotte and congrats on solo gold too!\n\nMy approach is to train a DL model end to end and use as little manual processing /postprocessing as possible. I only applied a box-cox transform to enmo, and used the raw anglez as input to the DL model.\n\nAt the last stages of the competition (~1 week), I found out that postprocessing to calibrate probabilities is quite important. I focused on the missing labels problem but the gains were trivial (+0.0004 CV, compared to approach already with matrix profile pruning).\n\nI tried very hard to find patterns leading to missing labels but I couldn't find any. The only consistent pattern was repeated data, which is could easily be pruned away with matrix profile. Interestingly, there are some labels in the training set for the repeated data.\n\nLet me first try some of your postprocessing methods and I'll post a detailed writeup of my methods and findings during the weekend!",
    "2550628": "There is always something to learn from you @cdeotte. Thanks for the nice writeup. Congratulations on one more gold",
    "2550695": "Amazing solution. Can you please share an inference code ?)",
    "2550761": "Despite not participating in the competition, I learned a lot about it just by reading this.\n\nImpressive solution as always, congrats Chris.",
    "2550824": "Well done on the solo gold ! @cdeotte . we missed out on these metric specific tricks which turned out to be a huge deal, will make sure to study the metric more carefully next time. Really appreciate you sharing this!",
    "2550916": "Hi,Congrats Chris on the gold!  I have a question I would like to ask. Is BertForTokenClassification much worse than BertForQuestionAnswering? Why did you choose BertForQuestionAnswering? I  understand that BertForTokenClassification can also be used for subsequent post-processing processes.",
    "2551066": "Well Done Chris! Impressive solution.",
    "2551434": "Thanks Ertugrul",
    "2551520": "Thanks, 3 more to go for Grandmaster 😁 Congrats to your 22nd Gold haha",
    "2551630": "Hi @sayoulala I think both methods work well. To me the task seemed like QA so I went QA from the beginning. Below are predictions from each technique. I think we need different post process for NER vs. QA. For my QA pipeline, I could simply find the top30 maxes to be my top30 predictions per night since QA makes peaks on single minute values. With NER, I think we would need to use a different way to find additional predictions.\n\nFor diversity, i also trained NER models and used them to improve the `score` value for each QA prediction.\n\n# NLP QA Predictions\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/qa.png)\n\n#NLP NER Predictions\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/ner.png)",
    "2551698": "Fabulous sharing on GPU deep learning. Learnt a lot from u.",
    "2551816": "Do you mind sharing the pseudo code you used to automatically generate features?",
    "2551940": "ResNet50 GPU deep learning",
    "2552021": "The observations on the evaluation metrics are most impressive to me so I will implement such technique in late submissions. Thank you!",
    "2552201": "Congratulations. Thanks for sharing your solution details. Very interesting approach indeed.",
    "2552957": "Thanks NikhilMishra. Congratulations to you and penguin46. Great job achieving cash gold !!",
    "2553212": "I have no word. It's a great post processing!",
    "2553215": "I have a problem to come up with what the right way to build input data is.\nCould you explain why you selected the input data with both an onset and a wakeup?",
    "2553543": "This is a powerful technique to achieve top results in object detection and object segmentation Kaggle competitions! \n\nWe want the model to **locate** where `onset` and `wakeup` is. So every train sample contains an `onset` and `wakeup`. (We cannot learn location if there is no onset wakeup). Therefore our dataloader, provides random 24 hour crops and **every crop contains** both `onset` and `wakeup`.\n\nThis model will beat other models and techniques for **locating** `onset` and `wakeup`. However this model can not determine existence. This model will think that every day contains an onset and wakeup. So we also need to build a second model (not described in my solution post). The second model job is a classifier that outputs 0 or 1 predicting when a 24 window has an onset and wakeup.\n\nWe train the second model with a different data loader. The data loader for the second model provides **all types of random 24 hour crops**. Some crops have onset wakeup, and some crops do not have onset wakeup. The second model is binary classifier that learns when onset wakeup is present or not.\n\nThen our inference pipeline uses both models, our first model predicts onset wakeup for **every night, i.e. 24 hours**. And our second model removes false positives. Whenever our second model outputs `prob < 0.2` for a night (i.e. 24 hour window), then we **remove** the first model prediction from `submission.csv`.",
    "2553796": "That's very logical approach.\nAnd I really appreciate your long and detail answer. I'm so touched. :)",
    "2554261": "**UPDATE** I published the code for these two TensorFlow models [here][1]\n\n[1]: https://www.kaggle.com/cdeotte/11th-place-gold-cv-835-public-lb-788",
    "2554642": "Excellent work! Really learnt a lot from this. I should have stuck with my keras framework rather than going to learn pytorch. Now I know...",
    "2554711": "Thanks for Sharing",
    "2555388": "The RNN, CNN, and Transformer blocks generate features for us. Code is shown [here][1]. Then the model heads makes the prediction using features from the proceeding blocks.\n\n[1]: https://www.kaggle.com/code/cdeotte/11th-place-gold-cv-835-public-lb-788",
    "2558156": "For reference, here are the 3 popular ways to create a target in this competition. All three performed well. From all three, we can compute a `step` and `score` for `submission.csv`:\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/targets2.png)",
    "2558157": "For reference, here are two Mel Spectrograms with 1D prediction and 2D prediction and ground truth:\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel1.png)\n![](https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Dec-2023/mel2.png)",
    "2559343": "Congratulations! Such an excellent work. As a beginner I have really learned a lot from your solution. I am still a little bit confused about two details of your approach. \n\nOne is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440. So I'm wondering whether you are using the mean of 12 steps as one data point as input. May I also asked about the 80 features you used?\n\nAnd the second one is about  labels. It is a great idea to seperate \"onset\" and \"awake\" as two different labels and I noticed that some competitors applied a gaussian window around the event step.  So did you use the same solution or just use original \"0\" and \"1\" labels?\n\nThank you so much if you can reply to my comment.",
    "2559395": "Thank you\n\n>One is that you set crops for 24 hours which is 17280 steps but your input for Transformer Model is 1440\n\nMy `CNN-Transformer-GRU` uses an input of 1440. The data loader output just skips every 12th using the following Python indexing `X_train[:,::12,:]`.\n\n>May I also asked about the 80 features you used?\n\nI used the 79 features from this popular LGBM notebook [here][1]. And I added the additional feature `minute%15` to learn the weird labeler bias. (I also built my own CatBoost with my own 200 features and my CatBoost scored LB 0.705 but my Transformer used those public notebook features). \n\n>So did you use the same solution or just use original \"0\" and \"1\" labels?\n\nI used the original \"0\" and \"1\". Each of my two models here has output sequence length 1440 which is the number of minutes per day. The target for each day crop were 1439 zeros with 1 one where the actual target is. My loss is softmax multi-class crossentropy, so the model had no trouble learning the unique target \"1\" out of \"1440\" different classes. (I.e. the multiclass is the 1440 different minutes each day and the model finds the correct minute each day)\n\n[1]: https://www.kaggle.com/code/renatoreggiani/lightgbm-starter-cmi",
    "2559403": "Got it. Thank you so much!",
    "2559919": "Congratulations! Always can  learn a lot from your work. Especially the Deep GRU model that only use 2 original features. Really impressive!\n\nI'm trying to train your Deep GRU model, but I got gradient vanishing problem. I use exactly your 'build_model_2()' code, but If I call the \"build_model_2()\" function 5 times, maybe got gradient vanishing for 3 or 4 times.\nI guess I must miss something somewhere, such as some special initializer? or some kind of random seed setting? Or other stuffs.\nSo, will you public all your code? Then I can check where I'm going wrong. \n\nAgain, thanks a lot for the sharing of your excellent work!",
    "2560579": "Wanted to perform this data transformation but implementation and computational bottleneck was a problem. Had wanted to use the sleeping and waking data spectrograms as images to a 2D CNN but kept crashing. Was this ever feasible given the constraints of the competition? Still would like to implement it fully and compare.",
    "2560603": "Yes this was feasible. My final solution used this model to predict a `score` for each `onset` and `wakeup` and I added the `score` to the `score` from my Transformer and GRU to improve CV and LB. Also by itself, this model achieved good results.\n\nAn easy way to avoid memory error is to process data in chunks and save intermediate data to disk. We can do this both for train and infer.\n\nFirst read Kaggle's train parquet in chunks and we iterate through every user and write each user to disk as a NumPy file. So for each user we have data shape `(days, 17280, 4)` where `days` is the number of 24 hour periods (per user), and 17280 is the number of steps in 24 hours. And `4` is anglez, enmo, and the two targets. (Also we begin each user at 3pm and end at 3pm and add padding to beginning and ending if necessary. That makes all the 24 hour windows the same).\n\nNext we iterate through each of these NumPys. We load from disk then convert to image. Then save images to disk. The code below creates 2 channel images of size 256x1536 for each day for each user:\n\n    import librosa\n    CROP = 17_280; SRR = 17_280; HL = 12; HH = 256\n\n    for j,u in enumerate(USERS):\n        data = np.nan_to_num( np.load(f'numpys/{u}.npy') )\n        jj = []\n        for r in range(len(data)):\n            ii = []\n            mel_spec = librosa.feature.melspectrogram(y=data[r,:,0], sr=SRR, n_fft=2048, hop_length=HL, \n                  n_mels=HH, fmin=0, fmax=SRR//2, win_length=2048//4)\n            mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max).astype(np.float32)\n            ii.append(mel_spec_db)\n        \n            mel_spec = librosa.feature.melspectrogram(y=data[r,:,1], sr=SRR, n_fft=2048, hop_length=HL, \n                  n_mels=HH, fmin=0, fmax=SRR//2, win_length=2048//4)\n            mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max).astype(np.float32)\n            ii.append(mel_spec_db)\n        \n            img2 = np.transpose( np.stack(ii), [1,2,0])\n            jj.append(img2)\n        \n        jj = np.stack(jj)\n        np.save(f'images/{u}.npy',jj)",
    "2560605": "Also note that the highest scoring public notebook uses Mel Spectrograms (created by PyTorch) and provides code on GitHub. Discussion [here][1]\n\n[1]: https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/452940",
    "2560620": "Thank you Chris. Wish I had had this earlier on. Gave up due to memory lags and crashes. I will work with this for future similar competitions. Once more, I really appreciate your hard work and taking the time to explain the secret dark arts of ML and DL in a succinct manner to us lost-in-the-woods folks.",
    "2560622": "Ok Chris. Will check it out. I wonder if I doing this on TPUs would make that much difference in training and inference speed? Its the scoring time that gives me ulcers.",
    "2560626": "Oh I see. The librosa library makes it easier. Was trying to do it from scratch but never got a spectrogram plot good enough as yours. Must be some bug in my code.",
    "2560778": "Congratulations! Very interesting approach indeed",
    "2561855": "Do you mean that you get gradient vanishing during training? If so, does your data loader output the correct train data? Every train sample must have `X_train` with shape `(batch, 17280, 2)` where the 2 features are anglez and enmo standardized (i.e minus mean divide by std using the mean and std of the entire train data). And the target is list of length two `[y_train_1, y_train_2]` where each are shape `(batch, 1440)` and each have exactly 1439 zeros and 1 one? (i.e. there is exactly 1 target in every sample. We do not use 24 hour windows that are missing target).",
    "2562037": "Thanks for your reply.\nYes, I get gradient vanishing when I train the Deep-GRU model.\nI checked many times, it seems my data loader satisfies all the demands that you described.  But gradient vanishing still happens from time to time.\nToday, I set global seed using \"tf.random.set_seed()\", and set  the operation seeds of initializers for the Conv1d, GRU, Dense layers in the model. so that the initial weights in the model will be the same every time the model is built.\nLuckily, it works. Gradient vanishing won't happen.\nMaybe there is still something wrong in my data loader, so that  it demand some special initial weights in the model.\nAnyway, I can avoid gradient vanishing for now. Hope the unknown bug doesn't affect the training result.\n😅😅😅",
    "2568995": "Really interesting approach. Your solution was like a Random Forrest, implemented each ML-Code separatelly, instead decision trees.. Haha! \nI'm completing this challenge (late submission), but in another way! Congrats bro!"
  },
  "source": "meta"
}