{
  "id": 582843,
  "title": "public 1st, private 2nd solution",
  "content": "<p>Thanks to the organizers and the Kaggle community for an outstanding competition — I’m happy to share the core ideas behind my final submission.</p>\n<p><a href=\"https://www.kaggle.com/code/nikitashevyrev/geologyforecast-final-version-2nd-in-private\" target=\"_blank\">Final Notebook</a></p>\n<hr>\n<h1>Data Section</h1>\n<p>To generate a robust training dataset, I used a modified version of <code>interpolate_and_split.py</code>. This produced approximately <strong>~38,000 additional samples</strong>, combined with the original samples from <code>train.csv</code>, yielding a total of <strong>~40,000 training samples</strong>.</p>\n<ul>\n<li><p>Missing values were filled with zeros.</p></li>\n<li><p>I did not use any handcrafted features — early experiments with metadata (like <code>geology_id</code>) and traditional feature engineering didn’t show meaningful gains.</p></li>\n</ul>\n<hr>\n<h1>Training and Model</h1>\n<p>I used <strong>5-fold cross-validation</strong> and trained one model per fold. Final predictions were averaged across all 5 models.</p>\n<ul>\n<li><p><strong>Optimizer:</strong> <code>AdamW</code></p></li>\n<li><p><strong>Scheduler:</strong> Cosine Annealing (<code>T_0 = 5</code>, <code>T_mult = 2</code>)</p></li>\n<li><p><strong>Loss:</strong> Normalized MSE, where both output and target are standardized per batch:</p></li>\n</ul>\n<pre><code>loss = F.mse_loss(\n    (output - target_mean) / target_std,\n    (target - target_mean) / target_std\n)\n</code></pre>\n<ul>\n<li><p><strong>Gradient clipping:</strong> <code>max_norm = 1.0</code></p></li>\n<li><p><strong>Epochs:</strong> 30</p></li>\n<li><p><strong>Batch size:</strong> 256</p></li>\n<li><p><strong>Mixup augmentation</strong> applied during training with α = 0.4</p></li>\n</ul>\n<hr>\n<h1>Reproducibility Notes</h1>\n<p>Although seeds were fixed and deterministic flags enabled, I encountered reproducibility issues between environments:</p>\n<ul>\n<li><p>Final model was trained on a local <strong>RTX 3080 Ti</strong></p></li>\n<li><p>Re-running on <strong>Kaggle P100</strong> produced slightly different weights (likely due to numerical precision and cuDNN backend differences)</p></li>\n</ul>\n<p>To ensure the notebook’s predictions exactly match the final submission, the weights are loaded from a <strong>private Kaggle dataset</strong>.</p>\n<p>The full training code is included (commented) in the final notebook, and the GitHub repo contains all implementation files.</p>\n<hr>\n<h1>Acknowledgements &amp; Influences</h1>\n<p>Several Kaggle participants shared ideas that shaped my approach:</p>\n<p><strong>Eva Koroleva</strong></p>\n<ul>\n<li>Idea: Using <strong>LSTM</strong> as a base architecture</li>\n<li>Notebook: <a href=\"https://www.kaggle.com/code/qmarva/lstm-kfold\" target=\"_blank\">LSTM KFold</a></li>\n<li>Profile: <a href=\"https://www.kaggle.com/qmarva\" target=\"_blank\">@qmarva</a></li>\n</ul>\n<p><strong>OlSch</strong></p>\n<ul>\n<li>Idea: Applying <strong>skip connections</strong> inside dense networks</li>\n<li>Notebook: <a href=\"https://www.kaggle.com/code/olasdsd/keras-geology-forecast-competition-58-4\" target=\"_blank\">Keras Geology Forecast Competition 58.4</a></li>\n<li>Profile: <a href=\"https://www.kaggle.com/olasdsd\" target=\"_blank\">@olasdsd</a></li>\n</ul>\n<p>This structure inspired me to apply residual connections within my LSTM stack:</p>\n<pre><code>x = Dense(UNITS, activation=ACTIVATION)(x)\nx = Dropout(DROPOUT)(x)\nx = x + skip  \n</code></pre>\n<p>Thanks to everyone who shared their insights — it made this journey both fun and impactful.</p>\n<hr>\n<h1>GitHub Repository</h1>\n<p>✅ Full pipeline (training, inference, augmentation, evaluation):<br>\n📂 <a href=\"https://github.com/NikitaShevyrev/Geology-Forecast-Challenge\" target=\"_blank\">GitHub</a><br>\n📄 Licensed under BSD 2-Clause in accordance with the competition rules.</p>",
  "comments": [],
  "comment_count": 0,
  "messages": [
    {
      "id": 3216140,
      "postDate": "2025-06-03T07:01:26.147Z",
      "content": "<p>Thanks to the organizers and the Kaggle community for an outstanding competition — I’m happy to share the core ideas behind my final submission.</p>\n<p><a href=\"https://www.kaggle.com/code/nikitashevyrev/geologyforecast-final-version-2nd-in-private\" target=\"_blank\">Final Notebook</a></p>\n<hr>\n<h1>Data Section</h1>\n<p>To generate a robust training dataset, I used a modified version of <code>interpolate_and_split.py</code>. This produced approximately <strong>~38,000 additional samples</strong>, combined with the original samples from <code>train.csv</code>, yielding a total of <strong>~40,000 training samples</strong>.</p>\n<ul>\n<li><p>Missing values were filled with zeros.</p></li>\n<li><p>I did not use any handcrafted features — early experiments with metadata (like <code>geology_id</code>) and traditional feature engineering didn’t show meaningful gains.</p></li>\n</ul>\n<hr>\n<h1>Training and Model</h1>\n<p>I used <strong>5-fold cross-validation</strong> and trained one model per fold. Final predictions were averaged across all 5 models.</p>\n<ul>\n<li><p><strong>Optimizer:</strong> <code>AdamW</code></p></li>\n<li><p><strong>Scheduler:</strong> Cosine Annealing (<code>T_0 = 5</code>, <code>T_mult = 2</code>)</p></li>\n<li><p><strong>Loss:</strong> Normalized MSE, where both output and target are standardized per batch:</p></li>\n</ul>\n<pre><code>loss = F.mse_loss(\n    (output - target_mean) / target_std,\n    (target - target_mean) / target_std\n)\n</code></pre>\n<ul>\n<li><p><strong>Gradient clipping:</strong> <code>max_norm = 1.0</code></p></li>\n<li><p><strong>Epochs:</strong> 30</p></li>\n<li><p><strong>Batch size:</strong> 256</p></li>\n<li><p><strong>Mixup augmentation</strong> applied during training with α = 0.4</p></li>\n</ul>\n<hr>\n<h1>Reproducibility Notes</h1>\n<p>Although seeds were fixed and deterministic flags enabled, I encountered reproducibility issues between environments:</p>\n<ul>\n<li><p>Final model was trained on a local <strong>RTX 3080 Ti</strong></p></li>\n<li><p>Re-running on <strong>Kaggle P100</strong> produced slightly different weights (likely due to numerical precision and cuDNN backend differences)</p></li>\n</ul>\n<p>To ensure the notebook’s predictions exactly match the final submission, the weights are loaded from a <strong>private Kaggle dataset</strong>.</p>\n<p>The full training code is included (commented) in the final notebook, and the GitHub repo contains all implementation files.</p>\n<hr>\n<h1>Acknowledgements &amp; Influences</h1>\n<p>Several Kaggle participants shared ideas that shaped my approach:</p>\n<p><strong>Eva Koroleva</strong></p>\n<ul>\n<li>Idea: Using <strong>LSTM</strong> as a base architecture</li>\n<li>Notebook: <a href=\"https://www.kaggle.com/code/qmarva/lstm-kfold\" target=\"_blank\">LSTM KFold</a></li>\n<li>Profile: <a href=\"https://www.kaggle.com/qmarva\" target=\"_blank\">@qmarva</a></li>\n</ul>\n<p><strong>OlSch</strong></p>\n<ul>\n<li>Idea: Applying <strong>skip connections</strong> inside dense networks</li>\n<li>Notebook: <a href=\"https://www.kaggle.com/code/olasdsd/keras-geology-forecast-competition-58-4\" target=\"_blank\">Keras Geology Forecast Competition 58.4</a></li>\n<li>Profile: <a href=\"https://www.kaggle.com/olasdsd\" target=\"_blank\">@olasdsd</a></li>\n</ul>\n<p>This structure inspired me to apply residual connections within my LSTM stack:</p>\n<pre><code>x = Dense(UNITS, activation=ACTIVATION)(x)\nx = Dropout(DROPOUT)(x)\nx = x + skip  \n</code></pre>\n<p>Thanks to everyone who shared their insights — it made this journey both fun and impactful.</p>\n<hr>\n<h1>GitHub Repository</h1>\n<p>✅ Full pipeline (training, inference, augmentation, evaluation):<br>\n📂 <a href=\"https://github.com/NikitaShevyrev/Geology-Forecast-Challenge\" target=\"_blank\">GitHub</a><br>\n📄 Licensed under BSD 2-Clause in accordance with the competition rules.</p>",
      "rawMarkdown": "Thanks to the organizers and the Kaggle community for an outstanding competition — I’m happy to share the core ideas behind my final submission.\n\n[Final Notebook](https://www.kaggle.com/code/nikitashevyrev/geologyforecast-final-version-2nd-in-private)\n\n---\n\n# Data Section\nTo generate a robust training dataset, I used a modified version of `interpolate_and_split.py`. This produced approximately **~38,000 additional samples**, combined with the original samples from `train.csv`, yielding a total of **~40,000 training samples**.\n\n- Missing values were filled with zeros.\n\n- I did not use any handcrafted features — early experiments with metadata (like `geology_id`) and traditional feature engineering didn’t show meaningful gains.\n\n---\n\n# Training and Model\nI used **5-fold cross-validation** and trained one model per fold. Final predictions were averaged across all 5 models.\n\n- **Optimizer:** `AdamW`\n\n- **Scheduler:** Cosine Annealing (`T_0 = 5`, `T_mult = 2`)\n\n- **Loss:** Normalized MSE, where both output and target are standardized per batch:\n\n```python\nloss = F.mse_loss(\n    (output - target_mean) / target_std,\n    (target - target_mean) / target_std\n)\n```\n- **Gradient clipping:** `max_norm = 1.0`\n\n- **Epochs:** 30\n\n- **Batch size:** 256\n\n- **Mixup augmentation** applied during training with α = 0.4\n\n---\n\n# Reproducibility Notes\nAlthough seeds were fixed and deterministic flags enabled, I encountered reproducibility issues between environments:\n\n- Final model was trained on a local **RTX 3080 Ti**\n\n- Re-running on **Kaggle P100** produced slightly different weights (likely due to numerical precision and cuDNN backend differences)\n\nTo ensure the notebook’s predictions exactly match the final submission, the weights are loaded from a **private Kaggle dataset**.\n\nThe full training code is included (commented) in the final notebook, and the GitHub repo contains all implementation files.\n\n---\n\n# Acknowledgements & Influences\nSeveral Kaggle participants shared ideas that shaped my approach:\n\n**Eva Koroleva**\n- Idea: Using **LSTM** as a base architecture\n- Notebook: [LSTM KFold](https://www.kaggle.com/code/qmarva/lstm-kfold)\n- Profile: [@qmarva](https://www.kaggle.com/qmarva)\n\n**OlSch**\n- Idea: Applying **skip connections** inside dense networks\n- Notebook: [Keras Geology Forecast Competition 58.4](https://www.kaggle.com/code/olasdsd/keras-geology-forecast-competition-58-4)\n- Profile: [@olasdsd](https://www.kaggle.com/olasdsd)\n\nThis structure inspired me to apply residual connections within my LSTM stack:\n\n```python\nx = Dense(UNITS, activation=ACTIVATION)(x)\nx = Dropout(DROPOUT)(x)\nx = x + skip  # ← residual connection\n```\nThanks to everyone who shared their insights — it made this journey both fun and impactful.\n\n---\n\n# GitHub Repository\n✅ Full pipeline (training, inference, augmentation, evaluation):\n📂 [GitHub](https://github.com/NikitaShevyrev/Geology-Forecast-Challenge)\n📄 Licensed under BSD 2-Clause in accordance with the competition rules.",
      "votes": 3
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-19T12:42:54Z",
  "competition_id": 95697,
  "competition_slug": "geology-forecast-challenge-open",
  "team_id": 13528439,
  "solution_url": "/competitions/geology-forecast-challenge-open/writeups/nikita-shevyrev-public-1st-private-2nd-solution"
}