{
  "id": 258148,
  "title": "🏅️ 4th Place Solution (0.447) 🏅️",
  "content": "<p>I'd like to thank Kaggle and CommonLit for hosting this competition, as well has everyone here who has shared such great discussions and notebooks. I'm still in shock as I've always dreamed of a solo gold but never thought I'd actually get here!</p>\n<h1>CV Strategy</h1>\n<p>This was my second NLP competitions after the <a href=\"https://www.kaggle.com/c/tweet-sentiment-extraction\" target=\"_blank\">Tweet Sentiment Extraction</a> competition last year. There was some similarity between the two, namely a) a small dataset and b) a fairly noisy target. The trick with the TSE competition was to use a 5-fold CV but to average multiple seeds (I used 5 for a total of 25 runs per experiment, which I would then average). <br>\nTo create my 5 folds, I used <a href=\"https://www.kaggle.com/abhishek/step-1-create-folds\" target=\"_blank\">Abhishek's binning and stratification</a> method. On average I was seeing about 0.01 gap between CV &amp; public LB, but the correlation was good. I didn't bother submitting the majority of my single models as I was happy with my CV setup and I'm lazy 😂️.<br>\nMy best performing model was a deberta-large with a CV of 0.4738 (average of 5 seeds).</p>\n<h1>Pipeline</h1>\n<h2>Transformers</h2>\n<p>For all of my transformer models I used the <a href=\"https://www.kaggle.com/gogo827jz/roberta-model-parallel-fold-training-on-tpu\" target=\"_blank\"><code>AttentionBlock</code> from this notebook</a>, but applied it to the sequence last hidden state of the transformer.</p>\n<pre><code>n_hidden = self.config.hidden_size  # from HF config\nself.seq_attn_head = nn.Sequential(\n   nn.LayerNorm(n_hidden),\n   AttentionBlock(n_hidden, n_hidden, 1),\n   nn.Linear(n_hidden + n_additional_features, 2 if kl_loss else 1),\n)\n</code></pre>\n<h2>Additional features</h2>\n<p>I also added a couple of features using <code>textstat</code>, <code>flesch_reading_ease</code> and <code>smog_index</code> and concatenated them to the output of the AttentionBlock before the regression head. These brought a tiny but repeatable improvement to my CV, but I'm not sure if this had any major impact on the final performance. I did a test during the late stages of the competition where I concatenated predictions of other models, and this didn't work any better than the ensemble methods below, which makes me think these features were doing very little.</p>\n<h2>Training config</h2>\n<ul>\n<li>Optimiser: AdamW<ul>\n<li>Weight decay: 1.0</li>\n<li>LR: 0.00005 or 0.000025 (depending on batch size)</li></ul></li>\n<li>Epochs: 6 with SWA after epoch 3</li>\n<li>Batch size: 16 (or 12 for the larger models)</li>\n<li>Validation/Checkpointing every 5 steps</li>\n<li>Loss: MSE</li>\n<li>No dropout</li>\n</ul>\n<h2>Other tools</h2>\n<ul>\n<li>Logging: combination of Weights &amp; Biases and Google Sheets (to track multiple seeds)</li>\n<li>Model Store: Google Cloud Bucket and transfer to a Kaggle Notebook (to /kaggle/output/). I found this was much more reliable than regular dataset uploads, plus you won't run into storage limitations.</li>\n<li>PyTorch Lightning</li>\n<li>Shell script using Kaggle API to measure notebook execution times</li>\n</ul>\n<h1>Ensemble</h1>\n<h2>Selection</h2>\n<p>I started with all of my models and iteratively removed the worst models until I could get down to the GPU time limit. (I found that this worked better than greedily adding models). I think this worked well in the end since the selection process would select models that will help the overall ensemble instead of models with the best CV.<br>\nI used 3 main methods for ensembling:</p>\n<ul>\n<li><code>RidgeCV</code> (which uses <code>LeaveOneOut</code> cross validation)</li>\n<li><code>BayesianRidgeRegression</code> (with a LOO CV loop)</li>\n<li>The <a href=\"https://kaggler.readthedocs.io/en/latest/_modules/kaggler/ensemble/linear.html#netflix\" target=\"_blank\">Netflix method from 2009 BigChaos solution</a> (<a href=\"https://www.netflixprize.com/assets/GrandPrize2009_BPC_BigChaos.pdf\" target=\"_blank\">paper</a>). This method uses RMSE scores from CV to allocate ensemble weights.</li>\n</ul>\n<h2>Final submission</h2>\n<p>My final ensembles usually had about 38 models to fit into the 3 hour run time and had quite a range of model architectures and CV scores.<br>\nI chose the RidgeCV &amp; BayesianRidgeRegression methods as my final 2 submissions with the former scoring 0.447. <br>\nInterestingly, the Netflix method scored 0.446, but I had more faith in the CV scores from LOO CV, as I was worried about leakage using the Netflix method.</p>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.484005</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.486186</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.495078</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.501851</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.482696</td>\n</tr>\n<tr>\n<td>distilroberta-base</td>\n<td>0.505654</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.495666</td>\n</tr>\n<tr>\n<td>bert-large-uncased</td>\n<td>0.524264</td>\n</tr>\n<tr>\n<td>bert-large-uncased</td>\n<td>0.538173</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.534491</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.556662</td>\n</tr>\n<tr>\n<td>facebook/bart-large</td>\n<td>0.543126</td>\n</tr>\n<tr>\n<td>facebook/bart-large</td>\n<td>0.526896</td>\n</tr>\n<tr>\n<td>roberta-base</td>\n<td>0.49835</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.474008</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.471707</td>\n</tr>\n<tr>\n<td>distilroberta-base</td>\n<td>0.502802</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.545104</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.506411</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.493789</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.491098</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.499093</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.509152</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.490829</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.489583</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.494185</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.523333</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.508817</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.529876</td>\n</tr>\n<tr>\n<td>sentence-transformers/LaBSE</td>\n<td>0.525731</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.471197</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.475243</td>\n</tr>\n<tr>\n<td>bert-large-cased-whole-word-masking</td>\n<td>0.514011</td>\n</tr>\n<tr>\n<td>bert-large-cased</td>\n<td>0.505559</td>\n</tr>\n<tr>\n<td>xlm-roberta-large</td>\n<td>0.505576</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.530183</td>\n</tr>\n<tr>\n<td>google/electra-large-discriminator</td>\n<td>0.514033</td>\n</tr>\n<tr>\n<td>sentence-transformers/paraphrase-mpnet-base-v2</td>\n<td>0.510096</td>\n</tr>\n</tbody>\n</table>\n<h1>Code</h1>\n<ul>\n<li>GitHub: <a href=\"https://github.com/Anjum48/commonlitreadabilityprize\" target=\"_blank\">https://github.com/Anjum48/commonlitreadabilityprize</a></li>\n<li>Submission code: <a href=\"https://www.kaggle.com/anjum48/commonlit-submission?scriptVersionId=67928130\" target=\"_blank\">https://www.kaggle.com/anjum48/commonlit-submission?scriptVersionId=67928130</a></li>\n</ul>",
  "comments": [
    {
      "id": 1461890,
      "author_name": "datasaurus",
      "author_url": "",
      "post_date": "2021-08-09T15:55:39.597000",
      "content": "<p>Code repository and submission notebook is now public :)</p>",
      "votes": 5,
      "replies": []
    },
    {
      "id": 1448914,
      "author_name": "Chris Deotte",
      "author_url": "",
      "post_date": "2021-08-04T19:10:39.200000",
      "content": "<p>Congratulations <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> Great job! Can you explain how to do <code>LeaveOneOut cross validation</code>? If the train data has 2500 rows, doesn't that require building 2500 models? (i.e. for each row, you build a model using all data except that row, and infer that row with that model).</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1449343,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-04T21:08:37.670000",
          "content": "<p>Thanks very much <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>! Normally when ensembling I try to keep the same folds for each model so that I can use the OOF predictions to create a blending model. In this case, since I had models trained with different seeds for CV this made things a little tricky and I wasn't sure if a normal 5 fold CV would be reliable.</p>\n<p>My default method was to build a dataset using all my OOF predictions and then use <code>RidgeCV</code>. If <code>cv=None</code>, by default it uses an&nbsp;efficient Leave-One-Out Cross-Validation (the code is <a href=\"https://github.com/scikit-learn/scikit-learn/blob/2beed55847ee70d363bdbfe14ee4401438fba057/sklearn/linear_model/_ridge.py#L1076\" target=\"_blank\">here</a> and it's quite interesting to see how it works). My understanding is that it uses LOO CV to select the best alpha and then fit the weights using the <strong>full</strong> X dataset. The CV score is then the <code>best_score_</code> attribute (which is negative MSE).</p>\n<p>I also tried to replicate this with other sklearn linear models, but using a manual <code>LeaveOneOut</code> CV loop, which was slower, but still gave me good CV/LB correlation. It was these CV scores I used to iteratively remove models for the final ensemble. In the final submission notebook I would just use fit &amp; predict using the OOFs for the chosen models.</p>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>BayesianRidge</td>\n<td>0.44256</td>\n<td>0.452</td>\n<td>0.448</td>\n</tr>\n<tr>\n<td>RidgeCV</td>\n<td>0.44254</td>\n<td>0.451</td>\n<td>0.447</td>\n</tr>\n</tbody>\n</table>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1449370,
          "author_name": "Chris Deotte",
          "author_url": "",
          "post_date": "2021-08-04T21:20:03.150000",
          "content": "<p>Cool. Thanks for the code link. Great job!</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1444733,
      "author_name": "Mohammed Deeb",
      "author_url": "",
      "post_date": "2021-08-04T06:47:35.620000",
      "content": "<p>Congrats. We know how much effort you have done to reach this solution. Many methods have been tested to be in the top 1% in any competitions. Great job. 💪😎</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1429713,
      "author_name": "Miguel González González",
      "author_url": "",
      "post_date": "2021-08-03T10:54:41.083000",
      "content": "<p>Impressive! Congrats and thanks for sharing. The /kaggle/working trick is something I didn't know!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1429270,
      "author_name": "Tim Yee",
      "author_url": "",
      "post_date": "2021-08-03T10:29:32.433000",
      "content": "<p>Congrats on solo gold and great solution! </p>\n<p>Did you average 25 models (5 seeds x 5 folds) and then perform RidgeCV w/ LOO? I had a lot of success stacking with Ridge early on and I found that averaging 5 folds prior to the ensembling stage performed better on LB and I later attributed it to leaking useful information from validation to training.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1429602,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-03T10:49:27.123000",
          "content": "<p>Thanks Tim! I averaged the 5 folds prior to the ensemble and treated the 5 seeds as independent models for the purpose of the ensemble (but only selected the models that improved the ensemble). This meant there were 38 * 5 = 195 model checkpoints.</p>\n<p>My final RidgeCV score was 0.44254 with an alpha of 0.01</p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 1429167,
      "author_name": "Luca Massaron",
      "author_url": "",
      "post_date": "2021-08-03T10:23:37.620000",
      "content": "<p>How did you handled the limited private storage offered by Kaggle? I guess 36 models should occupy more than 100Gb.</p>",
      "votes": 1,
      "replies": [
        {
          "id": 1429500,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-03T10:44:06.213000",
          "content": "<p>I used the method described by Nischay Dhankhar in this <a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/249689\" target=\"_blank\">discussion</a>.</p>\n<p>Essentially anything that gets saved into the /kaggle/output/ section of a notebook doesn't count towards your 100GB (seems like a weird loophole but it works). I just connected my Google Cloud Bucket and downloaded my model weights to that folder</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 1429534,
          "author_name": "Nicholas Broad",
          "author_url": "",
          "post_date": "2021-08-03T10:45:44.357000",
          "content": "<p>If you save them as output of a notebook there isn't a limit</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1430276,
          "author_name": "Tim Yee",
          "author_url": "",
          "post_date": "2021-08-03T11:28:42.573000",
          "content": "<p>Not long ago, the notebook output limit was 5GB. I remember very clearly from Pulmonary Embolism because I tried to use 40 notebooks to create resized images for the competition.</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1433295,
          "author_name": "Luca Massaron",
          "author_url": "",
          "post_date": "2021-08-03T13:54:08.310000",
          "content": "<p>That's a really nice trick! Thank you.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1450799,
      "author_name": "spy1234567",
      "author_url": "",
      "post_date": "2021-08-05T07:18:26.570000",
      "content": "<p>Hi, <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> , Congratulations! Thanks for your sharing.<br>\nI have a question: you said that you use 5 fold and each has 5 seed, this means that you have 25 trained models for a single model structure, after training, how did you make your prediction? to use the result of all of the 25 models or just use the result of the best model of these 25 models?</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1451171,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-05T09:22:26.593000",
          "content": "<p>Hi <a href=\"https://www.kaggle.com/spy1234567\" target=\"_blank\">@spy1234567</a>, yes I used 25 model checkpoints to determine if a change to heads/features/hyperparams etc. actually made an improvement that was worth keeping.</p>\n<p>But for my final prediction, I treated each of the 5 folds as a single model and averaged the predictions. So in the table above, you can see some models appear multiple times due to being from different seeds (or some other change).</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1451798,
          "author_name": "spy1234567",
          "author_url": "",
          "post_date": "2021-08-05T12:43:51.310000",
          "content": "<p>Hi, <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> , do you mean that you treat 5 folds (each has 5 seeds) as 25 single model and choose the best model among them?</p>",
          "votes": 0,
          "replies": []
        },
        {
          "id": 1452034,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-05T14:01:35.770000",
          "content": "<p>Perhaps a picture will help :)</p>\n<p>Each \"timestamp\" or row is a single model run with a single seed run for 5 folds. Each \"group name\" is a group of 5 identical models run with different seeds.</p>\n<p>I would take the mean RMSE of the group (25 model checkpoints) to determine if a change made something better or worse. This is how I calculated my CV score.</p>\n<p>But I would treat each timestamp as a unique model in my ensemble (averaging the 5 folds), but only using that model if it improved my ensemble CV.</p>\n<p><img src=\"https://i.imgur.com/sUBxnBI.png\" alt=\"\"></p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1452058,
          "author_name": "spy1234567",
          "author_url": "",
          "post_date": "2021-08-05T14:07:44.037000",
          "content": "<p><a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> thanks again for your patience and detailed reply!👍</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1443594,
      "author_name": "KhanhVD",
      "author_url": "",
      "post_date": "2021-08-04T03:31:57.367000",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> on 4th place. Well done</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 1426586,
      "author_name": "Allohvk",
      "author_url": "",
      "post_date": "2021-08-03T07:42:27.390000",
      "content": "<p>great job. I could see by the count of your submissions during the competition that you seem to be fairly confident of your CV..</p>\n<p>Also interesting to see you experiments with kl_loss</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1427485,
          "author_name": "datasaurus",
          "author_url": "",
          "post_date": "2021-08-03T08:29:03.767000",
          "content": "<p>Thank you! I actually forgot to mention KL Loss above.</p>\n<p>I tried the loss from <a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/239421#1310794\" target=\"_blank\">this discussion</a> but didn't really see gains on CV. However, there were some models which were difficult to train (the loss would suddenly jump up after a couple of epochs) and this loss function appeared to help slightly. MSE was my default loss for most models though</p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 1426127,
      "author_name": "Salim Khazem",
      "author_url": "",
      "post_date": "2021-08-03T07:18:59.550000",
      "content": "<p>Congratulations, thanks for sharing your approach  </p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 1455843,
      "author_name": "Amol Ambkar",
      "author_url": "",
      "post_date": "2021-08-06T17:51:32.410000",
      "content": "<p>Great One…</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1453440,
      "author_name": "lyo_gavin",
      "author_url": "",
      "post_date": "2021-08-05T21:20:13.367000",
      "content": "<p>Congrats! Great work! Learned a lot. Your method is probably the most replicable solution independent to the specific task.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1451855,
      "author_name": "arpita dutta",
      "author_url": "",
      "post_date": "2021-08-05T12:59:17.030000",
      "content": "<p>Congratulations! Thank you for providing this information.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1444881,
      "author_name": "Shubham Singh",
      "author_url": "",
      "post_date": "2021-08-04T07:14:50.567000",
      "content": "<p>Congrats and thanks for sharing .</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1427874,
      "author_name": "SSinyu",
      "author_url": "",
      "post_date": "2021-08-03T08:52:42.010000",
      "content": "<p>Thank you for sharing, Congratulations!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1453084,
      "author_name": "Shubham Chaurasia",
      "author_url": "",
      "post_date": "2021-08-05T18:54:13.587000",
      "content": "<p>Thanks for sharing!</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1451677,
      "author_name": "Devashree Madhugiri",
      "author_url": "",
      "post_date": "2021-08-05T12:02:18.717000",
      "content": "<p>Congratulations! Thanks for sharing.</p>",
      "votes": 0,
      "replies": []
    }
  ],
  "comment_count": 29,
  "messages": [
    {
      "id": 1425964,
      "postDate": "2021-08-03T07:11:25.213Z",
      "content": "<p>I'd like to thank Kaggle and CommonLit for hosting this competition, as well has everyone here who has shared such great discussions and notebooks. I'm still in shock as I've always dreamed of a solo gold but never thought I'd actually get here!</p>\n<h1>CV Strategy</h1>\n<p>This was my second NLP competitions after the <a href=\"https://www.kaggle.com/c/tweet-sentiment-extraction\" target=\"_blank\">Tweet Sentiment Extraction</a> competition last year. There was some similarity between the two, namely a) a small dataset and b) a fairly noisy target. The trick with the TSE competition was to use a 5-fold CV but to average multiple seeds (I used 5 for a total of 25 runs per experiment, which I would then average). <br>\nTo create my 5 folds, I used <a href=\"https://www.kaggle.com/abhishek/step-1-create-folds\" target=\"_blank\">Abhishek's binning and stratification</a> method. On average I was seeing about 0.01 gap between CV &amp; public LB, but the correlation was good. I didn't bother submitting the majority of my single models as I was happy with my CV setup and I'm lazy 😂️.<br>\nMy best performing model was a deberta-large with a CV of 0.4738 (average of 5 seeds).</p>\n<h1>Pipeline</h1>\n<h2>Transformers</h2>\n<p>For all of my transformer models I used the <a href=\"https://www.kaggle.com/gogo827jz/roberta-model-parallel-fold-training-on-tpu\" target=\"_blank\"><code>AttentionBlock</code> from this notebook</a>, but applied it to the sequence last hidden state of the transformer.</p>\n<pre><code>n_hidden = self.config.hidden_size  # from HF config\nself.seq_attn_head = nn.Sequential(\n   nn.LayerNorm(n_hidden),\n   AttentionBlock(n_hidden, n_hidden, 1),\n   nn.Linear(n_hidden + n_additional_features, 2 if kl_loss else 1),\n)\n</code></pre>\n<h2>Additional features</h2>\n<p>I also added a couple of features using <code>textstat</code>, <code>flesch_reading_ease</code> and <code>smog_index</code> and concatenated them to the output of the AttentionBlock before the regression head. These brought a tiny but repeatable improvement to my CV, but I'm not sure if this had any major impact on the final performance. I did a test during the late stages of the competition where I concatenated predictions of other models, and this didn't work any better than the ensemble methods below, which makes me think these features were doing very little.</p>\n<h2>Training config</h2>\n<ul>\n<li>Optimiser: AdamW<ul>\n<li>Weight decay: 1.0</li>\n<li>LR: 0.00005 or 0.000025 (depending on batch size)</li></ul></li>\n<li>Epochs: 6 with SWA after epoch 3</li>\n<li>Batch size: 16 (or 12 for the larger models)</li>\n<li>Validation/Checkpointing every 5 steps</li>\n<li>Loss: MSE</li>\n<li>No dropout</li>\n</ul>\n<h2>Other tools</h2>\n<ul>\n<li>Logging: combination of Weights &amp; Biases and Google Sheets (to track multiple seeds)</li>\n<li>Model Store: Google Cloud Bucket and transfer to a Kaggle Notebook (to /kaggle/output/). I found this was much more reliable than regular dataset uploads, plus you won't run into storage limitations.</li>\n<li>PyTorch Lightning</li>\n<li>Shell script using Kaggle API to measure notebook execution times</li>\n</ul>\n<h1>Ensemble</h1>\n<h2>Selection</h2>\n<p>I started with all of my models and iteratively removed the worst models until I could get down to the GPU time limit. (I found that this worked better than greedily adding models). I think this worked well in the end since the selection process would select models that will help the overall ensemble instead of models with the best CV.<br>\nI used 3 main methods for ensembling:</p>\n<ul>\n<li><code>RidgeCV</code> (which uses <code>LeaveOneOut</code> cross validation)</li>\n<li><code>BayesianRidgeRegression</code> (with a LOO CV loop)</li>\n<li>The <a href=\"https://kaggler.readthedocs.io/en/latest/_modules/kaggler/ensemble/linear.html#netflix\" target=\"_blank\">Netflix method from 2009 BigChaos solution</a> (<a href=\"https://www.netflixprize.com/assets/GrandPrize2009_BPC_BigChaos.pdf\" target=\"_blank\">paper</a>). This method uses RMSE scores from CV to allocate ensemble weights.</li>\n</ul>\n<h2>Final submission</h2>\n<p>My final ensembles usually had about 38 models to fit into the 3 hour run time and had quite a range of model architectures and CV scores.<br>\nI chose the RidgeCV &amp; BayesianRidgeRegression methods as my final 2 submissions with the former scoring 0.447. <br>\nInterestingly, the Netflix method scored 0.446, but I had more faith in the CV scores from LOO CV, as I was worried about leakage using the Netflix method.</p>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.484005</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.486186</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.495078</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.501851</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.482696</td>\n</tr>\n<tr>\n<td>distilroberta-base</td>\n<td>0.505654</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.495666</td>\n</tr>\n<tr>\n<td>bert-large-uncased</td>\n<td>0.524264</td>\n</tr>\n<tr>\n<td>bert-large-uncased</td>\n<td>0.538173</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.534491</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.556662</td>\n</tr>\n<tr>\n<td>facebook/bart-large</td>\n<td>0.543126</td>\n</tr>\n<tr>\n<td>facebook/bart-large</td>\n<td>0.526896</td>\n</tr>\n<tr>\n<td>roberta-base</td>\n<td>0.49835</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.474008</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.471707</td>\n</tr>\n<tr>\n<td>distilroberta-base</td>\n<td>0.502802</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.545104</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.506411</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.493789</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.491098</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.499093</td>\n</tr>\n<tr>\n<td>microsoft/deberta-base</td>\n<td>0.509152</td>\n</tr>\n<tr>\n<td>deepset/roberta-base-squad2</td>\n<td>0.490829</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.489583</td>\n</tr>\n<tr>\n<td>deepset/roberta-large-squad2</td>\n<td>0.494185</td>\n</tr>\n<tr>\n<td>funnel-transformer/large-base</td>\n<td>0.523333</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.508817</td>\n</tr>\n<tr>\n<td>albert-large-v2</td>\n<td>0.529876</td>\n</tr>\n<tr>\n<td>sentence-transformers/LaBSE</td>\n<td>0.525731</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.471197</td>\n</tr>\n<tr>\n<td>microsoft/deberta-large</td>\n<td>0.475243</td>\n</tr>\n<tr>\n<td>bert-large-cased-whole-word-masking</td>\n<td>0.514011</td>\n</tr>\n<tr>\n<td>bert-large-cased</td>\n<td>0.505559</td>\n</tr>\n<tr>\n<td>xlm-roberta-large</td>\n<td>0.505576</td>\n</tr>\n<tr>\n<td>facebook/bart-base</td>\n<td>0.530183</td>\n</tr>\n<tr>\n<td>google/electra-large-discriminator</td>\n<td>0.514033</td>\n</tr>\n<tr>\n<td>sentence-transformers/paraphrase-mpnet-base-v2</td>\n<td>0.510096</td>\n</tr>\n</tbody>\n</table>\n<h1>Code</h1>\n<ul>\n<li>GitHub: <a href=\"https://github.com/Anjum48/commonlitreadabilityprize\" target=\"_blank\">https://github.com/Anjum48/commonlitreadabilityprize</a></li>\n<li>Submission code: <a href=\"https://www.kaggle.com/anjum48/commonlit-submission?scriptVersionId=67928130\" target=\"_blank\">https://www.kaggle.com/anjum48/commonlit-submission?scriptVersionId=67928130</a></li>\n</ul>",
      "rawMarkdown": "\nI'd like to thank Kaggle and CommonLit for hosting this competition, as well has everyone here who has shared such great discussions and notebooks. I'm still in shock as I've always dreamed of a solo gold but never thought I'd actually get here!\n\n# CV Strategy\nThis was my second NLP competitions after the [Tweet Sentiment Extraction](https://www.kaggle.com/c/tweet-sentiment-extraction) competition last year. There was some similarity between the two, namely a) a small dataset and b) a fairly noisy target. The trick with the TSE competition was to use a 5-fold CV but to average multiple seeds (I used 5 for a total of 25 runs per experiment, which I would then average). \n\nTo create my 5 folds, I used [Abhishek's binning and stratification](https://www.kaggle.com/abhishek/step-1-create-folds) method. On average I was seeing about 0.01 gap between CV & public LB, but the correlation was good. I didn't bother submitting the majority of my single models as I was happy with my CV setup and I'm lazy 😂️.\n\nMy best performing model was a deberta-large with a CV of 0.4738 (average of 5 seeds).\n\n# Pipeline\n## Transformers\nFor all of my transformer models I used the [`AttentionBlock` from this notebook](https://www.kaggle.com/gogo827jz/roberta-model-parallel-fold-training-on-tpu), but applied it to the sequence last hidden state of the transformer.\n\n```\nn_hidden = self.config.hidden_size  # from HF config\n\nself.seq_attn_head = nn.Sequential(\n    nn.LayerNorm(n_hidden),\n    AttentionBlock(n_hidden, n_hidden, 1),\n    nn.Linear(n_hidden + n_additional_features, 2 if kl_loss else 1),\n)\n```\n\n## Additional features\nI also added a couple of features using `textstat`, `flesch_reading_ease` and `smog_index` and concatenated them to the output of the AttentionBlock before the regression head. These brought a tiny but repeatable improvement to my CV, but I'm not sure if this had any major impact on the final performance. I did a test during the late stages of the competition where I concatenated predictions of other models, and this didn't work any better than the ensemble methods below, which makes me think these features were doing very little.\n\n## Training config\n* Optimiser: AdamW\n    * Weight decay: 1.0\n    * LR: 0.00005 or 0.000025 (depending on batch size)\n* Epochs: 6 with SWA after epoch 3\n* Batch size: 16 (or 12 for the larger models)\n* Validation/Checkpointing every 5 steps\n* Loss: MSE\n* No dropout\n\n## Other tools\n* Logging: combination of Weights & Biases and Google Sheets (to track multiple seeds)\n* Model Store: Google Cloud Bucket and transfer to a Kaggle Notebook (to /kaggle/output/). I found this was much more reliable than regular dataset uploads, plus you won't run into storage limitations.\n* PyTorch Lightning\n* Shell script using Kaggle API to measure notebook execution times\n\n# Ensemble\n## Selection\nI started with all of my models and iteratively removed the worst models until I could get down to the GPU time limit. (I found that this worked better than greedily adding models). I think this worked well in the end since the selection process would select models that will help the overall ensemble instead of models with the best CV.\n\nI used 3 main methods for ensembling:\n* `RidgeCV` (which uses `LeaveOneOut` cross validation)\n* `BayesianRidgeRegression` (with a LOO CV loop)\n* The [Netflix method from 2009 BigChaos solution](https://kaggler.readthedocs.io/en/latest/_modules/kaggler/ensemble/linear.html#netflix) ([paper](https://www.netflixprize.com/assets/GrandPrize2009_BPC_BigChaos.pdf)). This method uses RMSE scores from CV to allocate ensemble weights.\n\n## Final submission\nMy final ensembles usually had about 38 models to fit into the 3 hour run time and had quite a range of model architectures and CV scores.\n\nI chose the RidgeCV & BayesianRidgeRegression methods as my final 2 submissions with the former scoring 0.447. \n\nInterestingly, the Netflix method scored 0.446, but I had more faith in the CV scores from LOO CV, as I was worried about leakage using the Netflix method.\n\n\n| Model                                          |       CV |\n|:-----------------------------------------------|---------:|\n| microsoft/deberta-large                        | 0.484005 |\n| microsoft/deberta-base                         | 0.486186 |\n| deepset/roberta-base-squad2                    | 0.495078 |\n| deepset/roberta-base-squad2                    | 0.501851 |\n| deepset/roberta-large-squad2                   | 0.482696 |\n| distilroberta-base                             | 0.505654 |\n| funnel-transformer/large-base                  | 0.495666 |\n| bert-large-uncased                             | 0.524264 |\n| bert-large-uncased                             | 0.538173 |\n| facebook/bart-base                             | 0.534491 |\n| facebook/bart-base                             | 0.556662 |\n| facebook/bart-large                            | 0.543126 |\n| facebook/bart-large                            | 0.526896 |\n| roberta-base                                   | 0.49835  |\n| microsoft/deberta-large                        | 0.474008 |\n| microsoft/deberta-large                        | 0.471707 |\n| distilroberta-base                             | 0.502802 |\n| albert-large-v2                                | 0.545104 |\n| albert-large-v2                                | 0.506411 |\n| funnel-transformer/large-base                  | 0.493789 |\n| funnel-transformer/large-base                  | 0.491098 |\n| microsoft/deberta-base                         | 0.499093 |\n| microsoft/deberta-base                         | 0.509152 |\n| deepset/roberta-base-squad2                    | 0.490829 |\n| deepset/roberta-large-squad2                   | 0.489583 |\n| deepset/roberta-large-squad2                   | 0.494185 |\n| funnel-transformer/large-base                  | 0.523333 |\n| albert-large-v2                                | 0.508817 |\n| albert-large-v2                                | 0.529876 |\n| sentence-transformers/LaBSE                    | 0.525731 |\n| microsoft/deberta-large                        | 0.471197 |\n| microsoft/deberta-large                        | 0.475243 |\n| bert-large-cased-whole-word-masking            | 0.514011 |\n| bert-large-cased                               | 0.505559 |\n| xlm-roberta-large                              | 0.505576 |\n| facebook/bart-base                             | 0.530183 |\n| google/electra-large-discriminator             | 0.514033 |\n| sentence-transformers/paraphrase-mpnet-base-v2 | 0.510096 | \n\n# Code\n* GitHub: https://github.com/Anjum48/commonlitreadabilityprize\n* Submission code: https://www.kaggle.com/anjum48/commonlit-submission?scriptVersionId=67928130",
      "votes": 105
    },
    {
      "id": 1461890,
      "postDate": "2021-08-09T15:55:39.597Z",
      "content": "<p>Code repository and submission notebook is now public :)</p>",
      "rawMarkdown": "Code repository and submission notebook is now public :)",
      "votes": 5
    },
    {
      "id": 1448914,
      "postDate": "2021-08-04T19:10:39.200Z",
      "content": "<p>Congratulations <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> Great job! Can you explain how to do <code>LeaveOneOut cross validation</code>? If the train data has 2500 rows, doesn't that require building 2500 models? (i.e. for each row, you build a model using all data except that row, and infer that row with that model).</p>",
      "rawMarkdown": "Congratulations @anjum48 Great job! Can you explain how to do `LeaveOneOut cross validation`? If the train data has 2500 rows, doesn't that require building 2500 models? (i.e. for each row, you build a model using all data except that row, and infer that row with that model).",
      "votes": 1,
      "replies": [
        {
          "id": 1449343,
          "postDate": "2021-08-04T21:08:37.670Z",
          "content": "<p>Thanks very much <a href=\"https://www.kaggle.com/cdeotte\" target=\"_blank\">@cdeotte</a>! Normally when ensembling I try to keep the same folds for each model so that I can use the OOF predictions to create a blending model. In this case, since I had models trained with different seeds for CV this made things a little tricky and I wasn't sure if a normal 5 fold CV would be reliable.</p>\n<p>My default method was to build a dataset using all my OOF predictions and then use <code>RidgeCV</code>. If <code>cv=None</code>, by default it uses an&nbsp;efficient Leave-One-Out Cross-Validation (the code is <a href=\"https://github.com/scikit-learn/scikit-learn/blob/2beed55847ee70d363bdbfe14ee4401438fba057/sklearn/linear_model/_ridge.py#L1076\" target=\"_blank\">here</a> and it's quite interesting to see how it works). My understanding is that it uses LOO CV to select the best alpha and then fit the weights using the <strong>full</strong> X dataset. The CV score is then the <code>best_score_</code> attribute (which is negative MSE).</p>\n<p>I also tried to replicate this with other sklearn linear models, but using a manual <code>LeaveOneOut</code> CV loop, which was slower, but still gave me good CV/LB correlation. It was these CV scores I used to iteratively remove models for the final ensemble. In the final submission notebook I would just use fit &amp; predict using the OOFs for the chosen models.</p>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>BayesianRidge</td>\n<td>0.44256</td>\n<td>0.452</td>\n<td>0.448</td>\n</tr>\n<tr>\n<td>RidgeCV</td>\n<td>0.44254</td>\n<td>0.451</td>\n<td>0.447</td>\n</tr>\n</tbody>\n</table>",
          "rawMarkdown": "Thanks very much @cdeotte! Normally when ensembling I try to keep the same folds for each model so that I can use the OOF predictions to create a blending model. In this case, since I had models trained with different seeds for CV this made things a little tricky and I wasn't sure if a normal 5 fold CV would be reliable.\n\nMy default method was to build a dataset using all my OOF predictions and then use `RidgeCV`. If `cv=None`, by default it uses an efficient Leave-One-Out Cross-Validation (the code is [here](https://github.com/scikit-learn/scikit-learn/blob/2beed55847ee70d363bdbfe14ee4401438fba057/sklearn/linear_model/_ridge.py#L1076) and it's quite interesting to see how it works). My understanding is that it uses LOO CV to select the best alpha and then fit the weights using the **full** X dataset. The CV score is then the `best_score_` attribute (which is negative MSE).\n\nI also tried to replicate this with other sklearn linear models, but using a manual `LeaveOneOut` CV loop, which was slower, but still gave me good CV/LB correlation. It was these CV scores I used to iteratively remove models for the final ensemble. In the final submission notebook I would just use fit & predict using the OOFs for the chosen models.\n\n| Model | CV | Public | Private |\n| --- | --- | --- | --- |\n| BayesianRidge | 0.44256 | 0.452 | 0.448 | \n| RidgeCV | 0.44254 | 0.451 | 0.447 |",
          "votes": 1
        },
        {
          "id": 1449370,
          "postDate": "2021-08-04T21:20:03.150Z",
          "content": "<p>Cool. Thanks for the code link. Great job!</p>",
          "rawMarkdown": "Cool. Thanks for the code link. Great job!",
          "votes": 1
        }
      ]
    },
    {
      "id": 1444733,
      "postDate": "2021-08-04T06:47:35.620Z",
      "content": "<p>Congrats. We know how much effort you have done to reach this solution. Many methods have been tested to be in the top 1% in any competitions. Great job. 💪😎</p>",
      "rawMarkdown": "Congrats. We know how much effort you have done to reach this solution. Many methods have been tested to be in the top 1% in any competitions. Great job. 💪😎",
      "votes": 1
    },
    {
      "id": 1429713,
      "postDate": "2021-08-03T10:54:41.083Z",
      "content": "<p>Impressive! Congrats and thanks for sharing. The /kaggle/working trick is something I didn't know!</p>",
      "rawMarkdown": "Impressive! Congrats and thanks for sharing. The /kaggle/working trick is something I didn't know!",
      "votes": 1
    },
    {
      "id": 1429270,
      "postDate": "2021-08-03T10:29:32.433Z",
      "content": "<p>Congrats on solo gold and great solution! </p>\n<p>Did you average 25 models (5 seeds x 5 folds) and then perform RidgeCV w/ LOO? I had a lot of success stacking with Ridge early on and I found that averaging 5 folds prior to the ensembling stage performed better on LB and I later attributed it to leaking useful information from validation to training.</p>",
      "rawMarkdown": "Congrats on solo gold and great solution! \n\nDid you average 25 models (5 seeds x 5 folds) and then perform RidgeCV w/ LOO? I had a lot of success stacking with Ridge early on and I found that averaging 5 folds prior to the ensembling stage performed better on LB and I later attributed it to leaking useful information from validation to training.",
      "votes": 1,
      "replies": [
        {
          "id": 1429602,
          "postDate": "2021-08-03T10:49:27.123Z",
          "content": "<p>Thanks Tim! I averaged the 5 folds prior to the ensemble and treated the 5 seeds as independent models for the purpose of the ensemble (but only selected the models that improved the ensemble). This meant there were 38 * 5 = 195 model checkpoints.</p>\n<p>My final RidgeCV score was 0.44254 with an alpha of 0.01</p>",
          "rawMarkdown": "Thanks Tim! I averaged the 5 folds prior to the ensemble and treated the 5 seeds as independent models for the purpose of the ensemble (but only selected the models that improved the ensemble). This meant there were 38 * 5 = 195 model checkpoints.\n\nMy final RidgeCV score was 0.44254 with an alpha of 0.01",
          "votes": 2
        }
      ]
    },
    {
      "id": 1429167,
      "postDate": "2021-08-03T10:23:37.620Z",
      "content": "<p>How did you handled the limited private storage offered by Kaggle? I guess 36 models should occupy more than 100Gb.</p>",
      "rawMarkdown": "How did you handled the limited private storage offered by Kaggle? I guess 36 models should occupy more than 100Gb.",
      "votes": 1,
      "replies": [
        {
          "id": 1429500,
          "postDate": "2021-08-03T10:44:06.213Z",
          "content": "<p>I used the method described by Nischay Dhankhar in this <a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/249689\" target=\"_blank\">discussion</a>.</p>\n<p>Essentially anything that gets saved into the /kaggle/output/ section of a notebook doesn't count towards your 100GB (seems like a weird loophole but it works). I just connected my Google Cloud Bucket and downloaded my model weights to that folder</p>",
          "rawMarkdown": "I used the method described by Nischay Dhankhar in this [discussion](https://www.kaggle.com/c/commonlitreadabilityprize/discussion/249689).\n\nEssentially anything that gets saved into the /kaggle/output/ section of a notebook doesn't count towards your 100GB (seems like a weird loophole but it works). I just connected my Google Cloud Bucket and downloaded my model weights to that folder",
          "votes": 2
        },
        {
          "id": 1429534,
          "postDate": "2021-08-03T10:45:44.357Z",
          "content": "<p>If you save them as output of a notebook there isn't a limit</p>",
          "rawMarkdown": "If you save them as output of a notebook there isn't a limit"
        },
        {
          "id": 1430276,
          "postDate": "2021-08-03T11:28:42.573Z",
          "content": "<p>Not long ago, the notebook output limit was 5GB. I remember very clearly from Pulmonary Embolism because I tried to use 40 notebooks to create resized images for the competition.</p>",
          "rawMarkdown": "Not long ago, the notebook output limit was 5GB. I remember very clearly from Pulmonary Embolism because I tried to use 40 notebooks to create resized images for the competition."
        },
        {
          "id": 1433295,
          "postDate": "2021-08-03T13:54:08.310Z",
          "content": "<p>That's a really nice trick! Thank you.</p>",
          "rawMarkdown": "That's a really nice trick! Thank you."
        }
      ]
    },
    {
      "id": 1450799,
      "postDate": "2021-08-05T07:18:26.570Z",
      "content": "<p>Hi, <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> , Congratulations! Thanks for your sharing.<br>\nI have a question: you said that you use 5 fold and each has 5 seed, this means that you have 25 trained models for a single model structure, after training, how did you make your prediction? to use the result of all of the 25 models or just use the result of the best model of these 25 models?</p>",
      "rawMarkdown": "Hi, @anjum48 , Congratulations! Thanks for your sharing.\nI have a question: you said that you use 5 fold and each has 5 seed, this means that you have 25 trained models for a single model structure, after training, how did you make your prediction? to use the result of all of the 25 models or just use the result of the best model of these 25 models?",
      "votes": 2,
      "replies": [
        {
          "id": 1451171,
          "postDate": "2021-08-05T09:22:26.593Z",
          "content": "<p>Hi <a href=\"https://www.kaggle.com/spy1234567\" target=\"_blank\">@spy1234567</a>, yes I used 25 model checkpoints to determine if a change to heads/features/hyperparams etc. actually made an improvement that was worth keeping.</p>\n<p>But for my final prediction, I treated each of the 5 folds as a single model and averaged the predictions. So in the table above, you can see some models appear multiple times due to being from different seeds (or some other change).</p>",
          "rawMarkdown": "Hi @spy1234567, yes I used 25 model checkpoints to determine if a change to heads/features/hyperparams etc. actually made an improvement that was worth keeping.\n\nBut for my final prediction, I treated each of the 5 folds as a single model and averaged the predictions. So in the table above, you can see some models appear multiple times due to being from different seeds (or some other change)."
        },
        {
          "id": 1451798,
          "postDate": "2021-08-05T12:43:51.310Z",
          "content": "<p>Hi, <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> , do you mean that you treat 5 folds (each has 5 seeds) as 25 single model and choose the best model among them?</p>",
          "rawMarkdown": "Hi, @anjum48 , do you mean that you treat 5 folds (each has 5 seeds) as 25 single model and choose the best model among them?"
        },
        {
          "id": 1452034,
          "postDate": "2021-08-05T14:01:35.770Z",
          "content": "<p>Perhaps a picture will help :)</p>\n<p>Each \"timestamp\" or row is a single model run with a single seed run for 5 folds. Each \"group name\" is a group of 5 identical models run with different seeds.</p>\n<p>I would take the mean RMSE of the group (25 model checkpoints) to determine if a change made something better or worse. This is how I calculated my CV score.</p>\n<p>But I would treat each timestamp as a unique model in my ensemble (averaging the 5 folds), but only using that model if it improved my ensemble CV.</p>\n<p><img src=\"https://i.imgur.com/sUBxnBI.png\" alt=\"\"></p>",
          "rawMarkdown": "Perhaps a picture will help :)\n\nEach \"timestamp\" or row is a single model run with a single seed run for 5 folds. Each \"group name\" is a group of 5 identical models run with different seeds.\n\nI would take the mean RMSE of the group (25 model checkpoints) to determine if a change made something better or worse. This is how I calculated my CV score.\n\nBut I would treat each timestamp as a unique model in my ensemble (averaging the 5 folds), but only using that model if it improved my ensemble CV.\n\n![](https://i.imgur.com/sUBxnBI.png)",
          "votes": 1
        },
        {
          "id": 1452058,
          "postDate": "2021-08-05T14:07:44.037Z",
          "content": "<p><a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> thanks again for your patience and detailed reply!👍</p>",
          "rawMarkdown": "@anjum48 thanks again for your patience and detailed reply!👍",
          "votes": 1
        }
      ]
    },
    {
      "id": 1443594,
      "postDate": "2021-08-04T03:31:57.367Z",
      "content": "<p>Congrats <a href=\"https://www.kaggle.com/anjum48\" target=\"_blank\">@anjum48</a> on 4th place. Well done</p>",
      "rawMarkdown": "Congrats @anjum48 on 4th place. Well done",
      "votes": 2
    },
    {
      "id": 1426586,
      "postDate": "2021-08-03T07:42:27.390Z",
      "content": "<p>great job. I could see by the count of your submissions during the competition that you seem to be fairly confident of your CV..</p>\n<p>Also interesting to see you experiments with kl_loss</p>",
      "rawMarkdown": "great job. I could see by the count of your submissions during the competition that you seem to be fairly confident of your CV..\n\nAlso interesting to see you experiments with kl_loss",
      "votes": 2,
      "replies": [
        {
          "id": 1427485,
          "postDate": "2021-08-03T08:29:03.767Z",
          "content": "<p>Thank you! I actually forgot to mention KL Loss above.</p>\n<p>I tried the loss from <a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/239421#1310794\" target=\"_blank\">this discussion</a> but didn't really see gains on CV. However, there were some models which were difficult to train (the loss would suddenly jump up after a couple of epochs) and this loss function appeared to help slightly. MSE was my default loss for most models though</p>",
          "rawMarkdown": "Thank you! I actually forgot to mention KL Loss above.\n\nI tried the loss from [this discussion](https://www.kaggle.com/c/commonlitreadabilityprize/discussion/239421#1310794) but didn't really see gains on CV. However, there were some models which were difficult to train (the loss would suddenly jump up after a couple of epochs) and this loss function appeared to help slightly. MSE was my default loss for most models though",
          "votes": 2
        }
      ]
    },
    {
      "id": 1426127,
      "postDate": "2021-08-03T07:18:59.550Z",
      "content": "<p>Congratulations, thanks for sharing your approach  </p>",
      "rawMarkdown": "Congratulations, thanks for sharing your approach  ",
      "votes": 2
    },
    {
      "id": 1455843,
      "postDate": "2021-08-06T17:51:32.410Z",
      "content": "<p>Great One…</p>",
      "rawMarkdown": "Great One...\n"
    },
    {
      "id": 1453440,
      "postDate": "2021-08-05T21:20:13.367Z",
      "content": "<p>Congrats! Great work! Learned a lot. Your method is probably the most replicable solution independent to the specific task.</p>",
      "rawMarkdown": "Congrats! Great work! Learned a lot. Your method is probably the most replicable solution independent to the specific task."
    },
    {
      "id": 1451855,
      "postDate": "2021-08-05T12:59:17.030Z",
      "content": "<p>Congratulations! Thank you for providing this information.</p>",
      "rawMarkdown": "Congratulations! Thank you for providing this information."
    },
    {
      "id": 1444881,
      "postDate": "2021-08-04T07:14:50.567Z",
      "content": "<p>Congrats and thanks for sharing .</p>",
      "rawMarkdown": "Congrats and thanks for sharing .",
      "votes": 1
    },
    {
      "id": 1427874,
      "postDate": "2021-08-03T08:52:42.010Z",
      "content": "<p>Thank you for sharing, Congratulations!</p>",
      "rawMarkdown": "Thank you for sharing, Congratulations!",
      "votes": 1
    },
    {
      "id": 1453084,
      "postDate": "2021-08-05T18:54:13.587Z",
      "content": "<p>Thanks for sharing!</p>",
      "rawMarkdown": "Thanks for sharing!"
    },
    {
      "id": 1451677,
      "postDate": "2021-08-05T12:02:18.717Z",
      "content": "<p>Congratulations! Thanks for sharing.</p>",
      "rawMarkdown": "Congratulations! Thanks for sharing."
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T23:46:32Z",
  "competition_id": 25914,
  "competition_slug": "commonlitreadabilityprize",
  "team_id": 6823320,
  "solution_url": "/competitions/commonlitreadabilityprize/writeups/datasaurus-4th-place-solution-0-447"
}