{
  "id": 587915,
  "title": "69th place solution",
  "url": "/competitions/waveform-inversion/writeups/team-epoch-69th-place-solution",
  "author_name": "",
  "post_date": "2025-07-03T12:19:00.223680800Z",
  "votes": 4,
  "comment_count": 1,
  "views": 0,
  "content": "<p>First, a huge thank-you to the competition organisers and the open-source community - we learned a lot, and our ~25 MAE would have been impossible without the high-quality code everyone shared.</p>\n<p><strong>Physics side</strong><br>\nWe wrote a CUDA 2-D acoustic FDTD kernel so we could generate “velocity → shot-gather” pairs on demand. Our first plan - an iterative loop (predict velocity, forward-model shots, back-prop the mismatch, repeat) - proved too slow, so we kept the kernel purely for data synthesis. Extra velocity maps came from</p>\n<ol>\n<li>random perturbations of the labelled maps, and </li>\n<li>the 2DseisvelGenerator diffusion model queried on the fly.</li>\n</ol>\n<p>We blended synthetic shots aggressively at the start (~80 %) and tapered to ~20 % by the end of training. This schedule was stable and shaved ≈ 0.18 MAE off CV on average.</p>\n<p><strong>Architecture</strong><br>\nStarting from Brendan Bartley’s public notebooks, we trained <strong>three CaFormer-B36</strong> checkpoints (ensembling identical backbones always helped) and our own <strong>ConvNeXt-v2-Base</strong> (CV = 28.3, LB = 30.0). We used the same training framework with three tweaks:</p>\n<ul>\n<li>family-weighted loss (weights being test set distribution, derived using family classifier, below)</li>\n<li>cropping the last trace row (all-zeros for two families)</li>\n<li>synthetic data mixing described above</li>\n</ul>\n<p><strong>Family classifier</strong><br>\nWe also attached a simple classification head to the best public ConvNeXt, hitting &gt; 99 % accuracy after three epochs. The idea was to run family-specific fine-tunes, but the gains were negligible, so we dropped the separate pipelines.</p>\n<p><strong>Final submission</strong><br>\nThe submission is a weighted median of eight CSVs:</p>\n<ul>\n<li>the public 25.6 baseline</li>\n<li>two public ConvNeXts</li>\n<li>the public CaFormer (finetuned with our 'synthetic' data)</li>\n<li>three CaFormers we trained</li>\n<li>our ConvNeXt-v2-Base</li>\n</ul>\n<p>Weights split roughly 0.4 (CaFormers) / 0.3 (ConvNeXts) / 0.3 (public baseline). Weighted median beat weighted mean by about 1 MAE.</p>\n<p><strong>What didn’t work</strong></p>\n<ul>\n<li>Any post-processing beyond simple clipping</li>\n<li>Loss functions other than plain L1</li>\n</ul>\n<p><strong>Results and takeways</strong><br>\nPrivate LB 24.57, 69th overall - just one place short of silver. The real limiter was training speed so exploring new (and bigger) architectures was very constrained. Still, with tight hardware and limited experience, we’re happy with the final results.</p>\n<p>Team Epoch</p>",
  "messages": [
    {
      "id": "3240056",
      "postDate": "07/03/2025 12:19:00",
      "content": "<p>First, a huge thank-you to the competition organisers and the open-source community - we learned a lot, and our ~25 MAE would have been impossible without the high-quality code everyone shared.</p>\n<p><strong>Physics side</strong><br>\nWe wrote a CUDA 2-D acoustic FDTD kernel so we could generate “velocity → shot-gather” pairs on demand. Our first plan - an iterative loop (predict velocity, forward-model shots, back-prop the mismatch, repeat) - proved too slow, so we kept the kernel purely for data synthesis. Extra velocity maps came from</p>\n<ol>\n<li>random perturbations of the labelled maps, and </li>\n<li>the 2DseisvelGenerator diffusion model queried on the fly.</li>\n</ol>\n<p>We blended synthetic shots aggressively at the start (~80 %) and tapered to ~20 % by the end of training. This schedule was stable and shaved ≈ 0.18 MAE off CV on average.</p>\n<p><strong>Architecture</strong><br>\nStarting from Brendan Bartley’s public notebooks, we trained <strong>three CaFormer-B36</strong> checkpoints (ensembling identical backbones always helped) and our own <strong>ConvNeXt-v2-Base</strong> (CV = 28.3, LB = 30.0). We used the same training framework with three tweaks:</p>\n<ul>\n<li>family-weighted loss (weights being test set distribution, derived using family classifier, below)</li>\n<li>cropping the last trace row (all-zeros for two families)</li>\n<li>synthetic data mixing described above</li>\n</ul>\n<p><strong>Family classifier</strong><br>\nWe also attached a simple classification head to the best public ConvNeXt, hitting &gt; 99 % accuracy after three epochs. The idea was to run family-specific fine-tunes, but the gains were negligible, so we dropped the separate pipelines.</p>\n<p><strong>Final submission</strong><br>\nThe submission is a weighted median of eight CSVs:</p>\n<ul>\n<li>the public 25.6 baseline</li>\n<li>two public ConvNeXts</li>\n<li>the public CaFormer (finetuned with our 'synthetic' data)</li>\n<li>three CaFormers we trained</li>\n<li>our ConvNeXt-v2-Base</li>\n</ul>\n<p>Weights split roughly 0.4 (CaFormers) / 0.3 (ConvNeXts) / 0.3 (public baseline). Weighted median beat weighted mean by about 1 MAE.</p>\n<p><strong>What didn’t work</strong></p>\n<ul>\n<li>Any post-processing beyond simple clipping</li>\n<li>Loss functions other than plain L1</li>\n</ul>\n<p><strong>Results and takeways</strong><br>\nPrivate LB 24.57, 69th overall - just one place short of silver. The real limiter was training speed so exploring new (and bigger) architectures was very constrained. Still, with tight hardware and limited experience, we’re happy with the final results.</p>\n<p>Team Epoch</p>",
      "rawMarkdown": "First, a huge thank-you to the competition organisers and the open-source community - we learned a lot, and our ~25 MAE would have been impossible without the high-quality code everyone shared.\n\n**Physics side**\nWe wrote a CUDA 2-D acoustic FDTD kernel so we could generate “velocity → shot-gather” pairs on demand. Our first plan - an iterative loop (predict velocity, forward-model shots, back-prop the mismatch, repeat) - proved too slow, so we kept the kernel purely for data synthesis. Extra velocity maps came from\n1. random perturbations of the labelled maps, and \n2. the 2DseisvelGenerator diffusion model queried on the fly.\n\nWe blended synthetic shots aggressively at the start (~80 %) and tapered to ~20 % by the end of training. This schedule was stable and shaved ≈ 0.18 MAE off CV on average.\n\n**Architecture**\nStarting from Brendan Bartley’s public notebooks, we trained **three CaFormer-B36** checkpoints (ensembling identical backbones always helped) and our own **ConvNeXt-v2-Base** (CV = 28.3, LB = 30.0). We used the same training framework with three tweaks:\n- family-weighted loss (weights being test set distribution, derived using family classifier, below)\n- cropping the last trace row (all-zeros for two families)\n- synthetic data mixing described above\n\n\n\n**Family classifier**\nWe also attached a simple classification head to the best public ConvNeXt, hitting > 99 % accuracy after three epochs. The idea was to run family-specific fine-tunes, but the gains were negligible, so we dropped the separate pipelines.\n\n**Final submission**\nThe submission is a weighted median of eight CSVs:\n- the public 25.6 baseline\n- two public ConvNeXts\n- the public CaFormer (finetuned with our 'synthetic' data)\n- three CaFormers we trained\n- our ConvNeXt-v2-Base\n\n\nWeights split roughly 0.4 (CaFormers) / 0.3 (ConvNeXts) / 0.3 (public baseline). Weighted median beat weighted mean by about 1 MAE.\n\n**What didn’t work**\n- Any post-processing beyond simple clipping\n- Loss functions other than plain L1\n\n\n**Results and takeways**\nPrivate LB 24.57, 69th overall - just one place short of silver. The real limiter was training speed so exploring new (and bigger) architectures was very constrained. Still, with tight hardware and limited experience, we’re happy with the final results.\n\nTeam Epoch",
      "votes": null
    },
    {
      "id": "3272421",
      "postDate": "08/20/2025 23:02:09",
      "content": "<p>can you share you code link? many thanks.</p>",
      "rawMarkdown": "can you share you code link? many thanks.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3272421,
      "author_name": "chaoshun",
      "author_url": "",
      "post_date": "08/20/2025 23:02:09",
      "content": "<p>can you share you code link? many thanks.</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3240056": "First, a huge thank-you to the competition organisers and the open-source community - we learned a lot, and our ~25 MAE would have been impossible without the high-quality code everyone shared.\n\n**Physics side**\nWe wrote a CUDA 2-D acoustic FDTD kernel so we could generate “velocity → shot-gather” pairs on demand. Our first plan - an iterative loop (predict velocity, forward-model shots, back-prop the mismatch, repeat) - proved too slow, so we kept the kernel purely for data synthesis. Extra velocity maps came from\n1. random perturbations of the labelled maps, and \n2. the 2DseisvelGenerator diffusion model queried on the fly.\n\nWe blended synthetic shots aggressively at the start (~80 %) and tapered to ~20 % by the end of training. This schedule was stable and shaved ≈ 0.18 MAE off CV on average.\n\n**Architecture**\nStarting from Brendan Bartley’s public notebooks, we trained **three CaFormer-B36** checkpoints (ensembling identical backbones always helped) and our own **ConvNeXt-v2-Base** (CV = 28.3, LB = 30.0). We used the same training framework with three tweaks:\n- family-weighted loss (weights being test set distribution, derived using family classifier, below)\n- cropping the last trace row (all-zeros for two families)\n- synthetic data mixing described above\n\n\n\n**Family classifier**\nWe also attached a simple classification head to the best public ConvNeXt, hitting > 99 % accuracy after three epochs. The idea was to run family-specific fine-tunes, but the gains were negligible, so we dropped the separate pipelines.\n\n**Final submission**\nThe submission is a weighted median of eight CSVs:\n- the public 25.6 baseline\n- two public ConvNeXts\n- the public CaFormer (finetuned with our 'synthetic' data)\n- three CaFormers we trained\n- our ConvNeXt-v2-Base\n\n\nWeights split roughly 0.4 (CaFormers) / 0.3 (ConvNeXts) / 0.3 (public baseline). Weighted median beat weighted mean by about 1 MAE.\n\n**What didn’t work**\n- Any post-processing beyond simple clipping\n- Loss functions other than plain L1\n\n\n**Results and takeways**\nPrivate LB 24.57, 69th overall - just one place short of silver. The real limiter was training speed so exploring new (and bigger) architectures was very constrained. Still, with tight hardware and limited experience, we’re happy with the final results.\n\nTeam Epoch",
    "3272421": "can you share you code link? many thanks."
  },
  "source": "meta"
}