{
  "id": 258095,
  "title": "3rd place solution (0.447 private - 3 models simple average)",
  "content": "<h3>update</h3>\n<p>Sept 10, 2021 - added link to submission notebook<br>\nAug 16, 2021 - added code link</p>\n<h3><strong>tl;dr at the bottom</strong></h3>\n<p>First, I would like to thank Kaggle and CommonLit for hosting this competition and the community here at Kaggle for making this platform a wonderful place to learn. This is my second competition at Kaggle, with the first one being the Coleridge Initiative; I have to say the past three months or so has been a tremendous journey. If anyone told me three months ago that I would end up in 3rd place in a Kaggle competition, I would not believe it. None of this would be possible without Kaggle and its incredible community.</p>\n<p>Special thanks to:<br>\n<a href=\"https://www.kaggle.com/rhtsingh\" target=\"_blank\">@rhtsingh</a> for sharing so many great notebooks with detailed and excellent explanations. Those notebooks guided my first few weeks in this competition. <br>\n<a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a> for sharing a simple yet elegant solution. Some parts of my final model are from his approach.</p>\n<h2>Analysis of the objective</h2>\n<p>Before I go over my approach, I'd like to share my point of view on the competition objective. Please correct me if what I say is wrong or doesn't make sense to you.<br>\nThis competition is characterized by small training data and noisy, non-intuitive to understand target values. The target is generated by the Bradley-Terry algorithm from a relatively small number of pair-wise comparison data. From my intuition, Bradley-Terry acts like an Elo rating system where match results are translated to raw numbers representing the \"strength\" of each player. (again, this could be wrong and is merely my point of view) In this competition, the texts are players, and the \"strength\" is \"easiness to read,\" where an easier-to-read text would score higher. <br>\nTraining data + public/private data nets to little less than 5k samples, and each sample is compared with others 46.47 times on average. That means each text was compared to only ~1% of the entire dataset on average. Imagine a chess player's Elo where the player has only played against 1% of the whole chess player population, and the opponents are selected at random. I believe most of the noise is due to the small number of comparisons. <br>\nThe objective of the competition is to predict where an arbitrary text would land on that leaderboard generated from 5k texts.</p>\n<h2>Path to public LB 0.442:</h2>\n<p>I've played with Roberta base mostly at the beginning of the competition, and with a gru+multihead attention on the last hidden layer + learning rate decay, I was able to get <strong>~0.473 on both public and private LB.</strong><br>\nI then switched to large and with the same setup I was at around <strong>0.465-0.467 on both public and private LB.</strong><br>\nAfter which I learned from <a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a>'s notebook and incorporated 3 group lr decay, simple attention head, and validation step policy into my solution<br>\nRoberta-large + simple attention head + learning rate decay: <strong>0.462 on both LB</strong></p>\n<p>0.462 + weighted average of all layers and multisample dropout (from google quest #1 solution) + separate lr for head: **0.459 on public **<br>\n0.459 + a 3 stage lr schedule: <strong>0.454 on public</strong><br>\n<img src=\"https://i.ibb.co/fNjh6pc/LR.png\" alt=\"custom schedule\"><br>\n0.454 + early stop at the beginning of 3rd epoch: <strong>0.453 on public</strong><br>\nHowever, <strong>the private did not agree with the improvement to 0.453</strong>, which I didn't know at the time. <strong>Private LB stayed at ~0.461</strong><br>\nAn ensemble of 2 Roberta large and a Roberta base trained this way, however, got <strong>0.454 on public</strong> and <strong>0.456 on private</strong>. </p>\n<p>I then used two of my 0.453 public models to label extra data consists of simple wiki dump, children's book test, and OneStopEnglishCropus.<br>\nUsing all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution. </p>\n<p>I first train the model on pseudo labeled data and then finish up with low lr 3 epoch and an lr scheduler with a decaying rate (1,0.5,0.25) for each epoch, no warmup.</p>\n<p>2 cycles improved my public to 0.448: <strong>0.453 -&gt; 0.450 -&gt; 0.448</strong><br>\n<strong>yet private still stayed at ~0.461</strong></p>\n<p>I then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with <strong>0.448 on public and 0.449 on private</strong></p>\n<p>ensemble of a Roberta-large and a Deberta-large: <strong>0.442 on public, 0.448 on private</strong></p>\n<p>Another model trained with a further cycle labeled with 0.442 public was added to the blend and got <strong>0.442/0.447 on public/private</strong>. This is the best scoring out of the two I selected.</p>\n<p>Best private was <strong>0.446</strong>, which I did not select because it didn't improve public LB. (I turned my eyes away from cv long ago) <br>\nThe difference of this one to the 0.447 private is the third model. The new model is trained with training data mixed into pseudo labeled extra data. The train data however, was relabeled and mixed with the original train data with weight of 0.5. I tested 0.8 and 1 but 0.5 performed the best.</p>\n<h2>what I wish I had time to do:</h2>\n<ul>\n<li>ensembling techniques, In my solution I only used simple average as I didn't have time to explore ensembling techniques</li>\n<li>better pseudo-label pipeline. I only tried a few variants and I believe some are always better than others </li>\n<li>pairwise comparison model which simply outputs which text is easier to read to generate raw data for Bradley-Terry algorithm, convert it to target score using Bradley-Terry algorithm, and then maybe recalibrate to competition training data distribution. (This might be a wild-goose chase, but seems like a very promising one to me)</li>\n</ul>\n<h2>hardware:</h2>\n<p>1080ti at the beginning of the competition <br>\nbought a 3090 when switching to large models</p>\n<h2>tl;dr:</h2>\n<p>what worked:</p>\n<ul>\n<li>3 group decaying lr for encoder</li>\n<li>simple attention head</li>\n<li>separate lr for head</li>\n<li>multi-sample dropout</li>\n<li>weighted average of hidden layers</li>\n<li>early stop</li>\n<li>fold specific pseudo-label</li>\n<li>Deberta-large</li>\n</ul>\n<p>code: <a href=\"https://github.com/Danielhuxc/CLRP-solution\" target=\"_blank\">https://github.com/Danielhuxc/CLRP-solution</a><br>\nnotebook: <a href=\"https://www.kaggle.com/potatoc5/final-sub\" target=\"_blank\">https://www.kaggle.com/potatoc5/final-sub</a></p>\n<p>PS: I am looking for ML/DL job (preferably within Canada), please DM me if you would like to get in touch.</p>",
  "comments": [
    {
      "id": 1433554,
      "author_name": "عثمان",
      "author_url": "",
      "post_date": "2021-08-03T14:05:50.033000",
      "content": "<blockquote>\n  <p>1080ti at the beginning of the competition<br>\n  bought a 3090 when switching to large models</p>\n</blockquote>\n<p>That's the kind of dedication needed! I'm sure the job will come soon and congratulations on the well deserved strong finish!</p>",
      "votes": 3,
      "replies": []
    },
    {
      "id": 1426853,
      "author_name": "Allohvk",
      "author_url": "",
      "post_date": "2021-08-03T07:56:40.433000",
      "content": "<p>Nice writeup!<br>\nYou forgot to mention you could have ended up with 2 solo golds in your first 3 months of Kaggle if you had not forgotten to submit your entries for Coleridge..<br>\nAnyway a tremendous achievement in such a short span!</p>",
      "votes": 3,
      "replies": [
        {
          "id": 1427168,
          "author_name": "hxcc",
          "author_url": "",
          "post_date": "2021-08-03T08:11:35.250000",
          "content": "<p>Thank you for your kind words! I've learned so much in the past 3 months and a solo gold with a prize is more than I can dream of. I consider myself very lucky already. what a wild journey. </p>",
          "votes": 4,
          "replies": []
        }
      ]
    },
    {
      "id": 1435764,
      "author_name": "Chris Deotte",
      "author_url": "",
      "post_date": "2021-08-03T14:49:59.037000",
      "content": "<p>Very impressive solution. I like how you did so well with few models. Awesome! Congrats on strong solo finish!</p>\n<p>I particularly like your cycles of pseudo labeling. Great stuff</p>",
      "votes": 4,
      "replies": []
    },
    {
      "id": 1429795,
      "author_name": "Miguel González González",
      "author_url": "",
      "post_date": "2021-08-03T10:59:26.597000",
      "content": "<p>Thanks for sharing! Apparently pseudo labelling extra data was quite helpful from what I'm reading in the forum solutions. Lesson learned!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1426184,
      "author_name": "Salim Khazem",
      "author_url": "",
      "post_date": "2021-08-03T07:21:54.993000",
      "content": "<p>Great job, very nice performance Congratulation, Thanks for sharing ! <br>\nGood luck for your job search ! </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1426187,
      "author_name": "Salim Khazem",
      "author_url": "",
      "post_date": "2021-08-03T07:21:54.993000",
      "content": "<p>Great job, very nice performance Congratulation, Thanks for sharing ! <br>\nGood luck for your job search ! </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2034908,
      "author_name": "Feng Qilong",
      "author_url": "",
      "post_date": "2022-11-18T13:50:15.663000",
      "content": "<p>Hi, as I was reading your code, I realised that u pretrained a MLM with the training data before fine tuning, will this cause leakage? As the model had already seen the data, when fine-tuning, wouldnt cv be unreliable?</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1507499,
      "author_name": "LuzhangCV",
      "author_url": "",
      "post_date": "2021-09-09T09:00:13.150000",
      "content": "<p>First of all, I congratulate you on winning the gold medal. I am a novice at bert. I am participating in a text classification competition. I intend to reuse your skills, but I don’t know how to adjust the parameters properly. My f1-score has risen slightly, and the loss is also It is rising, and finally the loss continues to rise, but the f1-score is constantly oscillating.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1489160,
      "author_name": "Abdur Rehman",
      "author_url": "",
      "post_date": "2021-08-24T18:43:32.830000",
      "content": "<p><a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> congrats. Very nice solution. Can you explain a bit about your <code>lr_schedulers('custom' and '3stage')</code> and how you come up with these schedulers with specific configurations? Can you share some resources or research papers that led you to design schedulers in this way? </p>",
      "votes": 0,
      "replies": [
        {
          "id": 1490801,
          "author_name": "hxcc",
          "author_url": "",
          "post_date": "2021-08-25T21:44:22.093000",
          "content": "<p>There might be some paper out there about lr schedule but I did not follow one. I tuned the lr scheduler by experimenting with different settings and kept the one that's learning the fastest (faster decrease of val loss) with the least amount of data. Stability of val loss is also important.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1457091,
      "author_name": "Shibata",
      "author_url": "",
      "post_date": "2021-08-07T08:21:04.787000",
      "content": "<p><a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> Thank you for sharing this great solution. I learned a lot from this. I was very surprised to see 3 stage learning rate is so effective in this competition👀</p>\n<p>I too tried to pseudo labelling to Simple/English Wikipedia data and experienced low CV score (CV:0.445, LB:0.456). I assume this is caused by leakage you mentioned in this thread.<br>\nPlease let me know your CV/LB difference before/after below processing.</p>\n<blockquote>\n  <p>Using all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution.</p>\n</blockquote>\n<p>Moreover, I would like to know how you decided the weights of your weighted average of all BERT's layers.<br>\nThanks in advance !!</p>",
      "votes": 0,
      "replies": [
        {
          "id": 1457275,
          "author_name": "hxcc",
          "author_url": "",
          "post_date": "2021-08-07T10:31:35.733000",
          "content": "<p>Before/after fold specific pseudo label:</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>CV</th>\n<th>Private</th>\n<th>Public</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Before</td>\n<td>449</td>\n<td>457</td>\n<td>456</td>\n</tr>\n<tr>\n<td>After</td>\n<td>479</td>\n<td>458</td>\n<td>450</td>\n</tr>\n</tbody>\n</table>\n<p>Looking back at it, it did not help in generalization to private LB. Instead, it might have learned more biases from each fold than generalizable knowledge. If you want to use this method, I'd suggest you do your own testing. And if you ever do, I'd appreciate it if you share the result with me.</p>\n<p>As for weights for hidden layers, I set them as parameters and have the model learn them during training. I learned this from <a href=\"https://www.kaggle.com/c/google-quest-challenge/discussion/129840\" target=\"_blank\">google quest 1st solution</a> as well.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1450875,
      "author_name": "Frank",
      "author_url": "",
      "post_date": "2021-08-05T07:47:48.967000",
      "content": "<p>Great job with the solo gold! <a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> </p>\n<p>How did you set <code>3 group decaying lr</code> for large models? Did you use a uniform strategy or tune it for each model?<br>\nAnd how did you set the <code>3 stage lr schedule</code>? Thanks.</p>",
      "votes": 0,
      "replies": [
        {
          "id": 1451038,
          "author_name": "hxcc",
          "author_url": "",
          "post_date": "2021-08-05T08:44:14.993000",
          "content": "<p>Thank you! For 3 group decaying lr I tuned a single parameter decay_rate/layer on base model. When used on large models I use the square root of it to maintain the relative lr ratio between groups. 3 stage lr schedule is made by eyeballing validation loss, while it should be different for every data-model combination I find my schedule work reasonably well for all models I used. The only graph in the original post is a full cycle of my lr scheduler. </p>",
          "votes": 2,
          "replies": []
        }
      ]
    },
    {
      "id": 1449712,
      "author_name": "HinePo",
      "author_url": "",
      "post_date": "2021-08-05T00:14:03.973000",
      "content": "<p>Thanks for letting us know your path and how you got so many improvements. In this comp I also decided to trust LB, and even so it was very hard and tricky to select only two submissions.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1443040,
      "author_name": "takuoko",
      "author_url": "",
      "post_date": "2021-08-04T01:30:53.647000",
      "content": "<p>Congrats! Thank you for your amazing writeup.<br>\nI have a question.</p>\n<blockquote>\n  <p>I then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with 0.448 on public and 0.449 on private</p>\n</blockquote>\n<p>In this part, are you doing relabel for train data or external data?</p>",
      "votes": 0,
      "replies": [
        {
          "id": 1443161,
          "author_name": "hxcc",
          "author_url": "",
          "post_date": "2021-08-04T01:57:25.720000",
          "content": "<p>Thank you for your question. In the part you quoted I relabeled external data only, however, I did make an attempt to relabel train data in the last day and it did boost my private to 0.446. I've updated the details about 0.446 private in the original post. I did not have the time to pursue this path but I think with a proper pipeline single model performance could be further boosted.</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1428669,
      "author_name": "",
      "author_url": "",
      "post_date": "2021-08-03T09:41:55.947000",
      "content": "",
      "votes": 1,
      "replies": []
    }
  ],
  "comment_count": 19,
  "messages": [
    {
      "id": 1425582,
      "postDate": "2021-08-03T06:55:49.757Z",
      "content": "<h3>update</h3>\n<p>Sept 10, 2021 - added link to submission notebook<br>\nAug 16, 2021 - added code link</p>\n<h3><strong>tl;dr at the bottom</strong></h3>\n<p>First, I would like to thank Kaggle and CommonLit for hosting this competition and the community here at Kaggle for making this platform a wonderful place to learn. This is my second competition at Kaggle, with the first one being the Coleridge Initiative; I have to say the past three months or so has been a tremendous journey. If anyone told me three months ago that I would end up in 3rd place in a Kaggle competition, I would not believe it. None of this would be possible without Kaggle and its incredible community.</p>\n<p>Special thanks to:<br>\n<a href=\"https://www.kaggle.com/rhtsingh\" target=\"_blank\">@rhtsingh</a> for sharing so many great notebooks with detailed and excellent explanations. Those notebooks guided my first few weeks in this competition. <br>\n<a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a> for sharing a simple yet elegant solution. Some parts of my final model are from his approach.</p>\n<h2>Analysis of the objective</h2>\n<p>Before I go over my approach, I'd like to share my point of view on the competition objective. Please correct me if what I say is wrong or doesn't make sense to you.<br>\nThis competition is characterized by small training data and noisy, non-intuitive to understand target values. The target is generated by the Bradley-Terry algorithm from a relatively small number of pair-wise comparison data. From my intuition, Bradley-Terry acts like an Elo rating system where match results are translated to raw numbers representing the \"strength\" of each player. (again, this could be wrong and is merely my point of view) In this competition, the texts are players, and the \"strength\" is \"easiness to read,\" where an easier-to-read text would score higher. <br>\nTraining data + public/private data nets to little less than 5k samples, and each sample is compared with others 46.47 times on average. That means each text was compared to only ~1% of the entire dataset on average. Imagine a chess player's Elo where the player has only played against 1% of the whole chess player population, and the opponents are selected at random. I believe most of the noise is due to the small number of comparisons. <br>\nThe objective of the competition is to predict where an arbitrary text would land on that leaderboard generated from 5k texts.</p>\n<h2>Path to public LB 0.442:</h2>\n<p>I've played with Roberta base mostly at the beginning of the competition, and with a gru+multihead attention on the last hidden layer + learning rate decay, I was able to get <strong>~0.473 on both public and private LB.</strong><br>\nI then switched to large and with the same setup I was at around <strong>0.465-0.467 on both public and private LB.</strong><br>\nAfter which I learned from <a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a>'s notebook and incorporated 3 group lr decay, simple attention head, and validation step policy into my solution<br>\nRoberta-large + simple attention head + learning rate decay: <strong>0.462 on both LB</strong></p>\n<p>0.462 + weighted average of all layers and multisample dropout (from google quest #1 solution) + separate lr for head: **0.459 on public **<br>\n0.459 + a 3 stage lr schedule: <strong>0.454 on public</strong><br>\n<img src=\"https://i.ibb.co/fNjh6pc/LR.png\" alt=\"custom schedule\"><br>\n0.454 + early stop at the beginning of 3rd epoch: <strong>0.453 on public</strong><br>\nHowever, <strong>the private did not agree with the improvement to 0.453</strong>, which I didn't know at the time. <strong>Private LB stayed at ~0.461</strong><br>\nAn ensemble of 2 Roberta large and a Roberta base trained this way, however, got <strong>0.454 on public</strong> and <strong>0.456 on private</strong>. </p>\n<p>I then used two of my 0.453 public models to label extra data consists of simple wiki dump, children's book test, and OneStopEnglishCropus.<br>\nUsing all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution. </p>\n<p>I first train the model on pseudo labeled data and then finish up with low lr 3 epoch and an lr scheduler with a decaying rate (1,0.5,0.25) for each epoch, no warmup.</p>\n<p>2 cycles improved my public to 0.448: <strong>0.453 -&gt; 0.450 -&gt; 0.448</strong><br>\n<strong>yet private still stayed at ~0.461</strong></p>\n<p>I then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with <strong>0.448 on public and 0.449 on private</strong></p>\n<p>ensemble of a Roberta-large and a Deberta-large: <strong>0.442 on public, 0.448 on private</strong></p>\n<p>Another model trained with a further cycle labeled with 0.442 public was added to the blend and got <strong>0.442/0.447 on public/private</strong>. This is the best scoring out of the two I selected.</p>\n<p>Best private was <strong>0.446</strong>, which I did not select because it didn't improve public LB. (I turned my eyes away from cv long ago) <br>\nThe difference of this one to the 0.447 private is the third model. The new model is trained with training data mixed into pseudo labeled extra data. The train data however, was relabeled and mixed with the original train data with weight of 0.5. I tested 0.8 and 1 but 0.5 performed the best.</p>\n<h2>what I wish I had time to do:</h2>\n<ul>\n<li>ensembling techniques, In my solution I only used simple average as I didn't have time to explore ensembling techniques</li>\n<li>better pseudo-label pipeline. I only tried a few variants and I believe some are always better than others </li>\n<li>pairwise comparison model which simply outputs which text is easier to read to generate raw data for Bradley-Terry algorithm, convert it to target score using Bradley-Terry algorithm, and then maybe recalibrate to competition training data distribution. (This might be a wild-goose chase, but seems like a very promising one to me)</li>\n</ul>\n<h2>hardware:</h2>\n<p>1080ti at the beginning of the competition <br>\nbought a 3090 when switching to large models</p>\n<h2>tl;dr:</h2>\n<p>what worked:</p>\n<ul>\n<li>3 group decaying lr for encoder</li>\n<li>simple attention head</li>\n<li>separate lr for head</li>\n<li>multi-sample dropout</li>\n<li>weighted average of hidden layers</li>\n<li>early stop</li>\n<li>fold specific pseudo-label</li>\n<li>Deberta-large</li>\n</ul>\n<p>code: <a href=\"https://github.com/Danielhuxc/CLRP-solution\" target=\"_blank\">https://github.com/Danielhuxc/CLRP-solution</a><br>\nnotebook: <a href=\"https://www.kaggle.com/potatoc5/final-sub\" target=\"_blank\">https://www.kaggle.com/potatoc5/final-sub</a></p>\n<p>PS: I am looking for ML/DL job (preferably within Canada), please DM me if you would like to get in touch.</p>",
      "rawMarkdown": "### update\nSept 10, 2021 - added link to submission notebook\nAug 16, 2021 - added code link\n\n###**tl;dr at the bottom**\n\nFirst, I would like to thank Kaggle and CommonLit for hosting this competition and the community here at Kaggle for making this platform a wonderful place to learn. This is my second competition at Kaggle, with the first one being the Coleridge Initiative; I have to say the past three months or so has been a tremendous journey. If anyone told me three months ago that I would end up in 3rd place in a Kaggle competition, I would not believe it. None of this would be possible without Kaggle and its incredible community.\n\nSpecial thanks to:\n@rhtsingh for sharing so many great notebooks with detailed and excellent explanations. Those notebooks guided my first few weeks in this competition. \n@andretugan for sharing a simple yet elegant solution. Some parts of my final model are from his approach.\n\n## Analysis of the objective\nBefore I go over my approach, I'd like to share my point of view on the competition objective. Please correct me if what I say is wrong or doesn't make sense to you.\nThis competition is characterized by small training data and noisy, non-intuitive to understand target values. The target is generated by the Bradley-Terry algorithm from a relatively small number of pair-wise comparison data. From my intuition, Bradley-Terry acts like an Elo rating system where match results are translated to raw numbers representing the \"strength\" of each player. (again, this could be wrong and is merely my point of view) In this competition, the texts are players, and the \"strength\" is \"easiness to read,\" where an easier-to-read text would score higher. \nTraining data + public/private data nets to little less than 5k samples, and each sample is compared with others 46.47 times on average. That means each text was compared to only ~1% of the entire dataset on average. Imagine a chess player's Elo where the player has only played against 1% of the whole chess player population, and the opponents are selected at random. I believe most of the noise is due to the small number of comparisons. \nThe objective of the competition is to predict where an arbitrary text would land on that leaderboard generated from 5k texts.\n\n##Path to public LB 0.442:\nI've played with Roberta base mostly at the beginning of the competition, and with a gru+multihead attention on the last hidden layer + learning rate decay, I was able to get **~0.473 on both public and private LB.**\nI then switched to large and with the same setup I was at around **0.465-0.467 on both public and private LB.**\nAfter which I learned from @andretugan's notebook and incorporated 3 group lr decay, simple attention head, and validation step policy into my solution\nRoberta-large + simple attention head + learning rate decay: **0.462 on both LB**\n\n0.462 + weighted average of all layers and multisample dropout (from google quest #1 solution) + separate lr for head: **0.459 on public **\n0.459 + a 3 stage lr schedule: **0.454 on public**\n![custom schedule](https://i.ibb.co/fNjh6pc/LR.png)\n0.454 + early stop at the beginning of 3rd epoch: **0.453 on public**\nHowever, **the private did not agree with the improvement to 0.453**, which I didn't know at the time. **Private LB stayed at ~0.461**\nAn ensemble of 2 Roberta large and a Roberta base trained this way, however, got **0.454 on public** and **0.456 on private**. \n\nI then used two of my 0.453 public models to label extra data consists of simple wiki dump, children's book test, and OneStopEnglishCropus.\nUsing all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution. \n\nI first train the model on pseudo labeled data and then finish up with low lr 3 epoch and an lr scheduler with a decaying rate (1,0.5,0.25) for each epoch, no warmup.\n\n2 cycles improved my public to 0.448: **0.453 -> 0.450 -> 0.448**\n**yet private still stayed at ~0.461**\n\nI then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with **0.448 on public and 0.449 on private**\n\nensemble of a Roberta-large and a Deberta-large: **0.442 on public, 0.448 on private**\n\nAnother model trained with a further cycle labeled with 0.442 public was added to the blend and got **0.442/0.447 on public/private**. This is the best scoring out of the two I selected.\n\nBest private was **0.446**, which I did not select because it didn't improve public LB. (I turned my eyes away from cv long ago) \nThe difference of this one to the 0.447 private is the third model. The new model is trained with training data mixed into pseudo labeled extra data. The train data however, was relabeled and mixed with the original train data with weight of 0.5. I tested 0.8 and 1 but 0.5 performed the best.\n\n##what I wish I had time to do:\n- ensembling techniques, In my solution I only used simple average as I didn't have time to explore ensembling techniques\n- better pseudo-label pipeline. I only tried a few variants and I believe some are always better than others \n- pairwise comparison model which simply outputs which text is easier to read to generate raw data for Bradley-Terry algorithm, convert it to target score using Bradley-Terry algorithm, and then maybe recalibrate to competition training data distribution. (This might be a wild-goose chase, but seems like a very promising one to me)\n\n##hardware:\n1080ti at the beginning of the competition \nbought a 3090 when switching to large models\n\n##tl;dr:\nwhat worked:\n- 3 group decaying lr for encoder\n- simple attention head\n- separate lr for head\n- multi-sample dropout\n- weighted average of hidden layers\n- early stop\n- fold specific pseudo-label\n- Deberta-large\n\ncode: https://github.com/Danielhuxc/CLRP-solution\nnotebook: https://www.kaggle.com/potatoc5/final-sub\n\nPS: I am looking for ML/DL job (preferably within Canada), please DM me if you would like to get in touch.",
      "votes": 111
    },
    {
      "id": 1433554,
      "postDate": "2021-08-03T14:05:50.033Z",
      "content": "<blockquote>\n  <p>1080ti at the beginning of the competition<br>\n  bought a 3090 when switching to large models</p>\n</blockquote>\n<p>That's the kind of dedication needed! I'm sure the job will come soon and congratulations on the well deserved strong finish!</p>",
      "rawMarkdown": "> 1080ti at the beginning of the competition\nbought a 3090 when switching to large models\n\nThat's the kind of dedication needed! I'm sure the job will come soon and congratulations on the well deserved strong finish!",
      "votes": 3
    },
    {
      "id": 1426853,
      "postDate": "2021-08-03T07:56:40.433Z",
      "content": "<p>Nice writeup!<br>\nYou forgot to mention you could have ended up with 2 solo golds in your first 3 months of Kaggle if you had not forgotten to submit your entries for Coleridge..<br>\nAnyway a tremendous achievement in such a short span!</p>",
      "rawMarkdown": "Nice writeup!\nYou forgot to mention you could have ended up with 2 solo golds in your first 3 months of Kaggle if you had not forgotten to submit your entries for Coleridge..\nAnyway a tremendous achievement in such a short span!",
      "votes": 3,
      "replies": [
        {
          "id": 1427168,
          "postDate": "2021-08-03T08:11:35.250Z",
          "content": "<p>Thank you for your kind words! I've learned so much in the past 3 months and a solo gold with a prize is more than I can dream of. I consider myself very lucky already. what a wild journey. </p>",
          "rawMarkdown": "Thank you for your kind words! I've learned so much in the past 3 months and a solo gold with a prize is more than I can dream of. I consider myself very lucky already. what a wild journey. ",
          "votes": 4
        }
      ]
    },
    {
      "id": 1435764,
      "postDate": "2021-08-03T14:49:59.037Z",
      "content": "<p>Very impressive solution. I like how you did so well with few models. Awesome! Congrats on strong solo finish!</p>\n<p>I particularly like your cycles of pseudo labeling. Great stuff</p>",
      "rawMarkdown": "Very impressive solution. I like how you did so well with few models. Awesome! Congrats on strong solo finish!\n\nI particularly like your cycles of pseudo labeling. Great stuff",
      "votes": 4
    },
    {
      "id": 1429795,
      "postDate": "2021-08-03T10:59:26.597Z",
      "content": "<p>Thanks for sharing! Apparently pseudo labelling extra data was quite helpful from what I'm reading in the forum solutions. Lesson learned!</p>",
      "rawMarkdown": "Thanks for sharing! Apparently pseudo labelling extra data was quite helpful from what I'm reading in the forum solutions. Lesson learned!",
      "votes": 1
    },
    {
      "id": 1426184,
      "postDate": "2021-08-03T07:21:54.993Z",
      "content": "<p>Great job, very nice performance Congratulation, Thanks for sharing ! <br>\nGood luck for your job search ! </p>",
      "rawMarkdown": "Great job, very nice performance Congratulation, Thanks for sharing ! \nGood luck for your job search ! ",
      "votes": 1
    },
    {
      "id": 1426187,
      "postDate": "2021-08-03T07:21:54.993Z",
      "content": "<p>Great job, very nice performance Congratulation, Thanks for sharing ! <br>\nGood luck for your job search ! </p>",
      "rawMarkdown": "Great job, very nice performance Congratulation, Thanks for sharing ! \nGood luck for your job search ! ",
      "votes": 1
    },
    {
      "id": 2034908,
      "postDate": "2022-11-18T13:50:15.663Z",
      "content": "<p>Hi, as I was reading your code, I realised that u pretrained a MLM with the training data before fine tuning, will this cause leakage? As the model had already seen the data, when fine-tuning, wouldnt cv be unreliable?</p>",
      "rawMarkdown": "Hi, as I was reading your code, I realised that u pretrained a MLM with the training data before fine tuning, will this cause leakage? As the model had already seen the data, when fine-tuning, wouldnt cv be unreliable?"
    },
    {
      "id": 1507499,
      "postDate": "2021-09-09T09:00:13.150Z",
      "content": "<p>First of all, I congratulate you on winning the gold medal. I am a novice at bert. I am participating in a text classification competition. I intend to reuse your skills, but I don’t know how to adjust the parameters properly. My f1-score has risen slightly, and the loss is also It is rising, and finally the loss continues to rise, but the f1-score is constantly oscillating.</p>",
      "rawMarkdown": "First of all, I congratulate you on winning the gold medal. I am a novice at bert. I am participating in a text classification competition. I intend to reuse your skills, but I don’t know how to adjust the parameters properly. My f1-score has risen slightly, and the loss is also It is rising, and finally the loss continues to rise, but the f1-score is constantly oscillating."
    },
    {
      "id": 1489160,
      "postDate": "2021-08-24T18:43:32.830Z",
      "content": "<p><a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> congrats. Very nice solution. Can you explain a bit about your <code>lr_schedulers('custom' and '3stage')</code> and how you come up with these schedulers with specific configurations? Can you share some resources or research papers that led you to design schedulers in this way? </p>",
      "rawMarkdown": "@potatoc5 congrats. Very nice solution. Can you explain a bit about your `lr_schedulers('custom' and '3stage')` and how you come up with these schedulers with specific configurations? Can you share some resources or research papers that led you to design schedulers in this way? ",
      "replies": [
        {
          "id": 1490801,
          "postDate": "2021-08-25T21:44:22.093Z",
          "content": "<p>There might be some paper out there about lr schedule but I did not follow one. I tuned the lr scheduler by experimenting with different settings and kept the one that's learning the fastest (faster decrease of val loss) with the least amount of data. Stability of val loss is also important.</p>",
          "rawMarkdown": "There might be some paper out there about lr schedule but I did not follow one. I tuned the lr scheduler by experimenting with different settings and kept the one that's learning the fastest (faster decrease of val loss) with the least amount of data. Stability of val loss is also important."
        }
      ]
    },
    {
      "id": 1457091,
      "postDate": "2021-08-07T08:21:04.787Z",
      "content": "<p><a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> Thank you for sharing this great solution. I learned a lot from this. I was very surprised to see 3 stage learning rate is so effective in this competition👀</p>\n<p>I too tried to pseudo labelling to Simple/English Wikipedia data and experienced low CV score (CV:0.445, LB:0.456). I assume this is caused by leakage you mentioned in this thread.<br>\nPlease let me know your CV/LB difference before/after below processing.</p>\n<blockquote>\n  <p>Using all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution.</p>\n</blockquote>\n<p>Moreover, I would like to know how you decided the weights of your weighted average of all BERT's layers.<br>\nThanks in advance !!</p>",
      "rawMarkdown": "@potatoc5 Thank you for sharing this great solution. I learned a lot from this. I was very surprised to see 3 stage learning rate is so effective in this competition👀\n\nI too tried to pseudo labelling to Simple/English Wikipedia data and experienced low CV score (CV:0.445, LB:0.456). I assume this is caused by leakage you mentioned in this thread.\nPlease let me know your CV/LB difference before/after below processing.\n> Using all folds to label lead to unrealistic low cv (due to leak) and no improvement to LB, so I used 5 fold pseudo label described in google quest #1 solution.\n\nMoreover, I would like to know how you decided the weights of your weighted average of all BERT's layers.\nThanks in advance !!",
      "replies": [
        {
          "id": 1457275,
          "postDate": "2021-08-07T10:31:35.733Z",
          "content": "<p>Before/after fold specific pseudo label:</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>CV</th>\n<th>Private</th>\n<th>Public</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Before</td>\n<td>449</td>\n<td>457</td>\n<td>456</td>\n</tr>\n<tr>\n<td>After</td>\n<td>479</td>\n<td>458</td>\n<td>450</td>\n</tr>\n</tbody>\n</table>\n<p>Looking back at it, it did not help in generalization to private LB. Instead, it might have learned more biases from each fold than generalizable knowledge. If you want to use this method, I'd suggest you do your own testing. And if you ever do, I'd appreciate it if you share the result with me.</p>\n<p>As for weights for hidden layers, I set them as parameters and have the model learn them during training. I learned this from <a href=\"https://www.kaggle.com/c/google-quest-challenge/discussion/129840\" target=\"_blank\">google quest 1st solution</a> as well.</p>",
          "rawMarkdown": "Before/after fold specific pseudo label:\n|  | CV | Private | Public |\n| --- | --- |\n| Before | 449 | 457 | 456 |\n| After | 479 | 458 | 450 |\n\nLooking back at it, it did not help in generalization to private LB. Instead, it might have learned more biases from each fold than generalizable knowledge. If you want to use this method, I'd suggest you do your own testing. And if you ever do, I'd appreciate it if you share the result with me.\n\nAs for weights for hidden layers, I set them as parameters and have the model learn them during training. I learned this from [google quest 1st solution](https://www.kaggle.com/c/google-quest-challenge/discussion/129840) as well."
        }
      ]
    },
    {
      "id": 1450875,
      "postDate": "2021-08-05T07:47:48.967Z",
      "content": "<p>Great job with the solo gold! <a href=\"https://www.kaggle.com/potatoc5\" target=\"_blank\">@potatoc5</a> </p>\n<p>How did you set <code>3 group decaying lr</code> for large models? Did you use a uniform strategy or tune it for each model?<br>\nAnd how did you set the <code>3 stage lr schedule</code>? Thanks.</p>",
      "rawMarkdown": "Great job with the solo gold! @potatoc5 \n\nHow did you set `3 group decaying lr` for large models? Did you use a uniform strategy or tune it for each model?\nAnd how did you set the `3 stage lr schedule`? Thanks.",
      "replies": [
        {
          "id": 1451038,
          "postDate": "2021-08-05T08:44:14.993Z",
          "content": "<p>Thank you! For 3 group decaying lr I tuned a single parameter decay_rate/layer on base model. When used on large models I use the square root of it to maintain the relative lr ratio between groups. 3 stage lr schedule is made by eyeballing validation loss, while it should be different for every data-model combination I find my schedule work reasonably well for all models I used. The only graph in the original post is a full cycle of my lr scheduler. </p>",
          "rawMarkdown": "Thank you! For 3 group decaying lr I tuned a single parameter decay_rate/layer on base model. When used on large models I use the square root of it to maintain the relative lr ratio between groups. 3 stage lr schedule is made by eyeballing validation loss, while it should be different for every data-model combination I find my schedule work reasonably well for all models I used. The only graph in the original post is a full cycle of my lr scheduler. ",
          "votes": 2
        }
      ]
    },
    {
      "id": 1449712,
      "postDate": "2021-08-05T00:14:03.973Z",
      "content": "<p>Thanks for letting us know your path and how you got so many improvements. In this comp I also decided to trust LB, and even so it was very hard and tricky to select only two submissions.</p>",
      "rawMarkdown": "Thanks for letting us know your path and how you got so many improvements. In this comp I also decided to trust LB, and even so it was very hard and tricky to select only two submissions."
    },
    {
      "id": 1443040,
      "postDate": "2021-08-04T01:30:53.647Z",
      "content": "<p>Congrats! Thank you for your amazing writeup.<br>\nI have a question.</p>\n<blockquote>\n  <p>I then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with 0.448 on public and 0.449 on private</p>\n</blockquote>\n<p>In this part, are you doing relabel for train data or external data?</p>",
      "rawMarkdown": "Congrats! Thank you for your amazing writeup.\nI have a question.\n\n>I then used the average of two 0.448 models to label the data again and used that data to train a Deberta-large; Deberta ends up with 0.448 on public and 0.449 on private\n\nIn this part, are you doing relabel for train data or external data?\n",
      "replies": [
        {
          "id": 1443161,
          "postDate": "2021-08-04T01:57:25.720Z",
          "content": "<p>Thank you for your question. In the part you quoted I relabeled external data only, however, I did make an attempt to relabel train data in the last day and it did boost my private to 0.446. I've updated the details about 0.446 private in the original post. I did not have the time to pursue this path but I think with a proper pipeline single model performance could be further boosted.</p>",
          "rawMarkdown": "Thank you for your question. In the part you quoted I relabeled external data only, however, I did make an attempt to relabel train data in the last day and it did boost my private to 0.446. I've updated the details about 0.446 private in the original post. I did not have the time to pursue this path but I think with a proper pipeline single model performance could be further boosted.",
          "votes": 1
        }
      ]
    },
    {
      "id": 1428669,
      "postDate": "2021-08-03T09:41:55.947Z",
      "rawMarkdown": "",
      "votes": 1,
      "isDeleted": true
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T23:46:24Z",
  "competition_id": 25914,
  "competition_slug": "commonlitreadabilityprize",
  "team_id": 6925863,
  "solution_url": "/competitions/commonlitreadabilityprize/writeups/hxcc-3rd-place-solution-0-447-private-3-models-sim"
}