感谢竞赛组织者举办这场具有挑战性的比赛。感谢 @zjayzz 提供的 公开 Notebook — 你的工作为我提供了很好的视角和坚实的基线来完成这项任务。这是我第一次在 Kaggle 上取得如此好的成绩。我从这次竞赛中学到了很多,下面我将介绍我所使用的方法:
概述
由于 CSIRO Biomass 的训练集非常小,我特意遵循了“冻结的基础模型 + 轻量级监督头”的方案,以减少过拟合并保持训练成本可忽略不计。这与 DINOv3 的下游实践非常一致:论文表明,完全冻结的 DINOv3 骨干网络在与相对较小的任务特定适配器/解码器配对时,仍然可以保持极高的竞争力,这对于小数据场景和高效的多任务复用特别有吸引力。
牧场生物量预测任务介于全局识别和密集理解之间:局部区域(覆盖率、干燥度、阴影、纹理)对最终的生物量目标贡献不均。据报道,DINOv3 在分类和密集预测基准测试中始终表现强劲,在密集任务上具有显著改进的局部特征——这正是我们想要的“局部证据聚合成全局回归”的表示类型。
具体来说,我将 DINOv3 保持冻结作为特征提取器,并围绕多视图表示 + 堆叠岭回归器构建了一个简单但有效的流程:多尺度(256/512/768)左右视图捕捉局部变化,而多深度 Token 抽取(最后一层 + 选定的中间块)利用高级语义和更多面向几何/结构的中级特征。DINOv3 的逐层分析表明,中间层对几何密集型任务可能有益,这激发了我们的中间层抽取策略。
我还发现多分辨率集成很有帮助,这与论文中强调的高分辨率适应和多分辨率推理以获得更好的局部特征是一致的。
最后,在这种冻结 + 岭回归堆叠设置下,扩展骨干网络(Large → Huge → 7B)提高了性能,且几乎不需要重新调整,而岭回归训练本身几乎瞬间完成。
模型
架构
Input → Views
│
├─ Left-right split → {L, R}
└─ Scales S = {256, 512, 768}
Frozen backbone
│
└─ DINOv3 ViT-7B (BF16 inference, final norm)
├─ token tap L0: last layer
└─ token taps L1,L2: mid blocks {35, 38}
→ Layers L = {last, b35, b38}
View definition (9 views)
│
└─ Each view is a (scale, layer) pair: v = (s, ℓ), with s∈S and ℓ∈L
→ 3 scales × 3 taps = 9 views total
(e.g., v1=(256,last), v2=(256,b35), …, v9=(768,b38))
Per-view embedding (computed independently for each v)
│
└─ Patch tokens (drop CLS/prefix) → pool over patches: mean + max + min + signed-GeM(p=3)
→ embedding matrix E_v: [n_samples, d_v] where d_v = 4C
→ RobustScaler fitted/applied per view (per E_v)
Stacking (Ridge-only)
│
├─ Level-1: one base model per view
│ └─ For each view v=1..9:
│ MultiOutput Ridge_v(α=5): E_v → OOF predictions P_v
│ where P_v is [n_train_samples, 5] (5 biomass targets)
│
└─ Level-2: meta model per target
└─ For each target t ∈ {1..5}:
X_meta(t) = concat of {P_v[:, t]} over v=1..9 → [n_train_samples, 9]
Meta Ridge_t(α=1): X_meta(t) → ŷ_t
Dual label-space ensemble (outside meta)
│
├─ Run the whole stack on raw y
├─ Run the whole stack on log1p(y) → expm1 back
└─ Blend: ŷ = 0.5·ŷ_raw + 0.5·ŷ_log
Outer ensemble + constraints
│
├─ Repeat with n_folds ∈ {2, 3, 5} → average
└─ Physics post-process: clip ≥ 0; GDM = Green + Clover; Total = GDM + Dead
Output: [Green, Dead, Clover, GDM, Total] per sample
这是我的主要模型架构;更多详情请参考下方的 Notebook。
关键点
- 多尺度分辨率 集成(256, 512, 768)
- 中间层特征 抽取(使用中间块 Token(35, 38))
- 多池化 聚合(mean / max / min / signed-GeM)
- 原始空间 + 对数空间 集成(训练两次,在原始空间混合)
- 高分辨率 特征提取 / 推理
- 来自强正则化 岭回归 的强归纳偏置
- 多折 集成(使用不同的 KFold 设置重复并平均)
消融实验
| 消融 / 变体 | 公共分数 | 私有分数 |
|---|---|---|
| base (基线) | 0.75696 | 0.64833 |
| multi-scale (768 only) | 0.75332 | 0.64324 |
| multi-scale (256, 512) | 0.74585 | 0.63738 |
| without mid layers (无中间层) | 0.74969 | 0.62957 |
| mid layer (35 only) | 0.75466 | 0.64466 |
| mid layer (38 only) | 0.75218 | 0.62950 |
| ensemble folds (5 only) | 0.75493 | 0.64774 |
| without post process (无后处理) | 0.75208 | 0.64986 |
| only raw-space (仅原始空间) | 0.74358 | 0.64147 |
| only avg pooling (仅平均池化) | 0.72056 | 0.60662 |
无效的方法
- 堆叠 XGBoost — 我尝试了一个简单的设置,但没有提高性能。
未来工作
从上面的消融实验可以看出,影响最大的两个组件是中间层特征和特征池化策略。两者都直接影响提取表示的质量,因此未来的工作可以专注于改进管道的这一部分——例如,探索更强的特征聚合模块,如基于注意力的池化。
参考文献
- Dinov3
- Stacked Generalization: An Introduction to Super Learning
- Stacked Generalization: when does it work?
- GeM pooling
下面是我的代码,它可以端到端地运行训练和推理,以及本解决方案中使用的 DINOv3-7B 模型。