返回列表

8th Place Solution | CSIRO Image2Biomass

687. CSIRO - Image2Biomass Prediction | csiro-biomass

开始: 2025-10-28 结束: 2026-01-28 作物智能识别 数据算法赛
第 8 名解决方案 | CSIRO Image2Biomass

第 8 名解决方案 | CSIRO Image2Biomass

缩放 DINOv3、SSA 适配与 SigLIP 融合

作者: Paritosh Kumar Tripathi (团队 leader)

合作者: Takumi Sakai, Yusuke, Diptyajit Das

发布日期: 2026-02-01

竞赛排名: 第 8 名

1. 概述与关键洞察

我们的解决方案是三个不同 pipeline 的加权集成,所有 pipeline 均以 DINOv3 Huge 骨干网络为核心。

我们的最终提交结合了:

  1. SSA 适配 Pipeline (50%):使用子空间对齐的测试时适配 (Test-Time Adaptation)。
  2. 物种感知 Pipeline (30%):两阶段注入物种元数据。
  3. 双骨干 Pipeline (20%):DINOv3 与 SigLIP 特征融合。

2. 核心骨干网络 (Takumi 的部分)

  • 我坚信缩放定律 (scaling laws) 的趋势,旨在在计算资源限制内利用尽可能大的模型。
  • 一个关键洞察是,在数据有限的竞赛中,利用在大规模数据集上预训练的强骨干网络至关重要。
  • 我花了大部分比赛时间优化 DINOv3 的训练方案,我相信这使我比使用相同架构的其他解决方案更具优势。
  • 我观察到随着模型大小的增加,公共榜单 (Public LB) 分数显著跳跃。增加模型大小被证明比增加图像分辨率更有效。由于 A100 内存限制,我们标准化为:
  • 模型: vit_huge_plus_patch16_dinov3.lvd1689m
  • 图像大小: 768px (大多数 pipeline 标准化)

我想强调仅仅改变骨干网络的影响。以下是进展:

  • convnext_tiny → vit_base_patch16_dinov3.lvd1689m: 0.61 → 0.67
  • vit_base_patch16_dinov3.lvd1689m → vit_large_patch16_dinov3.lvd1689m: 0.69 → 0.72
  • vit_large_patch16_dinov3.lvd1689m → vit_huge_plus_patch16_dinov3.lvd1689m: 0.72 → 0.74

头部架构 (Head Architecture)

我使用了带有 SiLU 激活和 dropout 的标准回归头。

nn.Sequential(
    nn.Linear(in_features, hidden),
    nn.SiLU(),
    nn.Dropout(0.3),
    nn.Linear(hidden, out_features),
)

训练策略

为了在有限数据上稳定如此大模型的训练,我采用了使用 AdamW 和混合精度 (AMP) 的两阶段训练过程。

  • 损失函数: nn.SmoothL1Loss()
  • Batch Size: 有效 batch size 为 8 (在 Batch Size 1 上使用 grad_accum_steps=8)。

阶段 1: 仅头部 (预热)

  • 目标: 在微调 transformer 之前稳定权重。
  • 轮次 (Epochs): 15
  • 学习率 (LR): 3e-4 配合 ReduceLROnPlateau

阶段 2: 全骨干微调

  • 目标: 适配 huge 骨干网络而不过拟合。
  • 轮次 (Epochs): 35
  • 权重衰减 (Weight Decay): 0.2 (高衰减对正则化至关重要)。
  • 调度器: 带有严格预热阶段的 Cosine。
# 阶段 2 调度器配置
CosineLRScheduler(
    lr_min=1e-6,           # 目标最小学习率
    warmup_t=3,            # 关键的 3 轮预热
    warmup_lr_init=1e-7,   # 从接近零开始
    cycle_limit=1,         # 单周期 (无重启)
    t_in_epochs=True
)

数据增强

我使用了 Albumentations 迫使模型学习不变特征, specifically 使用 RandomShadowRandomGamma 来处理光照变化。

A.Compose([
    A.HorizontalFlip(p=0.5),
    A.VerticalFlip(p=0.5),
    A.RandomRotate90(p=0.5),
    A.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.2, p=0.5),
    A.RandomGamma(gamma_limit=(80, 120), p=0.3),
    A.RandomShadow(num_shadows_limit=(1, 3), shadow_dimension=5, p=0.5),
    A.Resize(self.img_size, self.img_size),
    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ToTensorV2()
])

验证策略

我最初尝试使用 sampling_date 进行 GroupKFold,但这导致折间分布方差很高,某些模型未能学习足够的数据变化。这并没有改善公共榜单。

因此,我决定接受交叉验证 (CV) 与公共榜单之间的差异,并使用基于分箱和物种的分层方法最大化 CV 分数。

# 创建结合总生物量分箱和物种的分层键
df['strat_key'] = df['total_bin'].astype(int) * 100 + df['species_id'].astype(int)

skf = StratifiedKFold(
    n_splits=self.config.n_folds,
    shuffle=True,
    random_state=self.config.random_state
)

物种感知预测

