野外机器人语义分割竞赛冠军方案:DINOv3 + ViT-Adapter + Mask2Former 全解析
一句话总结
ICRA 2026 GOOSE 细粒度分割挑战赛冠军方案的核心是:用 DINOv3 的 [CLS] token 做粗粒度辅助监督,再借助 ViT-Adapter 把扁平 token 序列转成多尺度特征,喂给 Mask2Former 完成 64 类细粒度分割。
为什么这篇报告值得细读?
野外机器人(field robotics)的视觉感知比城市自动驾驶难得多。GOOSE 数据集里有 64 个细粒度语义类别——不是”草地”,而是”高草/低草/苔藓/杂草/蕨类”;不是”道路”,而是”泥路/碎石路/草径/车辙”。这种细粒度分类在工程上意味着:
- 类间相似度极高:苔藓和低草的纹理非常接近,仅靠局部感受野几乎无法区分
- 类间样本不平衡:”沼泽地”远少于”草地”
- 评测指标双轨制:同时看 64 类细粒度 mIoU(69.32%)和 11 类粗粒度 category mIoU(83.81%)
这两个数字之间 14 个百分点的差距才是最值得关注的信号:模型知道”大概是什么”,但在细粒度层面还有提升空间。冠军方案正是从这个矛盾出发,设计了层级监督机制。
核心架构解析
整体流程
输入图像 → DINOv3 ViT-L/16 → [CLS] token + patch tokens
↓ ↓
粗粒度辅助头 ViT-Adapter
(11类分类) (多尺度特征图)
↓
Mask2Former
(64类分割)
三个组件各司其职,缺一不可。
为什么选 DINOv3 而非监督预训练?
DINOv3 是 DINOv2 的后继版本,延续了自监督预训练范式。关键点:野外场景和 ImageNet 的分布差异极大。泥泞山路、密集植被、湿润岩石——这些 ImageNet 里很罕见。
DINOv2/DINOv3 的自监督训练目标迫使模型学习与类别标签无关的通用视觉表示,因此在 domain shift 场景下迁移效果优于监督预训练。更重要的是,DINO 系列的 patch token 保留了丰富的局部纹理信息,而 [CLS] token 则编码了全局语义——这个二元结构是后续设计的基础。
ViT-Adapter:解决”扁平 token vs 多尺度特征”的结构矛盾
标准 ViT 输出是一个长序列的 patch token,没有层级结构。而 Mask2Former、FPN 这类解码器需要多尺度特征图(类似 ResNet 的 C2/C3/C4/C5)。
ViT-Adapter 通过以下机制填补这个 gap:
- 空间先验注入:从卷积茎提取初始多尺度特征,注入 ViT 的 attention 计算
- 双向交互块:在 ViT 层间插入 adapter 块,让多尺度特征和 token 序列相互增强
- 多尺度输出:从不同深度的 adapter 特征聚合出类 FPN 的四级输出
数学上,第 $i$ 层交互可以表示为:
\[F^{i+1} = F^i + \text{Interact}(F^i, T^i)\] \[T^{i+1} = T^i + \text{Attn}(T^i, F^i)\]其中 $F^i$ 是多尺度特征,$T^i$ 是 ViT token 序列。双向更新让两侧都能受益。
Mask2Former 的”掩码分类”范式
传统语义分割是逐像素分类:对每个像素独立预测属于哪个类别。Mask2Former 的思路截然不同:
- 生成一组候选掩码(mask proposals)
- 对每个掩码预测其类别归属
- 通过二分图匹配训练
这对野外场景特别有价值:植被、岩石的形状往往不规则,非凸,逐像素分类容易在边界处出错,而掩码分类能建模整块区域的一致性。
核心创新:[CLS] Token 的粗粒度辅助损失
这是整篇报告最值得借鉴的技巧。
直觉:如果 [CLS] token 被显式训练成”理解场景的粗粒度语义”,那么整个 backbone 就被引导成同时具备全局感知和局部细节的双层表示。粗粒度监督像是给模型一个”场景上下文先验”。
实现:在 [CLS] token 上接一个线性分类头,用粗粒度的 11 类标签做监督。这个头只在训练时使用。
\[\mathcal{L} = \mathcal{L}_{\text{seg}} + \lambda \cdot \mathcal{L}_{\text{cls}}\]其中 $\mathcal{L}_{\text{cls}}$ 是 [CLS] token 的交叉熵损失,$\lambda$ 是平衡权重(通常取 0.1~0.3)。
动手实现
核心架构骨架
import torch
import torch.nn as nn
import torch.nn.functional as F
class GOOSESegModel(nn.Module):
def __init__(self, num_fine=64, num_coarse=11, embed_dim=1024):
super().__init__()
# DINOv3 ViT-L/16,patch_size=16,embed_dim=1024
self.backbone = DINOv3ViTL16(pretrained=True)
# ViT-Adapter:将 ViT token 转为 4 级多尺度特征
self.adapter = ViTAdapter(
embed_dim=embed_dim,
out_indices=(2, 5, 8, 11), # 从哪些层提取特征
out_channels=[256, 512, 1024, 1024],
)
# Mask2Former 解码器:细粒度 64 类分割
self.decoder = Mask2FormerHead(
in_channels=[256, 512, 1024, 1024],
num_classes=num_fine,
num_queries=100,
)
# [CLS] token 辅助头:粗粒度 11 类分类(训练专用)
self.coarse_head = nn.Linear(embed_dim, num_coarse)
def forward(self, x, return_coarse=True):
# backbone 输出:cls_token [B, D],patch_tokens [B, N, D]
cls_token, patch_tokens = self.backbone.forward_features(x)
# ViT-Adapter 转多尺度特征图
multi_scale = self.adapter(cls_token, patch_tokens, img_shape=x.shape[-2:])
# 细粒度分割主损失
seg_logits = self.decoder(multi_scale) # [B, 64, H, W]
if return_coarse:
# 粗粒度辅助损失(仅训练时)
coarse_logits = self.coarse_head(cls_token) # [B, 11]
return seg_logits, coarse_logits
return seg_logits
层级损失计算
def compute_hierarchical_loss(seg_logits, coarse_logits,
fine_targets, coarse_targets,
lambda_coarse=0.1):
# 主损失:Mask2Former 内部已实现 binary cross-entropy + dice
loss_seg = mask2former_criterion(seg_logits, fine_targets)
# 辅助损失:[CLS] token 粗粒度分类
# 注意:coarse_targets 由 fine_targets 映射得到,不需要额外标注
loss_coarse = F.cross_entropy(coarse_logits, coarse_targets)
return loss_seg + lambda_coarse * loss_coarse
关键点:粗粒度标签不需要额外标注,直接从细粒度标签映射即可(64 个细类归属于 11 个粗类)。这是零成本的额外监督信号。
推理时的 TTA 策略
@torch.no_grad()
def tta_inference(model, image, scales=(0.75, 1.0, 1.25, 1.5)):
"""多尺度 + 水平翻转 TTA"""
h, w = image.shape[-2:]
preds = []
for scale in scales:
# 多尺度缩放
scaled = F.interpolate(image, scale_factor=scale, mode='bilinear')
# 正向推理
logit = model(scaled, return_coarse=False)
preds.append(F.interpolate(logit, size=(h, w), mode='bilinear'))
# 水平翻转推理(flip → 推理 → flip back)
logit_flip = model(scaled.flip(-1), return_coarse=False)
preds.append(F.interpolate(logit_flip.flip(-1), size=(h, w), mode='bilinear'))
# 概率平均(对 logit 做 softmax 后平均,再 argmax)
prob = torch.stack([p.softmax(1) for p in preds]).mean(0)
return prob.argmax(1)
Checkpoint Ensemble
def ensemble_predict(model_paths, image, device):
"""Top-3 checkpoint 集成"""
probs = []
for ckpt_path in model_paths[:3]: # 仅取 top-3
model = load_model(ckpt_path, device)
model.eval()
with torch.no_grad():
logit = model(image, return_coarse=False)
probs.append(logit.softmax(1))
# 等权平均(也可以按 val mIoU 加权)
return torch.stack(probs).mean(0).argmax(1)
实现中的坑
ViT-Adapter 的 patch size 对齐问题:DINOv3 ViT-L/16 的 patch_size=16,输入分辨率必须是 16 的倍数。如果输入经过随机裁剪后尺寸不对齐,会导致 token 数量变化,影响位置编码插值。
# 错误:直接使用随机裁剪
transform = RandomCrop(size=513) # 513 不是 16 的倍数!
# 正确:裁剪尺寸对齐 patch_size
transform = RandomCrop(size=512) # 512 = 32 × 16 ✓
[CLS] 辅助损失在 warmup 阶段权重要小:训练初期 backbone 表示还没稳定,过强的粗粒度监督会干扰细粒度学习。
lambda_coarse = 0.1 * min(1.0, current_step / warmup_steps)
TTA 的显存消耗:5 个 scale × 2(flip)= 10 次前向。ViT-L 本身就很大,全部在 GPU 上跑会 OOM。解决方案是循环推理而不是并行。
实验结果解读:论文说的 vs 现实
| 指标 | 报告结果 | 分析 |
|---|---|---|
| Fine-class mIoU(64类) | 69.32% | 高频类别可能远超此值,长尾类别可能< 40% |
| Category mIoU(11粗类) | 83.81% | 粗类准确率高印证了 CLS 辅助损失的效果 |
| 综合分 | 76.57% | 两个指标的平均 |
14% 的细/粗 mIoU 差距意味着什么?
这个差距揭示了细粒度分割的本质困难:模型在”知道场景大概是什么”方面已经相当可靠,但区分同一粗类下的细粒度子类时仍然挣扎。这不是模型的失败,而是问题本身的难度——人类标注者在这些细粒度类别上的一致性也不会是 100%。
哪些条件下能复现?
- 需要 DINOv3 的官方预训练权重(或 DINOv2 作为替代)
- ViT-Adapter 的具体实现细节(interaction block 数量、spatial prior 配置)论文未全披露
- GOOSE 数据集需申请访问权限
什么时候用 / 不用这个方案?
| 适用场景 | 不适用场景 |
|---|---|
| 细粒度语义分割(>20类,类间相似度高) | 实时推理(ViT-L + TTA 很慢) |
| 有粗/细两级标签体系 | 嵌入式/边缘设备部署 |
| 户外、域外泛化要求高 | 只有粗粒度标签,无层级标注 |
| 训练算力充足(A100 × 8+) | 目标类别数 < 10 |
| 竞赛场景,追求极限精度 | 需要快速迭代的研究阶段 |
我的观点
[CLS] 辅助损失值得更广泛使用。这个技巧的成本几乎为零(一个线性层,标签从现有标注映射),但它显式地强化了 ViT 全局 token 的语义含义,对任何有层级标签体系的任务都适用:医学图像分割(器官→组织→细胞类型)、遥感分类(土地覆盖→植被类型)。
ViT-Adapter 正在成为 ViT 密集预测的标准中间件。随着 DINOv3 等自监督 ViT 的能力不断提升,”如何让 ViT backbone 适配 FPN/Mask2Former”这个工程问题的重要性超过很多人的预期。
这套方案的真正瓶颈在推理速度。ViT-L/16 + TTA × 10 的推理链路对野外机器人来说可能过重。下一步的挑战是:如何在保持 DINOv3 表示质量的前提下,做到实时推理?知识蒸馏到 ViT-S/ViT-B,或者直接优化 ViT-Adapter 的 interaction block,是值得探索的方向。
参考资料
- 原论文:arxiv.org/abs/2606.18582v1
- ViT-Adapter 原论文:Chen et al., Vision Transformer Adapter for Dense Predictions, ICLR 2023
- Mask2Former 原论文:Cheng et al., Masked-attention Mask Transformer for Universal Image Segmentation, CVPR 2022
- GOOSE 数据集:goosedataset.com
Comments