{
  "id": 446712,
  "title": "8th place solution",
  "content": "<h1>Submission Overview</h1>\n<p>I split the data into 4 folds on <code>prompt_id</code> and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data. My final submission is 6x deberta-v3-large: 2 models with different random seeds from each of my top 3 experiments. I took the unweighted mean of the 6 models' predictions.</p>\n<h1>Source code</h1>\n<p>I mostly work in Python scripts rather than notebooks. Here's a repo containing a package for running my training and inference scripts: <a href=\"https://github.com/AMontgomerie/commonlit-summaries-competition\" target=\"_blank\">https://github.com/AMontgomerie/commonlit-summaries-competition</a></p>\n<h1>Inputs and max length</h1>\n<p>In addition to using the summary text, I found that using the <code>prompt_question</code> improved the score slightly, and using the <code>prompt_text</code> helped quite a bit, assuming that the max length was also increased. Increasing the max length only helped up to 1024 tokens for training, although increasing up to 1536 during inference improved both CV (on prompt <code>ebad26</code>) and LB scores.</p>\n<p>It was hard to tell if increasing beyond 1536 was worth it as none of the prompts in the training set were long enough, and I didn't get any consistent improvements from the LB when increasing to 2048 either.</p>\n<h1>Special tokens</h1>\n<p>Another thing that helped was adding a special token for each section of the input rather than using <code>[SEP]</code>. I added <code>&lt;text&gt;</code>, <code>&lt;question&gt;</code>, and <code>&lt;summary&gt;</code> tokens to the tokenizer before training, and then fine-tuned them. Inputs took the format:</p>\n<pre><code>\"&lt;question&gt; The prompt question text here. &lt;&gt; The student  text here. &lt;text&gt; The original prompt text here.\"\n</code></pre>\n<p>I put the prompt text last to account for extremely long texts that would need to be truncated.</p>\n<p>I did also try adding the prompt title and a <code>&lt;title&gt;</code> token, but this didn't improve CV.</p>\n<h1>Inference</h1>\n<p>Earlier in the competition I was submitting the mean of the 4 models trained in each experiment. However after I started increasing the max length up to and beyond 1024 tokens, I found that inference time increased quite significantly. It took about an hour to run inference with 1 deberta-v3-large at 1024 token max length, and about 1.5 hours at 1280 or 1536 tokens.</p>\n<p>This means a 4-fold mean would take 6 hours or more at 1536 tokens. To be able to submit a more diverse ensemble I decided to start retraining on 100% of training data instead. I found the LB scores of these 100% models to be fairly consistent with the ones trained on 75% of the data. This allowed me to submit an ensemble of my best 3 CV experiments. I retrained on 100% of training data twice with different random seeds for each of the experiments.</p>\n<h1>GPU resources</h1>\n<p>I don't have access to any dedicated GPUs, and each 4 fold experiment took a long time on Kaggle P100s (particularly when training with long sequence lengths), so I subscribed to Paperspace Gradient which gave me intermittent access to an RTX5000 or an A4000, both of which allowed me to run experiments about 4x faster than running on Kaggle GPUs.</p>\n<p>Since none of these GPUs have more than 16GB of RAM, I was only able to train with a batch size of 1 at max length 1024. To compensate for this, I used gradient accumulation. I initially accumulated gradients for 8 steps per optimizer update, but found that 16 steps worked even better.</p>\n<h1>Dropout</h1>\n<p><a href=\"https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries/discussion/432186\" target=\"_blank\">This thread</a> pointed out that turning off dropout can be useful in regression tasks. I gave this a try and found that turning off dropout in fully-connected layers helped a little, but not in attention layers.</p>\n<h1>Pooling</h1>\n<p>I saw some public notebooks which used mean pooling or GeM pooling, but in my experiments neither of these worked better than the default <a href=\"https://github.com/huggingface/transformers/blob/3e93dd295b5343557a83bc07b0b2ea64c926f9b4/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L56C7-L56C8\" target=\"_blank\">ContextPooler</a> which is built into <code>transformers.DebertaV2ForSequenceClassification</code>.</p>\n<h1>Things which didn't work</h1>\n<p>Here's a list of ideas either by me, or which I  borrowed from public notebooks or discussions, which didn't lead to any noticeable improvement:</p>\n<ul>\n<li>Using <code>prompt_title</code>.</li>\n<li>Freezing embeddings.</li>\n<li>Freezing encoder layers.</li>\n<li>Max, mean, or GeMText pooling.</li>\n<li>Extra attention head.</li>\n<li>MSE, SmoothL1, or (modified) MarginRankingLoss. (I mostly used MCRMSE loss).</li>\n<li>Training separate models to predict content and wording scores.</li>\n<li>Training with max sequence lengths longer than 1024.</li>\n<li>deberta-v2-xlarge with LoRA (even with large alpha).</li>\n<li>Autocorrecting spelling.</li>\n<li>Ensembling with linear models or gradient-boosted regressors with hand-made features. (I didn't spend much time on this, but I tried using some of the features from the high-scoring public notebooks and they didn't seem very useful)</li>\n<li>Using abstractive summarization to reduce the length of the <code>prompt_text</code>. I was able to improve my CV a bit with this, but it significantly hurt my public LB, which was a good warning not to do this. I decided it was too risky, because I wouldn't be able to validate any generated summaries when scoring on the private test data. If the generative model hallucinated even once it could screw up my final LB score.</li>\n</ul>\n<p>I would've liked to have tried extractive summarization as this would prevent the hallucination problem, but I didn't come up with a good way to train a model to rank the most important sentences in each <code>prompt_text</code>. It would've been a fun direction to go down, but probably ultimately a waste of time in comparison to just increasing the max sequence length.</p>",
  "comments": [
    {
      "id": 2480409,
      "author_name": "Jason Heesang Lee",
      "author_url": "",
      "post_date": "2023-10-13T09:51:10.077000",
      "content": "<p>Great solution! I thought giving higher number for max sequence length would help, but seem like it didn't…<br>\nCongratulations!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2479815,
      "author_name": "empty",
      "author_url": "",
      "post_date": "2023-10-12T22:54:08.627000",
      "content": "<p>nice code, added to bookmarks 🌝</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 2479810,
      "author_name": "Oleksiy Kononenko",
      "author_url": "",
      "post_date": "2023-10-12T22:32:03.673000",
      "content": "<p>Thanks for sharing, <a href=\"https://www.kaggle.com/amontgomerie\" target=\"_blank\">@amontgomerie</a>.</p>\n<blockquote>\n  <p>I split the data into 4 folds on prompt_id and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data.</p>\n</blockquote>\n<p>I normally try both approaches and check their LB scores. How did you decide which one to follow? By the size of the training/test data, CV and LB score?</p>",
      "votes": 2,
      "replies": [
        {
          "id": 2480322,
          "author_name": "Adam Montgomerie",
          "author_url": "",
          "post_date": "2023-10-13T08:41:10.613000",
          "content": "<p>The main reason for choosing a single model trained on 100% of training data rather than submitting all folds in this competition was that the long maximum sequence length caused really long inference times, which limited the amount of models I could include in my final ensemble.</p>\n<p>I tried combining the OOF predictions of my best 3 runs, and found that my CV score improved noticeably. However, because I was doing inference with max length 1536, it took at least 90 minutes per model. If I submitted 4 models for each experiment then I would only be able to include one and a half experiments before hitting the inference runtime limit. </p>\n<p>I tried retraining on 100% of training data and submitting single models and found that the LB scores were reasonably in line with what I was expecting. Creating an ensemble of these models allowed me to increase the diversity in my final submission by including models from more different experiments.</p>",
          "votes": 3,
          "replies": [
            {
              "id": 2562139,
              "author_name": "Joseph Zhou",
              "author_url": "",
              "post_date": "2023-12-15T06:19:49.483000",
              "content": "<p><a href=\"https://www.kaggle.com/amontgomerie\" target=\"_blank\">@amontgomerie</a> Hi, could you please tell me how you decided the epochs of the 100% data retraining?</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 2480593,
      "author_name": "",
      "author_url": "",
      "post_date": "2023-10-13T12:26:56.590000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "comment_count": 6,
  "messages": [
    {
      "id": 2479592,
      "postDate": "2023-10-12T18:11:53.690Z",
      "content": "<h1>Submission Overview</h1>\n<p>I split the data into 4 folds on <code>prompt_id</code> and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data. My final submission is 6x deberta-v3-large: 2 models with different random seeds from each of my top 3 experiments. I took the unweighted mean of the 6 models' predictions.</p>\n<h1>Source code</h1>\n<p>I mostly work in Python scripts rather than notebooks. Here's a repo containing a package for running my training and inference scripts: <a href=\"https://github.com/AMontgomerie/commonlit-summaries-competition\" target=\"_blank\">https://github.com/AMontgomerie/commonlit-summaries-competition</a></p>\n<h1>Inputs and max length</h1>\n<p>In addition to using the summary text, I found that using the <code>prompt_question</code> improved the score slightly, and using the <code>prompt_text</code> helped quite a bit, assuming that the max length was also increased. Increasing the max length only helped up to 1024 tokens for training, although increasing up to 1536 during inference improved both CV (on prompt <code>ebad26</code>) and LB scores.</p>\n<p>It was hard to tell if increasing beyond 1536 was worth it as none of the prompts in the training set were long enough, and I didn't get any consistent improvements from the LB when increasing to 2048 either.</p>\n<h1>Special tokens</h1>\n<p>Another thing that helped was adding a special token for each section of the input rather than using <code>[SEP]</code>. I added <code>&lt;text&gt;</code>, <code>&lt;question&gt;</code>, and <code>&lt;summary&gt;</code> tokens to the tokenizer before training, and then fine-tuned them. Inputs took the format:</p>\n<pre><code>\"&lt;question&gt; The prompt question text here. &lt;&gt; The student  text here. &lt;text&gt; The original prompt text here.\"\n</code></pre>\n<p>I put the prompt text last to account for extremely long texts that would need to be truncated.</p>\n<p>I did also try adding the prompt title and a <code>&lt;title&gt;</code> token, but this didn't improve CV.</p>\n<h1>Inference</h1>\n<p>Earlier in the competition I was submitting the mean of the 4 models trained in each experiment. However after I started increasing the max length up to and beyond 1024 tokens, I found that inference time increased quite significantly. It took about an hour to run inference with 1 deberta-v3-large at 1024 token max length, and about 1.5 hours at 1280 or 1536 tokens.</p>\n<p>This means a 4-fold mean would take 6 hours or more at 1536 tokens. To be able to submit a more diverse ensemble I decided to start retraining on 100% of training data instead. I found the LB scores of these 100% models to be fairly consistent with the ones trained on 75% of the data. This allowed me to submit an ensemble of my best 3 CV experiments. I retrained on 100% of training data twice with different random seeds for each of the experiments.</p>\n<h1>GPU resources</h1>\n<p>I don't have access to any dedicated GPUs, and each 4 fold experiment took a long time on Kaggle P100s (particularly when training with long sequence lengths), so I subscribed to Paperspace Gradient which gave me intermittent access to an RTX5000 or an A4000, both of which allowed me to run experiments about 4x faster than running on Kaggle GPUs.</p>\n<p>Since none of these GPUs have more than 16GB of RAM, I was only able to train with a batch size of 1 at max length 1024. To compensate for this, I used gradient accumulation. I initially accumulated gradients for 8 steps per optimizer update, but found that 16 steps worked even better.</p>\n<h1>Dropout</h1>\n<p><a href=\"https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries/discussion/432186\" target=\"_blank\">This thread</a> pointed out that turning off dropout can be useful in regression tasks. I gave this a try and found that turning off dropout in fully-connected layers helped a little, but not in attention layers.</p>\n<h1>Pooling</h1>\n<p>I saw some public notebooks which used mean pooling or GeM pooling, but in my experiments neither of these worked better than the default <a href=\"https://github.com/huggingface/transformers/blob/3e93dd295b5343557a83bc07b0b2ea64c926f9b4/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L56C7-L56C8\" target=\"_blank\">ContextPooler</a> which is built into <code>transformers.DebertaV2ForSequenceClassification</code>.</p>\n<h1>Things which didn't work</h1>\n<p>Here's a list of ideas either by me, or which I  borrowed from public notebooks or discussions, which didn't lead to any noticeable improvement:</p>\n<ul>\n<li>Using <code>prompt_title</code>.</li>\n<li>Freezing embeddings.</li>\n<li>Freezing encoder layers.</li>\n<li>Max, mean, or GeMText pooling.</li>\n<li>Extra attention head.</li>\n<li>MSE, SmoothL1, or (modified) MarginRankingLoss. (I mostly used MCRMSE loss).</li>\n<li>Training separate models to predict content and wording scores.</li>\n<li>Training with max sequence lengths longer than 1024.</li>\n<li>deberta-v2-xlarge with LoRA (even with large alpha).</li>\n<li>Autocorrecting spelling.</li>\n<li>Ensembling with linear models or gradient-boosted regressors with hand-made features. (I didn't spend much time on this, but I tried using some of the features from the high-scoring public notebooks and they didn't seem very useful)</li>\n<li>Using abstractive summarization to reduce the length of the <code>prompt_text</code>. I was able to improve my CV a bit with this, but it significantly hurt my public LB, which was a good warning not to do this. I decided it was too risky, because I wouldn't be able to validate any generated summaries when scoring on the private test data. If the generative model hallucinated even once it could screw up my final LB score.</li>\n</ul>\n<p>I would've liked to have tried extractive summarization as this would prevent the hallucination problem, but I didn't come up with a good way to train a model to rank the most important sentences in each <code>prompt_text</code>. It would've been a fun direction to go down, but probably ultimately a waste of time in comparison to just increasing the max sequence length.</p>",
      "rawMarkdown": "# Submission Overview\nI split the data into 4 folds on `prompt_id` and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data. My final submission is 6x deberta-v3-large: 2 models with different random seeds from each of my top 3 experiments. I took the unweighted mean of the 6 models' predictions.\n\n# Source code\nI mostly work in Python scripts rather than notebooks. Here's a repo containing a package for running my training and inference scripts: https://github.com/AMontgomerie/commonlit-summaries-competition\n\n# Inputs and max length\n\nIn addition to using the summary text, I found that using the `prompt_question` improved the score slightly, and using the `prompt_text` helped quite a bit, assuming that the max length was also increased. Increasing the max length only helped up to 1024 tokens for training, although increasing up to 1536 during inference improved both CV (on prompt `ebad26`) and LB scores.\n\nIt was hard to tell if increasing beyond 1536 was worth it as none of the prompts in the training set were long enough, and I didn't get any consistent improvements from the LB when increasing to 2048 either.\n\n# Special tokens\n\nAnother thing that helped was adding a special token for each section of the input rather than using `[SEP]`. I added `<text>`, `<question>`, and `<summary>` tokens to the tokenizer before training, and then fine-tuned them. Inputs took the format:\n```\n\"<question> The prompt question text here. <summary> The student summary text here. <text> The original prompt text here.\"\n```\nI put the prompt text last to account for extremely long texts that would need to be truncated.\n\nI did also try adding the prompt title and a `<title>` token, but this didn't improve CV.\n\n# Inference\n\nEarlier in the competition I was submitting the mean of the 4 models trained in each experiment. However after I started increasing the max length up to and beyond 1024 tokens, I found that inference time increased quite significantly. It took about an hour to run inference with 1 deberta-v3-large at 1024 token max length, and about 1.5 hours at 1280 or 1536 tokens.\n\nThis means a 4-fold mean would take 6 hours or more at 1536 tokens. To be able to submit a more diverse ensemble I decided to start retraining on 100% of training data instead. I found the LB scores of these 100% models to be fairly consistent with the ones trained on 75% of the data. This allowed me to submit an ensemble of my best 3 CV experiments. I retrained on 100% of training data twice with different random seeds for each of the experiments.\n\n# GPU resources\n\nI don't have access to any dedicated GPUs, and each 4 fold experiment took a long time on Kaggle P100s (particularly when training with long sequence lengths), so I subscribed to Paperspace Gradient which gave me intermittent access to an RTX5000 or an A4000, both of which allowed me to run experiments about 4x faster than running on Kaggle GPUs.\n\nSince none of these GPUs have more than 16GB of RAM, I was only able to train with a batch size of 1 at max length 1024. To compensate for this, I used gradient accumulation. I initially accumulated gradients for 8 steps per optimizer update, but found that 16 steps worked even better.\n\n# Dropout\n\n[This thread](https://www.kaggle.com/competitions/commonlit-evaluate-student-summaries/discussion/432186) pointed out that turning off dropout can be useful in regression tasks. I gave this a try and found that turning off dropout in fully-connected layers helped a little, but not in attention layers.\n\n# Pooling\n\nI saw some public notebooks which used mean pooling or GeM pooling, but in my experiments neither of these worked better than the default [ContextPooler](https://github.com/huggingface/transformers/blob/3e93dd295b5343557a83bc07b0b2ea64c926f9b4/src/transformers/models/deberta_v2/modeling_deberta_v2.py#L56C7-L56C8) which is built into `transformers.DebertaV2ForSequenceClassification`.\n\n# Things which didn't work\n\nHere's a list of ideas either by me, or which I ~~stole~~ borrowed from public notebooks or discussions, which didn't lead to any noticeable improvement:\n\n* Using `prompt_title`.\n* Freezing embeddings.\n* Freezing encoder layers.\n* Max, mean, or GeMText pooling.\n* Extra attention head.\n* MSE, SmoothL1, or (modified) MarginRankingLoss. (I mostly used MCRMSE loss).\n* Training separate models to predict content and wording scores.\n* Training with max sequence lengths longer than 1024.\n* deberta-v2-xlarge with LoRA (even with large alpha).\n* Autocorrecting spelling.\n* Ensembling with linear models or gradient-boosted regressors with hand-made features. (I didn't spend much time on this, but I tried using some of the features from the high-scoring public notebooks and they didn't seem very useful)\n* Using abstractive summarization to reduce the length of the `prompt_text`. I was able to improve my CV a bit with this, but it significantly hurt my public LB, which was a good warning not to do this. I decided it was too risky, because I wouldn't be able to validate any generated summaries when scoring on the private test data. If the generative model hallucinated even once it could screw up my final LB score.\n\nI would've liked to have tried extractive summarization as this would prevent the hallucination problem, but I didn't come up with a good way to train a model to rank the most important sentences in each `prompt_text`. It would've been a fun direction to go down, but probably ultimately a waste of time in comparison to just increasing the max sequence length.",
      "votes": 30
    },
    {
      "id": 2480409,
      "postDate": "2023-10-13T09:51:10.077Z",
      "content": "<p>Great solution! I thought giving higher number for max sequence length would help, but seem like it didn't…<br>\nCongratulations!</p>",
      "rawMarkdown": "Great solution! I thought giving higher number for max sequence length would help, but seem like it didn't...\nCongratulations!",
      "votes": 1
    },
    {
      "id": 2479815,
      "postDate": "2023-10-12T22:54:08.627Z",
      "content": "<p>nice code, added to bookmarks 🌝</p>",
      "rawMarkdown": "nice code, added to bookmarks 🌝",
      "votes": 1
    },
    {
      "id": 2479810,
      "postDate": "2023-10-12T22:32:03.673Z",
      "content": "<p>Thanks for sharing, <a href=\"https://www.kaggle.com/amontgomerie\" target=\"_blank\">@amontgomerie</a>.</p>\n<blockquote>\n  <p>I split the data into 4 folds on prompt_id and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data.</p>\n</blockquote>\n<p>I normally try both approaches and check their LB scores. How did you decide which one to follow? By the size of the training/test data, CV and LB score?</p>",
      "rawMarkdown": "Thanks for sharing, @amontgomerie.\n\n>I split the data into 4 folds on prompt_id and computed a 4-fold CV. Rather than submitting all 4 models for inference, I retrained on 100% of the training data.\n\nI normally try both approaches and check their LB scores. How did you decide which one to follow? By the size of the training/test data, CV and LB score?",
      "votes": 2,
      "replies": [
        {
          "id": 2480322,
          "postDate": "2023-10-13T08:41:10.613Z",
          "content": "<p>The main reason for choosing a single model trained on 100% of training data rather than submitting all folds in this competition was that the long maximum sequence length caused really long inference times, which limited the amount of models I could include in my final ensemble.</p>\n<p>I tried combining the OOF predictions of my best 3 runs, and found that my CV score improved noticeably. However, because I was doing inference with max length 1536, it took at least 90 minutes per model. If I submitted 4 models for each experiment then I would only be able to include one and a half experiments before hitting the inference runtime limit. </p>\n<p>I tried retraining on 100% of training data and submitting single models and found that the LB scores were reasonably in line with what I was expecting. Creating an ensemble of these models allowed me to increase the diversity in my final submission by including models from more different experiments.</p>",
          "rawMarkdown": "The main reason for choosing a single model trained on 100% of training data rather than submitting all folds in this competition was that the long maximum sequence length caused really long inference times, which limited the amount of models I could include in my final ensemble.\n\nI tried combining the OOF predictions of my best 3 runs, and found that my CV score improved noticeably. However, because I was doing inference with max length 1536, it took at least 90 minutes per model. If I submitted 4 models for each experiment then I would only be able to include one and a half experiments before hitting the inference runtime limit. \n\nI tried retraining on 100% of training data and submitting single models and found that the LB scores were reasonably in line with what I was expecting. Creating an ensemble of these models allowed me to increase the diversity in my final submission by including models from more different experiments.",
          "votes": 3,
          "replies": [
            {
              "id": 2562139,
              "postDate": "2023-12-15T06:19:49.483Z",
              "content": "<p><a href=\"https://www.kaggle.com/amontgomerie\" target=\"_blank\">@amontgomerie</a> Hi, could you please tell me how you decided the epochs of the 100% data retraining?</p>",
              "rawMarkdown": "@amontgomerie Hi, could you please tell me how you decided the epochs of the 100% data retraining?"
            }
          ]
        }
      ]
    },
    {
      "id": 2480593,
      "postDate": "2023-10-13T12:26:56.590Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T23:04:51Z",
  "competition_id": 53482,
  "competition_slug": "commonlit-evaluate-student-summaries",
  "team_id": 10726831,
  "solution_url": "/competitions/commonlit-evaluate-student-summaries/writeups/adam-montgomerie-8th-place-solution"
}