{
  "id": 154664,
  "title": "4th Place Neural Network Solution",
  "content": "<p>I think the models we build are too late for being useful in this pandemic. They can hopefully (but not hopefully) be used in another pandemic. Therefore I wanted to have a re-usable Machine Learning solution. So far, it performs okay but it is early to talk about it. Anyway, I wanted to explain it before I forget the details. I have 2 notebooks, one for training and one for inference:\n<a href=\"https://www.kaggle.com/aerdem4/covid-19-w5-training\">https://www.kaggle.com/aerdem4/covid-19-w5-training</a>\n<a href=\"https://www.kaggle.com/aerdem4/covid-19-w5-pipeline\">https://www.kaggle.com/aerdem4/covid-19-w5-pipeline</a></p>\n\n<p>It is CNN Model trained on last 2 weeks of data. In last covid-19 competitions, my NN had diverged by time. I have learned from my mistakes and didn't want to do recursive predictions for this one. I have trained different model for each n day ahead. Here is the model architecture:</p>\n\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F471945%2Fa274824b8ac4631b021d4bcbbcc7aac2%2Fmodel.PNG?generation=1590745456988152&amp;alt=media\" alt=\"\"></p>\n\n<p>Some tricks that worked:\n- Cumulative sum over relu as the last layer guarantees that I have non-zero predictions and quantiles are always in order.\n- Training directly with pinball loss. In initial epochs, I have trained for 0.15, 0.50 and 0.85 quantiles. Then late epochs are trained with actual quantiles (0.05, 0.50, 0.95). Without this, model starts being cautious very early and gets stuck in a local minimum.\n- Bagging 5 NN models for each day to reduce randomness\n- Smoothing predictions for each day n: <code>y(n) = 0.2*y(n-1) + 0.6*y(n) + 0.2*y(n+1)</code>\n- Rounding predictions to integers. This probably helps a little with zero cases.</p>",
  "comments": [
    {
      "id": 866767,
      "author_name": "Chris Deotte",
      "author_url": "",
      "post_date": "2020-05-29T16:52:08.873000",
      "content": "<p>Great CNN solution Ahmet !</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 866503,
      "author_name": "CPMP",
      "author_url": "",
      "post_date": "2020-05-29T13:07:49.027000",
      "content": "<p>Nice, your model looks a bit like wavenet actually.  I agree that recursive prediction is very brittle, and removing it was probably a good idea.</p>\n\n<p>I don't understand what you do for quantile predictions.  Can you explain a bit more?</p>",
      "votes": 1,
      "replies": [
        {
          "id": 866514,
          "author_name": "Ahmet Erdem",
          "author_url": "",
          "post_date": "2020-05-29T13:17:20.353000",
          "content": "<p><code>\ndef get_custom_loss(q):\n    def custom_loss(y_true, y_pred):\n        return pinball_loss(y_true, y_pred, q)\n    return custom_loss\n</code></p>\n\n<p><code>\nfor loss, lr, epoch in [(get_custom_loss([0.15, 0.50, 0.85]), 0.0001, epochs[0]), (get_custom_loss([0.05, 0.50, 0.95]), 0.00005, epochs[1])]:\n            model.compile(loss=loss, optimizer=SWA(Nadam(lr=lr), average_period=2))\n            model.fit(X_hist_train, get_output(train_df), sample_weight=get_weight(train_df),\n                      shuffle=True, batch_size=128, epochs=epoch, verbose=0)\n</code></p>\n\n<p>Competition metric is pinball loss with [0.05, 0.50, 0.95]. Instead of directly optimizing for that, I first optimized for a narrower uncertainty ([0.15, 0.50, 0.85]) to avoid a very cautious local minimum.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1671892,
      "author_name": "Alex Horner",
      "author_url": "",
      "post_date": "2022-02-01T19:14:39.810000",
      "content": "<p>thank you for this. I'm surprised at how simple each layer of a prize-winning level network is. i wouldn't have guessed so a priori</p>",
      "votes": 0,
      "replies": []
    }
  ],
  "comment_count": 4,
  "messages": [
    {
      "id": 866328,
      "postDate": "2020-05-29T09:50:06.817Z",
      "content": "<p>I think the models we build are too late for being useful in this pandemic. They can hopefully (but not hopefully) be used in another pandemic. Therefore I wanted to have a re-usable Machine Learning solution. So far, it performs okay but it is early to talk about it. Anyway, I wanted to explain it before I forget the details. I have 2 notebooks, one for training and one for inference:\n<a href=\"https://www.kaggle.com/aerdem4/covid-19-w5-training\">https://www.kaggle.com/aerdem4/covid-19-w5-training</a>\n<a href=\"https://www.kaggle.com/aerdem4/covid-19-w5-pipeline\">https://www.kaggle.com/aerdem4/covid-19-w5-pipeline</a></p>\n\n<p>It is CNN Model trained on last 2 weeks of data. In last covid-19 competitions, my NN had diverged by time. I have learned from my mistakes and didn't want to do recursive predictions for this one. I have trained different model for each n day ahead. Here is the model architecture:</p>\n\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F471945%2Fa274824b8ac4631b021d4bcbbcc7aac2%2Fmodel.PNG?generation=1590745456988152&amp;alt=media\" alt=\"\"></p>\n\n<p>Some tricks that worked:\n- Cumulative sum over relu as the last layer guarantees that I have non-zero predictions and quantiles are always in order.\n- Training directly with pinball loss. In initial epochs, I have trained for 0.15, 0.50 and 0.85 quantiles. Then late epochs are trained with actual quantiles (0.05, 0.50, 0.95). Without this, model starts being cautious very early and gets stuck in a local minimum.\n- Bagging 5 NN models for each day to reduce randomness\n- Smoothing predictions for each day n: <code>y(n) = 0.2*y(n-1) + 0.6*y(n) + 0.2*y(n+1)</code>\n- Rounding predictions to integers. This probably helps a little with zero cases.</p>",
      "rawMarkdown": "I think the models we build are too late for being useful in this pandemic. They can hopefully (but not hopefully) be used in another pandemic. Therefore I wanted to have a re-usable Machine Learning solution. So far, it performs okay but it is early to talk about it. Anyway, I wanted to explain it before I forget the details. I have 2 notebooks, one for training and one for inference:\nhttps://www.kaggle.com/aerdem4/covid-19-w5-training\nhttps://www.kaggle.com/aerdem4/covid-19-w5-pipeline\n\nIt is CNN Model trained on last 2 weeks of data. In last covid-19 competitions, my NN had diverged by time. I have learned from my mistakes and didn't want to do recursive predictions for this one. I have trained different model for each n day ahead. Here is the model architecture:\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F471945%2Fa274824b8ac4631b021d4bcbbcc7aac2%2Fmodel.PNG?generation=1590745456988152&amp;alt=media)\n\nSome tricks that worked:\n- Cumulative sum over relu as the last layer guarantees that I have non-zero predictions and quantiles are always in order.\n- Training directly with pinball loss. In initial epochs, I have trained for 0.15, 0.50 and 0.85 quantiles. Then late epochs are trained with actual quantiles (0.05, 0.50, 0.95). Without this, model starts being cautious very early and gets stuck in a local minimum.\n- Bagging 5 NN models for each day to reduce randomness\n- Smoothing predictions for each day n: `y(n) = 0.2*y(n-1) + 0.6*y(n) + 0.2*y(n+1)`\n- Rounding predictions to integers. This probably helps a little with zero cases.",
      "votes": 18
    },
    {
      "id": 866767,
      "postDate": "2020-05-29T16:52:08.873Z",
      "content": "<p>Great CNN solution Ahmet !</p>",
      "rawMarkdown": "Great CNN solution Ahmet !",
      "votes": 1
    },
    {
      "id": 866503,
      "postDate": "2020-05-29T13:07:49.027Z",
      "content": "<p>Nice, your model looks a bit like wavenet actually.  I agree that recursive prediction is very brittle, and removing it was probably a good idea.</p>\n\n<p>I don't understand what you do for quantile predictions.  Can you explain a bit more?</p>",
      "rawMarkdown": "Nice, your model looks a bit like wavenet actually.  I agree that recursive prediction is very brittle, and removing it was probably a good idea.\n\nI don't understand what you do for quantile predictions.  Can you explain a bit more?\n",
      "votes": 1,
      "replies": [
        {
          "id": 866514,
          "postDate": "2020-05-29T13:17:20.353Z",
          "content": "<p><code>\ndef get_custom_loss(q):\n    def custom_loss(y_true, y_pred):\n        return pinball_loss(y_true, y_pred, q)\n    return custom_loss\n</code></p>\n\n<p><code>\nfor loss, lr, epoch in [(get_custom_loss([0.15, 0.50, 0.85]), 0.0001, epochs[0]), (get_custom_loss([0.05, 0.50, 0.95]), 0.00005, epochs[1])]:\n            model.compile(loss=loss, optimizer=SWA(Nadam(lr=lr), average_period=2))\n            model.fit(X_hist_train, get_output(train_df), sample_weight=get_weight(train_df),\n                      shuffle=True, batch_size=128, epochs=epoch, verbose=0)\n</code></p>\n\n<p>Competition metric is pinball loss with [0.05, 0.50, 0.95]. Instead of directly optimizing for that, I first optimized for a narrower uncertainty ([0.15, 0.50, 0.85]) to avoid a very cautious local minimum.</p>",
          "rawMarkdown": "```\ndef get_custom_loss(q):\n    def custom_loss(y_true, y_pred):\n        return pinball_loss(y_true, y_pred, q)\n    return custom_loss\n```\n\n\n```\nfor loss, lr, epoch in [(get_custom_loss([0.15, 0.50, 0.85]), 0.0001, epochs[0]), (get_custom_loss([0.05, 0.50, 0.95]), 0.00005, epochs[1])]:\n            model.compile(loss=loss, optimizer=SWA(Nadam(lr=lr), average_period=2))\n            model.fit(X_hist_train, get_output(train_df), sample_weight=get_weight(train_df),\n                      shuffle=True, batch_size=128, epochs=epoch, verbose=0)\n```\n\nCompetition metric is pinball loss with [0.05, 0.50, 0.95]. Instead of directly optimizing for that, I first optimized for a narrower uncertainty ([0.15, 0.50, 0.85]) to avoid a very cautious local minimum."
        }
      ]
    },
    {
      "id": 1671892,
      "postDate": "2022-02-01T19:14:39.810Z",
      "content": "<p>thank you for this. I'm surprised at how simple each layer of a prize-winning level network is. i wouldn't have guessed so a priori</p>",
      "rawMarkdown": "thank you for this. I'm surprised at how simple each layer of a prize-winning level network is. i wouldn't have guessed so a priori"
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T12:19:25Z",
  "competition_id": 20475,
  "competition_slug": "covid19-global-forecasting-week-5",
  "team_id": 4869471,
  "solution_url": "/competitions/covid19-global-forecasting-week-5/writeups/disinfectant-injection-4th-place-neural-network-so"
}