{
  "id": 596787,
  "title": "Tips for more Robust Validation",
  "url": "/competitions/cmi-detect-behavior-with-sensor-data/discussion/596787",
  "author_name": "Theo Viel",
  "post_date": "2025-08-05T08:49:07.690000",
  "votes": 63,
  "comment_count": 26,
  "views": 0,
  "content": "<p>I will address an issue some of the top public kernel have, nothing new for top teams here, sorry ! 🙂</p>\n<p>If you’ve trained a few models, you’ve probably noticed:</p>\n<ul>\n<li>Small hyperparameter changes can lead to significant score differences (e.g., &gt; ±0.005 F1)</li>\n<li>Scores can vary widely between different folds (&gt; ± 0.01 F1)</li>\n</ul>\n<p>This is expected. The F1 metric is inherently unstable, the dataset is small, and the task is not trivial.</p>\n<p>This also means we need to be very careful when optimizing models !</p>\n<h2><em>k</em>-fold Cross-Validation</h2>\n<p>The goal of <em>k</em>-fold CV is to evaluate your model across the entire dataset in a consistent way by training <em>k</em> models with the <strong>same hyperparameters</strong>. This leads to a more robust selection process.</p>\n<p>For instance, the <em>k</em> models have to be trained with :</p>\n<ul>\n<li>The same learning rate and associated scheduling strategy</li>\n<li>The same number of epochs<br>\nThis consistency allows you to properly evaluate which (learning rate, epoch count) pair works best for your overall CV setup.</li>\n</ul>\n<p>What you should <strong>not</strong> do:<br>\nUse 100 epochs for fold 0 and 60 for fold 1 just because those are the epochs where each fold individually peaked.</p>\n<p>When doing so, you are reducing robustness of you validation setup, and artificially boosting your CV score.  Instead, if 80 epochs works reasonably well across folds, stick with it.</p>\n<p><strong>The number of epochs that maximizes the average CV score is a better estimator of (private) test performance than the per-fold optimal values.</strong></p>\n<p>Keep this in mind when considering early-stopping at epoch 60:</p>\n<blockquote>\n  <p><em>What if your fold 0 validation score stopped increasing at 60 epoch, but your test score did not ?</em></p>\n</blockquote>\n<h2>Practices to Avoid</h2>\n<p>(Only in the case of unstable CV scores, do whatever you want with your big tabular datasets)</p>\n<h4>1. Checkpointing</h4>\n<p>When using checkpointing, you are using a different number of epochs for each fold.<br>\nAND you are choosing the checkpoint that maximizes the fold score.<br>\nIt is the best way to have an overestimated CV and to lose robustness. </p>\n<p><strong>Instead,</strong> train all folds for the same number of epochs, and <strong>always</strong> use the final checkpoint(s).</p>\n<h4>2.  Early stopping</h4>\n<p>Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.</p>\n<h4>3. Reduce LR on Plateau</h4>\n<p>This strategy relies on per-fold validation scores to adapt learning rate schedules, once again breaking consistency.</p>\n<p><strong>Instead,</strong> I recommend using a scheduler that progressively decreases your learning rate. E.g. Linear or Cosine :</p>\n<pre><code> torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR\ncosine = CosineAnnealingLR(optimizer, num_epochs, =1e-6)\nlinear = LinearLR(optimizer, =1.0, =0.0001, =num_epochs)\n</code></pre>\n<p>This will also bring more stability to your training, removing the need for 1. and 2.</p>\n<p>-- </p>\n<p>Thanks for reading and happy parameter optimization !</p>\n<p>And remember, trust your CV !<br>\n(you can, now that you've removed fold-score-dependent components)</p>",
  "messages": [
    {
      "id": 3263464,
      "postDate": "2025-08-05T08:49:07.690Z",
      "content": "<p>I will address an issue some of the top public kernel have, nothing new for top teams here, sorry ! 🙂</p>\n<p>If you’ve trained a few models, you’ve probably noticed:</p>\n<ul>\n<li>Small hyperparameter changes can lead to significant score differences (e.g., &gt; ±0.005 F1)</li>\n<li>Scores can vary widely between different folds (&gt; ± 0.01 F1)</li>\n</ul>\n<p>This is expected. The F1 metric is inherently unstable, the dataset is small, and the task is not trivial.</p>\n<p>This also means we need to be very careful when optimizing models !</p>\n<h2><em>k</em>-fold Cross-Validation</h2>\n<p>The goal of <em>k</em>-fold CV is to evaluate your model across the entire dataset in a consistent way by training <em>k</em> models with the <strong>same hyperparameters</strong>. This leads to a more robust selection process.</p>\n<p>For instance, the <em>k</em> models have to be trained with :</p>\n<ul>\n<li>The same learning rate and associated scheduling strategy</li>\n<li>The same number of epochs<br>\nThis consistency allows you to properly evaluate which (learning rate, epoch count) pair works best for your overall CV setup.</li>\n</ul>\n<p>What you should <strong>not</strong> do:<br>\nUse 100 epochs for fold 0 and 60 for fold 1 just because those are the epochs where each fold individually peaked.</p>\n<p>When doing so, you are reducing robustness of you validation setup, and artificially boosting your CV score.  Instead, if 80 epochs works reasonably well across folds, stick with it.</p>\n<p><strong>The number of epochs that maximizes the average CV score is a better estimator of (private) test performance than the per-fold optimal values.</strong></p>\n<p>Keep this in mind when considering early-stopping at epoch 60:</p>\n<blockquote>\n  <p><em>What if your fold 0 validation score stopped increasing at 60 epoch, but your test score did not ?</em></p>\n</blockquote>\n<h2>Practices to Avoid</h2>\n<p>(Only in the case of unstable CV scores, do whatever you want with your big tabular datasets)</p>\n<h4>1. Checkpointing</h4>\n<p>When using checkpointing, you are using a different number of epochs for each fold.<br>\nAND you are choosing the checkpoint that maximizes the fold score.<br>\nIt is the best way to have an overestimated CV and to lose robustness. </p>\n<p><strong>Instead,</strong> train all folds for the same number of epochs, and <strong>always</strong> use the final checkpoint(s).</p>\n<h4>2.  Early stopping</h4>\n<p>Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.</p>\n<h4>3. Reduce LR on Plateau</h4>\n<p>This strategy relies on per-fold validation scores to adapt learning rate schedules, once again breaking consistency.</p>\n<p><strong>Instead,</strong> I recommend using a scheduler that progressively decreases your learning rate. E.g. Linear or Cosine :</p>\n<pre><code> torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR\ncosine = CosineAnnealingLR(optimizer, num_epochs, =1e-6)\nlinear = LinearLR(optimizer, =1.0, =0.0001, =num_epochs)\n</code></pre>\n<p>This will also bring more stability to your training, removing the need for 1. and 2.</p>\n<p>-- </p>\n<p>Thanks for reading and happy parameter optimization !</p>\n<p>And remember, trust your CV !<br>\n(you can, now that you've removed fold-score-dependent components)</p>",
      "rawMarkdown": "I will address an issue some of the top public kernel have, nothing new for top teams here, sorry ! 🙂\n\nIf you’ve trained a few models, you’ve probably noticed:\n- Small hyperparameter changes can lead to significant score differences (e.g., > ±0.005 F1)\n- Scores can vary widely between different folds (> ± 0.01 F1)\n\nThis is expected. The F1 metric is inherently unstable, the dataset is small, and the task is not trivial.\n\nThis also means we need to be very careful when optimizing models !\n\n## *k*-fold Cross-Validation\n\nThe goal of *k*-fold CV is to evaluate your model across the entire dataset in a consistent way by training *k* models with the **same hyperparameters**. This leads to a more robust selection process.\n\nFor instance, the *k* models have to be trained with :\n- The same learning rate and associated scheduling strategy\n- The same number of epochs\nThis consistency allows you to properly evaluate which (learning rate, epoch count) pair works best for your overall CV setup.\n\nWhat you should **not** do:\nUse 100 epochs for fold 0 and 60 for fold 1 just because those are the epochs where each fold individually peaked.\n\nWhen doing so, you are reducing robustness of you validation setup, and artificially boosting your CV score.  Instead, if 80 epochs works reasonably well across folds, stick with it.\n\n**The number of epochs that maximizes the average CV score is a better estimator of (private) test performance than the per-fold optimal values.**\n\nKeep this in mind when considering early-stopping at epoch 60:\n> *What if your fold 0 validation score stopped increasing at 60 epoch, but your test score did not ?*\n\n## Practices to Avoid\n\n(Only in the case of unstable CV scores, do whatever you want with your big tabular datasets)\n\n#### 1. Checkpointing \n\nWhen using checkpointing, you are using a different number of epochs for each fold.\nAND you are choosing the checkpoint that maximizes the fold score.\nIt is the best way to have an overestimated CV and to lose robustness. \n\n**Instead,** train all folds for the same number of epochs, and **always** use the final checkpoint(s).\n\n#### 2.  Early stopping\n\nSame issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.\n\n#### 3. Reduce LR on Plateau\n\nThis strategy relies on per-fold validation scores to adapt learning rate schedules, once again breaking consistency.\n\n**Instead,** I recommend using a scheduler that progressively decreases your learning rate. E.g. Linear or Cosine :\n```\nfrom torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR\ncosine = CosineAnnealingLR(optimizer, num_epochs, eta_min=1e-6)\nlinear = LinearLR(optimizer, start_factor=1.0, end_factor=0.0001, total_iters=num_epochs)\n```\nThis will also bring more stability to your training, removing the need for 1. and 2.\n\n-- \n\nThanks for reading and happy parameter optimization !\n\nAnd remember, trust your CV !\n(you can, now that you've removed fold-score-dependent components)",
      "votes": 63
    },
    {
      "id": 3263492,
      "postDate": "2025-08-05T09:24:50.687Z",
      "content": "<p>All of them are enabled, I'm an aware sinner. 😌</p>",
      "rawMarkdown": "All of them are enabled, I'm an aware sinner. 😌",
      "votes": 9
    },
    {
      "id": 3265188,
      "postDate": "2025-08-07T06:41:57.723Z",
      "content": "<p>One competition-specific note: Since around 50% of the private test set will have missing thermo and tof values (a pattern not present in the training data); if your models rely on these features, you should try to simulate this missingness during validation…</p>",
      "rawMarkdown": "One competition-specific note: Since around 50% of the private test set will have missing thermo and tof values (a pattern not present in the training data); if your models rely on these features, you should try to simulate this missingness during validation...",
      "votes": 5,
      "replies": [
        {
          "id": 3265276,
          "postDate": "2025-08-07T09:01:42.143Z",
          "content": "<p>100% True</p>",
          "rawMarkdown": "100% True\n\n",
          "votes": 1
        }
      ]
    },
    {
      "id": 3263638,
      "postDate": "2025-08-05T13:45:37.410Z",
      "content": "<p>Thanks for the tips! One question, how would you recommend comparing different hyperparameters/FE if training the full k-fold takes too long? I'm currently tuning on 1 fold but I feel like that would lead to overfitting on that fold?</p>",
      "rawMarkdown": "Thanks for the tips! One question, how would you recommend comparing different hyperparameters/FE if training the full k-fold takes too long? I'm currently tuning on 1 fold but I feel like that would lead to overfitting on that fold?",
      "votes": 1,
      "replies": [
        {
          "id": 3263661,
          "postDate": "2025-08-05T14:19:22.893Z",
          "content": "<p>You can experiment on 1 or 2 folds and once you're satisfied with what you have, ensure the result translates to a k-fold improvement. That's what I usually do. Single fold can already be enough to reject a lot of hypothesis.</p>",
          "rawMarkdown": "You can experiment on 1 or 2 folds and once you're satisfied with what you have, ensure the result translates to a k-fold improvement. That's what I usually do. Single fold can already be enough to reject a lot of hypothesis.",
          "votes": 1,
          "replies": [
            {
              "id": 3263940,
              "postDate": "2025-08-05T22:57:31.287Z",
              "content": "<blockquote>\n  <p>Single fold can already be enough to reject a lot of hypothesis.  </p>\n</blockquote>\n<p>It will work, to a degree.  <br>\nChance to beat people that perform full k-fold --&gt; more robust experiments?<br>\nLow.<br>\nUnless you are very good and/or have great luck.</p>",
              "rawMarkdown": ">Single fold can already be enough to reject a lot of hypothesis.  \n\nIt will work, to a degree.  \nChance to beat people that perform full k-fold --> more robust experiments?\nLow.\nUnless you are very good and/or have great luck.",
              "votes": 1
            },
            {
              "id": 3264015,
              "postDate": "2025-08-06T03:21:37.967Z",
              "content": "<p>One more question: when tuning the model/FE, should I keep the same number of epochs for each experiment? (each experiment here is 1 fold only)</p>",
              "rawMarkdown": "One more question: when tuning the model/FE, should I keep the same number of epochs for each experiment? (each experiment here is 1 fold only)"
            },
            {
              "id": 3264343,
              "postDate": "2025-08-06T14:00:12.610Z",
              "content": "<p>If you change the model architecture by a lot you might need to adapt the number of epochs. Otherwise I like to keep it fixed.</p>",
              "rawMarkdown": "If you change the model architecture by a lot you might need to adapt the number of epochs. Otherwise I like to keep it fixed."
            }
          ]
        }
      ]
    },
    {
      "id": 3263545,
      "postDate": "2025-08-05T11:10:13.797Z",
      "content": "<p>Thanks for sharing. I have a few questions, though. You suggest avoiding early stopping, but many textbooks recommend it. So, when do you think early stopping is actually useful? You also said, \"If 80 epochs works reasonably well across folds, stick with it.\" But how do we know that 80 epochs is enough? Are we still using the validation set to decide on that number? Also, you recommend using the same number of epochs for all folds, but different folds might not converge at the same time. Isn’t that a problem?</p>",
      "rawMarkdown": "Thanks for sharing. I have a few questions, though. You suggest avoiding early stopping, but many textbooks recommend it. So, when do you think early stopping is actually useful? You also said, \"If 80 epochs works reasonably well across folds, stick with it.\" But how do we know that 80 epochs is enough? Are we still using the validation set to decide on that number? Also, you recommend using the same number of epochs for all folds, but different folds might not converge at the same time. Isn’t that a problem?",
      "votes": 1,
      "replies": [
        {
          "id": 3263556,
          "postDate": "2025-08-05T11:20:59.497Z",
          "content": "<blockquote>\n  <p>But how do we know that 80 epochs is enough</p>\n</blockquote>\n<p>Train your <em>k</em> folds with 60, 80, 100 epochs - compute your CV score and use whichever scores best.</p>\n<blockquote>\n  <p>Different folds might not converge at the same time.  Isn’t that a problem?</p>\n</blockquote>\n<p>If your training strategy is good (good lr scheduling, good augmentations), folds should converge at the same time. Keep in mind that single-fold validation f1-score is often not a good indicator of convergence.</p>",
          "rawMarkdown": ">  But how do we know that 80 epochs is enough\n\nTrain your *k* folds with 60, 80, 100 epochs - compute your CV score and use whichever scores best.\n\n> Different folds might not converge at the same time.  Isn’t that a problem?\n\nIf your training strategy is good (good lr scheduling, good augmentations), folds should converge at the same time. Keep in mind that single-fold validation f1-score is often not a good indicator of convergence."
        }
      ]
    },
    {
      "id": 3263824,
      "postDate": "2025-08-05T18:54:29.277Z",
      "content": "<p>Great insights. Sometimes Kagglers ignore these because it may perform better on kfold bagging on submission. Ensemble of overfit models can perform better (same idea as random forest). So in most cases Kagglers (including me) don't exactly validate their test case (single models on validation vs kfold bagging on test)</p>",
      "rawMarkdown": "Great insights. Sometimes Kagglers ignore these because it may perform better on kfold bagging on submission. Ensemble of overfit models can perform better (same idea as random forest). So in most cases Kagglers (including me) don't exactly validate their test case (single models on validation vs kfold bagging on test)",
      "votes": 2
    },
    {
      "id": 3267190,
      "postDate": "2025-08-10T16:54:11.283Z",
      "content": "<p>Theo, thanks for the interesting advice! I have a question then, can these graphs help us in this case or not?</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7279405%2Fc250e84961e3c29af8c8b4bf1e709fda%2FScreenshot%202025-08-10%20193847.png?generation=1754844635197396&amp;alt=media\" alt=\"\"></p>",
      "rawMarkdown": "Theo, thanks for the interesting advice! I have a question then, can these graphs help us in this case or not?\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7279405%2Fc250e84961e3c29af8c8b4bf1e709fda%2FScreenshot%202025-08-10%20193847.png?generation=1754844635197396&alt=media)",
      "replies": [
        {
          "id": 3267938,
          "postDate": "2025-08-12T06:42:12.320Z",
          "content": "<p>Yes, you can use them to build an understanding on how your models behave. E.g. regarding overfitting, instability. They're useful to tweak epochs and lr</p>",
          "rawMarkdown": "Yes, you can use them to build an understanding on how your models behave. E.g. regarding overfitting, instability. They're useful to tweak epochs and lr",
          "votes": 1
        }
      ]
    },
    {
      "id": 3264561,
      "postDate": "2025-08-06T18:06:15.150Z",
      "content": "<blockquote>\n  <ol>\n  <li>Early stopping</li>\n  </ol>\n  <p>Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.</p>\n</blockquote>\n<p>Sometimes, it could be helpful for faster training if you have ideas you want to iterate fast. </p>",
      "rawMarkdown": "> 2. Early stopping\n\n> Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.\n\nSometimes, it could be helpful for faster training if you have ideas you want to iterate fast. ",
      "replies": [
        {
          "id": 3265277,
          "postDate": "2025-08-07T09:02:42.413Z",
          "content": "<p>If your validation scores are stable yes :)</p>",
          "rawMarkdown": "If your validation scores are stable yes :)",
          "replies": [
            {
              "id": 3265867,
              "postDate": "2025-08-08T03:46:11.337Z",
              "content": "<p>For this competition i didn't do anything fancy for validation scheme.</p>\n<p>I did ablate using early stopping (apprx 5 subs), and i observe small correlation between improvement in cv and public lb.</p>\n<p>I think the nature of small dataset in this competition generally has more noise than that of from usage of early-stopping. </p>\n<p>Also, submission to public is average prediction for 5 folds, so i think it helps to reduce \"overfitting\" from early stopping. </p>",
              "rawMarkdown": "For this competition i didn't do anything fancy for validation scheme.\n\nI did ablate using early stopping (apprx 5 subs), and i observe small correlation between improvement in cv and public lb.\n\nI think the nature of small dataset in this competition generally has more noise than that of from usage of early-stopping. \n\nAlso, submission to public is average prediction for 5 folds, so i think it helps to reduce \"overfitting\" from early stopping. "
            }
          ]
        }
      ]
    },
    {
      "id": 3263663,
      "postDate": "2025-08-05T14:23:42.270Z",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15039814%2F9f684a6622a8ac1a48b6441cead2ef91%2FEkran%20Resmi%202025-08-05%2017.11.11.png?generation=1754403114078820&amp;alt=media\" alt=\"\"></p>\n<p>Hi, Thanks for the tips on robust validation. It's a very important point for me as a beginner.<br>\nFollowing your advice, I've been training with a consistent setup. Specifically, I'm using StratifiedGroupKFold, and the model architecture and all hyperparameters are identical for each fold. However, as you can see in the attached graph, one fold (fold_5) is a clear underperformer compared to the rest.<br>\nGiven your post, would you still consider it a bad practice to either:</p>\n<ol>\n<li>Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?</li>\n<li>Exclude this poorly performing fold from the final ensemble?</li>\n</ol>\n<p>Also, is it generally considered normal for one fold to perform worse than the others like this?</p>",
      "rawMarkdown": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15039814%2F9f684a6622a8ac1a48b6441cead2ef91%2FEkran%20Resmi%202025-08-05%2017.11.11.png?generation=1754403114078820&alt=media)\n\n\nHi, Thanks for the tips on robust validation. It's a very important point for me as a beginner.\nFollowing your advice, I've been training with a consistent setup. Specifically, I'm using StratifiedGroupKFold, and the model architecture and all hyperparameters are identical for each fold. However, as you can see in the attached graph, one fold (fold_5) is a clear underperformer compared to the rest.\nGiven your post, would you still consider it a bad practice to either:\n1. Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?\n2. Exclude this poorly performing fold from the final ensemble?\n\nAlso, is it generally considered normal for one fold to perform worse than the others like this?",
      "replies": [
        {
          "id": 3263803,
          "postDate": "2025-08-05T18:18:41.290Z",
          "content": "<blockquote>\n  <p>Given your post, would you still consider it a bad practice to either:<br>\n  Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?</p>\n</blockquote>\n<p>Yes</p>\n<blockquote>\n  <p>Exclude this poorly performing fold from the final ensemble?</p>\n</blockquote>\n<p>If you think the checkpoint will do poorly on test data, you can exclude it.</p>\n<p>-- <br>\nOverall, you should try to figure out why fold 5 performs poorly, 0.55 looks low, you can probably improve that.</p>",
          "rawMarkdown": "> Given your post, would you still consider it a bad practice to either:\nUse the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?\n\nYes\n\n> Exclude this poorly performing fold from the final ensemble?\n\nIf you think the checkpoint will do poorly on test data, you can exclude it.\n\n-- \nOverall, you should try to figure out why fold 5 performs poorly, 0.55 looks low, you can probably improve that."
        }
      ]
    },
    {
      "id": 3263553,
      "postDate": "2025-08-05T11:15:09.623Z",
      "content": "<p>Very interesting post/discussion, did you personally noticed a increase in your LB score by using the epoch with the best CV mean instead of the best epoch with the peak score for each different fold?</p>",
      "rawMarkdown": "Very interesting post/discussion, did you personally noticed a increase in your LB score by using the epoch with the best CV mean instead of the best epoch with the peak score for each different fold?",
      "replies": [
        {
          "id": 3263557,
          "postDate": "2025-08-05T11:22:19.377Z",
          "content": "<p>Not really since LB is a bit unstable - but it pays in the long run since you select your final models using a more reliable score</p>",
          "rawMarkdown": "Not really since LB is a bit unstable - but it pays in the long run since you select your final models using a more reliable score",
          "votes": 1,
          "replies": [
            {
              "id": 3267859,
              "postDate": "2025-08-12T03:28:27.700Z",
              "content": "<p>My LB score decreased 0.005, CV decreased 0.002 after doing your suggestions. Do you think this is normal and is just because of the unstable LB? I just really don’t know what to trust anymore…</p>",
              "rawMarkdown": "My LB score decreased 0.005, CV decreased 0.002 after doing your suggestions. Do you think this is normal and is just because of the unstable LB? I just really don’t know what to trust anymore…"
            },
            {
              "id": 3267936,
              "postDate": "2025-08-12T06:40:16.957Z",
              "content": "<blockquote>\n  <p>Do you think this is normal and is just because of the unstable LB?</p>\n</blockquote>\n<p>Could be yes, I've seen significant CV improvements lead to LB drops.</p>\n<p>It could also be that the early-stopping approach blends better when averaging k-folds.</p>",
              "rawMarkdown": "> Do you think this is normal and is just because of the unstable LB?\n\nCould be yes, I've seen significant CV improvements lead to LB drops.\n\nIt could also be that the early-stopping approach blends better when averaging k-folds."
            },
            {
              "id": 3267946,
              "postDate": "2025-08-12T06:57:19.793Z",
              "content": "<p>My worst fold score = 0.87, my best fold score = 0.91. And I was stuck for a long time, unable to improve CV and LB. Maybe ensembling a number of models will boost the LB significantly. Gradient boosting might be useful 🤤</p>",
              "rawMarkdown": "My worst fold score = 0.87, my best fold score = 0.91. And I was stuck for a long time, unable to improve CV and LB. Maybe ensembling a number of models will boost the LB significantly. Gradient boosting might be useful 🤤"
            },
            {
              "id": 3267954,
              "postDate": "2025-08-12T07:01:58.423Z",
              "content": "<p>I have tried comparing the last epoch and the best epoch, and the differences in both CV and LB are not significant, around 0.001-0.002.</p>",
              "rawMarkdown": "I have tried comparing the last epoch and the best epoch, and the differences in both CV and LB are not significant, around 0.001-0.002."
            }
          ]
        }
      ]
    },
    {
      "id": 3265511,
      "postDate": "2025-08-07T15:44:34.900Z",
      "content": "<p>I absolutely agree with your fact regarding F1 score being highly unstable. It works/ is great for further actions if the given dataset is skewed and large dataset. Because, it wont be optimal to perform hyperparameter tuning on large dataset given that constrains of your hardware specifications and at such cases better to stick on to F1 score. But if your dataset is less skewed and small, its always better to hyperparameter tuning and cross-validation method</p>",
      "rawMarkdown": "I absolutely agree with your fact regarding F1 score being highly unstable. It works/ is great for further actions if the given dataset is skewed and large dataset. Because, it wont be optimal to perform hyperparameter tuning on large dataset given that constrains of your hardware specifications and at such cases better to stick on to F1 score. But if your dataset is less skewed and small, its always better to hyperparameter tuning and cross-validation method",
      "isDeleted": true
    },
    {
      "id": 3268205,
      "postDate": "2025-08-12T15:14:50.800Z",
      "content": "<p>Thanks for the tips…!</p>",
      "rawMarkdown": "Thanks for the tips...!"
    }
  ],
  "comments": [
    {
      "id": 3263492,
      "author_name": "Anil Ozturk",
      "author_url": "",
      "post_date": "2025-08-05T09:24:50.687000",
      "content": "<p>All of them are enabled, I'm an aware sinner. 😌</p>",
      "votes": 9,
      "replies": []
    },
    {
      "id": 3265188,
      "author_name": "Ertuğrul Demir",
      "author_url": "",
      "post_date": "2025-08-07T06:41:57.723000",
      "content": "<p>One competition-specific note: Since around 50% of the private test set will have missing thermo and tof values (a pattern not present in the training data); if your models rely on these features, you should try to simulate this missingness during validation…</p>",
      "votes": 5,
      "replies": [
        {
          "id": 3265276,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-07T09:01:42.143000",
          "content": "<p>100% True</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 3263638,
      "author_name": "Mahog",
      "author_url": "",
      "post_date": "2025-08-05T13:45:37.410000",
      "content": "<p>Thanks for the tips! One question, how would you recommend comparing different hyperparameters/FE if training the full k-fold takes too long? I'm currently tuning on 1 fold but I feel like that would lead to overfitting on that fold?</p>",
      "votes": 1,
      "replies": [
        {
          "id": 3263661,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-05T14:19:22.893000",
          "content": "<p>You can experiment on 1 or 2 folds and once you're satisfied with what you have, ensure the result translates to a k-fold improvement. That's what I usually do. Single fold can already be enough to reject a lot of hypothesis.</p>",
          "votes": 1,
          "replies": [
            {
              "id": 3263940,
              "author_name": "greySnow",
              "author_url": "",
              "post_date": "2025-08-05T22:57:31.287000",
              "content": "<blockquote>\n  <p>Single fold can already be enough to reject a lot of hypothesis.  </p>\n</blockquote>\n<p>It will work, to a degree.  <br>\nChance to beat people that perform full k-fold --&gt; more robust experiments?<br>\nLow.<br>\nUnless you are very good and/or have great luck.</p>",
              "votes": 1,
              "replies": []
            },
            {
              "id": 3264015,
              "author_name": "Mahog",
              "author_url": "",
              "post_date": "2025-08-06T03:21:37.967000",
              "content": "<p>One more question: when tuning the model/FE, should I keep the same number of epochs for each experiment? (each experiment here is 1 fold only)</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3264343,
              "author_name": "Theo Viel",
              "author_url": "",
              "post_date": "2025-08-06T14:00:12.610000",
              "content": "<p>If you change the model architecture by a lot you might need to adapt the number of epochs. Otherwise I like to keep it fixed.</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3263545,
      "author_name": "atl132",
      "author_url": "",
      "post_date": "2025-08-05T11:10:13.797000",
      "content": "<p>Thanks for sharing. I have a few questions, though. You suggest avoiding early stopping, but many textbooks recommend it. So, when do you think early stopping is actually useful? You also said, \"If 80 epochs works reasonably well across folds, stick with it.\" But how do we know that 80 epochs is enough? Are we still using the validation set to decide on that number? Also, you recommend using the same number of epochs for all folds, but different folds might not converge at the same time. Isn’t that a problem?</p>",
      "votes": 1,
      "replies": [
        {
          "id": 3263556,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-05T11:20:59.497000",
          "content": "<blockquote>\n  <p>But how do we know that 80 epochs is enough</p>\n</blockquote>\n<p>Train your <em>k</em> folds with 60, 80, 100 epochs - compute your CV score and use whichever scores best.</p>\n<blockquote>\n  <p>Different folds might not converge at the same time.  Isn’t that a problem?</p>\n</blockquote>\n<p>If your training strategy is good (good lr scheduling, good augmentations), folds should converge at the same time. Keep in mind that single-fold validation f1-score is often not a good indicator of convergence.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3263824,
      "author_name": "Ahmet Erdem",
      "author_url": "",
      "post_date": "2025-08-05T18:54:29.277000",
      "content": "<p>Great insights. Sometimes Kagglers ignore these because it may perform better on kfold bagging on submission. Ensemble of overfit models can perform better (same idea as random forest). So in most cases Kagglers (including me) don't exactly validate their test case (single models on validation vs kfold bagging on test)</p>",
      "votes": 2,
      "replies": []
    },
    {
      "id": 3267190,
      "author_name": "AI-Cat",
      "author_url": "",
      "post_date": "2025-08-10T16:54:11.283000",
      "content": "<p>Theo, thanks for the interesting advice! I have a question then, can these graphs help us in this case or not?</p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7279405%2Fc250e84961e3c29af8c8b4bf1e709fda%2FScreenshot%202025-08-10%20193847.png?generation=1754844635197396&amp;alt=media\" alt=\"\"></p>",
      "votes": 0,
      "replies": [
        {
          "id": 3267938,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-12T06:42:12.320000",
          "content": "<p>Yes, you can use them to build an understanding on how your models behave. E.g. regarding overfitting, instability. They're useful to tweak epochs and lr</p>",
          "votes": 1,
          "replies": []
        }
      ]
    },
    {
      "id": 3264561,
      "author_name": "Gerwyn",
      "author_url": "",
      "post_date": "2025-08-06T18:06:15.150000",
      "content": "<blockquote>\n  <ol>\n  <li>Early stopping</li>\n  </ol>\n  <p>Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.</p>\n</blockquote>\n<p>Sometimes, it could be helpful for faster training if you have ideas you want to iterate fast. </p>",
      "votes": 0,
      "replies": [
        {
          "id": 3265277,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-07T09:02:42.413000",
          "content": "<p>If your validation scores are stable yes :)</p>",
          "votes": 0,
          "replies": [
            {
              "id": 3265867,
              "author_name": "Gerwyn",
              "author_url": "",
              "post_date": "2025-08-08T03:46:11.337000",
              "content": "<p>For this competition i didn't do anything fancy for validation scheme.</p>\n<p>I did ablate using early stopping (apprx 5 subs), and i observe small correlation between improvement in cv and public lb.</p>\n<p>I think the nature of small dataset in this competition generally has more noise than that of from usage of early-stopping. </p>\n<p>Also, submission to public is average prediction for 5 folds, so i think it helps to reduce \"overfitting\" from early stopping. </p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3263663,
      "author_name": "Hüseyin Bayoğlu",
      "author_url": "",
      "post_date": "2025-08-05T14:23:42.270000",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15039814%2F9f684a6622a8ac1a48b6441cead2ef91%2FEkran%20Resmi%202025-08-05%2017.11.11.png?generation=1754403114078820&amp;alt=media\" alt=\"\"></p>\n<p>Hi, Thanks for the tips on robust validation. It's a very important point for me as a beginner.<br>\nFollowing your advice, I've been training with a consistent setup. Specifically, I'm using StratifiedGroupKFold, and the model architecture and all hyperparameters are identical for each fold. However, as you can see in the attached graph, one fold (fold_5) is a clear underperformer compared to the rest.<br>\nGiven your post, would you still consider it a bad practice to either:</p>\n<ol>\n<li>Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?</li>\n<li>Exclude this poorly performing fold from the final ensemble?</li>\n</ol>\n<p>Also, is it generally considered normal for one fold to perform worse than the others like this?</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3263803,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-05T18:18:41.290000",
          "content": "<blockquote>\n  <p>Given your post, would you still consider it a bad practice to either:<br>\n  Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?</p>\n</blockquote>\n<p>Yes</p>\n<blockquote>\n  <p>Exclude this poorly performing fold from the final ensemble?</p>\n</blockquote>\n<p>If you think the checkpoint will do poorly on test data, you can exclude it.</p>\n<p>-- <br>\nOverall, you should try to figure out why fold 5 performs poorly, 0.55 looks low, you can probably improve that.</p>",
          "votes": 0,
          "replies": []
        }
      ]
    },
    {
      "id": 3263553,
      "author_name": "Mauro Abidal Carrer",
      "author_url": "",
      "post_date": "2025-08-05T11:15:09.623000",
      "content": "<p>Very interesting post/discussion, did you personally noticed a increase in your LB score by using the epoch with the best CV mean instead of the best epoch with the peak score for each different fold?</p>",
      "votes": 0,
      "replies": [
        {
          "id": 3263557,
          "author_name": "Theo Viel",
          "author_url": "",
          "post_date": "2025-08-05T11:22:19.377000",
          "content": "<p>Not really since LB is a bit unstable - but it pays in the long run since you select your final models using a more reliable score</p>",
          "votes": 1,
          "replies": [
            {
              "id": 3267859,
              "author_name": "Ravon",
              "author_url": "",
              "post_date": "2025-08-12T03:28:27.700000",
              "content": "<p>My LB score decreased 0.005, CV decreased 0.002 after doing your suggestions. Do you think this is normal and is just because of the unstable LB? I just really don’t know what to trust anymore…</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3267936,
              "author_name": "Theo Viel",
              "author_url": "",
              "post_date": "2025-08-12T06:40:16.957000",
              "content": "<blockquote>\n  <p>Do you think this is normal and is just because of the unstable LB?</p>\n</blockquote>\n<p>Could be yes, I've seen significant CV improvements lead to LB drops.</p>\n<p>It could also be that the early-stopping approach blends better when averaging k-folds.</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3267946,
              "author_name": "Quan Vu",
              "author_url": "",
              "post_date": "2025-08-12T06:57:19.793000",
              "content": "<p>My worst fold score = 0.87, my best fold score = 0.91. And I was stuck for a long time, unable to improve CV and LB. Maybe ensembling a number of models will boost the LB significantly. Gradient boosting might be useful 🤤</p>",
              "votes": 0,
              "replies": []
            },
            {
              "id": 3267954,
              "author_name": "Quan Vu",
              "author_url": "",
              "post_date": "2025-08-12T07:01:58.423000",
              "content": "<p>I have tried comparing the last epoch and the best epoch, and the differences in both CV and LB are not significant, around 0.001-0.002.</p>",
              "votes": 0,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3265511,
      "author_name": "",
      "author_url": "",
      "post_date": "2025-08-07T15:44:34.900000",
      "content": "<p>I absolutely agree with your fact regarding F1 score being highly unstable. It works/ is great for further actions if the given dataset is skewed and large dataset. Because, it wont be optimal to perform hyperparameter tuning on large dataset given that constrains of your hardware specifications and at such cases better to stick on to F1 score. But if your dataset is less skewed and small, its always better to hyperparameter tuning and cross-validation method</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 3268205,
      "author_name": "Sarah Arshad",
      "author_url": "",
      "post_date": "2025-08-12T15:14:50.800000",
      "content": "<p>Thanks for the tips…!</p>",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3263464": "I will address an issue some of the top public kernel have, nothing new for top teams here, sorry ! 🙂\n\nIf you’ve trained a few models, you’ve probably noticed:\n- Small hyperparameter changes can lead to significant score differences (e.g., > ±0.005 F1)\n- Scores can vary widely between different folds (> ± 0.01 F1)\n\nThis is expected. The F1 metric is inherently unstable, the dataset is small, and the task is not trivial.\n\nThis also means we need to be very careful when optimizing models !\n\n## *k*-fold Cross-Validation\n\nThe goal of *k*-fold CV is to evaluate your model across the entire dataset in a consistent way by training *k* models with the **same hyperparameters**. This leads to a more robust selection process.\n\nFor instance, the *k* models have to be trained with :\n- The same learning rate and associated scheduling strategy\n- The same number of epochs\nThis consistency allows you to properly evaluate which (learning rate, epoch count) pair works best for your overall CV setup.\n\nWhat you should **not** do:\nUse 100 epochs for fold 0 and 60 for fold 1 just because those are the epochs where each fold individually peaked.\n\nWhen doing so, you are reducing robustness of you validation setup, and artificially boosting your CV score.  Instead, if 80 epochs works reasonably well across folds, stick with it.\n\n**The number of epochs that maximizes the average CV score is a better estimator of (private) test performance than the per-fold optimal values.**\n\nKeep this in mind when considering early-stopping at epoch 60:\n> *What if your fold 0 validation score stopped increasing at 60 epoch, but your test score did not ?*\n\n## Practices to Avoid\n\n(Only in the case of unstable CV scores, do whatever you want with your big tabular datasets)\n\n#### 1. Checkpointing \n\nWhen using checkpointing, you are using a different number of epochs for each fold.\nAND you are choosing the checkpoint that maximizes the fold score.\nIt is the best way to have an overestimated CV and to lose robustness. \n\n**Instead,** train all folds for the same number of epochs, and **always** use the final checkpoint(s).\n\n#### 2.  Early stopping\n\nSame issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.\n\n#### 3. Reduce LR on Plateau\n\nThis strategy relies on per-fold validation scores to adapt learning rate schedules, once again breaking consistency.\n\n**Instead,** I recommend using a scheduler that progressively decreases your learning rate. E.g. Linear or Cosine :\n```\nfrom torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR\ncosine = CosineAnnealingLR(optimizer, num_epochs, eta_min=1e-6)\nlinear = LinearLR(optimizer, start_factor=1.0, end_factor=0.0001, total_iters=num_epochs)\n```\nThis will also bring more stability to your training, removing the need for 1. and 2.\n\n-- \n\nThanks for reading and happy parameter optimization !\n\nAnd remember, trust your CV !\n(you can, now that you've removed fold-score-dependent components)",
    "3263492": "All of them are enabled, I'm an aware sinner. 😌",
    "3265188": "One competition-specific note: Since around 50% of the private test set will have missing thermo and tof values (a pattern not present in the training data); if your models rely on these features, you should try to simulate this missingness during validation...",
    "3263638": "Thanks for the tips! One question, how would you recommend comparing different hyperparameters/FE if training the full k-fold takes too long? I'm currently tuning on 1 fold but I feel like that would lead to overfitting on that fold?",
    "3263545": "Thanks for sharing. I have a few questions, though. You suggest avoiding early stopping, but many textbooks recommend it. So, when do you think early stopping is actually useful? You also said, \"If 80 epochs works reasonably well across folds, stick with it.\" But how do we know that 80 epochs is enough? Are we still using the validation set to decide on that number? Also, you recommend using the same number of epochs for all folds, but different folds might not converge at the same time. Isn’t that a problem?",
    "3263824": "Great insights. Sometimes Kagglers ignore these because it may perform better on kfold bagging on submission. Ensemble of overfit models can perform better (same idea as random forest). So in most cases Kagglers (including me) don't exactly validate their test case (single models on validation vs kfold bagging on test)",
    "3267190": "Theo, thanks for the interesting advice! I have a question then, can these graphs help us in this case or not?\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7279405%2Fc250e84961e3c29af8c8b4bf1e709fda%2FScreenshot%202025-08-10%20193847.png?generation=1754844635197396&alt=media)",
    "3264561": "> 2. Early stopping\n\n> Same issue: you end up with a different number of epochs per fold, guided by a weak estimator—individual fold validation scores.\n\nSometimes, it could be helpful for faster training if you have ideas you want to iterate fast. ",
    "3263663": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F15039814%2F9f684a6622a8ac1a48b6441cead2ef91%2FEkran%20Resmi%202025-08-05%2017.11.11.png?generation=1754403114078820&alt=media)\n\n\nHi, Thanks for the tips on robust validation. It's a very important point for me as a beginner.\nFollowing your advice, I've been training with a consistent setup. Specifically, I'm using StratifiedGroupKFold, and the model architecture and all hyperparameters are identical for each fold. However, as you can see in the attached graph, one fold (fold_5) is a clear underperformer compared to the rest.\nGiven your post, would you still consider it a bad practice to either:\n1. Use the best checkpoint for this specific fold, even if it breaks the \"fixed epoch\" rule?\n2. Exclude this poorly performing fold from the final ensemble?\n\nAlso, is it generally considered normal for one fold to perform worse than the others like this?",
    "3263553": "Very interesting post/discussion, did you personally noticed a increase in your LB score by using the epoch with the best CV mean instead of the best epoch with the peak score for each different fold?",
    "3265511": "I absolutely agree with your fact regarding F1 score being highly unstable. It works/ is great for further actions if the given dataset is skewed and large dataset. Because, it wont be optimal to perform hyperparameter tuning on large dataset given that constrains of your hardware specifications and at such cases better to stick on to F1 score. But if your dataset is less skewed and small, its always better to hyperparameter tuning and cross-validation method",
    "3268205": "Thanks for the tips...!"
  }
}