{
  "id": 259982,
  "title": "9th place solution -Ensemble of four models",
  "content": "<p>To begin with, We would like to thank Kaggle and Commonlit for hosting such an interesting competition! This is our first challenge in the field of NLP competition and very thanks to&nbsp;@rhtsingh, <a href=\"https://www.kaggle.com/maunish\" target=\"_blank\">@maunish</a> and <a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a> for sharing their wonderful kernels.  Their notebooks were great help to making this competition a great one for sure.</p>\n<h2>Summary</h2>\n<p>We chose&nbsp;the one with best Public LB and the one with the best CV as our final submissions. The following are our best submissions.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>best Public LB</td>\n<td>0.450</td>\n<td>0.451</td>\n</tr>\n<tr>\n<td>best CV</td>\n<td>0.451</td>\n<td>0.448</td>\n</tr>\n</tbody>\n</table>\n<p>We ensembled 10 models including two 25-fold CV models.</p>\n<h2>Cross validation strategy</h2>\n<p>The dataset size is one of the most important factor for machine learning. In this competition, train.csv contained about 3000 samples. Generally speaking, this number is very small for training deep learning models. To exhaustively utilize this small dataset, we carefully determined the number of folds (K) in K-fold cross validation. Our hypothesis was that if we increased K, models would perform better thanks to larger number of training samples (Of course, there would be an upper limit of K because the number of validation samples becomes too small). We tried 4 candidates(K=5,10,15,25) to test this hypothesis. As we expected, we observed small but stable improvement of LB score with larger K. To be more specific, increasing K from 5 to 15 improved public (and private) LB by 0.002. Increasing 15 to 25 did not change the displayed score but improved the score slightly (we confirmed that by sorting the submissions by the scores).We decided to employ 25 folds for some strong single models (deberta-large, roberta-large trained by cross entropy loss), paying attention to inference time. As a side note, we used normal k fold cross validation because stratified k fold using binned target did not seem to improve cv-lb correlation much. </p>\n<h2>Models</h2>\n<p>Like most teams, we used pretrained models from huggingface implemented in pytorch. Through several experiments,and found that deberta-large performed significantly better. However,deberta-large required much longer training time than other models, so we attempted to obtain the optimal parameters for deberta-large in a short time by using deberta base. Several kernels and papers were very helpful in this experiments (e.g.: <a href=\"https://arxiv.org/abs/2006.04884\" target=\"_blank\">https://arxiv.org/abs/2006.04884</a>) . After changing many parameters, including lerning rate, activation layer, the best results were obtained by changing loss function. Some models using cross-entropy loss have shown excellent results in previous NLP competitions(e.g. :<a href=\"https://www.kaggle.com/c/google-quest-challenge/discussion/129978)\" target=\"_blank\">https://www.kaggle.com/c/google-quest-challenge/discussion/129978)</a>. So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Median(target) was added to the regressor during prediction.This idea significantly contributed to both CV and LB score, and also contributed significantly to the ensemble. </p>\n<h2>Weights</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Public</th>\n<th>Weight</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RoBERTa-Large (25 fold cross entropy)</td>\n<td>-</td>\n<td>0.4</td>\n</tr>\n<tr>\n<td>DeBERTa large (25fold)</td>\n<td>0.458</td>\n<td>0.25</td>\n</tr>\n<tr>\n<td>DeBERTa large (15 fold cross entropy)</td>\n<td>-</td>\n<td>0.25</td>\n</tr>\n<tr>\n<td>DeBERTa large 5epochs 5fold</td>\n<td>0.460</td>\n<td>0.1</td>\n</tr>\n</tbody>\n</table>\n<h2>WHAT did not work</h2>\n<ul>\n<li>large model<ul>\n<li>deberta-xlarge</li></ul></li>\n<li>other model<ul>\n<li>ernie_large</li>\n<li>xlnet-base-cased</li>\n<li>albert-base-v1</li>\n<li>distilbert-base-uncased</li>\n<li>xlm-roberta-base</li>\n<li>microsoft/deberta-base</li>\n<li>nghuyong/ernie-2.0-en</li>\n<li>nghuyong/ernie-2.0-large-en</li></ul></li>\n<li>CV strategy<ul>\n<li>stratified k-fold by target</li>\n<li>stratified k-fold by std</li></ul></li>\n<li>pseudo labeling</li>\n<li>data argumentation</li>\n<li>post processing</li>\n<li>SWA</li>\n</ul>\n<h2>Computing environments</h2>\n<ul>\n<li>google colab pro *3 </li>\n<li>AWS p3.8xlarge (for deberta-xlarge, not worked)</li>\n<li>GCP v100*4 (for deberta-xlarge, not worked)</li>\n</ul>",
  "comments": [
    {
      "id": 1446376,
      "author_name": "HinePo",
      "author_url": "",
      "post_date": "2021-08-04T12:02:37.440000",
      "content": "<p>I also could not find any improvement with data augmentation or SWA.</p>\n<p>Thanks for sharing, I did not know DeBERTa models. I will check them out</p>",
      "votes": 3,
      "replies": []
    },
    {
      "id": 1442407,
      "author_name": "Salim Khazem",
      "author_url": "",
      "post_date": "2021-08-03T22:39:44.573000",
      "content": "<p>Congratulations! , Thanks for sharing your approach </p>",
      "votes": 3,
      "replies": []
    },
    {
      "id": 1436588,
      "author_name": "Chris Deotte",
      "author_url": "",
      "post_date": "2021-08-03T15:14:56.273000",
      "content": "<p>Congratulations! Awesome idea to</p>\n<blockquote>\n  <p>So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Meidan(target) was added to the regressor during prediction.</p>\n</blockquote>",
      "votes": 4,
      "replies": [
        {
          "id": 1437718,
          "author_name": "wakepon",
          "author_url": "",
          "post_date": "2021-08-03T15:42:22.230000",
          "content": "<p>Thanks a lot!<br>\nWe never would have thought of your great ideas.<br>\n(<a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/257446\" target=\"_blank\">https://www.kaggle.com/c/commonlitreadabilityprize/discussion/257446</a>)</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1450898,
      "author_name": "Allohvk",
      "author_url": "",
      "post_date": "2021-08-05T07:58:41.253000",
      "content": "<blockquote>\n  <p><em>trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label.</em></p>\n  <p><em>Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction</em></p>\n</blockquote>\n<p>As I understand you pass the target thru' a sigmoid and then do a BCE. So say from -3.X to +1.Y we now have a target from 0-1. So we can apply BCE as a loss. So far I understood</p>\n<p>My doubt - to convert to actual predictions we would have to do the inverse of a sigmoid basically apply a logit function what Feng is saying. (and then add the mean or median that part is ok). Is that understanding correct? If so it is very elegant &amp; effective method of converting a regression loss to entropy loss. Thanks for sharing</p>",
      "votes": 2,
      "replies": [
        {
          "id": 1451803,
          "author_name": "K-NKSM",
          "author_url": "",
          "post_date": "2021-08-05T12:45:03.640000",
          "content": "<p>Thank you for your comment😊</p>\n<blockquote>\n  <p>As I understand you pass the target thru' a sigmoid and then do a BCE.</p>\n</blockquote>\n<p><a href=\"https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html\" target=\"_blank\">BCEWithLogitsLoss internally applies sigmoid to the first argument</a>. Therefore, we did not manually apply sigmoid to the model output. This is why logit function was unnecessary. What we did is conceptually equivalent to putting sigmoid layer after regressor, calculating binary cross entropy during training and inverting the sigmoid function during inference. However, BCEWithLogitsLoss is supposed to be numerically more stable than doing that. For details, please take a look at LitModel.training_step, LitModel.validation_step, LitModel.predict_step in <a href=\"https://www.kaggle.com/nmkt6e6d6b74/training-roberta-large-using-cross-entropy/log\" target=\"_blank\">this notebook</a> we published.</p>",
          "votes": 1,
          "replies": []
        },
        {
          "id": 1451921,
          "author_name": "Allohvk",
          "author_url": "",
          "post_date": "2021-08-05T13:23:03.273000",
          "content": "<p>Thanks a lot for your kind reply and notebook reference. This is really a neat technique!</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 1445501,
      "author_name": "Frank",
      "author_url": "",
      "post_date": "2021-08-04T09:08:00.483000",
      "content": "<p>Congratulations! Thank you for sharing the great idea. I've got a few questions. <a href=\"https://www.kaggle.com/wakepon\" target=\"_blank\">@wakepon</a> </p>\n<ol>\n<li>During prediction, did you reverse the calculation of <code>Sigmoid(target-Median(target))</code> using the target median of the training set to get the predicted target value? </li>\n<li>Why do you need <code>-Median(target)</code> instead of <code>sigmoid(target)</code>? And why choosing median instead of mean?</li>\n</ol>",
      "votes": 2,
      "replies": [
        {
          "id": 1446372,
          "author_name": "wakepon",
          "author_url": "",
          "post_date": "2021-08-04T12:01:40.540000",
          "content": "<p>Thanks for your questions!</p>\n<blockquote>\n  <p>1 During prediction, did you reverse the calculation of Sigmoid(target-Median(target)) using the target median of the training set to get the predicted target value?</p>\n</blockquote>\n<p>Yes, that's right. Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction.</p>\n<blockquote>\n  <p>2 Why do you need -Median(target) instead of sigmoid(target)?</p>\n</blockquote>\n<p>Because we were concerned about the side effect of biased sigmoid(target).<br>\nSince target values are biased to the negative side by about -0.9, sigmoid(target) will be also biased to &lt;0.5.  This situation is close to class inbalance in ordinary classification problems. To avoid side effect of bias, we introduced-Median(target). However, we did not test whether the bias towards &lt;0.5 really has any side effect.</p>\n<blockquote>\n  <p>And why choosing median instead of mean?</p>\n</blockquote>\n<p>Because median is known to be more robust against outliers than mean.<br>\nHowever, to be honest, we just wanted to get the center of the distribution and didn't have a strong reason. </p>",
          "votes": 2,
          "replies": []
        },
        {
          "id": 1449771,
          "author_name": "Frank",
          "author_url": "",
          "post_date": "2021-08-05T00:39:22.413000",
          "content": "<p>Cool. Thanks for the reply!</p>",
          "votes": 1,
          "replies": []
        }
      ]
    }
  ],
  "comment_count": 10,
  "messages": [
    {
      "id": 1436358,
      "postDate": "2021-08-03T15:04:51.870Z",
      "content": "<p>To begin with, We would like to thank Kaggle and Commonlit for hosting such an interesting competition! This is our first challenge in the field of NLP competition and very thanks to&nbsp;@rhtsingh, <a href=\"https://www.kaggle.com/maunish\" target=\"_blank\">@maunish</a> and <a href=\"https://www.kaggle.com/andretugan\" target=\"_blank\">@andretugan</a> for sharing their wonderful kernels.  Their notebooks were great help to making this competition a great one for sure.</p>\n<h2>Summary</h2>\n<p>We chose&nbsp;the one with best Public LB and the one with the best CV as our final submissions. The following are our best submissions.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>best Public LB</td>\n<td>0.450</td>\n<td>0.451</td>\n</tr>\n<tr>\n<td>best CV</td>\n<td>0.451</td>\n<td>0.448</td>\n</tr>\n</tbody>\n</table>\n<p>We ensembled 10 models including two 25-fold CV models.</p>\n<h2>Cross validation strategy</h2>\n<p>The dataset size is one of the most important factor for machine learning. In this competition, train.csv contained about 3000 samples. Generally speaking, this number is very small for training deep learning models. To exhaustively utilize this small dataset, we carefully determined the number of folds (K) in K-fold cross validation. Our hypothesis was that if we increased K, models would perform better thanks to larger number of training samples (Of course, there would be an upper limit of K because the number of validation samples becomes too small). We tried 4 candidates(K=5,10,15,25) to test this hypothesis. As we expected, we observed small but stable improvement of LB score with larger K. To be more specific, increasing K from 5 to 15 improved public (and private) LB by 0.002. Increasing 15 to 25 did not change the displayed score but improved the score slightly (we confirmed that by sorting the submissions by the scores).We decided to employ 25 folds for some strong single models (deberta-large, roberta-large trained by cross entropy loss), paying attention to inference time. As a side note, we used normal k fold cross validation because stratified k fold using binned target did not seem to improve cv-lb correlation much. </p>\n<h2>Models</h2>\n<p>Like most teams, we used pretrained models from huggingface implemented in pytorch. Through several experiments,and found that deberta-large performed significantly better. However,deberta-large required much longer training time than other models, so we attempted to obtain the optimal parameters for deberta-large in a short time by using deberta base. Several kernels and papers were very helpful in this experiments (e.g.: <a href=\"https://arxiv.org/abs/2006.04884\" target=\"_blank\">https://arxiv.org/abs/2006.04884</a>) . After changing many parameters, including lerning rate, activation layer, the best results were obtained by changing loss function. Some models using cross-entropy loss have shown excellent results in previous NLP competitions(e.g. :<a href=\"https://www.kaggle.com/c/google-quest-challenge/discussion/129978)\" target=\"_blank\">https://www.kaggle.com/c/google-quest-challenge/discussion/129978)</a>. So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Median(target) was added to the regressor during prediction.This idea significantly contributed to both CV and LB score, and also contributed significantly to the ensemble. </p>\n<h2>Weights</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Public</th>\n<th>Weight</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>RoBERTa-Large (25 fold cross entropy)</td>\n<td>-</td>\n<td>0.4</td>\n</tr>\n<tr>\n<td>DeBERTa large (25fold)</td>\n<td>0.458</td>\n<td>0.25</td>\n</tr>\n<tr>\n<td>DeBERTa large (15 fold cross entropy)</td>\n<td>-</td>\n<td>0.25</td>\n</tr>\n<tr>\n<td>DeBERTa large 5epochs 5fold</td>\n<td>0.460</td>\n<td>0.1</td>\n</tr>\n</tbody>\n</table>\n<h2>WHAT did not work</h2>\n<ul>\n<li>large model<ul>\n<li>deberta-xlarge</li></ul></li>\n<li>other model<ul>\n<li>ernie_large</li>\n<li>xlnet-base-cased</li>\n<li>albert-base-v1</li>\n<li>distilbert-base-uncased</li>\n<li>xlm-roberta-base</li>\n<li>microsoft/deberta-base</li>\n<li>nghuyong/ernie-2.0-en</li>\n<li>nghuyong/ernie-2.0-large-en</li></ul></li>\n<li>CV strategy<ul>\n<li>stratified k-fold by target</li>\n<li>stratified k-fold by std</li></ul></li>\n<li>pseudo labeling</li>\n<li>data argumentation</li>\n<li>post processing</li>\n<li>SWA</li>\n</ul>\n<h2>Computing environments</h2>\n<ul>\n<li>google colab pro *3 </li>\n<li>AWS p3.8xlarge (for deberta-xlarge, not worked)</li>\n<li>GCP v100*4 (for deberta-xlarge, not worked)</li>\n</ul>",
      "rawMarkdown": "To begin with, We would like to thank Kaggle and Commonlit for hosting such an interesting competition! This is our first challenge in the field of NLP competition and very thanks to @rhtsingh, @maunish and @andretugan for sharing their wonderful kernels.  Their notebooks were great help to making this competition a great one for sure.\n\n## Summary\nWe chose the one with best Public LB and the one with the best CV as our final submissions. The following are our best submissions.\n\n|   | Public LB |Private LB|\n| --- | --- | --- |\n| best Public LB | 0.450 | 0.451 |\n| best CV | 0.451 | 0.448 |\n\nWe ensembled 10 models including two 25-fold CV models.\n\n## Cross validation strategy\nThe dataset size is one of the most important factor for machine learning. In this competition, train.csv contained about 3000 samples. Generally speaking, this number is very small for training deep learning models. To exhaustively utilize this small dataset, we carefully determined the number of folds (K) in K-fold cross validation. Our hypothesis was that if we increased K, models would perform better thanks to larger number of training samples (Of course, there would be an upper limit of K because the number of validation samples becomes too small). We tried 4 candidates(K=5,10,15,25) to test this hypothesis. As we expected, we observed small but stable improvement of LB score with larger K. To be more specific, increasing K from 5 to 15 improved public (and private) LB by 0.002. Increasing 15 to 25 did not change the displayed score but improved the score slightly (we confirmed that by sorting the submissions by the scores).We decided to employ 25 folds for some strong single models (deberta-large, roberta-large trained by cross entropy loss), paying attention to inference time. As a side note, we used normal k fold cross validation because stratified k fold using binned target did not seem to improve cv-lb correlation much. \n\n## Models\nLike most teams, we used pretrained models from huggingface implemented in pytorch. Through several experiments,and found that deberta-large performed significantly better. However,deberta-large required much longer training time than other models, so we attempted to obtain the optimal parameters for deberta-large in a short time by using deberta base. Several kernels and papers were very helpful in this experiments (e.g.: https://arxiv.org/abs/2006.04884) . After changing many parameters, including lerning rate, activation layer, the best results were obtained by changing loss function. Some models using cross-entropy loss have shown excellent results in previous NLP competitions(e.g. :https://www.kaggle.com/c/google-quest-challenge/discussion/129978). So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Median(target) was added to the regressor during prediction.This idea significantly contributed to both CV and LB score, and also contributed significantly to the ensemble. \n\n## Weights\n|Model  | Public | Weight| \n| --- | --- | --- |\n|  RoBERTa-Large (25 fold cross entropy)| - |0.4 |\n|DeBERTa large (25fold)|\t0.458\t|0.25|\n|DeBERTa large (15 fold cross entropy)|-|\t0.25|\n|DeBERTa large 5epochs 5fold |0.460\t|0.1|\n\n##  WHAT did not work\n* large model\n    * deberta-xlarge\n* other model\n    * ernie_large\n    * xlnet-base-cased\n    * albert-base-v1\n    * distilbert-base-uncased\n    * xlm-roberta-base\n    * microsoft/deberta-base\n    * nghuyong/ernie-2.0-en\n    * nghuyong/ernie-2.0-large-en\n* CV strategy\n    * stratified k-fold by target\n    * stratified k-fold by std\n* pseudo labeling\n* data argumentation\n* post processing\n* SWA\n\n## Computing environments\n* google colab pro *3 \n* AWS p3.8xlarge (for deberta-xlarge, not worked)\n* GCP v100*4 (for deberta-xlarge, not worked)",
      "votes": 34
    },
    {
      "id": 1446376,
      "postDate": "2021-08-04T12:02:37.440Z",
      "content": "<p>I also could not find any improvement with data augmentation or SWA.</p>\n<p>Thanks for sharing, I did not know DeBERTa models. I will check them out</p>",
      "rawMarkdown": "I also could not find any improvement with data augmentation or SWA.\n\nThanks for sharing, I did not know DeBERTa models. I will check them out",
      "votes": 3
    },
    {
      "id": 1442407,
      "postDate": "2021-08-03T22:39:44.573Z",
      "content": "<p>Congratulations! , Thanks for sharing your approach </p>",
      "rawMarkdown": "Congratulations! , Thanks for sharing your approach \n\n",
      "votes": 3
    },
    {
      "id": 1436588,
      "postDate": "2021-08-03T15:14:56.273Z",
      "content": "<p>Congratulations! Awesome idea to</p>\n<blockquote>\n  <p>So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Meidan(target) was added to the regressor during prediction.</p>\n</blockquote>",
      "rawMarkdown": "Congratulations! Awesome idea to\n>So we trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label. Meidan(target) was added to the regressor during prediction.\n",
      "votes": 4,
      "replies": [
        {
          "id": 1437718,
          "postDate": "2021-08-03T15:42:22.230Z",
          "content": "<p>Thanks a lot!<br>\nWe never would have thought of your great ideas.<br>\n(<a href=\"https://www.kaggle.com/c/commonlitreadabilityprize/discussion/257446\" target=\"_blank\">https://www.kaggle.com/c/commonlitreadabilityprize/discussion/257446</a>)</p>",
          "rawMarkdown": "Thanks a lot!\nWe never would have thought of your great ideas.\n(https://www.kaggle.com/c/commonlitreadabilityprize/discussion/257446)",
          "votes": 1
        }
      ]
    },
    {
      "id": 1450898,
      "postDate": "2021-08-05T07:58:41.253Z",
      "content": "<blockquote>\n  <p><em>trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label.</em></p>\n  <p><em>Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction</em></p>\n</blockquote>\n<p>As I understand you pass the target thru' a sigmoid and then do a BCE. So say from -3.X to +1.Y we now have a target from 0-1. So we can apply BCE as a loss. So far I understood</p>\n<p>My doubt - to convert to actual predictions we would have to do the inverse of a sigmoid basically apply a logit function what Feng is saying. (and then add the mean or median that part is ok). Is that understanding correct? If so it is very elegant &amp; effective method of converting a regression loss to entropy loss. Thanks for sharing</p>",
      "rawMarkdown": "> *trained BCEWithLogitsLoss using Sigmoid(target-Median(target)) as the prediction label.*\n\n> *Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction*\n\nAs I understand you pass the target thru' a sigmoid and then do a BCE. So say from -3.X to +1.Y we now have a target from 0-1. So we can apply BCE as a loss. So far I understood\n\nMy doubt - to convert to actual predictions we would have to do the inverse of a sigmoid basically apply a logit function what Feng is saying. (and then add the mean or median that part is ok). Is that understanding correct? If so it is very elegant & effective method of converting a regression loss to entropy loss. Thanks for sharing",
      "votes": 2,
      "replies": [
        {
          "id": 1451803,
          "postDate": "2021-08-05T12:45:03.640Z",
          "content": "<p>Thank you for your comment😊</p>\n<blockquote>\n  <p>As I understand you pass the target thru' a sigmoid and then do a BCE.</p>\n</blockquote>\n<p><a href=\"https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html\" target=\"_blank\">BCEWithLogitsLoss internally applies sigmoid to the first argument</a>. Therefore, we did not manually apply sigmoid to the model output. This is why logit function was unnecessary. What we did is conceptually equivalent to putting sigmoid layer after regressor, calculating binary cross entropy during training and inverting the sigmoid function during inference. However, BCEWithLogitsLoss is supposed to be numerically more stable than doing that. For details, please take a look at LitModel.training_step, LitModel.validation_step, LitModel.predict_step in <a href=\"https://www.kaggle.com/nmkt6e6d6b74/training-roberta-large-using-cross-entropy/log\" target=\"_blank\">this notebook</a> we published.</p>",
          "rawMarkdown": "Thank you for your comment😊\n> As I understand you pass the target thru' a sigmoid and then do a BCE.\n\n[BCEWithLogitsLoss internally applies sigmoid to the first argument](https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html). Therefore, we did not manually apply sigmoid to the model output. This is why logit function was unnecessary. What we did is conceptually equivalent to putting sigmoid layer after regressor, calculating binary cross entropy during training and inverting the sigmoid function during inference. However, BCEWithLogitsLoss is supposed to be numerically more stable than doing that. For details, please take a look at LitModel.training_step, LitModel.validation_step, LitModel.predict_step in [this notebook](https://www.kaggle.com/nmkt6e6d6b74/training-roberta-large-using-cross-entropy/log) we published.",
          "votes": 1
        },
        {
          "id": 1451921,
          "postDate": "2021-08-05T13:23:03.273Z",
          "content": "<p>Thanks a lot for your kind reply and notebook reference. This is really a neat technique!</p>",
          "rawMarkdown": "Thanks a lot for your kind reply and notebook reference. This is really a neat technique!",
          "votes": 1
        }
      ]
    },
    {
      "id": 1445501,
      "postDate": "2021-08-04T09:08:00.483Z",
      "content": "<p>Congratulations! Thank you for sharing the great idea. I've got a few questions. <a href=\"https://www.kaggle.com/wakepon\" target=\"_blank\">@wakepon</a> </p>\n<ol>\n<li>During prediction, did you reverse the calculation of <code>Sigmoid(target-Median(target))</code> using the target median of the training set to get the predicted target value? </li>\n<li>Why do you need <code>-Median(target)</code> instead of <code>sigmoid(target)</code>? And why choosing median instead of mean?</li>\n</ol>",
      "rawMarkdown": "Congratulations! Thank you for sharing the great idea. I've got a few questions. @wakepon \n\n1. During prediction, did you reverse the calculation of `Sigmoid(target-Median(target))` using the target median of the training set to get the predicted target value? \n2. Why do you need `-Median(target)` instead of `sigmoid(target)`? And why choosing median instead of mean?",
      "votes": 2,
      "replies": [
        {
          "id": 1446372,
          "postDate": "2021-08-04T12:01:40.540Z",
          "content": "<p>Thanks for your questions!</p>\n<blockquote>\n  <p>1 During prediction, did you reverse the calculation of Sigmoid(target-Median(target)) using the target median of the training set to get the predicted target value?</p>\n</blockquote>\n<p>Yes, that's right. Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction.</p>\n<blockquote>\n  <p>2 Why do you need -Median(target) instead of sigmoid(target)?</p>\n</blockquote>\n<p>Because we were concerned about the side effect of biased sigmoid(target).<br>\nSince target values are biased to the negative side by about -0.9, sigmoid(target) will be also biased to &lt;0.5.  This situation is close to class inbalance in ordinary classification problems. To avoid side effect of bias, we introduced-Median(target). However, we did not test whether the bias towards &lt;0.5 really has any side effect.</p>\n<blockquote>\n  <p>And why choosing median instead of mean?</p>\n</blockquote>\n<p>Because median is known to be more robust against outliers than mean.<br>\nHowever, to be honest, we just wanted to get the center of the distribution and didn't have a strong reason. </p>",
          "rawMarkdown": "Thanks for your questions!\n\n> 1 During prediction, did you reverse the calculation of Sigmoid(target-Median(target)) using the target median of the training set to get the predicted target value?\n\nYes, that's right. Thanks to BCEWithLogitsLoss, we don't need to add another sigmoid layer. All we need is add Median(target) during prediction.\n\n> 2 Why do you need -Median(target) instead of sigmoid(target)?\n\nBecause we were concerned about the side effect of biased sigmoid(target).\nSince target values are biased to the negative side by about -0.9, sigmoid(target) will be also biased to <0.5.  This situation is close to class inbalance in ordinary classification problems. To avoid side effect of bias, we introduced-Median(target). However, we did not test whether the bias towards <0.5 really has any side effect.\n\n> And why choosing median instead of mean?\n\nBecause median is known to be more robust against outliers than mean.\nHowever, to be honest, we just wanted to get the center of the distribution and didn't have a strong reason. ",
          "votes": 2
        },
        {
          "id": 1449771,
          "postDate": "2021-08-05T00:39:22.413Z",
          "content": "<p>Cool. Thanks for the reply!</p>",
          "rawMarkdown": "Cool. Thanks for the reply!",
          "votes": 1
        }
      ]
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T23:48:45Z",
  "competition_id": 25914,
  "competition_slug": "commonlitreadabilityprize",
  "team_id": 6784148,
  "solution_url": "/competitions/commonlitreadabilityprize/writeups/pondefrogisland-9th-place-solution-ensemble-of-fou"
}