{
  "id": 671363,
  "title": "8th Place Solution | PixelScale 🌿",
  "url": "/competitions/csiro-biomass/writeups/8th-place-solution-csiro-image2biomass",
  "author_name": "",
  "post_date": "2026-02-01T12:23:11.177Z",
  "votes": 10,
  "comment_count": 2,
  "views": 0,
  "content": "<h2>1. Overview &amp; Key Insight</h2>\n<p>Our solution is a weighted ensemble of three distinct pipelines, all anchored by a <strong>DINOv3 Huge</strong> backbone.</p>\n<p>Our final submission combined:</p>\n<ol>\n<li><strong>SSA-Adapted Pipeline (50%)</strong>: Test-Time Adaptation using subspace alignment.</li>\n<li><strong>Species-Aware Pipeline (30%)</strong>: Two-stage injection of species metadata.</li>\n<li><strong>Dual-Backbone Pipeline (20%)</strong>: DINOv3 fused with SigLIP features.</li>\n</ol>\n<hr>\n<h2>2. The Core Backbone (Takumi's Part)</h2>\n<ul>\n<li><p>I strongly believed in the trend of scaling laws and aimed to utilize the largest model possible within my compute constraints.</p></li>\n<li><p>A key insight was that in competitions with limited data, utilizing a strong backbone pretrained on a massive dataset is crucial.</p></li>\n<li><p>I spent the majority of the competition optimizing the training recipe for DINOv3, which I believe gave me an edge over other solutions using the same architecture.</p></li>\n<li><p>I observed a significant jump in the Public LB score as I increased the model size. Increasing the model size proved to be more effective than increasing the image resolution. Due to A100 memory constraints, we standardized on:</p></li>\n<li><p><strong>Model:</strong> <code>vit_huge_plus_patch16_dinov3.lvd1689m</code></p></li>\n<li><p><strong>Image Size:</strong> 768px (Standardized across most pipelines)</p></li>\n</ul>\n<p>I wanted to emphasize the impact of simply changing the backbone. Here is the progression:</p>\n<ul>\n<li><strong>convnext_tiny → vit_base_patch16_dinov3.lvd1689m:</strong> 0.61 → 0.67  </li>\n<li><strong>vit_base_patch16_dinov3.lvd1689m → vit_large_patch16_dinov3.lvd1689m:</strong> 0.69 → 0.72  </li>\n<li><strong>vit_large_patch16_dinov3.lvd1689m → vit_huge_plus_patch16_dinov3.lvd1689m:</strong> 0.72 → 0.74</li>\n</ul>\n<h3>Head Architecture</h3>\n<p>I utilized a standard regression head with <code>SiLU</code> activation and dropout.</p>\n<pre><code>nn.Sequential(\n    nn.Linear(in_features, hidden),\n    nn.SiLU(),\n    nn.Dropout(0.3),\n    nn.Linear(hidden, out_features),\n)\n</code></pre>\n<h3>Training Strategy</h3>\n<p>To stabilize the training of such a large model on limited data, I employed a <strong>Two-Stage Training</strong> process using <code>AdamW</code> and Mixed Precision (AMP).</p>\n<ul>\n<li><strong>Loss Function:</strong> <code>nn.SmoothL1Loss()</code></li>\n<li><strong>Batch Size:</strong> Effective batch size of 8 (using <code>grad_accum_steps=8</code> on Batch Size 1).</li>\n</ul>\n<h3>Stage 1: Head Only (Warmup)</h3>\n<ul>\n<li><strong>Goal:</strong> Stabilize weights before fine-tuning the transformer.</li>\n<li><strong>Epochs:</strong> 15</li>\n<li><strong>LR:</strong> <code>3e-4</code> with <code>ReduceLROnPlateau</code>.</li>\n</ul>\n<h3>Stage 2: Full Backbone Finetuning</h3>\n<ul>\n<li><strong>Goal:</strong> Adapt the huge backbone without overfitting.</li>\n<li><strong>Epochs:</strong> 35</li>\n<li><strong>Weight Decay:</strong> <code>0.2</code> (High decay was crucial for regularization).</li>\n<li><strong>Scheduler:</strong> Cosine with a strict warmup phase.</li>\n</ul>\n<pre><code># Stage 2 Scheduler Configuration\nCosineLRScheduler(\n    lr_min=1e-6,           # Target minimum LR\n    warmup_t=3,            # Crucial 3-epoch warmup\n    warmup_lr_init=1e-7,   # Start near zero\n    cycle_limit=1,         # Single cycle (no restarts)\n    t_in_epochs=True\n)\n</code></pre>\n<h3>Data Augmentation</h3>\n<p>I used <strong>Albumentations</strong> to force the model to learn invariant features, specifically using <code>RandomShadow</code> and <code>RandomGamma</code> to handle lighting variations.</p>\n<pre><code>A.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.RandomRotate90(p=0.5),\n    A.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.2, p=0.5),\n    A.RandomGamma(gamma_limit=(80, 120), p=0.3),\n    A.RandomShadow(num_shadows_limit=(1, 3), shadow_dimension=5, p=0.5),\n    A.Resize(self.img_size, self.img_size),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2()\n])\n</code></pre>\n<h3>Validation Strategy</h3>\n<p>I initially tried <strong>GroupKFold</strong> using <code>sampling_date</code>, but it led to high distribution variance between folds, and some models failed to learn sufficient data variation. This did not improve the Public LB.</p>\n<p>Therefore, I decided to accept the discrepancy between CV and Public LB and maximized the CV score using a stratified approach based on bins and species.</p>\n<pre><code># Create a stratification key combining total biomass bin and species\ndf['strat_key'] = df['total_bin'].astype(int) * 100 + df['species_id'].astype(int)\n\nskf = StratifiedKFold(\n    n_splits=self.config.n_folds,\n    shuffle=True,\n    random_state=self.config.random_state\n)\n</code></pre>\n<h3>Species-Aware Prediction</h3>\n<p>To utilize the species metadata effectively during inference (where metadata might not be available or reliable):</p>\n<ol>\n<li><p><strong>Species Model</strong>\nTrained a separate <code>dinov3_large</code> model (same head structure) to classify species from images.</p></li>\n<li><p><strong>Inference</strong></p>\n<ul>\n<li>Predicted the probability of the image belonging to each species using the Species Model.</li>\n<li>Used this predicted probability as an input feature for the main Biomass Prediction model.</li></ul></li>\n</ol>\n<hr>\n<h2>3. Critical Optimizations (Diptyajit Das's Part)</h2>\n<p>While the backbone provided the power, Diptyajit’s experiments with targets and resolution provided the stability and generalization needed for the Private LB.</p>\n<h3>A. Target Reformulation</h3>\n<p>Instead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.</p>\n<ul>\n<li><strong>Old Targets:</strong> <code>Dry_Green_g</code>, <code>GDM_g</code>, <code>Dry_Total_g</code></li>\n<li><strong>New Targets:</strong> <code>Dry_Clover_g</code>, <code>GDM_g</code>, <code>Dry_Total_g</code></li>\n<li><strong>Impact:</strong> This specific change was crucial for the <strong>Huge DINOv3</strong> variant, directly improving the Public LB from <strong>0.73  to 0.74</strong>.</li>\n</ul>\n<h3>B. Auxiliary Heads &amp; Stability</h3>\n<p>I experimented with adding an auxiliary NDVI regression head alongside species classification in Stage 1. This boosted the <code>vit_large</code> model to 0.73, but had negligible impact on <code>vit_huge_plus</code> model's score.</p>\n<h3>C. The \"Golden\" Resolution (640px)</h3>\n<p>While 768px provided the <strong>best Public LB</strong>, Diptyajit’s experiments revealed that <strong>640px</strong> offered superior generalization and resulted in our <strong>highest single-model Private LB (0.657)</strong>, but we couldn't select this for final evaluation because of lower Public LB (0.75)</p>\n<hr>\n<h2>4. Pipeline A: The SSA Adapter &amp; MLP Head (Paritosh's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.5</p>\n<p>This pipeline addressed the domain shift between training and test sets without expensive retraining. Instead of standard fine-tuning, we used <strong>Significant Subspace Alignment (SSA)</strong> as a lightweight Test-Time Adaptation (TTA) technique.</p>\n<h3>The \"2-Layer\" MLP Head</h3>\n<ul>\n<li><p>I replaced the standard linear head with a deeper projection head, which gave a +0.02 boost from Public LB <strong>0.74 to 0.76</strong> and +0.01 improvement from <strong>0.635 to 0.646</strong> in Private LB.</p></li>\n<li><p>I then finalized upon 3-Layer MLP Head because it was slightly better than 2-Layers.</p></li>\n</ul>\n<pre><code>nn.Sequential(\n    nn.Linear(input_dim, 512), # Hidden Layer 1\n    nn.BatchNorm1d(512),\n    nn.ReLU(),\n    nn.Dropout(0.3),\n\n    nn.Linear(512, 256),       # Hidden Layer 2\n    nn.BatchNorm1d(256),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(256, 128),       # Hidden Layer 3\n    nn.BatchNorm1d(128),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(128, n_targets)\n)\n</code></pre>\n<h3>SSA Adapter (Test-Time Adaptation)</h3>\n<p>I inserted a learnable linear adapter between the backbone and the head. During inference, we froze the backbone and updated <em>only</em> this adapter to align the test image features with the training distribution (using pre-calculated PCA statistics <code>mu_s</code> and <code>U</code>). More details here: <a href=\"https://arxiv.org/pdf/2410.03263\" target=\"_blank\">https://arxiv.org/pdf/2410.03263</a></p>\n<p>This had negligible change in Public LB but I trusted this approach and it improved the score from <strong>0.646 to 0.652</strong> in Private LB :)</p>\n<hr>\n<h2>5. Pipeline B: Species-Aware Injection (Takumi's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.3</p>\n<ol>\n<li><strong>Stage 1 (Species Model):</strong> Trained <code>vit_large_patch16_dinov3</code> to classify 15 species.</li>\n<li><strong>Stage 2 (Biomass Model):</strong></li>\n</ol>\n<ul>\n<li>Backbone: <code>vit_huge_plus_patch16_dinov3</code>.</li>\n<li>Input: Concatenates image features + <strong>Predicted Species Probabilities</strong>.</li>\n<li>Targets: Predicted <code>Dry_Clover_g</code> and <code>GDM_g</code> to reconstruct the total.</li>\n</ul>\n<hr>\n<h2>6. Pipeline C: Dual-Backbone Fusion with SigLIP (Takumi's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.2</p>\n<p>To capture different semantic granularities, we fused features from two state-of-the-art vision models.</p>\n<ul>\n<li><strong>Branch 1:</strong> DINOv3 Huge (768px) - Excellent for structure and local details.</li>\n<li><strong>Branch 2:</strong> SigLIP <code>vit_so400m_patch16_siglip_512</code> (512px) - Excellent for semantic understanding.</li>\n<li><strong>Fusion:</strong> Features from both backbones were concatenated before passing to the MLP head.</li>\n</ul>\n<pre><code># Feature Fusion Logic\nfeat_dino = dino_backbone(img_768)   # DINOv3 Features\nfeat_siglip = siglip_backbone(img_512) # SigLIP Features\n\n# Concatenate: [Backbone_L, Backbone_R, SigLIP_L, SigLIP_R]\ncombined_features = torch.cat([feat_dino, feat_siglip], dim=1)\n</code></pre>\n<hr>\n<h2>7. Final Ensemble &amp; Results</h2>\n<p>Our final submission was a weighted average of the three pipelines. The heavy weighting on the SSA model (0.5) reflects its robustness to the distribution shift in the private test set. The final ensemble helped gained the last few decimals.</p>\n<pre><code># Final Ensemble Logic\nfinal_submission = (\n    0.5 * prediction_ssa +       # Pipeline A (Robustness)\n    0.3 * prediction_species +   # Pipeline B (Metadata Context)\n    0.2 * prediction_siglip      # Pipeline C (Feature Diversity)\n)\n</code></pre>\n<h3>Validation Strategy</h3>\n<p>We used <strong>StratifiedKFold (5 Folds)</strong>, stratifying by a composite key of <code>total_biomass_bin</code> * <code>species_id</code> to ensure every fold saw a representative distribution of species and weight classes.</p>\n<h3>Performance</h3>\n<ul>\n<li><strong>Public LB:</strong> 0.760</li>\n<li><strong>Private LB:</strong> 0.652</li>\n</ul>",
  "messages": [
    {
      "id": "3400351",
      "postDate": "02/01/2026 12:22:48",
      "content": "<h2>1. Overview &amp; Key Insight</h2>\n<p>Our solution is a weighted ensemble of three distinct pipelines, all anchored by a <strong>DINOv3 Huge</strong> backbone.</p>\n<p>Our final submission combined:</p>\n<ol>\n<li><strong>SSA-Adapted Pipeline (50%)</strong>: Test-Time Adaptation using subspace alignment.</li>\n<li><strong>Species-Aware Pipeline (30%)</strong>: Two-stage injection of species metadata.</li>\n<li><strong>Dual-Backbone Pipeline (20%)</strong>: DINOv3 fused with SigLIP features.</li>\n</ol>\n<hr>\n<h2>2. The Core Backbone (Takumi's Part)</h2>\n<ul>\n<li><p>I strongly believed in the trend of scaling laws and aimed to utilize the largest model possible within my compute constraints.</p></li>\n<li><p>A key insight was that in competitions with limited data, utilizing a strong backbone pretrained on a massive dataset is crucial.</p></li>\n<li><p>I spent the majority of the competition optimizing the training recipe for DINOv3, which I believe gave me an edge over other solutions using the same architecture.</p></li>\n<li><p>I observed a significant jump in the Public LB score as I increased the model size. Increasing the model size proved to be more effective than increasing the image resolution. Due to A100 memory constraints, we standardized on:</p></li>\n<li><p><strong>Model:</strong> <code>vit_huge_plus_patch16_dinov3.lvd1689m</code></p></li>\n<li><p><strong>Image Size:</strong> 768px (Standardized across most pipelines)</p></li>\n</ul>\n<p>I wanted to emphasize the impact of simply changing the backbone. Here is the progression:</p>\n<ul>\n<li><strong>convnext_tiny → vit_base_patch16_dinov3.lvd1689m:</strong> 0.61 → 0.67  </li>\n<li><strong>vit_base_patch16_dinov3.lvd1689m → vit_large_patch16_dinov3.lvd1689m:</strong> 0.69 → 0.72  </li>\n<li><strong>vit_large_patch16_dinov3.lvd1689m → vit_huge_plus_patch16_dinov3.lvd1689m:</strong> 0.72 → 0.74</li>\n</ul>\n<h3>Head Architecture</h3>\n<p>I utilized a standard regression head with <code>SiLU</code> activation and dropout.</p>\n<pre><code>nn.Sequential(\n    nn.Linear(in_features, hidden),\n    nn.SiLU(),\n    nn.Dropout(0.3),\n    nn.Linear(hidden, out_features),\n)\n</code></pre>\n<h3>Training Strategy</h3>\n<p>To stabilize the training of such a large model on limited data, I employed a <strong>Two-Stage Training</strong> process using <code>AdamW</code> and Mixed Precision (AMP).</p>\n<ul>\n<li><strong>Loss Function:</strong> <code>nn.SmoothL1Loss()</code></li>\n<li><strong>Batch Size:</strong> Effective batch size of 8 (using <code>grad_accum_steps=8</code> on Batch Size 1).</li>\n</ul>\n<h3>Stage 1: Head Only (Warmup)</h3>\n<ul>\n<li><strong>Goal:</strong> Stabilize weights before fine-tuning the transformer.</li>\n<li><strong>Epochs:</strong> 15</li>\n<li><strong>LR:</strong> <code>3e-4</code> with <code>ReduceLROnPlateau</code>.</li>\n</ul>\n<h3>Stage 2: Full Backbone Finetuning</h3>\n<ul>\n<li><strong>Goal:</strong> Adapt the huge backbone without overfitting.</li>\n<li><strong>Epochs:</strong> 35</li>\n<li><strong>Weight Decay:</strong> <code>0.2</code> (High decay was crucial for regularization).</li>\n<li><strong>Scheduler:</strong> Cosine with a strict warmup phase.</li>\n</ul>\n<pre><code># Stage 2 Scheduler Configuration\nCosineLRScheduler(\n    lr_min=1e-6,           # Target minimum LR\n    warmup_t=3,            # Crucial 3-epoch warmup\n    warmup_lr_init=1e-7,   # Start near zero\n    cycle_limit=1,         # Single cycle (no restarts)\n    t_in_epochs=True\n)\n</code></pre>\n<h3>Data Augmentation</h3>\n<p>I used <strong>Albumentations</strong> to force the model to learn invariant features, specifically using <code>RandomShadow</code> and <code>RandomGamma</code> to handle lighting variations.</p>\n<pre><code>A.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.RandomRotate90(p=0.5),\n    A.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.2, p=0.5),\n    A.RandomGamma(gamma_limit=(80, 120), p=0.3),\n    A.RandomShadow(num_shadows_limit=(1, 3), shadow_dimension=5, p=0.5),\n    A.Resize(self.img_size, self.img_size),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2()\n])\n</code></pre>\n<h3>Validation Strategy</h3>\n<p>I initially tried <strong>GroupKFold</strong> using <code>sampling_date</code>, but it led to high distribution variance between folds, and some models failed to learn sufficient data variation. This did not improve the Public LB.</p>\n<p>Therefore, I decided to accept the discrepancy between CV and Public LB and maximized the CV score using a stratified approach based on bins and species.</p>\n<pre><code># Create a stratification key combining total biomass bin and species\ndf['strat_key'] = df['total_bin'].astype(int) * 100 + df['species_id'].astype(int)\n\nskf = StratifiedKFold(\n    n_splits=self.config.n_folds,\n    shuffle=True,\n    random_state=self.config.random_state\n)\n</code></pre>\n<h3>Species-Aware Prediction</h3>\n<p>To utilize the species metadata effectively during inference (where metadata might not be available or reliable):</p>\n<ol>\n<li><p><strong>Species Model</strong>\nTrained a separate <code>dinov3_large</code> model (same head structure) to classify species from images.</p></li>\n<li><p><strong>Inference</strong></p>\n<ul>\n<li>Predicted the probability of the image belonging to each species using the Species Model.</li>\n<li>Used this predicted probability as an input feature for the main Biomass Prediction model.</li></ul></li>\n</ol>\n<hr>\n<h2>3. Critical Optimizations (Diptyajit Das's Part)</h2>\n<p>While the backbone provided the power, Diptyajit’s experiments with targets and resolution provided the stability and generalization needed for the Private LB.</p>\n<h3>A. Target Reformulation</h3>\n<p>Instead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.</p>\n<ul>\n<li><strong>Old Targets:</strong> <code>Dry_Green_g</code>, <code>GDM_g</code>, <code>Dry_Total_g</code></li>\n<li><strong>New Targets:</strong> <code>Dry_Clover_g</code>, <code>GDM_g</code>, <code>Dry_Total_g</code></li>\n<li><strong>Impact:</strong> This specific change was crucial for the <strong>Huge DINOv3</strong> variant, directly improving the Public LB from <strong>0.73  to 0.74</strong>.</li>\n</ul>\n<h3>B. Auxiliary Heads &amp; Stability</h3>\n<p>I experimented with adding an auxiliary NDVI regression head alongside species classification in Stage 1. This boosted the <code>vit_large</code> model to 0.73, but had negligible impact on <code>vit_huge_plus</code> model's score.</p>\n<h3>C. The \"Golden\" Resolution (640px)</h3>\n<p>While 768px provided the <strong>best Public LB</strong>, Diptyajit’s experiments revealed that <strong>640px</strong> offered superior generalization and resulted in our <strong>highest single-model Private LB (0.657)</strong>, but we couldn't select this for final evaluation because of lower Public LB (0.75)</p>\n<hr>\n<h2>4. Pipeline A: The SSA Adapter &amp; MLP Head (Paritosh's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.5</p>\n<p>This pipeline addressed the domain shift between training and test sets without expensive retraining. Instead of standard fine-tuning, we used <strong>Significant Subspace Alignment (SSA)</strong> as a lightweight Test-Time Adaptation (TTA) technique.</p>\n<h3>The \"2-Layer\" MLP Head</h3>\n<ul>\n<li><p>I replaced the standard linear head with a deeper projection head, which gave a +0.02 boost from Public LB <strong>0.74 to 0.76</strong> and +0.01 improvement from <strong>0.635 to 0.646</strong> in Private LB.</p></li>\n<li><p>I then finalized upon 3-Layer MLP Head because it was slightly better than 2-Layers.</p></li>\n</ul>\n<pre><code>nn.Sequential(\n    nn.Linear(input_dim, 512), # Hidden Layer 1\n    nn.BatchNorm1d(512),\n    nn.ReLU(),\n    nn.Dropout(0.3),\n\n    nn.Linear(512, 256),       # Hidden Layer 2\n    nn.BatchNorm1d(256),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(256, 128),       # Hidden Layer 3\n    nn.BatchNorm1d(128),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(128, n_targets)\n)\n</code></pre>\n<h3>SSA Adapter (Test-Time Adaptation)</h3>\n<p>I inserted a learnable linear adapter between the backbone and the head. During inference, we froze the backbone and updated <em>only</em> this adapter to align the test image features with the training distribution (using pre-calculated PCA statistics <code>mu_s</code> and <code>U</code>). More details here: <a href=\"https://arxiv.org/pdf/2410.03263\" target=\"_blank\">https://arxiv.org/pdf/2410.03263</a></p>\n<p>This had negligible change in Public LB but I trusted this approach and it improved the score from <strong>0.646 to 0.652</strong> in Private LB :)</p>\n<hr>\n<h2>5. Pipeline B: Species-Aware Injection (Takumi's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.3</p>\n<ol>\n<li><strong>Stage 1 (Species Model):</strong> Trained <code>vit_large_patch16_dinov3</code> to classify 15 species.</li>\n<li><strong>Stage 2 (Biomass Model):</strong></li>\n</ol>\n<ul>\n<li>Backbone: <code>vit_huge_plus_patch16_dinov3</code>.</li>\n<li>Input: Concatenates image features + <strong>Predicted Species Probabilities</strong>.</li>\n<li>Targets: Predicted <code>Dry_Clover_g</code> and <code>GDM_g</code> to reconstruct the total.</li>\n</ul>\n<hr>\n<h2>6. Pipeline C: Dual-Backbone Fusion with SigLIP (Takumi's Part)</h2>\n<p><strong>Weight in Ensemble:</strong> 0.2</p>\n<p>To capture different semantic granularities, we fused features from two state-of-the-art vision models.</p>\n<ul>\n<li><strong>Branch 1:</strong> DINOv3 Huge (768px) - Excellent for structure and local details.</li>\n<li><strong>Branch 2:</strong> SigLIP <code>vit_so400m_patch16_siglip_512</code> (512px) - Excellent for semantic understanding.</li>\n<li><strong>Fusion:</strong> Features from both backbones were concatenated before passing to the MLP head.</li>\n</ul>\n<pre><code># Feature Fusion Logic\nfeat_dino = dino_backbone(img_768)   # DINOv3 Features\nfeat_siglip = siglip_backbone(img_512) # SigLIP Features\n\n# Concatenate: [Backbone_L, Backbone_R, SigLIP_L, SigLIP_R]\ncombined_features = torch.cat([feat_dino, feat_siglip], dim=1)\n</code></pre>\n<hr>\n<h2>7. Final Ensemble &amp; Results</h2>\n<p>Our final submission was a weighted average of the three pipelines. The heavy weighting on the SSA model (0.5) reflects its robustness to the distribution shift in the private test set. The final ensemble helped gained the last few decimals.</p>\n<pre><code># Final Ensemble Logic\nfinal_submission = (\n    0.5 * prediction_ssa +       # Pipeline A (Robustness)\n    0.3 * prediction_species +   # Pipeline B (Metadata Context)\n    0.2 * prediction_siglip      # Pipeline C (Feature Diversity)\n)\n</code></pre>\n<h3>Validation Strategy</h3>\n<p>We used <strong>StratifiedKFold (5 Folds)</strong>, stratifying by a composite key of <code>total_biomass_bin</code> * <code>species_id</code> to ensure every fold saw a representative distribution of species and weight classes.</p>\n<h3>Performance</h3>\n<ul>\n<li><strong>Public LB:</strong> 0.760</li>\n<li><strong>Private LB:</strong> 0.652</li>\n</ul>",
      "rawMarkdown": "## 1. Overview & Key Insight\n\nOur solution is a weighted ensemble of three distinct pipelines, all anchored by a **DINOv3 Huge** backbone.\n\nOur final submission combined:\n\n1. **SSA-Adapted Pipeline (50%)**: Test-Time Adaptation using subspace alignment.\n2. **Species-Aware Pipeline (30%)**: Two-stage injection of species metadata.\n3. **Dual-Backbone Pipeline (20%)**: DINOv3 fused with SigLIP features.\n\n---\n\n## 2. The Core Backbone (Takumi's Part)\n\n* I strongly believed in the trend of scaling laws and aimed to utilize the largest model possible within my compute constraints.\n* A key insight was that in competitions with limited data, utilizing a strong backbone pretrained on a massive dataset is crucial.\n* I spent the majority of the competition optimizing the training recipe for DINOv3, which I believe gave me an edge over other solutions using the same architecture.\n* I observed a significant jump in the Public LB score as I increased the model size. Increasing the model size proved to be more effective than increasing the image resolution. Due to A100 memory constraints, we standardized on:\n\n* **Model:** `vit_huge_plus_patch16_dinov3.lvd1689m`\n* **Image Size:** 768px (Standardized across most pipelines)\n\nI wanted to emphasize the impact of simply changing the backbone. Here is the progression:\n\n- **convnext_tiny → vit_base_patch16_dinov3.lvd1689m:** 0.61 → 0.67  \n- **vit_base_patch16_dinov3.lvd1689m → vit_large_patch16_dinov3.lvd1689m:** 0.69 → 0.72  \n- **vit_large_patch16_dinov3.lvd1689m → vit_huge_plus_patch16_dinov3.lvd1689m:** 0.72 → 0.74\n\n### Head Architecture\n\nI utilized a standard regression head with `SiLU` activation and dropout.\n\n```python\nnn.Sequential(\n    nn.Linear(in_features, hidden),\n    nn.SiLU(),\n    nn.Dropout(0.3),\n    nn.Linear(hidden, out_features),\n)\n\n```\n\n### Training Strategy\n\nTo stabilize the training of such a large model on limited data, I employed a **Two-Stage Training** process using `AdamW` and Mixed Precision (AMP).\n\n* **Loss Function:** `nn.SmoothL1Loss()`\n* **Batch Size:** Effective batch size of 8 (using `grad_accum_steps=8` on Batch Size 1).\n\n### Stage 1: Head Only (Warmup)\n\n* **Goal:** Stabilize weights before fine-tuning the transformer.\n* **Epochs:** 15\n* **LR:** `3e-4` with `ReduceLROnPlateau`.\n\n### Stage 2: Full Backbone Finetuning\n\n* **Goal:** Adapt the huge backbone without overfitting.\n* **Epochs:** 35\n* **Weight Decay:** `0.2` (High decay was crucial for regularization).\n* **Scheduler:** Cosine with a strict warmup phase.\n\n```python\n# Stage 2 Scheduler Configuration\nCosineLRScheduler(\n    lr_min=1e-6,           # Target minimum LR\n    warmup_t=3,            # Crucial 3-epoch warmup\n    warmup_lr_init=1e-7,   # Start near zero\n    cycle_limit=1,         # Single cycle (no restarts)\n    t_in_epochs=True\n)\n```\n\n### Data Augmentation\n\nI used **Albumentations** to force the model to learn invariant features, specifically using `RandomShadow` and `RandomGamma` to handle lighting variations.\n\n```python\nA.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.RandomRotate90(p=0.5),\n    A.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.2, p=0.5),\n    A.RandomGamma(gamma_limit=(80, 120), p=0.3),\n    A.RandomShadow(num_shadows_limit=(1, 3), shadow_dimension=5, p=0.5),\n    A.Resize(self.img_size, self.img_size),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2()\n])\n```\n### Validation Strategy\n\nI initially tried **GroupKFold** using `sampling_date`, but it led to high distribution variance between folds, and some models failed to learn sufficient data variation. This did not improve the Public LB.\n\nTherefore, I decided to accept the discrepancy between CV and Public LB and maximized the CV score using a stratified approach based on bins and species.\n\n```python\n# Create a stratification key combining total biomass bin and species\ndf['strat_key'] = df['total_bin'].astype(int) * 100 + df['species_id'].astype(int)\n\nskf = StratifiedKFold(\n    n_splits=self.config.n_folds,\n    shuffle=True,\n    random_state=self.config.random_state\n)\n```\n\n### Species-Aware Prediction\n\nTo utilize the species metadata effectively during inference (where metadata might not be available or reliable):\n\n1. **Species Model**\n   Trained a separate `dinov3_large` model (same head structure) to classify species from images.\n\n2. **Inference**\n\n   * Predicted the probability of the image belonging to each species using the Species Model.\n   * Used this predicted probability as an input feature for the main Biomass Prediction model.\n\n---\n\n## 3. Critical Optimizations (Diptyajit Das's Part)\n\nWhile the backbone provided the power, Diptyajit’s experiments with targets and resolution provided the stability and generalization needed for the Private LB.\n\n### A. Target Reformulation\n\nInstead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\n\n* **Old Targets:** `Dry_Green_g`, `GDM_g`, `Dry_Total_g`\n* **New Targets:** `Dry_Clover_g`, `GDM_g`, `Dry_Total_g`\n* **Impact:** This specific change was crucial for the **Huge DINOv3** variant, directly improving the Public LB from **0.73  to 0.74**.\n\n### B. Auxiliary Heads & Stability\n\nI experimented with adding an auxiliary NDVI regression head alongside species classification in Stage 1. This boosted the `vit_large` model to 0.73, but had negligible impact on `vit_huge_plus` model's score.\n\n### C. The \"Golden\" Resolution (640px)\n\nWhile 768px provided the **best Public LB**, Diptyajit’s experiments revealed that **640px** offered superior generalization and resulted in our **highest single-model Private LB (0.657)**, but we couldn't select this for final evaluation because of lower Public LB (0.75)\n\n---\n\n## 4. Pipeline A: The SSA Adapter & MLP Head (Paritosh's Part)\n\n**Weight in Ensemble:** 0.5\n\nThis pipeline addressed the domain shift between training and test sets without expensive retraining. Instead of standard fine-tuning, we used **Significant Subspace Alignment (SSA)** as a lightweight Test-Time Adaptation (TTA) technique.\n\n### The \"2-Layer\" MLP Head\n\n* I replaced the standard linear head with a deeper projection head, which gave a +0.02 boost from Public LB **0.74 to 0.76** and +0.01 improvement from **0.635 to 0.646** in Private LB.\n\n* I then finalized upon 3-Layer MLP Head because it was slightly better than 2-Layers.\n\n```python\nnn.Sequential(\n    nn.Linear(input_dim, 512), # Hidden Layer 1\n    nn.BatchNorm1d(512),\n    nn.ReLU(),\n    nn.Dropout(0.3),\n\n    nn.Linear(512, 256),       # Hidden Layer 2\n    nn.BatchNorm1d(256),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(256, 128),       # Hidden Layer 3\n    nn.BatchNorm1d(128),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(128, n_targets)\n)\n\n```\n\n### SSA Adapter (Test-Time Adaptation)\n\nI inserted a learnable linear adapter between the backbone and the head. During inference, we froze the backbone and updated *only* this adapter to align the test image features with the training distribution (using pre-calculated PCA statistics `mu_s` and `U`). More details here: https://arxiv.org/pdf/2410.03263\n\nThis had negligible change in Public LB but I trusted this approach and it improved the score from **0.646 to 0.652** in Private LB :)\n\n---\n\n## 5. Pipeline B: Species-Aware Injection (Takumi's Part)\n\n**Weight in Ensemble:** 0.3\n\n1. **Stage 1 (Species Model):** Trained `vit_large_patch16_dinov3` to classify 15 species.\n2. **Stage 2 (Biomass Model):**\n* Backbone: `vit_huge_plus_patch16_dinov3`.\n* Input: Concatenates image features + **Predicted Species Probabilities**.\n* Targets: Predicted `Dry_Clover_g` and `GDM_g` to reconstruct the total.\n\n\n\n---\n\n## 6. Pipeline C: Dual-Backbone Fusion with SigLIP (Takumi's Part)\n\n**Weight in Ensemble:** 0.2\n\nTo capture different semantic granularities, we fused features from two state-of-the-art vision models.\n\n* **Branch 1:** DINOv3 Huge (768px) - Excellent for structure and local details.\n* **Branch 2:** SigLIP `vit_so400m_patch16_siglip_512` (512px) - Excellent for semantic understanding.\n* **Fusion:** Features from both backbones were concatenated before passing to the MLP head.\n\n```python\n# Feature Fusion Logic\nfeat_dino = dino_backbone(img_768)   # DINOv3 Features\nfeat_siglip = siglip_backbone(img_512) # SigLIP Features\n\n# Concatenate: [Backbone_L, Backbone_R, SigLIP_L, SigLIP_R]\ncombined_features = torch.cat([feat_dino, feat_siglip], dim=1)\n\n```\n\n---\n\n## 7. Final Ensemble & Results\n\nOur final submission was a weighted average of the three pipelines. The heavy weighting on the SSA model (0.5) reflects its robustness to the distribution shift in the private test set. The final ensemble helped gained the last few decimals.\n\n```python\n# Final Ensemble Logic\nfinal_submission = (\n    0.5 * prediction_ssa +       # Pipeline A (Robustness)\n    0.3 * prediction_species +   # Pipeline B (Metadata Context)\n    0.2 * prediction_siglip      # Pipeline C (Feature Diversity)\n)\n```\n\n### Validation Strategy\n\nWe used **StratifiedKFold (5 Folds)**, stratifying by a composite key of `total_biomass_bin` * `species_id` to ensure every fold saw a representative distribution of species and weight classes.\n\n### Performance\n\n* **Public LB:** 0.760\n* **Private LB:** 0.652",
      "votes": null
    },
    {
      "id": "3401145",
      "postDate": "02/03/2026 02:49:20",
      "content": "<p>Congratulations🎉！</p>\n<blockquote>\n  <p>A. Target Reformulation\n  Instead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\n  Old Targets: Dry_Green_g, GDM_g, Dry_Total_g\n  New Targets: Dry_Clover_g, GDM_g, Dry_Total_g\n  Impact: This specific change was crucial for the Huge DINOv3 variant, directly improving the Public LB from 0.73 to 0.74.</p>\n</blockquote>\n<p>The meaning is that use 'Dry_Clover_g', 'GDM_g', and 'Dry_Total_g' will perform better than 'Dry_Green_g', 'GDM_g', and 'Dry_Total_g'. Is this the case for all of your models? 🤔</p>",
      "rawMarkdown": "Congratulations🎉！\n\n>A. Target Reformulation\nInstead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\nOld Targets: Dry_Green_g, GDM_g, Dry_Total_g\nNew Targets: Dry_Clover_g, GDM_g, Dry_Total_g\nImpact: This specific change was crucial for the Huge DINOv3 variant, directly improving the Public LB from 0.73 to 0.74.\n\n\nThe meaning is that use 'Dry_Clover_g', 'GDM_g', and 'Dry_Total_g' will perform better than 'Dry_Green_g', 'GDM_g', and 'Dry_Total_g'. Is this the case for all of your models? 🤔",
      "votes": null
    },
    {
      "id": "3401739",
      "postDate": "02/04/2026 12:52:56",
      "content": "<p>We did not test it on all of our models, but for dino v3 huge there was indeed improvements in both CV and LB. We focused on diversity so my MLP heads predicted all 5 targets (Pipeline A), whereas Pipeline B and C predicted 3 targets and recreated the 5 from these 3.</p>",
      "rawMarkdown": "We did not test it on all of our models, but for dino v3 huge there was indeed improvements in both CV and LB. We focused on diversity so my MLP heads predicted all 5 targets (Pipeline A), whereas Pipeline B and C predicted 3 targets and recreated the 5 from these 3.",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3401145,
      "author_name": "minghigh",
      "author_url": "",
      "post_date": "02/03/2026 02:49:20",
      "content": "<p>Congratulations🎉！</p>\n<blockquote>\n  <p>A. Target Reformulation\n  Instead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\n  Old Targets: Dry_Green_g, GDM_g, Dry_Total_g\n  New Targets: Dry_Clover_g, GDM_g, Dry_Total_g\n  Impact: This specific change was crucial for the Huge DINOv3 variant, directly improving the Public LB from 0.73 to 0.74.</p>\n</blockquote>\n<p>The meaning is that use 'Dry_Clover_g', 'GDM_g', and 'Dry_Total_g' will perform better than 'Dry_Green_g', 'GDM_g', and 'Dry_Total_g'. Is this the case for all of your models? 🤔</p>",
      "votes": null,
      "replies": [
        {
          "id": 3401739,
          "author_name": "paritoshtripathi5",
          "author_url": "",
          "post_date": "02/04/2026 12:52:56",
          "content": "<p>We did not test it on all of our models, but for dino v3 huge there was indeed improvements in both CV and LB. We focused on diversity so my MLP heads predicted all 5 targets (Pipeline A), whereas Pipeline B and C predicted 3 targets and recreated the 5 from these 3.</p>",
          "votes": null,
          "replies": []
        }
      ]
    }
  ],
  "raw_markdown_by_id": {
    "3400351": "## 1. Overview & Key Insight\n\nOur solution is a weighted ensemble of three distinct pipelines, all anchored by a **DINOv3 Huge** backbone.\n\nOur final submission combined:\n\n1. **SSA-Adapted Pipeline (50%)**: Test-Time Adaptation using subspace alignment.\n2. **Species-Aware Pipeline (30%)**: Two-stage injection of species metadata.\n3. **Dual-Backbone Pipeline (20%)**: DINOv3 fused with SigLIP features.\n\n---\n\n## 2. The Core Backbone (Takumi's Part)\n\n* I strongly believed in the trend of scaling laws and aimed to utilize the largest model possible within my compute constraints.\n* A key insight was that in competitions with limited data, utilizing a strong backbone pretrained on a massive dataset is crucial.\n* I spent the majority of the competition optimizing the training recipe for DINOv3, which I believe gave me an edge over other solutions using the same architecture.\n* I observed a significant jump in the Public LB score as I increased the model size. Increasing the model size proved to be more effective than increasing the image resolution. Due to A100 memory constraints, we standardized on:\n\n* **Model:** `vit_huge_plus_patch16_dinov3.lvd1689m`\n* **Image Size:** 768px (Standardized across most pipelines)\n\nI wanted to emphasize the impact of simply changing the backbone. Here is the progression:\n\n- **convnext_tiny → vit_base_patch16_dinov3.lvd1689m:** 0.61 → 0.67  \n- **vit_base_patch16_dinov3.lvd1689m → vit_large_patch16_dinov3.lvd1689m:** 0.69 → 0.72  \n- **vit_large_patch16_dinov3.lvd1689m → vit_huge_plus_patch16_dinov3.lvd1689m:** 0.72 → 0.74\n\n### Head Architecture\n\nI utilized a standard regression head with `SiLU` activation and dropout.\n\n```python\nnn.Sequential(\n    nn.Linear(in_features, hidden),\n    nn.SiLU(),\n    nn.Dropout(0.3),\n    nn.Linear(hidden, out_features),\n)\n\n```\n\n### Training Strategy\n\nTo stabilize the training of such a large model on limited data, I employed a **Two-Stage Training** process using `AdamW` and Mixed Precision (AMP).\n\n* **Loss Function:** `nn.SmoothL1Loss()`\n* **Batch Size:** Effective batch size of 8 (using `grad_accum_steps=8` on Batch Size 1).\n\n### Stage 1: Head Only (Warmup)\n\n* **Goal:** Stabilize weights before fine-tuning the transformer.\n* **Epochs:** 15\n* **LR:** `3e-4` with `ReduceLROnPlateau`.\n\n### Stage 2: Full Backbone Finetuning\n\n* **Goal:** Adapt the huge backbone without overfitting.\n* **Epochs:** 35\n* **Weight Decay:** `0.2` (High decay was crucial for regularization).\n* **Scheduler:** Cosine with a strict warmup phase.\n\n```python\n# Stage 2 Scheduler Configuration\nCosineLRScheduler(\n    lr_min=1e-6,           # Target minimum LR\n    warmup_t=3,            # Crucial 3-epoch warmup\n    warmup_lr_init=1e-7,   # Start near zero\n    cycle_limit=1,         # Single cycle (no restarts)\n    t_in_epochs=True\n)\n```\n\n### Data Augmentation\n\nI used **Albumentations** to force the model to learn invariant features, specifically using `RandomShadow` and `RandomGamma` to handle lighting variations.\n\n```python\nA.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.RandomRotate90(p=0.5),\n    A.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.2, p=0.5),\n    A.RandomGamma(gamma_limit=(80, 120), p=0.3),\n    A.RandomShadow(num_shadows_limit=(1, 3), shadow_dimension=5, p=0.5),\n    A.Resize(self.img_size, self.img_size),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2()\n])\n```\n### Validation Strategy\n\nI initially tried **GroupKFold** using `sampling_date`, but it led to high distribution variance between folds, and some models failed to learn sufficient data variation. This did not improve the Public LB.\n\nTherefore, I decided to accept the discrepancy between CV and Public LB and maximized the CV score using a stratified approach based on bins and species.\n\n```python\n# Create a stratification key combining total biomass bin and species\ndf['strat_key'] = df['total_bin'].astype(int) * 100 + df['species_id'].astype(int)\n\nskf = StratifiedKFold(\n    n_splits=self.config.n_folds,\n    shuffle=True,\n    random_state=self.config.random_state\n)\n```\n\n### Species-Aware Prediction\n\nTo utilize the species metadata effectively during inference (where metadata might not be available or reliable):\n\n1. **Species Model**\n   Trained a separate `dinov3_large` model (same head structure) to classify species from images.\n\n2. **Inference**\n\n   * Predicted the probability of the image belonging to each species using the Species Model.\n   * Used this predicted probability as an input feature for the main Biomass Prediction model.\n\n---\n\n## 3. Critical Optimizations (Diptyajit Das's Part)\n\nWhile the backbone provided the power, Diptyajit’s experiments with targets and resolution provided the stability and generalization needed for the Private LB.\n\n### A. Target Reformulation\n\nInstead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\n\n* **Old Targets:** `Dry_Green_g`, `GDM_g`, `Dry_Total_g`\n* **New Targets:** `Dry_Clover_g`, `GDM_g`, `Dry_Total_g`\n* **Impact:** This specific change was crucial for the **Huge DINOv3** variant, directly improving the Public LB from **0.73  to 0.74**.\n\n### B. Auxiliary Heads & Stability\n\nI experimented with adding an auxiliary NDVI regression head alongside species classification in Stage 1. This boosted the `vit_large` model to 0.73, but had negligible impact on `vit_huge_plus` model's score.\n\n### C. The \"Golden\" Resolution (640px)\n\nWhile 768px provided the **best Public LB**, Diptyajit’s experiments revealed that **640px** offered superior generalization and resulted in our **highest single-model Private LB (0.657)**, but we couldn't select this for final evaluation because of lower Public LB (0.75)\n\n---\n\n## 4. Pipeline A: The SSA Adapter & MLP Head (Paritosh's Part)\n\n**Weight in Ensemble:** 0.5\n\nThis pipeline addressed the domain shift between training and test sets without expensive retraining. Instead of standard fine-tuning, we used **Significant Subspace Alignment (SSA)** as a lightweight Test-Time Adaptation (TTA) technique.\n\n### The \"2-Layer\" MLP Head\n\n* I replaced the standard linear head with a deeper projection head, which gave a +0.02 boost from Public LB **0.74 to 0.76** and +0.01 improvement from **0.635 to 0.646** in Private LB.\n\n* I then finalized upon 3-Layer MLP Head because it was slightly better than 2-Layers.\n\n```python\nnn.Sequential(\n    nn.Linear(input_dim, 512), # Hidden Layer 1\n    nn.BatchNorm1d(512),\n    nn.ReLU(),\n    nn.Dropout(0.3),\n\n    nn.Linear(512, 256),       # Hidden Layer 2\n    nn.BatchNorm1d(256),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(256, 128),       # Hidden Layer 3\n    nn.BatchNorm1d(128),\n    nn.ReLU(),\n    nn.Dropout(0.2),\n\n    nn.Linear(128, n_targets)\n)\n\n```\n\n### SSA Adapter (Test-Time Adaptation)\n\nI inserted a learnable linear adapter between the backbone and the head. During inference, we froze the backbone and updated *only* this adapter to align the test image features with the training distribution (using pre-calculated PCA statistics `mu_s` and `U`). More details here: https://arxiv.org/pdf/2410.03263\n\nThis had negligible change in Public LB but I trusted this approach and it improved the score from **0.646 to 0.652** in Private LB :)\n\n---\n\n## 5. Pipeline B: Species-Aware Injection (Takumi's Part)\n\n**Weight in Ensemble:** 0.3\n\n1. **Stage 1 (Species Model):** Trained `vit_large_patch16_dinov3` to classify 15 species.\n2. **Stage 2 (Biomass Model):**\n* Backbone: `vit_huge_plus_patch16_dinov3`.\n* Input: Concatenates image features + **Predicted Species Probabilities**.\n* Targets: Predicted `Dry_Clover_g` and `GDM_g` to reconstruct the total.\n\n\n\n---\n\n## 6. Pipeline C: Dual-Backbone Fusion with SigLIP (Takumi's Part)\n\n**Weight in Ensemble:** 0.2\n\nTo capture different semantic granularities, we fused features from two state-of-the-art vision models.\n\n* **Branch 1:** DINOv3 Huge (768px) - Excellent for structure and local details.\n* **Branch 2:** SigLIP `vit_so400m_patch16_siglip_512` (512px) - Excellent for semantic understanding.\n* **Fusion:** Features from both backbones were concatenated before passing to the MLP head.\n\n```python\n# Feature Fusion Logic\nfeat_dino = dino_backbone(img_768)   # DINOv3 Features\nfeat_siglip = siglip_backbone(img_512) # SigLIP Features\n\n# Concatenate: [Backbone_L, Backbone_R, SigLIP_L, SigLIP_R]\ncombined_features = torch.cat([feat_dino, feat_siglip], dim=1)\n\n```\n\n---\n\n## 7. Final Ensemble & Results\n\nOur final submission was a weighted average of the three pipelines. The heavy weighting on the SSA model (0.5) reflects its robustness to the distribution shift in the private test set. The final ensemble helped gained the last few decimals.\n\n```python\n# Final Ensemble Logic\nfinal_submission = (\n    0.5 * prediction_ssa +       # Pipeline A (Robustness)\n    0.3 * prediction_species +   # Pipeline B (Metadata Context)\n    0.2 * prediction_siglip      # Pipeline C (Feature Diversity)\n)\n```\n\n### Validation Strategy\n\nWe used **StratifiedKFold (5 Folds)**, stratifying by a composite key of `total_biomass_bin` * `species_id` to ensure every fold saw a representative distribution of species and weight classes.\n\n### Performance\n\n* **Public LB:** 0.760\n* **Private LB:** 0.652",
    "3401145": "Congratulations🎉！\n\n>A. Target Reformulation\nInstead of predicting the standard targets directly, we reformulated the regression problem to align better with the biological components.\nOld Targets: Dry_Green_g, GDM_g, Dry_Total_g\nNew Targets: Dry_Clover_g, GDM_g, Dry_Total_g\nImpact: This specific change was crucial for the Huge DINOv3 variant, directly improving the Public LB from 0.73 to 0.74.\n\n\nThe meaning is that use 'Dry_Clover_g', 'GDM_g', and 'Dry_Total_g' will perform better than 'Dry_Green_g', 'GDM_g', and 'Dry_Total_g'. Is this the case for all of your models? 🤔",
    "3401739": "We did not test it on all of our models, but for dino v3 huge there was indeed improvements in both CV and LB. We focused on diversity so my MLP heads predicted all 5 targets (Pipeline A), whereas Pipeline B and C predicted 3 targets and recreated the 5 from these 3."
  },
  "source": "meta"
}