为了在推理期间有效利用物种元数据(其中元数据可能不可用或不可靠):

  1. 物种模型 训练了一个单独的 dinov3_large 模型(相同头部结构)来从图像分类物种。
  2. 推理
    • 使用物种模型预测图像属于每个物种的概率。
    • 将此预测概率用作主生物量预测模型的输入特征。

3. 关键优化 (Diptyajit Das 的部分)

虽然骨干网络提供了 power,但 Diptyajit 关于目标和分辨率的实验提供了私有榜单 (Private LB) 所需的稳定性和泛化能力。

A. 目标重构

我们没有直接预测标准目标,而是重构了回归问题以更好地 align 生物成分。

  • 旧目标: Dry_Green_g, GDM_g, Dry_Total_g
  • 新目标: Dry_Clover_g, GDM_g, Dry_Total_g
  • 影响: 这一特定变化对 Huge DINOv3 变体至关重要,直接将公共榜单从 0.73 提高到 0.74

B. 辅助头部与稳定性

我 experimented 在阶段 1 中添加辅助 NDVI 回归头 alongside 物种分类。这将 vit_large 模型提升至 0.73,但对 vit_huge_plus 模型的分数影响 negligible。

C. "黄金" 分辨率 (640px)

虽然 768px 提供了最佳公共榜单,但 Diptyajit 的实验显示 640px 提供了 superior 泛化能力,并产生了我们最高的单模型私有榜单 (0.657),但由于公共榜单较低 (0.75),我们无法在最终评估中选择此项。


4. Pipeline A: SSA 适配器与 MLP 头 (Paritosh 的部分)

集成中的权重: 0.5

此 pipeline 解决了训练集和测试集之间的域偏移,而无需昂贵的重新训练。我们没有使用标准微调,而是使用显著子空间对齐 (SSA) 作为轻量级测试时适配 (TTA) 技术。

"2 层" MLP 头

  • 我将标准线性头替换为更深的投影头,这使得公共榜单从 0.74 提高到 0.76,私有榜单从 0.635 提高到 0.646
  • 我最终确定了 3 层 MLP 头,因为它比 2 层稍好。
nn.Sequential(
    nn.Linear(input_dim, 512), # 隐藏层 1
    nn.BatchNorm1d(512),
    nn.ReLU(),
    nn.Dropout(0.3),

    nn.Linear(512, 256),       # 隐藏层 2
    nn.BatchNorm1d(256),
    nn.ReLU(),
    nn.Dropout(0.2),

    nn.Linear(256, 128),       # 隐藏层 3
    nn.BatchNorm1d(128),
    nn.ReLU(),
    nn.Dropout(0.2),

    nn.Linear(128, n_targets)
)

SSA 适配器 (测试时适配)

我在骨干网络和头部之间插入了一个可学习的线性适配器。在推理期间,我们冻结骨干网络并仅更新此适配器,以将测试图像特征与训练分布对齐(使用预计算的 PCA 统计量 mu_sU)。更多细节见:https://arxiv.org/pdf/2410.03263

这对公共榜单的变化 negligible,但我信任这种方法,它将私有榜单分数从 0.646 提高到 0.652 :)


5. Pipeline B: 物种感知注入 (Takumi 的部分)

集成中的权重: 0.3

  1. 阶段 1 (物种模型): 训练 vit_large_patch16_dinov3 分类 15 个物种。
  2. 阶段 2 (生物量模型):
  • 骨干网络:vit_huge_plus_patch16_dinov3
  • 输入:连接图像特征 + 预测的物种概率
  • 目标:预测 Dry_Clover_gGDM_g 以重构总量。

6. Pipeline C: 双骨干融合与 SigLIP (Takumi 的部分)

集成中的权重: 0.2

为了捕捉不同的语义粒度,我们融合了两个 state-of-the-art 视觉模型的特征。

  • 分支 1: DINOv3 Huge (768px) - 擅长结构和局部细节。
  • 分支 2: SigLIP vit_so400m_patch16_siglip_512 (512px) - 擅长语义理解。
  • 融合: 来自两个骨干网络的特征在传递给 MLP 头之前被连接。
# 特征融合逻辑
feat_dino = dino_backbone(img_768)   # DINOv3 特征
feat_siglip = siglip_backbone(img_512) # SigLIP 特征

# 连接:[Backbone_L, Backbone_R, SigLIP_L, SigLIP_R]
combined_features = torch.cat([feat_dino, feat_siglip], dim=1)

7. 最终集成与结果

我们的最终提交是三个 pipeline 的加权平均。对 SSA 模型 (0.5) 的高权重反映了其对私有测试集中分布偏移的鲁棒性。最终集成帮助获得了最后的几位小数提升。

# 最终集成逻辑
final_submission = (
    0.5 * prediction_ssa +       # Pipeline A (鲁棒性)
    0.3 * prediction_species +   # Pipeline B (元数据上下文)
    0.2 * prediction_siglip      # Pipeline C (特征多样性)
)

验证策略

我们使用了 StratifiedKFold (5 折),通过 total_biomass_bin * species_id 的复合键进行分层,以确保每个折都能看到具有代表性的物种和重量类别分布。

性能

  • 公共榜单: 0.760
  • 私有榜单: 0.652
同比赛其他方案