{
  "id": 663032,
  "title": "6th Place Solution (monnu's Part)",
  "url": "/competitions/MABe-mouse-behavior-detection/discussion/663032",
  "author_name": "",
  "post_date": "2025-12-16T00:19:17.131324200Z",
  "votes": 22,
  "comment_count": 2,
  "views": 0,
  "content": "<p>We would like to extend our sincere gratitude to the organizers for hosting such an engaging and fascinating competition.</p>\n<p>Below is monnnu's portion from Team yu4u and monnnu; <a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028\" target=\"_blank\">yu4u's great write-up is available separately</a>. Our final submission blends yu4u's models, monnnu's models, and a public notebook via a weighted ensemble.</p>\n<h2>My Solution Approach</h2>\n<p>Here, I present my approach to this competition.</p>\n<h2>Solution Overview</h2>\n<ol>\n<li>Time series modeling with <strong>1D Convolution</strong> and <strong>bi-LSTM</strong></li>\n<li><strong>Two-stage training: All-Lab training → Lab-specific Fine-tuning</strong></li>\n<li><strong>Data Augmentation</strong>: Spatial flips, window overlapping, random shifts, random rotations, and inference-time TTA.</li>\n<li><strong>Multi-Label Classification Approach</strong>: Implemented with <strong>masking of unlabeled regions</strong> to reduce noise during loss calculation. This ensures that only labeled frames contribute to the loss.</li>\n</ol>\n<h2>1. Model Architecture</h2>\n<p>For time series data, I created a model combining 1D CNN and BiLSTM.\nInput is processed with a fixed-length window, with window size set to 500 frames.</p>\n<h3>Model A: 1D Convolutional Network</h3>\n<pre><code>Input (T, Features) → Transpose → (Features, T)\n  ↓ Stem Conv1d\n  ↓ 8× Dilated Residual Blocks\n  ↓   Depthwise Separable Conv + GroupNorm + GELU\n  ↓ Head Conv1d\n  ↓\nOutput (Classes, T) → Frame-wise logits\n</code></pre>\n<h3>Model B: Bidirectional LSTM Network</h3>\n<pre><code>Input (T, Features)\n  ↓ Embedding Conv\n  ↓ Bi-LSTM layers (2 layers)\n  ↓ Head (Linear layer)\n  ↓\nOutput (Classes, T) → Frame-wise logits\n</code></pre>\n<p>In the final submission, I averaged the predicted probabilities from models trained with several variations.</p>\n<h2>2. Training Strategy</h2>\n<h3>Two-Stage Training</h3>\n<p>To Train common patterns while adapting to Lab-specific characteristics, I used two-stage training.</p>\n<p><strong>Stage 1: All-Lab Training</strong></p>\n<ul>\n<li>Pair behaviors: 19 Pair Labs</li>\n<li>Self behaviors: 10 Self Labs</li>\n<li>Acquire general behavioral patterns for each type and build robust models with diverse data.</li>\n</ul>\n<p><strong>Stage 2: Lab-specific Fine-tuning</strong></p>\n<ul>\n<li>Use Stage 1 model as initialization for individual Lab training</li>\n<li>Adapt to Lab-specific characteristics</li>\n</ul>\n<p>This resulted in improvements across all Labs compared to training only on the combined dataset or only on each individual Lab.</p>\n<h3>Self/Pair-Specific Models</h3>\n<p>Trained separate models for each behavior type (self/pair).\nInitially used a single model, but separation resulted in slight accuracy improvements for both behavior types.</p>\n<h2>3. Multi-Label Classification and Loss Masking for Unlabeled Regions</h2>\n<p>Solved as a multi-label task, excluding unlabeled regions from loss calculation.</p>\n<h3>Multi-Label Classification</h3>\n<ul>\n<li>Loss: BCEWithLogitsLoss</li>\n<li>Apply sigmoid + BCE independently for each class</li>\n</ul>\n<h3>Loss Masking for Unlabeled Regions</h3>\n<ul>\n<li>In this dataset, only labels contained in behaviors_labeled are annotated.</li>\n<li><strong>Unlabeled ≠ No behavior</strong>, and treating unlabeled as negative examples (0) would introduce noise, so I used this loss approach.</li>\n</ul>\n<pre><code># 1. Identify labeled frames\nnan_mask = (~torch.isnan(y)).float()\n\n# 2. Combine with valid frame mask\neffective_mask = frame_mask * nan_mask\n\n# 3. Compute loss only on labeled frames\nloss = (raw_loss * effective_mask).sum() / effective_mask.sum()\n</code></pre>\n<h2>4. Feature Engineering</h2>\n<p>In addition to raw pose features and meta features, I added several engineered features.</p>\n<h3>A. Basic Coordinate Features (Raw Pose)</h3>\n<ul>\n<li>12 body parts × 2 mice × (x, y) = 48 dimensions</li>\n<li>Body parts: body_center, ear, head, hip, lateral, neck, nose, tail_base, tail_tip, etc.</li>\n<li>All coordinates for both Agent and Target</li>\n</ul>\n<h3>B. Derived Features - Distance and Relative Position</h3>\n<ul>\n<li>Distance between corresponding body parts</li>\n<li>Center-to-center distance</li>\n<li>Distance from nose to opponent's tail base</li>\n</ul>\n<h3>C. Derived Features - Movement and Velocity</h3>\n<ul>\n<li>Frame-to-frame velocity for each body part</li>\n<li>For Pair: both mice; for Self: Agent only</li>\n</ul>\n<h3>D. Derived Features - Direction and Angle</h3>\n<ul>\n<li>Direction angle from Agent's nose to Target's body center</li>\n<li>Angle between Agent's movement direction and Target direction (invariant to rotation/reflection)</li>\n</ul>\n<h3>E. Metadata and Video Features</h3>\n<ul>\n<li>fps, resolution, aspect ratio</li>\n<li>Arena width/height/area (cm)</li>\n<li>Conversion coefficient between pixels and cm</li>\n</ul>\n<h3>F. Mouse Attribute Features (Pair)</h3>\n<ul>\n<li>Strain, sex, age (Agent/Target)</li>\n<li>Same-strain/same-condition flags, age difference, average age, etc.</li>\n</ul>\n<p><strong>For Self behaviors</strong>: Exclude Target-side attributes and distance-related features</p>\n<h2>5. Data Augmentation</h2>\n<h3>Augmentation During Training</h3>\n<p><strong>A. Spatial Flips</strong></p>\n<ul>\n<li>Horizontal flip: <code>x' = width - x</code>, <code>angle' = π - angle</code></li>\n<li>Vertical flip: <code>y' = height - y</code>, <code>angle' = -angle</code></li>\n<li>Both-axis flip: Combination of both</li>\n<li>Swap Left/Right body parts → Expand training data to 4 patterns</li>\n</ul>\n<p><strong>B. Window Overlapping</strong></p>\n<ul>\n<li>Fixed-length window (window=500 frames) processed with stride=250</li>\n<li>50% overlap amplifies training data</li>\n</ul>\n<p><strong>C. Random Frame Shifts</strong></p>\n<ul>\n<li>During training only, randomly shift window start position in range [0, stride)</li>\n<li>Shift position changes each epoch, achieving further data amplification</li>\n</ul>\n<p><strong>D. Random Rotation</strong></p>\n<ul>\n<li>With 50% probability, apply rotation by random angle ([-π, π]) to coordinates</li>\n<li>Rotation center is the centroid of all coordinates in each frame</li>\n</ul>\n<h3>TTA (Test Time Augmentation) During Inference</h3>\n<p><strong>A. Dense Sliding Window</strong></p>\n<ul>\n<li>Predict multiple windows with window=500, stride=250</li>\n<li>Average predicted probabilities across all test sequences</li>\n</ul>\n<p><strong>B. Spatial Flip Variations</strong></p>\n<ul>\n<li>Original data + horizontal flip + vertical flip + both-axis flip (4 patterns)</li>\n<li>Predict for each variation and average probabilities</li>\n</ul>\n<h2>6. Other Training Settings</h2>\n<ul>\n<li><strong>Max Epochs</strong>: 1000 (terminated by early stopping)</li>\n<li><strong>Early stopping</strong>: 5 epochs (Pair), 10 epochs (Self)</li>\n<li><strong>Optimizer</strong>: AdamW (lr=5e-4, warmup 5 epochs + cosine decay)</li>\n</ul>\n<h2>7. Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Random Rotation/Shift</th>\n<th>CV</th>\n<th>LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1DConv</td>\n<td>No</td>\n<td>0.524896</td>\n<td>0.530</td>\n</tr>\n<tr>\n<td>LSTM</td>\n<td>No</td>\n<td>0.523124</td>\n<td>-</td>\n</tr>\n<tr>\n<td>1DConv</td>\n<td>Yes</td>\n<td>0.532914</td>\n<td>0.522</td>\n</tr>\n<tr>\n<td>LSTM</td>\n<td>Yes</td>\n<td>0.522641</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Ensemble</td>\n<td>-</td>\n<td>0.546648</td>\n<td>-</td>\n</tr>\n</tbody>\n</table>\n<p>In the final submission, predictions were combined with weighted averaging using team members' models and GBDT models from public notebooks.</p>",
  "messages": [
    {
      "id": "3377237",
      "postDate": "12/16/2025 00:19:17",
      "content": "<p>We would like to extend our sincere gratitude to the organizers for hosting such an engaging and fascinating competition.</p>\n<p>Below is monnnu's portion from Team yu4u and monnnu; <a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028\" target=\"_blank\">yu4u's great write-up is available separately</a>. Our final submission blends yu4u's models, monnnu's models, and a public notebook via a weighted ensemble.</p>\n<h2>My Solution Approach</h2>\n<p>Here, I present my approach to this competition.</p>\n<h2>Solution Overview</h2>\n<ol>\n<li>Time series modeling with <strong>1D Convolution</strong> and <strong>bi-LSTM</strong></li>\n<li><strong>Two-stage training: All-Lab training → Lab-specific Fine-tuning</strong></li>\n<li><strong>Data Augmentation</strong>: Spatial flips, window overlapping, random shifts, random rotations, and inference-time TTA.</li>\n<li><strong>Multi-Label Classification Approach</strong>: Implemented with <strong>masking of unlabeled regions</strong> to reduce noise during loss calculation. This ensures that only labeled frames contribute to the loss.</li>\n</ol>\n<h2>1. Model Architecture</h2>\n<p>For time series data, I created a model combining 1D CNN and BiLSTM.\nInput is processed with a fixed-length window, with window size set to 500 frames.</p>\n<h3>Model A: 1D Convolutional Network</h3>\n<pre><code>Input (T, Features) → Transpose → (Features, T)\n  ↓ Stem Conv1d\n  ↓ 8× Dilated Residual Blocks\n  ↓   Depthwise Separable Conv + GroupNorm + GELU\n  ↓ Head Conv1d\n  ↓\nOutput (Classes, T) → Frame-wise logits\n</code></pre>\n<h3>Model B: Bidirectional LSTM Network</h3>\n<pre><code>Input (T, Features)\n  ↓ Embedding Conv\n  ↓ Bi-LSTM layers (2 layers)\n  ↓ Head (Linear layer)\n  ↓\nOutput (Classes, T) → Frame-wise logits\n</code></pre>\n<p>In the final submission, I averaged the predicted probabilities from models trained with several variations.</p>\n<h2>2. Training Strategy</h2>\n<h3>Two-Stage Training</h3>\n<p>To Train common patterns while adapting to Lab-specific characteristics, I used two-stage training.</p>\n<p><strong>Stage 1: All-Lab Training</strong></p>\n<ul>\n<li>Pair behaviors: 19 Pair Labs</li>\n<li>Self behaviors: 10 Self Labs</li>\n<li>Acquire general behavioral patterns for each type and build robust models with diverse data.</li>\n</ul>\n<p><strong>Stage 2: Lab-specific Fine-tuning</strong></p>\n<ul>\n<li>Use Stage 1 model as initialization for individual Lab training</li>\n<li>Adapt to Lab-specific characteristics</li>\n</ul>\n<p>This resulted in improvements across all Labs compared to training only on the combined dataset or only on each individual Lab.</p>\n<h3>Self/Pair-Specific Models</h3>\n<p>Trained separate models for each behavior type (self/pair).\nInitially used a single model, but separation resulted in slight accuracy improvements for both behavior types.</p>\n<h2>3. Multi-Label Classification and Loss Masking for Unlabeled Regions</h2>\n<p>Solved as a multi-label task, excluding unlabeled regions from loss calculation.</p>\n<h3>Multi-Label Classification</h3>\n<ul>\n<li>Loss: BCEWithLogitsLoss</li>\n<li>Apply sigmoid + BCE independently for each class</li>\n</ul>\n<h3>Loss Masking for Unlabeled Regions</h3>\n<ul>\n<li>In this dataset, only labels contained in behaviors_labeled are annotated.</li>\n<li><strong>Unlabeled ≠ No behavior</strong>, and treating unlabeled as negative examples (0) would introduce noise, so I used this loss approach.</li>\n</ul>\n<pre><code># 1. Identify labeled frames\nnan_mask = (~torch.isnan(y)).float()\n\n# 2. Combine with valid frame mask\neffective_mask = frame_mask * nan_mask\n\n# 3. Compute loss only on labeled frames\nloss = (raw_loss * effective_mask).sum() / effective_mask.sum()\n</code></pre>\n<h2>4. Feature Engineering</h2>\n<p>In addition to raw pose features and meta features, I added several engineered features.</p>\n<h3>A. Basic Coordinate Features (Raw Pose)</h3>\n<ul>\n<li>12 body parts × 2 mice × (x, y) = 48 dimensions</li>\n<li>Body parts: body_center, ear, head, hip, lateral, neck, nose, tail_base, tail_tip, etc.</li>\n<li>All coordinates for both Agent and Target</li>\n</ul>\n<h3>B. Derived Features - Distance and Relative Position</h3>\n<ul>\n<li>Distance between corresponding body parts</li>\n<li>Center-to-center distance</li>\n<li>Distance from nose to opponent's tail base</li>\n</ul>\n<h3>C. Derived Features - Movement and Velocity</h3>\n<ul>\n<li>Frame-to-frame velocity for each body part</li>\n<li>For Pair: both mice; for Self: Agent only</li>\n</ul>\n<h3>D. Derived Features - Direction and Angle</h3>\n<ul>\n<li>Direction angle from Agent's nose to Target's body center</li>\n<li>Angle between Agent's movement direction and Target direction (invariant to rotation/reflection)</li>\n</ul>\n<h3>E. Metadata and Video Features</h3>\n<ul>\n<li>fps, resolution, aspect ratio</li>\n<li>Arena width/height/area (cm)</li>\n<li>Conversion coefficient between pixels and cm</li>\n</ul>\n<h3>F. Mouse Attribute Features (Pair)</h3>\n<ul>\n<li>Strain, sex, age (Agent/Target)</li>\n<li>Same-strain/same-condition flags, age difference, average age, etc.</li>\n</ul>\n<p><strong>For Self behaviors</strong>: Exclude Target-side attributes and distance-related features</p>\n<h2>5. Data Augmentation</h2>\n<h3>Augmentation During Training</h3>\n<p><strong>A. Spatial Flips</strong></p>\n<ul>\n<li>Horizontal flip: <code>x' = width - x</code>, <code>angle' = π - angle</code></li>\n<li>Vertical flip: <code>y' = height - y</code>, <code>angle' = -angle</code></li>\n<li>Both-axis flip: Combination of both</li>\n<li>Swap Left/Right body parts → Expand training data to 4 patterns</li>\n</ul>\n<p><strong>B. Window Overlapping</strong></p>\n<ul>\n<li>Fixed-length window (window=500 frames) processed with stride=250</li>\n<li>50% overlap amplifies training data</li>\n</ul>\n<p><strong>C. Random Frame Shifts</strong></p>\n<ul>\n<li>During training only, randomly shift window start position in range [0, stride)</li>\n<li>Shift position changes each epoch, achieving further data amplification</li>\n</ul>\n<p><strong>D. Random Rotation</strong></p>\n<ul>\n<li>With 50% probability, apply rotation by random angle ([-π, π]) to coordinates</li>\n<li>Rotation center is the centroid of all coordinates in each frame</li>\n</ul>\n<h3>TTA (Test Time Augmentation) During Inference</h3>\n<p><strong>A. Dense Sliding Window</strong></p>\n<ul>\n<li>Predict multiple windows with window=500, stride=250</li>\n<li>Average predicted probabilities across all test sequences</li>\n</ul>\n<p><strong>B. Spatial Flip Variations</strong></p>\n<ul>\n<li>Original data + horizontal flip + vertical flip + both-axis flip (4 patterns)</li>\n<li>Predict for each variation and average probabilities</li>\n</ul>\n<h2>6. Other Training Settings</h2>\n<ul>\n<li><strong>Max Epochs</strong>: 1000 (terminated by early stopping)</li>\n<li><strong>Early stopping</strong>: 5 epochs (Pair), 10 epochs (Self)</li>\n<li><strong>Optimizer</strong>: AdamW (lr=5e-4, warmup 5 epochs + cosine decay)</li>\n</ul>\n<h2>7. Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Random Rotation/Shift</th>\n<th>CV</th>\n<th>LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1DConv</td>\n<td>No</td>\n<td>0.524896</td>\n<td>0.530</td>\n</tr>\n<tr>\n<td>LSTM</td>\n<td>No</td>\n<td>0.523124</td>\n<td>-</td>\n</tr>\n<tr>\n<td>1DConv</td>\n<td>Yes</td>\n<td>0.532914</td>\n<td>0.522</td>\n</tr>\n<tr>\n<td>LSTM</td>\n<td>Yes</td>\n<td>0.522641</td>\n<td>-</td>\n</tr>\n<tr>\n<td>Ensemble</td>\n<td>-</td>\n<td>0.546648</td>\n<td>-</td>\n</tr>\n</tbody>\n</table>\n<p>In the final submission, predictions were combined with weighted averaging using team members' models and GBDT models from public notebooks.</p>",
      "rawMarkdown": "We would like to extend our sincere gratitude to the organizers for hosting such an engaging and fascinating competition.\n\nBelow is monnnu's portion from Team yu4u and monnnu; [yu4u's great write-up is available separately](https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028). Our final submission blends yu4u's models, monnnu's models, and a public notebook via a weighted ensemble.\n\n\n## My Solution Approach\nHere, I present my approach to this competition.\n\n\n## Solution Overview\n1. Time series modeling with **1D Convolution** and **bi-LSTM**\n2. **Two-stage training: All-Lab training → Lab-specific Fine-tuning**\n3. **Data Augmentation**: Spatial flips, window overlapping, random shifts, random rotations, and inference-time TTA.\n4. **Multi-Label Classification Approach**: Implemented with **masking of unlabeled regions** to reduce noise during loss calculation. This ensures that only labeled frames contribute to the loss.\n\n## 1. Model Architecture\nFor time series data, I created a model combining 1D CNN and BiLSTM.\nInput is processed with a fixed-length window, with window size set to 500 frames.\n\n### Model A: 1D Convolutional Network\n```\nInput (T, Features) → Transpose → (Features, T)\n  ↓ Stem Conv1d\n  ↓ 8× Dilated Residual Blocks\n  ↓   Depthwise Separable Conv + GroupNorm + GELU\n  ↓ Head Conv1d\n  ↓\nOutput (Classes, T) → Frame-wise logits\n```\n\n### Model B: Bidirectional LSTM Network\n```\nInput (T, Features)\n  ↓ Embedding Conv\n  ↓ Bi-LSTM layers (2 layers)\n  ↓ Head (Linear layer)\n  ↓\nOutput (Classes, T) → Frame-wise logits\n```\n\nIn the final submission, I averaged the predicted probabilities from models trained with several variations.\n\n## 2. Training Strategy\n\n### Two-Stage Training\nTo Train common patterns while adapting to Lab-specific characteristics, I used two-stage training.\n\n**Stage 1: All-Lab Training**\n- Pair behaviors: 19 Pair Labs\n- Self behaviors: 10 Self Labs\n- Acquire general behavioral patterns for each type and build robust models with diverse data.\n\n**Stage 2: Lab-specific Fine-tuning**\n- Use Stage 1 model as initialization for individual Lab training\n- Adapt to Lab-specific characteristics\n\nThis resulted in improvements across all Labs compared to training only on the combined dataset or only on each individual Lab.\n\n### Self/Pair-Specific Models\nTrained separate models for each behavior type (self/pair).\nInitially used a single model, but separation resulted in slight accuracy improvements for both behavior types.\n\n## 3. Multi-Label Classification and Loss Masking for Unlabeled Regions\nSolved as a multi-label task, excluding unlabeled regions from loss calculation.\n\n### Multi-Label Classification\n- Loss: BCEWithLogitsLoss\n- Apply sigmoid + BCE independently for each class\n\n### Loss Masking for Unlabeled Regions\n- In this dataset, only labels contained in behaviors_labeled are annotated.\n- **Unlabeled ≠ No behavior**, and treating unlabeled as negative examples (0) would introduce noise, so I used this loss approach.\n\n```python\n# 1. Identify labeled frames\nnan_mask = (~torch.isnan(y)).float()\n\n# 2. Combine with valid frame mask\neffective_mask = frame_mask * nan_mask\n\n# 3. Compute loss only on labeled frames\nloss = (raw_loss * effective_mask).sum() / effective_mask.sum()\n```\n\n## 4. Feature Engineering\nIn addition to raw pose features and meta features, I added several engineered features.\n\n### A. Basic Coordinate Features (Raw Pose)\n\n- 12 body parts × 2 mice × (x, y) = 48 dimensions\n- Body parts: body_center, ear, head, hip, lateral, neck, nose, tail_base, tail_tip, etc.\n- All coordinates for both Agent and Target\n\n### B. Derived Features - Distance and Relative Position\n\n- Distance between corresponding body parts\n- Center-to-center distance\n- Distance from nose to opponent's tail base\n\n### C. Derived Features - Movement and Velocity\n\n- Frame-to-frame velocity for each body part\n- For Pair: both mice; for Self: Agent only\n\n### D. Derived Features - Direction and Angle\n\n- Direction angle from Agent's nose to Target's body center\n- Angle between Agent's movement direction and Target direction (invariant to rotation/reflection)\n\n### E. Metadata and Video Features\n\n- fps, resolution, aspect ratio\n- Arena width/height/area (cm)\n- Conversion coefficient between pixels and cm\n\n### F. Mouse Attribute Features (Pair)\n\n- Strain, sex, age (Agent/Target)\n- Same-strain/same-condition flags, age difference, average age, etc.\n\n**For Self behaviors**: Exclude Target-side attributes and distance-related features\n\n## 5. Data Augmentation\n\n### Augmentation During Training\n\n**A. Spatial Flips**\n- Horizontal flip: `x' = width - x`, `angle' = π - angle`\n- Vertical flip: `y' = height - y`, `angle' = -angle`\n- Both-axis flip: Combination of both\n- Swap Left/Right body parts → Expand training data to 4 patterns\n\n**B. Window Overlapping**\n- Fixed-length window (window=500 frames) processed with stride=250\n- 50% overlap amplifies training data\n\n**C. Random Frame Shifts**\n- During training only, randomly shift window start position in range [0, stride)\n- Shift position changes each epoch, achieving further data amplification\n\n**D. Random Rotation**\n- With 50% probability, apply rotation by random angle ([-π, π]) to coordinates\n- Rotation center is the centroid of all coordinates in each frame\n\n### TTA (Test Time Augmentation) During Inference\n\n**A. Dense Sliding Window**\n- Predict multiple windows with window=500, stride=250\n- Average predicted probabilities across all test sequences\n\n**B. Spatial Flip Variations**\n- Original data + horizontal flip + vertical flip + both-axis flip (4 patterns)\n- Predict for each variation and average probabilities\n\n## 6. Other Training Settings\n- **Max Epochs**: 1000 (terminated by early stopping)\n- **Early stopping**: 5 epochs (Pair), 10 epochs (Self)\n- **Optimizer**: AdamW (lr=5e-4, warmup 5 epochs + cosine decay)\n\n## 7. Results\n\n| Model | Random Rotation/Shift | CV | LB |\n|--------|-------------------|-----|-----|\n| 1DConv | No | 0.524896 | 0.530 |\n| LSTM | No | 0.523124 | - |\n| 1DConv | Yes | 0.532914 | 0.522 |\n| LSTM | Yes | 0.522641 | - |\n| Ensemble | - | 0.546648 | - |\n\nIn the final submission, predictions were combined with weighted averaging using team members' models and GBDT models from public notebooks.",
      "votes": null
    },
    {
      "id": "3378100",
      "postDate": "12/17/2025 14:44:04",
      "content": "<p>Congratulations winning 6th place gold. I like your use of Bi-RNN instead of transformer. Using 2 stage training is smart. How much did the second stage boost CV and LB?</p>\n<p>How did you handle AdaptableSnail fps=25 during test inference?</p>",
      "rawMarkdown": "Congratulations winning 6th place gold. I like your use of Bi-RNN instead of transformer. Using 2 stage training is smart. How much did the second stage boost CV and LB?\n\nHow did you handle AdaptableSnail fps=25 during test inference?",
      "votes": null
    },
    {
      "id": "3379425",
      "postDate": "12/19/2025 19:38:01",
      "content": "<p>Thanks for the comment, and congrats on your solo gold!</p>\n<p>The improvements from the 2nd stage were about 0.013 for CV and 0.023 for LB. </p>\n<p>We didn't do anything specific regarding the 25 fps for AdaptableSnail. My teammate is investigating the details over here.\n<a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361\" target=\"_blank\">https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361</a></p>",
      "rawMarkdown": "Thanks for the comment, and congrats on your solo gold!\n\nThe improvements from the 2nd stage were about 0.013 for CV and 0.023 for LB. \n\nWe didn't do anything specific regarding the 25 fps for AdaptableSnail. My teammate is investigating the details over here.\nhttps://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3378100,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/17/2025 14:44:04",
      "content": "<p>Congratulations winning 6th place gold. I like your use of Bi-RNN instead of transformer. Using 2 stage training is smart. How much did the second stage boost CV and LB?</p>\n<p>How did you handle AdaptableSnail fps=25 during test inference?</p>",
      "votes": null,
      "replies": [
        {
          "id": 3379425,
          "author_name": "fuumin621",
          "author_url": "",
          "post_date": "12/19/2025 19:38:01",
          "content": "<p>Thanks for the comment, and congrats on your solo gold!</p>\n<p>The improvements from the 2nd stage were about 0.013 for CV and 0.023 for LB. </p>\n<p>We didn't do anything specific regarding the 25 fps for AdaptableSnail. My teammate is investigating the details over here.\n<a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361\" target=\"_blank\">https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361</a></p>",
          "votes": null,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "3377237": "We would like to extend our sincere gratitude to the organizers for hosting such an engaging and fascinating competition.\n\nBelow is monnnu's portion from Team yu4u and monnnu; [yu4u's great write-up is available separately](https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028). Our final submission blends yu4u's models, monnnu's models, and a public notebook via a weighted ensemble.\n\n\n## My Solution Approach\nHere, I present my approach to this competition.\n\n\n## Solution Overview\n1. Time series modeling with **1D Convolution** and **bi-LSTM**\n2. **Two-stage training: All-Lab training → Lab-specific Fine-tuning**\n3. **Data Augmentation**: Spatial flips, window overlapping, random shifts, random rotations, and inference-time TTA.\n4. **Multi-Label Classification Approach**: Implemented with **masking of unlabeled regions** to reduce noise during loss calculation. This ensures that only labeled frames contribute to the loss.\n\n## 1. Model Architecture\nFor time series data, I created a model combining 1D CNN and BiLSTM.\nInput is processed with a fixed-length window, with window size set to 500 frames.\n\n### Model A: 1D Convolutional Network\n```\nInput (T, Features) → Transpose → (Features, T)\n  ↓ Stem Conv1d\n  ↓ 8× Dilated Residual Blocks\n  ↓   Depthwise Separable Conv + GroupNorm + GELU\n  ↓ Head Conv1d\n  ↓\nOutput (Classes, T) → Frame-wise logits\n```\n\n### Model B: Bidirectional LSTM Network\n```\nInput (T, Features)\n  ↓ Embedding Conv\n  ↓ Bi-LSTM layers (2 layers)\n  ↓ Head (Linear layer)\n  ↓\nOutput (Classes, T) → Frame-wise logits\n```\n\nIn the final submission, I averaged the predicted probabilities from models trained with several variations.\n\n## 2. Training Strategy\n\n### Two-Stage Training\nTo Train common patterns while adapting to Lab-specific characteristics, I used two-stage training.\n\n**Stage 1: All-Lab Training**\n- Pair behaviors: 19 Pair Labs\n- Self behaviors: 10 Self Labs\n- Acquire general behavioral patterns for each type and build robust models with diverse data.\n\n**Stage 2: Lab-specific Fine-tuning**\n- Use Stage 1 model as initialization for individual Lab training\n- Adapt to Lab-specific characteristics\n\nThis resulted in improvements across all Labs compared to training only on the combined dataset or only on each individual Lab.\n\n### Self/Pair-Specific Models\nTrained separate models for each behavior type (self/pair).\nInitially used a single model, but separation resulted in slight accuracy improvements for both behavior types.\n\n## 3. Multi-Label Classification and Loss Masking for Unlabeled Regions\nSolved as a multi-label task, excluding unlabeled regions from loss calculation.\n\n### Multi-Label Classification\n- Loss: BCEWithLogitsLoss\n- Apply sigmoid + BCE independently for each class\n\n### Loss Masking for Unlabeled Regions\n- In this dataset, only labels contained in behaviors_labeled are annotated.\n- **Unlabeled ≠ No behavior**, and treating unlabeled as negative examples (0) would introduce noise, so I used this loss approach.\n\n```python\n# 1. Identify labeled frames\nnan_mask = (~torch.isnan(y)).float()\n\n# 2. Combine with valid frame mask\neffective_mask = frame_mask * nan_mask\n\n# 3. Compute loss only on labeled frames\nloss = (raw_loss * effective_mask).sum() / effective_mask.sum()\n```\n\n## 4. Feature Engineering\nIn addition to raw pose features and meta features, I added several engineered features.\n\n### A. Basic Coordinate Features (Raw Pose)\n\n- 12 body parts × 2 mice × (x, y) = 48 dimensions\n- Body parts: body_center, ear, head, hip, lateral, neck, nose, tail_base, tail_tip, etc.\n- All coordinates for both Agent and Target\n\n### B. Derived Features - Distance and Relative Position\n\n- Distance between corresponding body parts\n- Center-to-center distance\n- Distance from nose to opponent's tail base\n\n### C. Derived Features - Movement and Velocity\n\n- Frame-to-frame velocity for each body part\n- For Pair: both mice; for Self: Agent only\n\n### D. Derived Features - Direction and Angle\n\n- Direction angle from Agent's nose to Target's body center\n- Angle between Agent's movement direction and Target direction (invariant to rotation/reflection)\n\n### E. Metadata and Video Features\n\n- fps, resolution, aspect ratio\n- Arena width/height/area (cm)\n- Conversion coefficient between pixels and cm\n\n### F. Mouse Attribute Features (Pair)\n\n- Strain, sex, age (Agent/Target)\n- Same-strain/same-condition flags, age difference, average age, etc.\n\n**For Self behaviors**: Exclude Target-side attributes and distance-related features\n\n## 5. Data Augmentation\n\n### Augmentation During Training\n\n**A. Spatial Flips**\n- Horizontal flip: `x' = width - x`, `angle' = π - angle`\n- Vertical flip: `y' = height - y`, `angle' = -angle`\n- Both-axis flip: Combination of both\n- Swap Left/Right body parts → Expand training data to 4 patterns\n\n**B. Window Overlapping**\n- Fixed-length window (window=500 frames) processed with stride=250\n- 50% overlap amplifies training data\n\n**C. Random Frame Shifts**\n- During training only, randomly shift window start position in range [0, stride)\n- Shift position changes each epoch, achieving further data amplification\n\n**D. Random Rotation**\n- With 50% probability, apply rotation by random angle ([-π, π]) to coordinates\n- Rotation center is the centroid of all coordinates in each frame\n\n### TTA (Test Time Augmentation) During Inference\n\n**A. Dense Sliding Window**\n- Predict multiple windows with window=500, stride=250\n- Average predicted probabilities across all test sequences\n\n**B. Spatial Flip Variations**\n- Original data + horizontal flip + vertical flip + both-axis flip (4 patterns)\n- Predict for each variation and average probabilities\n\n## 6. Other Training Settings\n- **Max Epochs**: 1000 (terminated by early stopping)\n- **Early stopping**: 5 epochs (Pair), 10 epochs (Self)\n- **Optimizer**: AdamW (lr=5e-4, warmup 5 epochs + cosine decay)\n\n## 7. Results\n\n| Model | Random Rotation/Shift | CV | LB |\n|--------|-------------------|-----|-----|\n| 1DConv | No | 0.524896 | 0.530 |\n| LSTM | No | 0.523124 | - |\n| 1DConv | Yes | 0.532914 | 0.522 |\n| LSTM | Yes | 0.522641 | - |\n| Ensemble | - | 0.546648 | - |\n\nIn the final submission, predictions were combined with weighted averaging using team members' models and GBDT models from public notebooks.",
    "3378100": "Congratulations winning 6th place gold. I like your use of Bi-RNN instead of transformer. Using 2 stage training is smart. How much did the second stage boost CV and LB?\n\nHow did you handle AdaptableSnail fps=25 during test inference?",
    "3379425": "Thanks for the comment, and congrats on your solo gold!\n\nThe improvements from the 2nd stage were about 0.013 for CV and 0.023 for LB. \n\nWe didn't do anything specific regarding the 25 fps for AdaptableSnail. My teammate is investigating the details over here.\nhttps://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663028#3378361"
  },
  "source": "meta"
}