{
  "id": 347713,
  "title": "0.577 single model with full code",
  "content": "<p>The first step to achieve this model was to train an mlm on the old dataset. I took all the data from previous feedback competition and fine-tuned deberta-v3-large using <code>run_mlm.py</code> script available in the transformers library. The perplexity in the end was around 4.5. I could have trained more but I didn't.</p>\n<p>Now comes the more interesting part. I was inspired by <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a> 's kernel that showed how we can use token classification for this problem. This was the kernel that piqued my interest in this competition and I decided to give it a go. The idea was simple but effective.</p>\n<p>Essay texts were represented as follows:</p>\n<pre><code>[CLS]some text [CLS_{discourse_type}] some valid discourse text [END_{discourse_type}] ..... [SEP]\n</code></pre>\n<p>Mapping:</p>\n<pre><code>disc_types = [\n    \"Claim\",\n    \"Concluding Statement\",\n    \"Counterclaim\",\n    \"Evidence\",\n    \"Lead\",\n    \"Position\",\n    \"Rebuttal\",\n]\ncls_tokens_map = {label: f\"[CLS_{label.upper()}]\" for label in disc_types}\nend_tokens_map = {label: f\"[END_{label.upper()}]\" for label in disc_types}\n</code></pre>\n<p>I arranged the data as follows:</p>\n<ul>\n<li>Convert the data to old format (I had already made my kernel public for this part)</li>\n<li>For each token, add on <code>O</code> label for discourse types if they are not a valid discourse</li>\n<li>For each token, add -100 as label for discourse effectiveness if they are not a valid discourse</li>\n<li>If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse type id as their label</li>\n<li>If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse effectiveness id as their label</li>\n<li>discourse effectiveness label was kept only for the CLS_{discourse_type} and END_{discourse_type} tokens</li>\n</ul>\n<p>So, now we have for each essay:</p>\n<ul>\n<li>input_ids</li>\n<li>input_types (discourse type ids, one for each input id)</li>\n<li>input_labels (the actual label, most are -100, only start of a discourse and end have an actual label)</li>\n<li>attention_mask</li>\n</ul>\n<p>Now it's time to train a model. I made a crucial change in the model's embedding layer that gave a good lift. The change was to add another embedding layer for discourse_types (input_types) and add the result to the original embeddings:</p>\n<pre><code>class DebertaV2Embeddings(nn.Module):\n    \"\"\"Construct the embeddings from word, position and token_type embeddings.\"\"\"\n\n    def __init__(self, config):\n        super().__init__()\n        pad_token_id = getattr(config, \"pad_token_id\", 0)\n        self.embedding_size = getattr(config, \"embedding_size\", config.hidden_size)\n        self.word_embeddings = nn.Embedding(config.vocab_size, self.embedding_size, padding_idx=pad_token_id)\n        self.disc_type_embeddings = nn.Embedding(9, self.embedding_size)\n        .\n        .\n        .\n\n    def forward(\n        self, input_ids=None, token_type_ids=None, disc_type_ids=None, position_ids=None, mask=None, inputs_embeds=None\n    ):\n        .\n        .\n        if self.config.disc_type_vocab_size &gt; 0:\n            disc_type_embeddings = self.disc_type_embeddings(disc_type_ids)\n            embeddings += disc_type_embeddings\n        .\n        .\n        .\n        return embeddings\n</code></pre>\n<p>Other than all this, I used polynomial learning rate scheduler and AdamW optimizer from pytorch.</p>\n<p>During inference, I just averaged the probabilities for CLS_{discourse_type} and END_{discourse_type} tokens to get the final label.</p>\n<p>That's it. Nothing too complicated to get a good score using a single model (5-fold). Running it with some variations and averaging the models gave us 14th rank on the leaderboard.</p>\n<p>The full code to train and infer is available here: <a href=\"https://www.kaggle.com/code/abhishek/0-577-single-model-full-code\" target=\"_blank\">https://www.kaggle.com/code/abhishek/0-577-single-model-full-code</a></p>\n<p>I used my own library for training the models: tez. Please give it some love here: <a href=\"https://github.com/abhishekkrthakur/tez\" target=\"_blank\">https://github.com/abhishekkrthakur/tez</a></p>\n<p>If you have any questions, please feel free to ask. It was a fun competition and I learnt a lot! :)</p>",
  "comments": [
    {
      "id": 1913246,
      "author_name": "DeepUnderstanding",
      "author_url": "",
      "post_date": "2022-08-25T08:56:02.183000",
      "content": "<p>Can be your next video explaining it😬</p>",
      "votes": 4,
      "replies": [
        {
          "id": 1913365,
          "author_name": "nymfree",
          "author_url": "",
          "post_date": "2022-08-25T09:49:46.780000",
          "content": "<p>+1 on this humble request.</p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 1913414,
          "author_name": "Abhishek Thakur",
          "author_url": "",
          "post_date": "2022-08-25T10:13:04.243000",
          "content": "<p>dunno if this solution is worth a video. there are many more interesting solutions that have been shared here. but ill give it a thought. the only interesting part in my solution is modification of embedding layer in deberta :) </p>",
          "votes": 4,
          "replies": []
        },
        {
          "id": 1913764,
          "author_name": "Ravi Ramakrishnan",
          "author_url": "",
          "post_date": "2022-08-25T13:50:57.623000",
          "content": "<p>Many thanks for the solution, your approaches are a great learning experience for beginners like me to learn and augment our knowledge <a href=\"https://www.kaggle.com/abhishek\" target=\"_blank\">@abhishek</a> !!</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 1914351,
      "author_name": "yukiya",
      "author_url": "",
      "post_date": "2022-08-26T02:56:09.547000",
      "content": "<p>Thank you for sharing. I use your baseline kernel for sentence classification, but I was out of time and couldn't push much. <br>\nCongrats on the neat score with token classification ! <br>\nCan I ask about when you combine embeddings, is there any pros and cons whether you add them up or you concatenate ? </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1913383,
      "author_name": "The Devastator",
      "author_url": "",
      "post_date": "2022-08-25T09:57:22.323000",
      "content": "<p>Impressive work.. Thank you for sharing! </p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1913231,
      "author_name": "gezi",
      "author_url": "",
      "post_date": "2022-08-25T08:44:19.300000",
      "content": "<p>Thanks for sharing, token type embedding is intersting!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 1916803,
      "author_name": "🐳鲲(China)",
      "author_url": "",
      "post_date": "2022-08-28T06:56:02.163000",
      "content": "<p>I checked the run_mlm.py code, as document said perplexity is not well defined for masked language models like BERT, so it may not a good metrics?</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1914448,
      "author_name": "Raja Biswas",
      "author_url": "",
      "post_date": "2022-08-26T05:31:16.470000",
      "content": "<p>Thanks <a href=\"https://www.kaggle.com/abhishek\" target=\"_blank\">@abhishek</a> for sharing the great solution. I think the embedding modification is a really cool idea. I have two queries:</p>\n<ul>\n<li>if you add the discourse type embeddings to tokens, won't it be too easy for the model to predict the auxiliary discourse type target?</li>\n<li>will it be better to use the same modification during mlm training as well?</li>\n</ul>\n<p>Thanks again for the writeup!  </p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1913947,
      "author_name": "Julien Chaumond",
      "author_url": "",
      "post_date": "2022-08-25T15:44:03.250000",
      "content": "<p>Cool explanation, thanks for sharing ❤️</p>",
      "votes": 1,
      "replies": []
    }
  ],
  "comment_count": 10,
  "messages": [
    {
      "id": 1913200,
      "postDate": "2022-08-25T08:09:58.110Z",
      "content": "<p>The first step to achieve this model was to train an mlm on the old dataset. I took all the data from previous feedback competition and fine-tuned deberta-v3-large using <code>run_mlm.py</code> script available in the transformers library. The perplexity in the end was around 4.5. I could have trained more but I didn't.</p>\n<p>Now comes the more interesting part. I was inspired by <a href=\"https://www.kaggle.com/nbroad\" target=\"_blank\">@nbroad</a> 's kernel that showed how we can use token classification for this problem. This was the kernel that piqued my interest in this competition and I decided to give it a go. The idea was simple but effective.</p>\n<p>Essay texts were represented as follows:</p>\n<pre><code>[CLS]some text [CLS_{discourse_type}] some valid discourse text [END_{discourse_type}] ..... [SEP]\n</code></pre>\n<p>Mapping:</p>\n<pre><code>disc_types = [\n    \"Claim\",\n    \"Concluding Statement\",\n    \"Counterclaim\",\n    \"Evidence\",\n    \"Lead\",\n    \"Position\",\n    \"Rebuttal\",\n]\ncls_tokens_map = {label: f\"[CLS_{label.upper()}]\" for label in disc_types}\nend_tokens_map = {label: f\"[END_{label.upper()}]\" for label in disc_types}\n</code></pre>\n<p>I arranged the data as follows:</p>\n<ul>\n<li>Convert the data to old format (I had already made my kernel public for this part)</li>\n<li>For each token, add on <code>O</code> label for discourse types if they are not a valid discourse</li>\n<li>For each token, add -100 as label for discourse effectiveness if they are not a valid discourse</li>\n<li>If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse type id as their label</li>\n<li>If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse effectiveness id as their label</li>\n<li>discourse effectiveness label was kept only for the CLS_{discourse_type} and END_{discourse_type} tokens</li>\n</ul>\n<p>So, now we have for each essay:</p>\n<ul>\n<li>input_ids</li>\n<li>input_types (discourse type ids, one for each input id)</li>\n<li>input_labels (the actual label, most are -100, only start of a discourse and end have an actual label)</li>\n<li>attention_mask</li>\n</ul>\n<p>Now it's time to train a model. I made a crucial change in the model's embedding layer that gave a good lift. The change was to add another embedding layer for discourse_types (input_types) and add the result to the original embeddings:</p>\n<pre><code>class DebertaV2Embeddings(nn.Module):\n    \"\"\"Construct the embeddings from word, position and token_type embeddings.\"\"\"\n\n    def __init__(self, config):\n        super().__init__()\n        pad_token_id = getattr(config, \"pad_token_id\", 0)\n        self.embedding_size = getattr(config, \"embedding_size\", config.hidden_size)\n        self.word_embeddings = nn.Embedding(config.vocab_size, self.embedding_size, padding_idx=pad_token_id)\n        self.disc_type_embeddings = nn.Embedding(9, self.embedding_size)\n        .\n        .\n        .\n\n    def forward(\n        self, input_ids=None, token_type_ids=None, disc_type_ids=None, position_ids=None, mask=None, inputs_embeds=None\n    ):\n        .\n        .\n        if self.config.disc_type_vocab_size &gt; 0:\n            disc_type_embeddings = self.disc_type_embeddings(disc_type_ids)\n            embeddings += disc_type_embeddings\n        .\n        .\n        .\n        return embeddings\n</code></pre>\n<p>Other than all this, I used polynomial learning rate scheduler and AdamW optimizer from pytorch.</p>\n<p>During inference, I just averaged the probabilities for CLS_{discourse_type} and END_{discourse_type} tokens to get the final label.</p>\n<p>That's it. Nothing too complicated to get a good score using a single model (5-fold). Running it with some variations and averaging the models gave us 14th rank on the leaderboard.</p>\n<p>The full code to train and infer is available here: <a href=\"https://www.kaggle.com/code/abhishek/0-577-single-model-full-code\" target=\"_blank\">https://www.kaggle.com/code/abhishek/0-577-single-model-full-code</a></p>\n<p>I used my own library for training the models: tez. Please give it some love here: <a href=\"https://github.com/abhishekkrthakur/tez\" target=\"_blank\">https://github.com/abhishekkrthakur/tez</a></p>\n<p>If you have any questions, please feel free to ask. It was a fun competition and I learnt a lot! :)</p>",
      "rawMarkdown": "The first step to achieve this model was to train an mlm on the old dataset. I took all the data from previous feedback competition and fine-tuned deberta-v3-large using `run_mlm.py` script available in the transformers library. The perplexity in the end was around 4.5. I could have trained more but I didn't.\n\nNow comes the more interesting part. I was inspired by @nbroad 's kernel that showed how we can use token classification for this problem. This was the kernel that piqued my interest in this competition and I decided to give it a go. The idea was simple but effective.\n\nEssay texts were represented as follows:\n\n```\n[CLS]some text [CLS_{discourse_type}] some valid discourse text [END_{discourse_type}] ..... [SEP]\n```\n\nMapping:\n\n```\ndisc_types = [\n    \"Claim\",\n    \"Concluding Statement\",\n    \"Counterclaim\",\n    \"Evidence\",\n    \"Lead\",\n    \"Position\",\n    \"Rebuttal\",\n]\ncls_tokens_map = {label: f\"[CLS_{label.upper()}]\" for label in disc_types}\nend_tokens_map = {label: f\"[END_{label.upper()}]\" for label in disc_types}\n```\n\nI arranged the data as follows:\n- Convert the data to old format (I had already made my kernel public for this part)\n- For each token, add on `O` label for discourse types if they are not a valid discourse\n- For each token, add -100 as label for discourse effectiveness if they are not a valid discourse\n- If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse type id as their label\n- If the token belongs to one of the discourse cls or end token or is a valid discourse, I added discourse effectiveness id as their label\n- discourse effectiveness label was kept only for the CLS_{discourse_type} and END_{discourse_type} tokens\n\nSo, now we have for each essay:\n- input_ids\n- input_types (discourse type ids, one for each input id)\n- input_labels (the actual label, most are -100, only start of a discourse and end have an actual label)\n- attention_mask\n\nNow it's time to train a model. I made a crucial change in the model's embedding layer that gave a good lift. The change was to add another embedding layer for discourse_types (input_types) and add the result to the original embeddings:\n\n```python\nclass DebertaV2Embeddings(nn.Module):\n    \"\"\"Construct the embeddings from word, position and token_type embeddings.\"\"\"\n\n    def __init__(self, config):\n        super().__init__()\n        pad_token_id = getattr(config, \"pad_token_id\", 0)\n        self.embedding_size = getattr(config, \"embedding_size\", config.hidden_size)\n        self.word_embeddings = nn.Embedding(config.vocab_size, self.embedding_size, padding_idx=pad_token_id)\n        self.disc_type_embeddings = nn.Embedding(9, self.embedding_size)\n        .\n        .\n        .\n\n    def forward(\n        self, input_ids=None, token_type_ids=None, disc_type_ids=None, position_ids=None, mask=None, inputs_embeds=None\n    ):\n        .\n        .\n        if self.config.disc_type_vocab_size > 0:\n            disc_type_embeddings = self.disc_type_embeddings(disc_type_ids)\n            embeddings += disc_type_embeddings\n        .\n        .\n        .\n        return embeddings\n\n```\n\nOther than all this, I used polynomial learning rate scheduler and AdamW optimizer from pytorch.\n\nDuring inference, I just averaged the probabilities for CLS_{discourse_type} and END_{discourse_type} tokens to get the final label.\n\nThat's it. Nothing too complicated to get a good score using a single model (5-fold). Running it with some variations and averaging the models gave us 14th rank on the leaderboard.\n\nThe full code to train and infer is available here: https://www.kaggle.com/code/abhishek/0-577-single-model-full-code\n\nI used my own library for training the models: tez. Please give it some love here: https://github.com/abhishekkrthakur/tez\n\nIf you have any questions, please feel free to ask. It was a fun competition and I learnt a lot! :)\n",
      "votes": 77
    },
    {
      "id": 1913246,
      "postDate": "2022-08-25T08:56:02.183Z",
      "content": "<p>Can be your next video explaining it😬</p>",
      "rawMarkdown": "Can be your next video explaining it😬",
      "votes": 4,
      "replies": [
        {
          "id": 1913365,
          "postDate": "2022-08-25T09:49:46.780Z",
          "content": "<p>+1 on this humble request.</p>",
          "rawMarkdown": "+1 on this humble request.",
          "votes": 2
        },
        {
          "id": 1913414,
          "postDate": "2022-08-25T10:13:04.243Z",
          "content": "<p>dunno if this solution is worth a video. there are many more interesting solutions that have been shared here. but ill give it a thought. the only interesting part in my solution is modification of embedding layer in deberta :) </p>",
          "rawMarkdown": "dunno if this solution is worth a video. there are many more interesting solutions that have been shared here. but ill give it a thought. the only interesting part in my solution is modification of embedding layer in deberta :) ",
          "votes": 4
        },
        {
          "id": 1913764,
          "postDate": "2022-08-25T13:50:57.623Z",
          "content": "<p>Many thanks for the solution, your approaches are a great learning experience for beginners like me to learn and augment our knowledge <a href=\"https://www.kaggle.com/abhishek\" target=\"_blank\">@abhishek</a> !!</p>",
          "rawMarkdown": "Many thanks for the solution, your approaches are a great learning experience for beginners like me to learn and augment our knowledge @abhishek !!"
        }
      ]
    },
    {
      "id": 1914351,
      "postDate": "2022-08-26T02:56:09.547Z",
      "content": "<p>Thank you for sharing. I use your baseline kernel for sentence classification, but I was out of time and couldn't push much. <br>\nCongrats on the neat score with token classification ! <br>\nCan I ask about when you combine embeddings, is there any pros and cons whether you add them up or you concatenate ? </p>",
      "rawMarkdown": "Thank you for sharing. I use your baseline kernel for sentence classification, but I was out of time and couldn't push much. \nCongrats on the neat score with token classification ! \nCan I ask about when you combine embeddings, is there any pros and cons whether you add them up or you concatenate ? \n",
      "votes": 1
    },
    {
      "id": 1913383,
      "postDate": "2022-08-25T09:57:22.323Z",
      "content": "<p>Impressive work.. Thank you for sharing! </p>",
      "rawMarkdown": "Impressive work.. Thank you for sharing! ",
      "votes": 1
    },
    {
      "id": 1913231,
      "postDate": "2022-08-25T08:44:19.300Z",
      "content": "<p>Thanks for sharing, token type embedding is intersting!</p>",
      "rawMarkdown": "Thanks for sharing, token type embedding is intersting!",
      "votes": 1
    },
    {
      "id": 1916803,
      "postDate": "2022-08-28T06:56:02.163Z",
      "content": "<p>I checked the run_mlm.py code, as document said perplexity is not well defined for masked language models like BERT, so it may not a good metrics?</p>",
      "rawMarkdown": "I checked the run_mlm.py code, as document said perplexity is not well defined for masked language models like BERT, so it may not a good metrics?"
    },
    {
      "id": 1914448,
      "postDate": "2022-08-26T05:31:16.470Z",
      "content": "<p>Thanks <a href=\"https://www.kaggle.com/abhishek\" target=\"_blank\">@abhishek</a> for sharing the great solution. I think the embedding modification is a really cool idea. I have two queries:</p>\n<ul>\n<li>if you add the discourse type embeddings to tokens, won't it be too easy for the model to predict the auxiliary discourse type target?</li>\n<li>will it be better to use the same modification during mlm training as well?</li>\n</ul>\n<p>Thanks again for the writeup!  </p>",
      "rawMarkdown": "Thanks @abhishek for sharing the great solution. I think the embedding modification is a really cool idea. I have two queries:\n- if you add the discourse type embeddings to tokens, won't it be too easy for the model to predict the auxiliary discourse type target?\n- will it be better to use the same modification during mlm training as well?\n\nThanks again for the writeup!  "
    },
    {
      "id": 1913947,
      "postDate": "2022-08-25T15:44:03.250Z",
      "content": "<p>Cool explanation, thanks for sharing ❤️</p>",
      "rawMarkdown": "Cool explanation, thanks for sharing ❤️",
      "votes": 1
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T17:53:35Z",
  "competition_id": 35308,
  "competition_slug": "feedback-prize-effectiveness",
  "team_id": 8686673,
  "solution_url": "/competitions/feedback-prize-effectiveness/writeups/0-577-single-model-with-full-code"
}