{
  "id": 663028,
  "title": "6th Place Solution (yu4u's Part)",
  "url": "/competitions/MABe-mouse-behavior-detection/discussion/663028",
  "author_name": "",
  "post_date": "2025-12-16T00:08:33.745106300Z",
  "votes": 23,
  "comment_count": 2,
  "views": 0,
  "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F29376aa0fc9e5f0e4d918a13d112ada7%2FGemini_Generated_Image_su9owosu9owosu9o.jpg?generation=1765878783281637&amp;alt=media\" alt=\"\">\nThis illustration was created with reference to <a href=\"https://zenn.dev/kuto5046/articles/5cdcd1b274abc8\" target=\"_blank\">this article</a>.</p>\n<p>We would like to express our gratitude to the competition host and the Kaggle staff for organizing this outstanding competition.\nBelow, we introduce yu4u’s part of the solution from Team monnu and yu4u. Please refer to monnu’s awesome solution <a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663032\" target=\"_blank\">here</a>.\nOur submission is a weighted ensemble of monnu's models, yu4u's models, and a public notebook.</p>\n<h2>Solution Summary</h2>\n<p>When we started working on this competition, we first explored how to design an architecture that could handle the diversity of Labs, trackers, annotated actions, and both self-actions and interactions.\nAs a result, we decided to adopt an approach in which a single model is trained jointly on all labs, trackers, and actions.\nIt may be worth noting that even self-actions and interactions are handled together within this one model - although of course many of you might already be doing something similar.</p>\n<h2>Preprocessing and Feature Extraction</h2>\n<p>My model makes independent predictions for each mouse pair, even when four mice are present.\nTherefore, for each video, we extracted features for all pairs listed in train.csv.\nWe extracted features from the keypoint coordinates.</p>\n<p>Since the available keypoint types differ across trackers, we selected the following 11 keypoints that are available as consistently as possible across trackers:\n<code>ear_left</code>, <code>ear_right</code>, <code>tail_base</code>, <code>nose</code>, <code>hip_left</code>, <code>hip_right</code>, <code>neck</code>, <code>body_center</code>, <code>lateral_left</code>, <code>lateral_right</code>, and <code>tail_tip</code>.\nAs preprocessing, we resampled all frames to 30 fps and normalized the coordinates by <code>video_width_pix</code>.</p>\n<p>Then, the following features were extracted:</p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Velocity (dx, dy)</td>\n<td>22</td>\n<td>Velocity vectors for each keypoint (11 body parts × 2 coords).</td>\n</tr>\n<tr>\n<td>Velocity (norm)</td>\n<td>11</td>\n<td>Speed magnitude for each keypoint (11 body parts).</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>11</td>\n<td>Acceleration for each keypoint (11 body parts).</td>\n</tr>\n<tr>\n<td>Relative Position</td>\n<td>33</td>\n<td>Target position in actor's coordinate system (dx, dy, distance) × 11 parts.</td>\n</tr>\n<tr>\n<td>Metadata Embedding</td>\n<td>72</td>\n<td>Tracker ID, Arena ID, Lab ID, Mouse1/2's sex, strain, and color (9 attributes × 8 dims).</td>\n</tr>\n</tbody>\n</table>\n<p>All missing values were filled with -1.</p>\n<h3>Relative Position Calculation</h3>\n<ul>\n<li>Set the midpoint between actor's left and right ears as the origin.</li>\n<li>Rotate so that the vector from the ear midpoint to the tail base points to the -Y axis.</li>\n<li>Compute relative position (dx, dy) and distance for each target body part in this coordinate system.</li>\n</ul>\n<h2>Model</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F22adcdc04740acd6ec13cf4da81a4e3f%2Fmodel.png?generation=1765843833369256&amp;alt=media\" alt=\"\"></p>\n<p>The model architecture is shown in the figure above.\nThis model takes four types of inputs: mouse1’s features, mouse2’s features, relative features, and meta embeddings.\nThe features for mouse1 and mouse2 each consist of 44 channels: 22 for velocity, 11 for speed, and 11 for acceleration.\nThe relative features have 33 channels, and the metadata embeddings have 72 channels.\nWhen predicting self-actions, the same feature set is fed into both the mouse1 and mouse2 branches.</p>\n<p>Each of these four feature types is first mapped to the same dimensionality by its own stem convolution, and then passed into the backbone network.\nA key characteristic of this model is that it alternates between Grouped Inverted Residual Blocks, which process the four inputs independently, and standard Inverted Residual Blocks, which mix information across them.\nThe Grouped Inverted Residual Blocks are implemented using grouped convolutions, allowing the model to learn features for each input type independently.</p>\n<p>We used three types of backbones: a convolution-based backbone, a GRU-based backbone, and a ModernBERT-based backbone. In all of them, the internal blocks are grouped.</p>\n<h3>Loss Function</h3>\n<p>Since the task in this competition is essentially a frame-wise classification problem, it is natural to use cross-entropy loss.\nHowever, actions that are not listed in train.csv (unannotated actions) cannot be explicitly treated as negative samples.\nTo address this, we add −∞ to the logits of unannotated actions before computing the cross-entropy loss. This way, the model is not penalized even if it predicts an unannotated action as positive.\nIn addition, we introduced separate background classes for self-actions and interactions.</p>\n<h3>Pretraining</h3>\n<p>We pre-trained the backbone using a masked keypoint reconstruction task, where a subset of keypoints is masked and then predicted.\nWe conducted two types of pretraining: one including the MABe22 data and one excluding it.\nAlthough this did not yield a significant improvement in metrics compared with training from scratch, we used both pre-trained models in the ensemble, expecting them to increase model diversity.</p>\n<h2>Training</h2>\n<p>AdamW optimizer with cosine annealing, 64 epochs, batch size = 256, learning rate = 5e-3, weight decay = 0.2, and an exponential moving average (EMA) decay of 0.997. 5-fold cross-validation stratified by lab_id.\nFor validation, we excluded these labs <code>CalMS21_*</code>, <code>CRIM13</code>, and <code>MABe22</code>, which are not included in the test data, and used the official competition metric.</p>\n<h3>Augmentations</h3>\n<ul>\n<li>Random rotation (-180° to +180°).</li>\n<li>Random scaling (0.8x to 1.2x).</li>\n<li>Horizontal flip with left-right keypoint label swapping.</li>\n<li>Random temporal crop.</li>\n<li>Mixup.</li>\n</ul>\n<h3>Post-processing</h3>\n<ul>\n<li><strong>Ensemble</strong>: Average probabilities from 45 models (3 backbones × (1 scratch + 2 pretrained variants) × 5 folds).</li>\n<li><strong>Sliding Window Aggregation</strong>: Overlapping inference with stride=512, averaging probabilities.</li>\n<li><strong>Threshold Optimization</strong>: We search for the optimal threshold for each (lab, action) pair on validation set.</li>\n</ul>\n<h2>Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Pretrain</th>\n<th>CV</th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Conv</td>\n<td>None</td>\n<td>0.5206</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>Conv</td>\n<td>w/o MABe22</td>\n<td>0.5305</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>Conv</td>\n<td>w/ MABe22</td>\n<td>0.5233</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>None</td>\n<td>0.5221</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>w/o MABe22</td>\n<td>0.5228</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>w/ MABe22</td>\n<td>0.5225</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>None</td>\n<td>0.5150</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>w/o MABe22</td>\n<td>0.5225</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>w/ MABe22</td>\n<td>0.5192</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>yu4u Ensemble</td>\n<td></td>\n<td>0.5430</td>\n<td>0.543</td>\n<td>0.508</td>\n</tr>\n<tr>\n<td>Team Ensemble</td>\n<td></td>\n<td>0.5702</td>\n<td>0.556</td>\n<td>0.525</td>\n</tr>\n</tbody>\n</table>",
  "messages": [
    {
      "id": "3377226",
      "postDate": "12/16/2025 00:08:33",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F29376aa0fc9e5f0e4d918a13d112ada7%2FGemini_Generated_Image_su9owosu9owosu9o.jpg?generation=1765878783281637&amp;alt=media\" alt=\"\">\nThis illustration was created with reference to <a href=\"https://zenn.dev/kuto5046/articles/5cdcd1b274abc8\" target=\"_blank\">this article</a>.</p>\n<p>We would like to express our gratitude to the competition host and the Kaggle staff for organizing this outstanding competition.\nBelow, we introduce yu4u’s part of the solution from Team monnu and yu4u. Please refer to monnu’s awesome solution <a href=\"https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663032\" target=\"_blank\">here</a>.\nOur submission is a weighted ensemble of monnu's models, yu4u's models, and a public notebook.</p>\n<h2>Solution Summary</h2>\n<p>When we started working on this competition, we first explored how to design an architecture that could handle the diversity of Labs, trackers, annotated actions, and both self-actions and interactions.\nAs a result, we decided to adopt an approach in which a single model is trained jointly on all labs, trackers, and actions.\nIt may be worth noting that even self-actions and interactions are handled together within this one model - although of course many of you might already be doing something similar.</p>\n<h2>Preprocessing and Feature Extraction</h2>\n<p>My model makes independent predictions for each mouse pair, even when four mice are present.\nTherefore, for each video, we extracted features for all pairs listed in train.csv.\nWe extracted features from the keypoint coordinates.</p>\n<p>Since the available keypoint types differ across trackers, we selected the following 11 keypoints that are available as consistently as possible across trackers:\n<code>ear_left</code>, <code>ear_right</code>, <code>tail_base</code>, <code>nose</code>, <code>hip_left</code>, <code>hip_right</code>, <code>neck</code>, <code>body_center</code>, <code>lateral_left</code>, <code>lateral_right</code>, and <code>tail_tip</code>.\nAs preprocessing, we resampled all frames to 30 fps and normalized the coordinates by <code>video_width_pix</code>.</p>\n<p>Then, the following features were extracted:</p>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Channels</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Velocity (dx, dy)</td>\n<td>22</td>\n<td>Velocity vectors for each keypoint (11 body parts × 2 coords).</td>\n</tr>\n<tr>\n<td>Velocity (norm)</td>\n<td>11</td>\n<td>Speed magnitude for each keypoint (11 body parts).</td>\n</tr>\n<tr>\n<td>Acceleration</td>\n<td>11</td>\n<td>Acceleration for each keypoint (11 body parts).</td>\n</tr>\n<tr>\n<td>Relative Position</td>\n<td>33</td>\n<td>Target position in actor's coordinate system (dx, dy, distance) × 11 parts.</td>\n</tr>\n<tr>\n<td>Metadata Embedding</td>\n<td>72</td>\n<td>Tracker ID, Arena ID, Lab ID, Mouse1/2's sex, strain, and color (9 attributes × 8 dims).</td>\n</tr>\n</tbody>\n</table>\n<p>All missing values were filled with -1.</p>\n<h3>Relative Position Calculation</h3>\n<ul>\n<li>Set the midpoint between actor's left and right ears as the origin.</li>\n<li>Rotate so that the vector from the ear midpoint to the tail base points to the -Y axis.</li>\n<li>Compute relative position (dx, dy) and distance for each target body part in this coordinate system.</li>\n</ul>\n<h2>Model</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F22adcdc04740acd6ec13cf4da81a4e3f%2Fmodel.png?generation=1765843833369256&amp;alt=media\" alt=\"\"></p>\n<p>The model architecture is shown in the figure above.\nThis model takes four types of inputs: mouse1’s features, mouse2’s features, relative features, and meta embeddings.\nThe features for mouse1 and mouse2 each consist of 44 channels: 22 for velocity, 11 for speed, and 11 for acceleration.\nThe relative features have 33 channels, and the metadata embeddings have 72 channels.\nWhen predicting self-actions, the same feature set is fed into both the mouse1 and mouse2 branches.</p>\n<p>Each of these four feature types is first mapped to the same dimensionality by its own stem convolution, and then passed into the backbone network.\nA key characteristic of this model is that it alternates between Grouped Inverted Residual Blocks, which process the four inputs independently, and standard Inverted Residual Blocks, which mix information across them.\nThe Grouped Inverted Residual Blocks are implemented using grouped convolutions, allowing the model to learn features for each input type independently.</p>\n<p>We used three types of backbones: a convolution-based backbone, a GRU-based backbone, and a ModernBERT-based backbone. In all of them, the internal blocks are grouped.</p>\n<h3>Loss Function</h3>\n<p>Since the task in this competition is essentially a frame-wise classification problem, it is natural to use cross-entropy loss.\nHowever, actions that are not listed in train.csv (unannotated actions) cannot be explicitly treated as negative samples.\nTo address this, we add −∞ to the logits of unannotated actions before computing the cross-entropy loss. This way, the model is not penalized even if it predicts an unannotated action as positive.\nIn addition, we introduced separate background classes for self-actions and interactions.</p>\n<h3>Pretraining</h3>\n<p>We pre-trained the backbone using a masked keypoint reconstruction task, where a subset of keypoints is masked and then predicted.\nWe conducted two types of pretraining: one including the MABe22 data and one excluding it.\nAlthough this did not yield a significant improvement in metrics compared with training from scratch, we used both pre-trained models in the ensemble, expecting them to increase model diversity.</p>\n<h2>Training</h2>\n<p>AdamW optimizer with cosine annealing, 64 epochs, batch size = 256, learning rate = 5e-3, weight decay = 0.2, and an exponential moving average (EMA) decay of 0.997. 5-fold cross-validation stratified by lab_id.\nFor validation, we excluded these labs <code>CalMS21_*</code>, <code>CRIM13</code>, and <code>MABe22</code>, which are not included in the test data, and used the official competition metric.</p>\n<h3>Augmentations</h3>\n<ul>\n<li>Random rotation (-180° to +180°).</li>\n<li>Random scaling (0.8x to 1.2x).</li>\n<li>Horizontal flip with left-right keypoint label swapping.</li>\n<li>Random temporal crop.</li>\n<li>Mixup.</li>\n</ul>\n<h3>Post-processing</h3>\n<ul>\n<li><strong>Ensemble</strong>: Average probabilities from 45 models (3 backbones × (1 scratch + 2 pretrained variants) × 5 folds).</li>\n<li><strong>Sliding Window Aggregation</strong>: Overlapping inference with stride=512, averaging probabilities.</li>\n<li><strong>Threshold Optimization</strong>: We search for the optimal threshold for each (lab, action) pair on validation set.</li>\n</ul>\n<h2>Results</h2>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Pretrain</th>\n<th>CV</th>\n<th>Public LB</th>\n<th>Private LB</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Conv</td>\n<td>None</td>\n<td>0.5206</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>Conv</td>\n<td>w/o MABe22</td>\n<td>0.5305</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>Conv</td>\n<td>w/ MABe22</td>\n<td>0.5233</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>None</td>\n<td>0.5221</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>w/o MABe22</td>\n<td>0.5228</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>GRU</td>\n<td>w/ MABe22</td>\n<td>0.5225</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>None</td>\n<td>0.5150</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>w/o MABe22</td>\n<td>0.5225</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>ModernBERT</td>\n<td>w/ MABe22</td>\n<td>0.5192</td>\n<td></td>\n<td></td>\n</tr>\n<tr>\n<td>yu4u Ensemble</td>\n<td></td>\n<td>0.5430</td>\n<td>0.543</td>\n<td>0.508</td>\n</tr>\n<tr>\n<td>Team Ensemble</td>\n<td></td>\n<td>0.5702</td>\n<td>0.556</td>\n<td>0.525</td>\n</tr>\n</tbody>\n</table>",
      "rawMarkdown": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F29376aa0fc9e5f0e4d918a13d112ada7%2FGemini_Generated_Image_su9owosu9owosu9o.jpg?generation=1765878783281637&alt=media)\nThis illustration was created with reference to [this article](https://zenn.dev/kuto5046/articles/5cdcd1b274abc8).\n\nWe would like to express our gratitude to the competition host and the Kaggle staff for organizing this outstanding competition.\nBelow, we introduce yu4u’s part of the solution from Team monnu and yu4u. Please refer to monnu’s awesome solution [here](https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663032).\nOur submission is a weighted ensemble of monnu's models, yu4u's models, and a public notebook.\n\n## Solution Summary\n\nWhen we started working on this competition, we first explored how to design an architecture that could handle the diversity of Labs, trackers, annotated actions, and both self-actions and interactions.\nAs a result, we decided to adopt an approach in which a single model is trained jointly on all labs, trackers, and actions.\nIt may be worth noting that even self-actions and interactions are handled together within this one model - although of course many of you might already be doing something similar.\n\n## Preprocessing and Feature Extraction\nMy model makes independent predictions for each mouse pair, even when four mice are present.\nTherefore, for each video, we extracted features for all pairs listed in train.csv.\nWe extracted features from the keypoint coordinates.\n\nSince the available keypoint types differ across trackers, we selected the following 11 keypoints that are available as consistently as possible across trackers:\n`ear_left`, `ear_right`, `tail_base`, `nose`, `hip_left`, `hip_right`, `neck`, `body_center`, `lateral_left`, `lateral_right`, and `tail_tip`.\nAs preprocessing, we resampled all frames to 30 fps and normalized the coordinates by `video_width_pix`.\n\nThen, the following features were extracted:\n\n| Feature            | Channels | Description                                                            |\n|--------------------|----------|------------------------------------------------------------------------|\n| Velocity (dx, dy)  | 22       | Velocity vectors for each keypoint (11 body parts × 2 coords).         |\n| Velocity (norm)    | 11       | Speed magnitude for each keypoint (11 body parts).                     |\n| Acceleration       | 11       | Acceleration for each keypoint (11 body parts).                        |\n| Relative Position  | 33       | Target position in actor's coordinate system (dx, dy, distance) × 11 parts. |\n| Metadata Embedding | 72       | Tracker ID, Arena ID, Lab ID, Mouse1/2's sex, strain, and color (9 attributes × 8 dims). |\n\nAll missing values were filled with -1.\n\n### Relative Position Calculation\n- Set the midpoint between actor's left and right ears as the origin.\n- Rotate so that the vector from the ear midpoint to the tail base points to the -Y axis.\n- Compute relative position (dx, dy) and distance for each target body part in this coordinate system.\n\n\n## Model\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F22adcdc04740acd6ec13cf4da81a4e3f%2Fmodel.png?generation=1765843833369256&alt=media)\n\nThe model architecture is shown in the figure above.\nThis model takes four types of inputs: mouse1’s features, mouse2’s features, relative features, and meta embeddings.\nThe features for mouse1 and mouse2 each consist of 44 channels: 22 for velocity, 11 for speed, and 11 for acceleration.\nThe relative features have 33 channels, and the metadata embeddings have 72 channels.\nWhen predicting self-actions, the same feature set is fed into both the mouse1 and mouse2 branches.\n\nEach of these four feature types is first mapped to the same dimensionality by its own stem convolution, and then passed into the backbone network.\nA key characteristic of this model is that it alternates between Grouped Inverted Residual Blocks, which process the four inputs independently, and standard Inverted Residual Blocks, which mix information across them.\nThe Grouped Inverted Residual Blocks are implemented using grouped convolutions, allowing the model to learn features for each input type independently.\n\nWe used three types of backbones: a convolution-based backbone, a GRU-based backbone, and a ModernBERT-based backbone. In all of them, the internal blocks are grouped.\n\n\n### Loss Function\nSince the task in this competition is essentially a frame-wise classification problem, it is natural to use cross-entropy loss.\nHowever, actions that are not listed in train.csv (unannotated actions) cannot be explicitly treated as negative samples.\nTo address this, we add −∞ to the logits of unannotated actions before computing the cross-entropy loss. This way, the model is not penalized even if it predicts an unannotated action as positive.\nIn addition, we introduced separate background classes for self-actions and interactions.\n\n\n### Pretraining\nWe pre-trained the backbone using a masked keypoint reconstruction task, where a subset of keypoints is masked and then predicted.\nWe conducted two types of pretraining: one including the MABe22 data and one excluding it.\nAlthough this did not yield a significant improvement in metrics compared with training from scratch, we used both pre-trained models in the ensemble, expecting them to increase model diversity.\n\n\n## Training\nAdamW optimizer with cosine annealing, 64 epochs, batch size = 256, learning rate = 5e-3, weight decay = 0.2, and an exponential moving average (EMA) decay of 0.997. 5-fold cross-validation stratified by lab_id.\nFor validation, we excluded these labs `CalMS21_*`, `CRIM13`, and `MABe22`, which are not included in the test data, and used the official competition metric.\n\n### Augmentations\n- Random rotation (-180° to +180°).\n- Random scaling (0.8x to 1.2x).\n- Horizontal flip with left-right keypoint label swapping.\n- Random temporal crop.\n- Mixup.\n\n\n### Post-processing\n- **Ensemble**: Average probabilities from 45 models (3 backbones × (1 scratch + 2 pretrained variants) × 5 folds).\n- **Sliding Window Aggregation**: Overlapping inference with stride=512, averaging probabilities.\n- **Threshold Optimization**: We search for the optimal threshold for each (lab, action) pair on validation set.\n\n## Results\n\n| Model         | Pretrain   | CV     | Public LB | Private LB |\n|---------------|------------|--------|-----------|------------|\n| Conv          | None       | 0.5206 |           |            |\n| Conv          | w/o MABe22 | 0.5305 |           |            |\n| Conv          | w/ MABe22  | 0.5233 |           |            |\n| GRU           | None       | 0.5221 |           |            |\n| GRU           | w/o MABe22 | 0.5228 |           |            |\n| GRU           | w/ MABe22  | 0.5225 |           |            |\n| ModernBERT    | None       | 0.5150 |           |            |\n| ModernBERT    | w/o MABe22 | 0.5225 |           |            |\n| ModernBERT    | w/ MABe22  | 0.5192 |           |            |\n| yu4u Ensemble |            | 0.5430 | 0.543     |  0.508      |\n| Team Ensemble |            | 0.5702 | 0.556     | 0.525      |",
      "votes": null
    },
    {
      "id": "3378099",
      "postDate": "12/17/2025 14:42:51",
      "content": "<p>Congratulations winning 6th place gold. I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here? I like how you pretrained the models with MABe unlabeled data.</p>\n<p>How did you handle AdaptableSnail fps=25 during test inference?</p>",
      "rawMarkdown": "Congratulations winning 6th place gold. I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here? I like how you pretrained the models with MABe unlabeled data.\n\nHow did you handle AdaptableSnail fps=25 during test inference?",
      "votes": null
    },
    {
      "id": "3378361",
      "postDate": "12/18/2025 00:22:25",
      "content": "<p>Congratulations to you as well on your 7th place finish.</p>\n<blockquote>\n  <p>I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here?</p>\n</blockquote>\n<p>I simply replaced the Inverted Residual Block with <code>ModernBertEncoderLayer</code>.\nNotably, I did not need to tune the hyperparameters at all; I could just reuse the same hyperparameters as for the 1D CNN, and I was able to achieve comparable scores while also gaining model diversity. This is based on <a href=\"https://www.kaggle.com/competitions/cmi-detect-behavior-with-sensor-data/writeups/3rd-place-solution\" target=\"_blank\">a successful experience we had in CMI3</a>.\nFor the grouped convolution, I created a wrapper layer that holds the same numer (=4) of ModernBertEncoderLayers as the group internally.</p>\n<p><code>from transformers.models.modernbert.modeling_modernbert import ModernBertEncoderLayer</code></p>\n<blockquote>\n  <p>I like how you pretrained the models with MABe unlabeled data.</p>\n</blockquote>\n<p>I defined a task where I mask the original keypoints, extract features from those masked keypoints, and then reconstruct the original keypoints from those features. The loss is an MSE applied only on the masked keypoints.</p>\n<blockquote>\n  <p>How did you handle AdaptableSnail fps=25 during test inference?</p>\n</blockquote>\n<p>During training, I excluded the 25 fps data, but at inference time I did nothing.\nIf I remove the 25 fps videos also at inference, the private LB score changes from 0.52524 -&gt; 0.53039.\nIf I instead change the start/end to <code>* 30 / 25</code>, it goes from 0.52524 -&gt; 0.52644.\nIf the original 25 fps data are not properly corrected and used for training, it might simply be better to drop them.</p>",
      "rawMarkdown": "Congratulations to you as well on your 7th place finish.\n\n> I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here?\n\nI simply replaced the Inverted Residual Block with `ModernBertEncoderLayer`.\nNotably, I did not need to tune the hyperparameters at all; I could just reuse the same hyperparameters as for the 1D CNN, and I was able to achieve comparable scores while also gaining model diversity. This is based on [a successful experience we had in CMI3](https://www.kaggle.com/competitions/cmi-detect-behavior-with-sensor-data/writeups/3rd-place-solution).\nFor the grouped convolution, I created a wrapper layer that holds the same numer (=4) of ModernBertEncoderLayers as the group internally.\n\n```from transformers.models.modernbert.modeling_modernbert import ModernBertEncoderLayer```\n\n\n> I like how you pretrained the models with MABe unlabeled data.\n\nI defined a task where I mask the original keypoints, extract features from those masked keypoints, and then reconstruct the original keypoints from those features. The loss is an MSE applied only on the masked keypoints.\n\n\n> How did you handle AdaptableSnail fps=25 during test inference?\n\nDuring training, I excluded the 25 fps data, but at inference time I did nothing.\nIf I remove the 25 fps videos also at inference, the private LB score changes from 0.52524 -> 0.53039.\nIf I instead change the start/end to `* 30 / 25`, it goes from 0.52524 -> 0.52644.\nIf the original 25 fps data are not properly corrected and used for training, it might simply be better to drop them.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3378099,
      "author_name": "cdeotte",
      "author_url": "",
      "post_date": "12/17/2025 14:42:51",
      "content": "<p>Congratulations winning 6th place gold. I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here? I like how you pretrained the models with MABe unlabeled data.</p>\n<p>How did you handle AdaptableSnail fps=25 during test inference?</p>",
      "votes": null,
      "replies": [
        {
          "id": 3378361,
          "author_name": "ren4yu",
          "author_url": "",
          "post_date": "12/18/2025 00:22:25",
          "content": "<p>Congratulations to you as well on your 7th place finish.</p>\n<blockquote>\n  <p>I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here?</p>\n</blockquote>\n<p>I simply replaced the Inverted Residual Block with <code>ModernBertEncoderLayer</code>.\nNotably, I did not need to tune the hyperparameters at all; I could just reuse the same hyperparameters as for the 1D CNN, and I was able to achieve comparable scores while also gaining model diversity. This is based on <a href=\"https://www.kaggle.com/competitions/cmi-detect-behavior-with-sensor-data/writeups/3rd-place-solution\" target=\"_blank\">a successful experience we had in CMI3</a>.\nFor the grouped convolution, I created a wrapper layer that holds the same numer (=4) of ModernBertEncoderLayers as the group internally.</p>\n<p><code>from transformers.models.modernbert.modeling_modernbert import ModernBertEncoderLayer</code></p>\n<blockquote>\n  <p>I like how you pretrained the models with MABe unlabeled data.</p>\n</blockquote>\n<p>I defined a task where I mask the original keypoints, extract features from those masked keypoints, and then reconstruct the original keypoints from those features. The loss is an MSE applied only on the masked keypoints.</p>\n<blockquote>\n  <p>How did you handle AdaptableSnail fps=25 during test inference?</p>\n</blockquote>\n<p>During training, I excluded the 25 fps data, but at inference time I did nothing.\nIf I remove the 25 fps videos also at inference, the private LB score changes from 0.52524 -&gt; 0.53039.\nIf I instead change the start/end to <code>* 30 / 25</code>, it goes from 0.52524 -&gt; 0.52644.\nIf the original 25 fps data are not properly corrected and used for training, it might simply be better to drop them.</p>",
          "votes": null,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "3377226": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F29376aa0fc9e5f0e4d918a13d112ada7%2FGemini_Generated_Image_su9owosu9owosu9o.jpg?generation=1765878783281637&alt=media)\nThis illustration was created with reference to [this article](https://zenn.dev/kuto5046/articles/5cdcd1b274abc8).\n\nWe would like to express our gratitude to the competition host and the Kaggle staff for organizing this outstanding competition.\nBelow, we introduce yu4u’s part of the solution from Team monnu and yu4u. Please refer to monnu’s awesome solution [here](https://www.kaggle.com/competitions/MABe-mouse-behavior-detection/discussion/663032).\nOur submission is a weighted ensemble of monnu's models, yu4u's models, and a public notebook.\n\n## Solution Summary\n\nWhen we started working on this competition, we first explored how to design an architecture that could handle the diversity of Labs, trackers, annotated actions, and both self-actions and interactions.\nAs a result, we decided to adopt an approach in which a single model is trained jointly on all labs, trackers, and actions.\nIt may be worth noting that even self-actions and interactions are handled together within this one model - although of course many of you might already be doing something similar.\n\n## Preprocessing and Feature Extraction\nMy model makes independent predictions for each mouse pair, even when four mice are present.\nTherefore, for each video, we extracted features for all pairs listed in train.csv.\nWe extracted features from the keypoint coordinates.\n\nSince the available keypoint types differ across trackers, we selected the following 11 keypoints that are available as consistently as possible across trackers:\n`ear_left`, `ear_right`, `tail_base`, `nose`, `hip_left`, `hip_right`, `neck`, `body_center`, `lateral_left`, `lateral_right`, and `tail_tip`.\nAs preprocessing, we resampled all frames to 30 fps and normalized the coordinates by `video_width_pix`.\n\nThen, the following features were extracted:\n\n| Feature            | Channels | Description                                                            |\n|--------------------|----------|------------------------------------------------------------------------|\n| Velocity (dx, dy)  | 22       | Velocity vectors for each keypoint (11 body parts × 2 coords).         |\n| Velocity (norm)    | 11       | Speed magnitude for each keypoint (11 body parts).                     |\n| Acceleration       | 11       | Acceleration for each keypoint (11 body parts).                        |\n| Relative Position  | 33       | Target position in actor's coordinate system (dx, dy, distance) × 11 parts. |\n| Metadata Embedding | 72       | Tracker ID, Arena ID, Lab ID, Mouse1/2's sex, strain, and color (9 attributes × 8 dims). |\n\nAll missing values were filled with -1.\n\n### Relative Position Calculation\n- Set the midpoint between actor's left and right ears as the origin.\n- Rotate so that the vector from the ear midpoint to the tail base points to the -Y axis.\n- Compute relative position (dx, dy) and distance for each target body part in this coordinate system.\n\n\n## Model\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F745525%2F22adcdc04740acd6ec13cf4da81a4e3f%2Fmodel.png?generation=1765843833369256&alt=media)\n\nThe model architecture is shown in the figure above.\nThis model takes four types of inputs: mouse1’s features, mouse2’s features, relative features, and meta embeddings.\nThe features for mouse1 and mouse2 each consist of 44 channels: 22 for velocity, 11 for speed, and 11 for acceleration.\nThe relative features have 33 channels, and the metadata embeddings have 72 channels.\nWhen predicting self-actions, the same feature set is fed into both the mouse1 and mouse2 branches.\n\nEach of these four feature types is first mapped to the same dimensionality by its own stem convolution, and then passed into the backbone network.\nA key characteristic of this model is that it alternates between Grouped Inverted Residual Blocks, which process the four inputs independently, and standard Inverted Residual Blocks, which mix information across them.\nThe Grouped Inverted Residual Blocks are implemented using grouped convolutions, allowing the model to learn features for each input type independently.\n\nWe used three types of backbones: a convolution-based backbone, a GRU-based backbone, and a ModernBERT-based backbone. In all of them, the internal blocks are grouped.\n\n\n### Loss Function\nSince the task in this competition is essentially a frame-wise classification problem, it is natural to use cross-entropy loss.\nHowever, actions that are not listed in train.csv (unannotated actions) cannot be explicitly treated as negative samples.\nTo address this, we add −∞ to the logits of unannotated actions before computing the cross-entropy loss. This way, the model is not penalized even if it predicts an unannotated action as positive.\nIn addition, we introduced separate background classes for self-actions and interactions.\n\n\n### Pretraining\nWe pre-trained the backbone using a masked keypoint reconstruction task, where a subset of keypoints is masked and then predicted.\nWe conducted two types of pretraining: one including the MABe22 data and one excluding it.\nAlthough this did not yield a significant improvement in metrics compared with training from scratch, we used both pre-trained models in the ensemble, expecting them to increase model diversity.\n\n\n## Training\nAdamW optimizer with cosine annealing, 64 epochs, batch size = 256, learning rate = 5e-3, weight decay = 0.2, and an exponential moving average (EMA) decay of 0.997. 5-fold cross-validation stratified by lab_id.\nFor validation, we excluded these labs `CalMS21_*`, `CRIM13`, and `MABe22`, which are not included in the test data, and used the official competition metric.\n\n### Augmentations\n- Random rotation (-180° to +180°).\n- Random scaling (0.8x to 1.2x).\n- Horizontal flip with left-right keypoint label swapping.\n- Random temporal crop.\n- Mixup.\n\n\n### Post-processing\n- **Ensemble**: Average probabilities from 45 models (3 backbones × (1 scratch + 2 pretrained variants) × 5 folds).\n- **Sliding Window Aggregation**: Overlapping inference with stride=512, averaging probabilities.\n- **Threshold Optimization**: We search for the optimal threshold for each (lab, action) pair on validation set.\n\n## Results\n\n| Model         | Pretrain   | CV     | Public LB | Private LB |\n|---------------|------------|--------|-----------|------------|\n| Conv          | None       | 0.5206 |           |            |\n| Conv          | w/o MABe22 | 0.5305 |           |            |\n| Conv          | w/ MABe22  | 0.5233 |           |            |\n| GRU           | None       | 0.5221 |           |            |\n| GRU           | w/o MABe22 | 0.5228 |           |            |\n| GRU           | w/ MABe22  | 0.5225 |           |            |\n| ModernBERT    | None       | 0.5150 |           |            |\n| ModernBERT    | w/o MABe22 | 0.5225 |           |            |\n| ModernBERT    | w/ MABe22  | 0.5192 |           |            |\n| yu4u Ensemble |            | 0.5430 | 0.543     |  0.508      |\n| Team Ensemble |            | 0.5702 | 0.556     | 0.525      |",
    "3378099": "Congratulations winning 6th place gold. I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here? I like how you pretrained the models with MABe unlabeled data.\n\nHow did you handle AdaptableSnail fps=25 during test inference?",
    "3378361": "Congratulations to you as well on your 7th place finish.\n\n> I've never used a BERT transformer outside of NLP. How does it work, how do you adapt it to work here?\n\nI simply replaced the Inverted Residual Block with `ModernBertEncoderLayer`.\nNotably, I did not need to tune the hyperparameters at all; I could just reuse the same hyperparameters as for the 1D CNN, and I was able to achieve comparable scores while also gaining model diversity. This is based on [a successful experience we had in CMI3](https://www.kaggle.com/competitions/cmi-detect-behavior-with-sensor-data/writeups/3rd-place-solution).\nFor the grouped convolution, I created a wrapper layer that holds the same numer (=4) of ModernBertEncoderLayers as the group internally.\n\n```from transformers.models.modernbert.modeling_modernbert import ModernBertEncoderLayer```\n\n\n> I like how you pretrained the models with MABe unlabeled data.\n\nI defined a task where I mask the original keypoints, extract features from those masked keypoints, and then reconstruct the original keypoints from those features. The loss is an MSE applied only on the masked keypoints.\n\n\n> How did you handle AdaptableSnail fps=25 during test inference?\n\nDuring training, I excluded the 25 fps data, but at inference time I did nothing.\nIf I remove the 25 fps videos also at inference, the private LB score changes from 0.52524 -> 0.53039.\nIf I instead change the start/end to `* 30 / 25`, it goes from 0.52524 -> 0.52644.\nIf the original 25 fps data are not properly corrected and used for training, it might simply be better to drop them."
  },
  "source": "meta"
}