{
  "id": 663083,
  "title": "2nd place solution",
  "url": "/competitions/MABe-mouse-behavior-detection/writeups/2nd-place-solution",
  "author_name": "",
  "post_date": "2025-12-16T09:54:14.180Z",
  "votes": 46,
  "comment_count": 7,
  "views": 0,
  "content": "<p>We would like to sincerely thank the organizers and the Kaggle team for running such an engaging and enjoyable competition.</p>\n<h1>Overview</h1>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5547431%2Fc715804b314a45116d6faf883cf15cef%2Fkaggle%20mabe.jpg?generation=1765952024369758&amp;alt=media\" alt=\"\">\nWe train <strong>separate models for solo and pair actions</strong>.</p>\n<ul>\n<li>Input: time-series of shape <strong>(T = 512, num_features)</strong></li>\n<li>Loss: <strong>Binary Cross Entropy</strong></li>\n<li>Final predictions are obtained using <strong>lab ×actions–specific thresholds</strong></li>\n</ul>\n<hr>\n<h2>Data Preprocessing</h2>\n<ul>\n<li>All tracking data are converted to <strong>30 FPS</strong><ul>\n<li>Features: linear interpolation</li>\n<li>Labels: nearest-neighbor interpolation</li></ul></li>\n<li>Distance / velocity / acceleration are standardized using precomputed statistics</li>\n<li>Missing values are filled by linear interpolation<ul>\n<li>Missing body-part features are replaced with the mean of existing body-part features in the same frame.</li></ul></li>\n</ul>\n<h3>Handling AdaptableSnail’s 25 FPS Tracking Data</h3>\n<p>Reference:\n<a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943\" target=\"_blank\">https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943</a></p>\n<p>Issues:</p>\n<ul>\n<li>Labels are provided at <strong>30 FPS</strong></li>\n<li><strong>Mouse ID swapping</strong> occurs</li>\n</ul>\n<p>Fixes:</p>\n<ul>\n<li>Label frame rates were adjusted accordingly</li>\n<li>Mouse IDs were manually corrected by visually inspecting tracking visualization videos</li>\n</ul>\n<h2>Input Features</h2>\n<h3>Meta Features (shared across frames)</h3>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Sex</td>\n<td>solo=1, pair=2</td>\n</tr>\n<tr>\n<td>Frame-rate scale</td>\n<td>1</td>\n</tr>\n<tr>\n<td>Lab ID(passed through an embedding layer)</td>\n<td>16</td>\n</tr>\n<tr>\n<td>Candidate action label</td>\n<td>num_classes（solo=11, pair=26）</td>\n</tr>\n</tbody>\n</table>\n<h3>Per-frame Features</h3>\n<p><strong>Solo</strong></p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Body-part distances</td>\n<td>num_bodyparts²</td>\n</tr>\n<tr>\n<td>Velocity</td>\n<td>num_bodyparts</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>num_bodyparts</td>\n</tr>\n</tbody>\n</table>\n<p><br>\n<strong>Pair</strong></p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Cross-mouse body-part distances</td>\n<td>num_bodyparts²</td>\n</tr>\n<tr>\n<td>Velocity</td>\n<td>2 × num_bodyparts</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>2 × num_bodyparts</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Model Architectures</h2>\n<p>We used two architecture families.</p>\n<p><strong>CNN + RNN / Transformer</strong></p>\n<pre><code>Input\n → Multi-scale Conv (k =3,5,7,9)\n → Conv Fusion\n → Bi-GRU or Transformer\n → Linear\n → Output\n</code></pre>\n<p><strong>SqueezeFormer</strong></p>\n<pre><code>Input\n → SqueezeFormer\n → Output\n</code></pre>\n<p>We trained <strong>5 variants</strong> with different depths and hyperparameters.</p>\n<hr>\n<h2>Training</h2>\n<ul>\n<li><strong>5-fold stratified cross-validation</strong><ul>\n<li>Folds are created using only data from lab IDs that appear in the test set</li>\n<li>Lab IDs are stratified so that their distributions are consistent across folds</li>\n<li>Labs from CalMS21* and CRIM13 are always included in the training set</li></ul></li>\n<li>One-vs-rest training per actions with BCE</li>\n<li>EMA with decay = 0.999</li>\n<li>Cosine LR schedule with warmup</li>\n<li>At each epoch, optimize the thresholds for each lab–action pair on the validation set and apply early stopping based on the resulting score.</li>\n</ul>\n<h2>Data Augmentation</h2>\n<ul>\n<li>Gaussian noise</li>\n<li>Time stretching</li>\n<li>Frame shift (shift features only; labels unchanged)</li>\n<li>Left/right body-part flipping</li>\n<li>Mixup</li>\n</ul>\n<hr>\n<h2>Inference</h2>\n<ul>\n<li>Sliding-window inference with <strong>stride = 128</strong></li>\n<li>We discard <strong>32 frames at both window boundaries</strong> and average the remaining predictions.</li>\n<li>Flip test-time augmentation (TTA) </li>\n</ul>\n<hr>\n<h2>Post-processing</h2>\n<h3>Thresholding</h3>\n<ol>\n<li>Optimal thresholds are computed independently for each fold and for each lab × action pair, and the final threshold is obtained by averaging the fold-specific thresholds.</li>\n<li>For each frame, among actions above threshold, the <strong>highest-scoring action</strong> is selected</li>\n</ol>\n<h3>AdaptableSnail 25 FPS Adjustment</h3>\n<ul>\n<li><code>start_frame</code> and <code>stop_frame</code> are multiplied by <strong>30 / 25</strong></li>\n<li>When mouse ID swaps are present in the tracking data, this adjustment is not meaningful</li>\n<li>The private dataset appears to include tracking sequences without mouse ID swaps<ul>\n<li>For these sequences, predictions are aligned to the 30 FPS labels</li>\n<li>This resulted in a <strong>+0.009 improvement in the private score</strong></li></ul></li>\n</ul>\n<hr>\n<h2>Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV (Solo)</th>\n<th>CV (Pair)</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Ensemble</td>\n<td>0.069</td>\n<td>0.499</td>\n<td>0.542</td>\n<td>0.521</td>\n</tr>\n<tr>\n<td>+ AdaptableSnail post-processing</td>\n<td>—</td>\n<td>—</td>\n<td>0.542</td>\n<td><strong>0.530</strong></td>\n</tr>\n</tbody>\n</table>",
  "messages": [
    {
      "id": "3377426",
      "postDate": "12/16/2025 09:52:19",
      "content": "<p>We would like to sincerely thank the organizers and the Kaggle team for running such an engaging and enjoyable competition.</p>\n<h1>Overview</h1>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5547431%2Fc715804b314a45116d6faf883cf15cef%2Fkaggle%20mabe.jpg?generation=1765952024369758&amp;alt=media\" alt=\"\">\nWe train <strong>separate models for solo and pair actions</strong>.</p>\n<ul>\n<li>Input: time-series of shape <strong>(T = 512, num_features)</strong></li>\n<li>Loss: <strong>Binary Cross Entropy</strong></li>\n<li>Final predictions are obtained using <strong>lab ×actions–specific thresholds</strong></li>\n</ul>\n<hr>\n<h2>Data Preprocessing</h2>\n<ul>\n<li>All tracking data are converted to <strong>30 FPS</strong><ul>\n<li>Features: linear interpolation</li>\n<li>Labels: nearest-neighbor interpolation</li></ul></li>\n<li>Distance / velocity / acceleration are standardized using precomputed statistics</li>\n<li>Missing values are filled by linear interpolation<ul>\n<li>Missing body-part features are replaced with the mean of existing body-part features in the same frame.</li></ul></li>\n</ul>\n<h3>Handling AdaptableSnail’s 25 FPS Tracking Data</h3>\n<p>Reference:\n<a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943\" target=\"_blank\">https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943</a></p>\n<p>Issues:</p>\n<ul>\n<li>Labels are provided at <strong>30 FPS</strong></li>\n<li><strong>Mouse ID swapping</strong> occurs</li>\n</ul>\n<p>Fixes:</p>\n<ul>\n<li>Label frame rates were adjusted accordingly</li>\n<li>Mouse IDs were manually corrected by visually inspecting tracking visualization videos</li>\n</ul>\n<h2>Input Features</h2>\n<h3>Meta Features (shared across frames)</h3>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Sex</td>\n<td>solo=1, pair=2</td>\n</tr>\n<tr>\n<td>Frame-rate scale</td>\n<td>1</td>\n</tr>\n<tr>\n<td>Lab ID(passed through an embedding layer)</td>\n<td>16</td>\n</tr>\n<tr>\n<td>Candidate action label</td>\n<td>num_classes（solo=11, pair=26）</td>\n</tr>\n</tbody>\n</table>\n<h3>Per-frame Features</h3>\n<p><strong>Solo</strong></p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Body-part distances</td>\n<td>num_bodyparts²</td>\n</tr>\n<tr>\n<td>Velocity</td>\n<td>num_bodyparts</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>num_bodyparts</td>\n</tr>\n</tbody>\n</table>\n<p><br>\n<strong>Pair</strong></p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Cross-mouse body-part distances</td>\n<td>num_bodyparts²</td>\n</tr>\n<tr>\n<td>Velocity</td>\n<td>2 × num_bodyparts</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>2 × num_bodyparts</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Model Architectures</h2>\n<p>We used two architecture families.</p>\n<p><strong>CNN + RNN / Transformer</strong></p>\n<pre><code>Input\n → Multi-scale Conv (k =3,5,7,9)\n → Conv Fusion\n → Bi-GRU or Transformer\n → Linear\n → Output\n</code></pre>\n<p><strong>SqueezeFormer</strong></p>\n<pre><code>Input\n → SqueezeFormer\n → Output\n</code></pre>\n<p>We trained <strong>5 variants</strong> with different depths and hyperparameters.</p>\n<hr>\n<h2>Training</h2>\n<ul>\n<li><strong>5-fold stratified cross-validation</strong><ul>\n<li>Folds are created using only data from lab IDs that appear in the test set</li>\n<li>Lab IDs are stratified so that their distributions are consistent across folds</li>\n<li>Labs from CalMS21* and CRIM13 are always included in the training set</li></ul></li>\n<li>One-vs-rest training per actions with BCE</li>\n<li>EMA with decay = 0.999</li>\n<li>Cosine LR schedule with warmup</li>\n<li>At each epoch, optimize the thresholds for each lab–action pair on the validation set and apply early stopping based on the resulting score.</li>\n</ul>\n<h2>Data Augmentation</h2>\n<ul>\n<li>Gaussian noise</li>\n<li>Time stretching</li>\n<li>Frame shift (shift features only; labels unchanged)</li>\n<li>Left/right body-part flipping</li>\n<li>Mixup</li>\n</ul>\n<hr>\n<h2>Inference</h2>\n<ul>\n<li>Sliding-window inference with <strong>stride = 128</strong></li>\n<li>We discard <strong>32 frames at both window boundaries</strong> and average the remaining predictions.</li>\n<li>Flip test-time augmentation (TTA) </li>\n</ul>\n<hr>\n<h2>Post-processing</h2>\n<h3>Thresholding</h3>\n<ol>\n<li>Optimal thresholds are computed independently for each fold and for each lab × action pair, and the final threshold is obtained by averaging the fold-specific thresholds.</li>\n<li>For each frame, among actions above threshold, the <strong>highest-scoring action</strong> is selected</li>\n</ol>\n<h3>AdaptableSnail 25 FPS Adjustment</h3>\n<ul>\n<li><code>start_frame</code> and <code>stop_frame</code> are multiplied by <strong>30 / 25</strong></li>\n<li>When mouse ID swaps are present in the tracking data, this adjustment is not meaningful</li>\n<li>The private dataset appears to include tracking sequences without mouse ID swaps<ul>\n<li>For these sequences, predictions are aligned to the 30 FPS labels</li>\n<li>This resulted in a <strong>+0.009 improvement in the private score</strong></li></ul></li>\n</ul>\n<hr>\n<h2>Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>CV (Solo)</th>\n<th>CV (Pair)</th>\n<th>Public</th>\n<th>Private</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Ensemble</td>\n<td>0.069</td>\n<td>0.499</td>\n<td>0.542</td>\n<td>0.521</td>\n</tr>\n<tr>\n<td>+ AdaptableSnail post-processing</td>\n<td>—</td>\n<td>—</td>\n<td>0.542</td>\n<td><strong>0.530</strong></td>\n</tr>\n</tbody>\n</table>",
      "rawMarkdown": "We would like to sincerely thank the organizers and the Kaggle team for running such an engaging and enjoyable competition.\n\n# Overview\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5547431%2Fc715804b314a45116d6faf883cf15cef%2Fkaggle%20mabe.jpg?generation=1765952024369758&alt=media)\nWe train **separate models for solo and pair actions**.\n\n- Input: time-series of shape **(T = 512, num_features)**\n- Loss: **Binary Cross Entropy**\n- Final predictions are obtained using **lab ×actions–specific thresholds**\n\n---\n\n## Data Preprocessing\n- All tracking data are converted to **30 FPS**\n    - Features: linear interpolation\n    - Labels: nearest-neighbor interpolation\n- Distance / velocity / acceleration are standardized using precomputed statistics\n- Missing values are filled by linear interpolation\n    - Missing body-part features are replaced with the mean of existing body-part features in the same frame.\n\n### Handling AdaptableSnail’s 25 FPS Tracking Data\nReference:\nhttps://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943\n\nIssues:\n- Labels are provided at **30 FPS**\n- **Mouse ID swapping** occurs\n\nFixes:\n- Label frame rates were adjusted accordingly\n- Mouse IDs were manually corrected by visually inspecting tracking visualization videos\n\n## Input Features\n### Meta Features (shared across frames)\n| Feature | Channels |\n| --- | --- |\n| Sex | solo=1, pair=2 |\n| Frame-rate scale | 1 |\n| Lab ID(passed through an embedding layer) | 16 |\n| Candidate action label | num_classes（solo=11, pair=26） |\n\n### Per-frame Features\n**Solo**\n| Feature | Channels |\n| --- | --- |\n| Body-part distances | num_bodyparts² |\n| Velocity | num_bodyparts |\n| Acceleration | num_bodyparts |\n\n<br>\n**Pair**\n| Feature | Channels |\n| --- | --- |\n| Cross-mouse body-part distances | num_bodyparts² |\n| Velocity | 2 × num_bodyparts |\n| Acceleration | 2 × num_bodyparts |\n\n---\n## Model Architectures\nWe used two architecture families.\n\n**CNN + RNN / Transformer**\n```\nInput\n → Multi-scale Conv (k =3,5,7,9)\n → Conv Fusion\n → Bi-GRU or Transformer\n → Linear\n → Output\n```\n\n**SqueezeFormer**\n```\nInput\n → SqueezeFormer\n → Output\n```\nWe trained **5 variants** with different depths and hyperparameters.\n\n---\n\n## Training\n\n- **5-fold stratified cross-validation**\n    - Folds are created using only data from lab IDs that appear in the test set\n    - Lab IDs are stratified so that their distributions are consistent across folds\n    - Labs from CalMS21* and CRIM13 are always included in the training set\n- One-vs-rest training per actions with BCE\n- EMA with decay = 0.999\n- Cosine LR schedule with warmup\n- At each epoch, optimize the thresholds for each lab–action pair on the validation set and apply early stopping based on the resulting score.\n\n## Data Augmentation\n\n- Gaussian noise\n- Time stretching\n- Frame shift (shift features only; labels unchanged)\n- Left/right body-part flipping\n- Mixup\n\n---\n\n## Inference\n\n- Sliding-window inference with **stride = 128**\n- We discard **32 frames at both window boundaries** and average the remaining predictions.\n- Flip test-time augmentation (TTA) \n\n---\n\n## Post-processing\n\n### Thresholding\n\n1. Optimal thresholds are computed independently for each fold and for each lab × action pair, and the final threshold is obtained by averaging the fold-specific thresholds.\n2. For each frame, among actions above threshold, the **highest-scoring action** is selected\n\n### AdaptableSnail 25 FPS Adjustment\n\n- `start_frame` and `stop_frame` are multiplied by **30 / 25**\n- When mouse ID swaps are present in the tracking data, this adjustment is not meaningful\n- The private dataset appears to include tracking sequences without mouse ID swaps\n    - For these sequences, predictions are aligned to the 30 FPS labels\n    - This resulted in a **+0.009 improvement in the private score**\n\n---\n\n## Results\n\n| Model | CV (Solo) | CV (Pair) | Public | Private |\n| --- | --- | --- | --- | --- |\n| Ensemble | 0.069 | 0.499 | 0.542 | 0.521 |\n| + AdaptableSnail post-processing | — | — | 0.542 | **0.530** |",
      "votes": null
    },
    {
      "id": "3377450",
      "postDate": "12/16/2025 10:41:16",
      "content": "<p>Congratulations on the 2nd place! Really neat solution and clever way to make the NN work!</p>\n<blockquote>\n  <p>We discard 32 frames at both window boundaries and average the remaining predictions.</p>\n</blockquote>\n<p>Does this mean that your output is a sequence of labels for each frame, i.e., you trained your model similarly to a semantic segmentation model? Or did you train similar to a classification model where the target is only the label for the central frame of the window?</p>\n<p>Thank you!</p>",
      "rawMarkdown": "Congratulations on the 2nd place! Really neat solution and clever way to make the NN work!\n\n>We discard 32 frames at both window boundaries and average the remaining predictions.\n\nDoes this mean that your output is a sequence of labels for each frame, i.e., you trained your model similarly to a semantic segmentation model? Or did you train similar to a classification model where the target is only the label for the central frame of the window?\n\nThank you!",
      "votes": null
    },
    {
      "id": "3377453",
      "postDate": "12/16/2025 11:07:55",
      "content": "<p>Thank you! And congratulations on the 4th place!\nYes, it’s trained as a segmentation model, predicting all frames at once.</p>",
      "rawMarkdown": "Thank you! And congratulations on the 4th place!\nYes, it’s trained as a segmentation model, predicting all frames at once.",
      "votes": null
    },
    {
      "id": "3377963",
      "postDate": "12/17/2025 08:39:08",
      "content": "<p>Would it be possible for you to share your training and prediction submission code, i tried to work with NN, gave them a fair amount of time, but for some reason i was training them wrong, so didn't perform at all in submission.\nIf anyone who uses NN and got good score can share their code.</p>\n<p>Btw congratulations for the win.</p>",
      "rawMarkdown": "Would it be possible for you to share your training and prediction submission code, i tried to work with NN, gave them a fair amount of time, but for some reason i was training them wrong, so didn't perform at all in submission.\nIf anyone who uses NN and got good score can share their code.\n\nBtw congratulations for the win.",
      "votes": null
    },
    {
      "id": "3377964",
      "postDate": "12/17/2025 08:40:14",
      "content": "<p>oh as segmentation, that's really a nice thinking.\nNeat solution.</p>",
      "rawMarkdown": "oh as segmentation, that's really a nice thinking.\nNeat solution.",
      "votes": null
    },
    {
      "id": "3378843",
      "postDate": "12/18/2025 17:18:49",
      "content": "<p>Congratulations winning 2nd place cash gold! I like how simple your set of features are. I also like how you used invariant distances. </p>\n<p>What does \"One-vs-rest training per actions with BCE\" mean? Do you train 1 NN per action (and each NN has 1 output neuron)? Or do you train 1 NN with 26 actions (and 26 output neurons) for pair model (and 11 actions for self model)?</p>\n<p>Also do you train separate models per lab, or do you train one NN using multiple labs?</p>",
      "rawMarkdown": "Congratulations winning 2nd place cash gold! I like how simple your set of features are. I also like how you used invariant distances. \n\nWhat does \"One-vs-rest training per actions with BCE\" mean? Do you train 1 NN per action (and each NN has 1 output neuron)? Or do you train 1 NN with 26 actions (and 26 output neurons) for pair model (and 11 actions for self model)?\n\nAlso do you train separate models per lab, or do you train one NN using multiple labs?",
      "votes": null
    },
    {
      "id": "3379618",
      "postDate": "12/20/2025 08:54:59",
      "content": "<p>Thank you! Congratulations on your 7th place!</p>\n<p>Regarding the model architecture, I trained a single NN with multiple output neurons—26 for the pair model and 11 for the self model. For the labs, I used a single NN trained on all labs combined. I tried fine-tuning the model for each individual lab, but it didn't lead to any performance gains, so I opted for the simpler approach.</p>",
      "rawMarkdown": "Thank you! Congratulations on your 7th place!\n\nRegarding the model architecture, I trained a single NN with multiple output neurons—26 for the pair model and 11 for the self model. For the labs, I used a single NN trained on all labs combined. I tried fine-tuning the model for each individual lab, but it didn't lead to any performance gains, so I opted for the simpler approach.",
      "votes": null
    },
    {
      "id": "3379676",
      "postDate": "12/20/2025 11:25:14",
      "content": "<p>congratulations on your success and thanks for this write up!</p>",
      "rawMarkdown": "congratulations on your success and thanks for this write up!",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3377450,
      "author_name": "arc144",
      "author_url": "",
      "post_date": "12/16/2025 10:41:16",
      "content": "<p>Congratulations on the 2nd place! Really neat solution and clever way to make the NN work!</p>\n<blockquote>\n  <p>We discard 32 frames at both window boundaries and average the remaining predictions.</p>\n</blockquote>\n<p>Does this mean that your output is a sequence of labels for each frame, i.e., you trained your model similarly to a semantic segmentation model? Or did you train similar to a classification model where the target is only the label for the central frame of the window?</p>\n<p>Thank you!</p>",
      "votes": null,
      "replies": [
        {
          "id": 3377453,
          "author_name": "takatoyoshikawa",
          "author_url": "",
          "post_date": "12/16/2025 11:07:55",
          "content": "<p>Thank you! And congratulations on the 4th place!\nYes, it’s trained as a segmentation model, predicting all frames at once.</p>",
          "votes": null,
          "replies": [
            {
              "id": 3377964,
              "author_name": "arpit1bansal",
              "author_url": "",
              "post_date": "12/17/2025 08:40:14",
              "content": "<p>oh as segmentation, that's really a nice thinking.\nNeat solution.</p>",
              "votes": null,
              "replies": []
            }
          ]
        }
      ]
    },
    {
      "id": 3377963,
      "author_name": "arpit1bansal",
      "author_url": "",
      "post_date": "12/17/2025 08:39:08",
      "content": "<p>Would it be possible for you to share your training and prediction submission code, i tried to work with NN, gave them a fair amount of time, but for some reason i was training them wrong, so didn't perform at all in submission.\nIf anyone who uses NN and got good score can share their code.</p>\n<p>Btw congratulations for the win.</p>",
      "votes": null,
      "replies": []
    },
    {
      "id": 3378843,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/18/2025 17:18:49",
      "content": "<p>Congratulations winning 2nd place cash gold! I like how simple your set of features are. I also like how you used invariant distances. </p>\n<p>What does \"One-vs-rest training per actions with BCE\" mean? Do you train 1 NN per action (and each NN has 1 output neuron)? Or do you train 1 NN with 26 actions (and 26 output neurons) for pair model (and 11 actions for self model)?</p>\n<p>Also do you train separate models per lab, or do you train one NN using multiple labs?</p>",
      "votes": null,
      "replies": [
        {
          "id": 3379618,
          "author_name": "takatoyoshikawa",
          "author_url": "",
          "post_date": "12/20/2025 08:54:59",
          "content": "<p>Thank you! Congratulations on your 7th place!</p>\n<p>Regarding the model architecture, I trained a single NN with multiple output neurons—26 for the pair model and 11 for the self model. For the labs, I used a single NN trained on all labs combined. I tried fine-tuning the model for each individual lab, but it didn't lead to any performance gains, so I opted for the simpler approach.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 3379676,
      "author_name": "irakozekelly",
      "author_url": "",
      "post_date": "12/20/2025 11:25:14",
      "content": "<p>congratulations on your success and thanks for this write up!</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3377426": "We would like to sincerely thank the organizers and the Kaggle team for running such an engaging and enjoyable competition.\n\n# Overview\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-user-content/o/inbox%2F5547431%2Fc715804b314a45116d6faf883cf15cef%2Fkaggle%20mabe.jpg?generation=1765952024369758&alt=media)\nWe train **separate models for solo and pair actions**.\n\n- Input: time-series of shape **(T = 512, num_features)**\n- Loss: **Binary Cross Entropy**\n- Final predictions are obtained using **lab ×actions–specific thresholds**\n\n---\n\n## Data Preprocessing\n- All tracking data are converted to **30 FPS**\n    - Features: linear interpolation\n    - Labels: nearest-neighbor interpolation\n- Distance / velocity / acceleration are standardized using precomputed statistics\n- Missing values are filled by linear interpolation\n    - Missing body-part features are replaced with the mean of existing body-part features in the same frame.\n\n### Handling AdaptableSnail’s 25 FPS Tracking Data\nReference:\nhttps://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/612531#3305943\n\nIssues:\n- Labels are provided at **30 FPS**\n- **Mouse ID swapping** occurs\n\nFixes:\n- Label frame rates were adjusted accordingly\n- Mouse IDs were manually corrected by visually inspecting tracking visualization videos\n\n## Input Features\n### Meta Features (shared across frames)\n| Feature | Channels |\n| --- | --- |\n| Sex | solo=1, pair=2 |\n| Frame-rate scale | 1 |\n| Lab ID(passed through an embedding layer) | 16 |\n| Candidate action label | num_classes（solo=11, pair=26） |\n\n### Per-frame Features\n**Solo**\n| Feature | Channels |\n| --- | --- |\n| Body-part distances | num_bodyparts² |\n| Velocity | num_bodyparts |\n| Acceleration | num_bodyparts |\n\n<br>\n**Pair**\n| Feature | Channels |\n| --- | --- |\n| Cross-mouse body-part distances | num_bodyparts² |\n| Velocity | 2 × num_bodyparts |\n| Acceleration | 2 × num_bodyparts |\n\n---\n## Model Architectures\nWe used two architecture families.\n\n**CNN + RNN / Transformer**\n```\nInput\n → Multi-scale Conv (k =3,5,7,9)\n → Conv Fusion\n → Bi-GRU or Transformer\n → Linear\n → Output\n```\n\n**SqueezeFormer**\n```\nInput\n → SqueezeFormer\n → Output\n```\nWe trained **5 variants** with different depths and hyperparameters.\n\n---\n\n## Training\n\n- **5-fold stratified cross-validation**\n    - Folds are created using only data from lab IDs that appear in the test set\n    - Lab IDs are stratified so that their distributions are consistent across folds\n    - Labs from CalMS21* and CRIM13 are always included in the training set\n- One-vs-rest training per actions with BCE\n- EMA with decay = 0.999\n- Cosine LR schedule with warmup\n- At each epoch, optimize the thresholds for each lab–action pair on the validation set and apply early stopping based on the resulting score.\n\n## Data Augmentation\n\n- Gaussian noise\n- Time stretching\n- Frame shift (shift features only; labels unchanged)\n- Left/right body-part flipping\n- Mixup\n\n---\n\n## Inference\n\n- Sliding-window inference with **stride = 128**\n- We discard **32 frames at both window boundaries** and average the remaining predictions.\n- Flip test-time augmentation (TTA) \n\n---\n\n## Post-processing\n\n### Thresholding\n\n1. Optimal thresholds are computed independently for each fold and for each lab × action pair, and the final threshold is obtained by averaging the fold-specific thresholds.\n2. For each frame, among actions above threshold, the **highest-scoring action** is selected\n\n### AdaptableSnail 25 FPS Adjustment\n\n- `start_frame` and `stop_frame` are multiplied by **30 / 25**\n- When mouse ID swaps are present in the tracking data, this adjustment is not meaningful\n- The private dataset appears to include tracking sequences without mouse ID swaps\n    - For these sequences, predictions are aligned to the 30 FPS labels\n    - This resulted in a **+0.009 improvement in the private score**\n\n---\n\n## Results\n\n| Model | CV (Solo) | CV (Pair) | Public | Private |\n| --- | --- | --- | --- | --- |\n| Ensemble | 0.069 | 0.499 | 0.542 | 0.521 |\n| + AdaptableSnail post-processing | — | — | 0.542 | **0.530** |",
    "3377450": "Congratulations on the 2nd place! Really neat solution and clever way to make the NN work!\n\n>We discard 32 frames at both window boundaries and average the remaining predictions.\n\nDoes this mean that your output is a sequence of labels for each frame, i.e., you trained your model similarly to a semantic segmentation model? Or did you train similar to a classification model where the target is only the label for the central frame of the window?\n\nThank you!",
    "3377453": "Thank you! And congratulations on the 4th place!\nYes, it’s trained as a segmentation model, predicting all frames at once.",
    "3377963": "Would it be possible for you to share your training and prediction submission code, i tried to work with NN, gave them a fair amount of time, but for some reason i was training them wrong, so didn't perform at all in submission.\nIf anyone who uses NN and got good score can share their code.\n\nBtw congratulations for the win.",
    "3377964": "oh as segmentation, that's really a nice thinking.\nNeat solution.",
    "3378843": "Congratulations winning 2nd place cash gold! I like how simple your set of features are. I also like how you used invariant distances. \n\nWhat does \"One-vs-rest training per actions with BCE\" mean? Do you train 1 NN per action (and each NN has 1 output neuron)? Or do you train 1 NN with 26 actions (and 26 output neurons) for pair model (and 11 actions for self model)?\n\nAlso do you train separate models per lab, or do you train one NN using multiple labs?",
    "3379618": "Thank you! Congratulations on your 7th place!\n\nRegarding the model architecture, I trained a single NN with multiple output neurons—26 for the pair model and 11 for the self model. For the labs, I used a single NN trained on all labs combined. I tried fine-tuning the model for each individual lab, but it didn't lead to any performance gains, so I opted for the simpler approach.",
    "3379676": "congratulations on your success and thanks for this write up!"
  },
  "source": "meta"
}