特征提取 | DINO 到 DINOv3

从 DINO 到 DINOv3:没有人工标签,视觉模型为什么依然能够"看懂"图像?

DINO 让模型在没有标签的情况下学会观察,DINOv2 将这种能力变成通用视觉特征,DINOv3 则进一步增强了对局部结构和空间关系的理解。

1. 从一个简单问题开始

训练传统图像分类网络时,我们通常需要告诉模型:

  • 这是一棵苹果树;
  • 这是主干;
  • 这是侧枝;
  • 这里是背景。

模型通过人工标签学习不同类别之间的边界。但是,真实世界中的图像远比预先定义的标签复杂。

例如,同一根苹果树枝条可能出现在:

  • 晴天或阴天;
  • 正面或侧面视角;
  • 室内或室外背景;
  • 冬季无叶或春季萌芽状态;
  • 不同相机、焦距和曝光条件下。

虽然图像像素发生了明显变化,人仍然能够判断这些图像描述的是同一类结构。原因是人不会只记忆具体像素,而会关注更加稳定的形状、纹理、结构和语义。

DINO 要解决的核心问题就是:

能否不提供人工标签,只通过观察同一图像的不同变化,让网络自己学习稳定的视觉表示?

DINO 的全称是 Self-Distillation with No Labels,即"无标签自蒸馏"。它不是一个专门用于分类、分割或检测的任务模型,而是一种学习通用视觉特征的方法。


2. DINO:让学生从"过去的自己"学习

2.1 教师---学生结构

DINO 使用两个结构相同的网络:

  • Student Network:学生网络,通过梯度下降更新;
  • Teacher Network:教师网络,不直接进行反向传播。

训练时,同一张图像会经过不同的数据增强,然后分别输入教师和学生网络。

一个直观例子

假设原始图像是一棵冬季苹果树:

  1. 教师看到完整的树,但图像亮度较低;
  2. 学生只看到一部分侧枝,而且图像经过颜色扰动;
  3. 学生需要预测教师对这张图像的理解。

教师并不会告诉学生"这是苹果树"或"这是侧枝"。它只提供一个特征分布作为学习目标。学生必须从有限的局部视图中找到与完整图像一致的信息。

如果这个过程在大量图像上不断重复,学生逐渐会发现:

  • 亮度变化通常不改变目标身份;
  • 随机裁剪可能只保留目标的一部分;
  • 背景变化不一定代表前景目标变化;
  • 某些纹理和结构比单个像素更加稳定。

2.2 教师从哪里获得知识?

这里容易产生一个疑问:如果没有人工标签,教师网络又是从谁那里学习的?

DINO 的答案是:教师是学生参数的缓慢移动平均。

教师参数并不是直接复制学生参数,而是由"原有教师参数"和"当前学生参数"加权得到。原有教师参数占绝大部分,当前学生参数只占很小一部分。因此,教师能够跟随学生持续更新,但不会因学生某一次训练产生剧烈变化。

可以把教师理解为学生过去多个训练状态的"稳定平均"。学生每一步变化较快,而教师变化较慢,因此能够提供相对平稳的训练目标。

这有点像一个人学习摄影:

今天的自己向过去几个月积累下来的经验学习;新的经验又会逐渐更新长期认知。

2.3 如何避免所有图像得到相同特征?

如果只要求学生模仿教师,网络可能找到一个没有意义的捷径:无论输入什么图像,都输出相同结果。这被称为表示坍塌

DINO 使用两个关键机制缓解这一问题:

  • Centering:对教师输出进行中心化,避免少数维度长期占据优势;
  • Sharpening:降低教师端 Softmax 温度,使输出更加明确。

DINO 最有意思的发现之一是:经过自监督训练后,Vision Transformer 的注意力图能够自然覆盖图像中的前景目标。即使没有像素级分割标签,网络也可能自动区分物体与背景。

这说明网络学到的不只是颜色统计,而是带有一定语义和空间结构的信息。

参考:DINO 原始论文


3. 为什么 DINO 和 Vision Transformer 很合拍?

DINO 通常使用 Vision Transformer(ViT)作为视觉骨干网络。

3.1 先把图像切成 Patch

ViT 不直接逐像素处理图像,而是先将图像划分为固定大小的图像块,即 Patch

以 DINOv2 ViT-S/14 为例:

  • 输入图像尺寸:518 × 518;
  • Patch 尺寸:14 × 14;
  • 每行 Patch 数量:518 ÷ 14 = 37;
  • Patch 总数:37 × 37 = 1369。

因此,一张图像被转换为 1369 个 Patch Token。

"1369张信息卡片"的例子

可以把整张图像想象成一块被切成 1369 格的拼图。每一格都会生成一张"信息卡片",上面记录该区域的视觉特征。

如果某个 Patch 位于枝条上,它的卡片可能包含:

  • 棕灰色的局部纹理;
  • 细长的边缘方向;
  • 与相邻枝条区域的连续关系;
  • 它在整棵树结构中的上下文。

这些卡片随后进入 Transformer,通过自注意力机制相互交流。

3.2 自注意力为什么重要?

卷积神经网络主要通过局部卷积逐层扩大感受野。Transformer 则允许不同 Patch 直接计算相关性。

例如,一根枝条可能被其他枝条遮挡,导致图像中间出现短暂断裂。只观察断裂位置附近的像素,模型可能认为这是两个独立目标。但是,自注意力可以同时参考:

  • 断裂两侧的方向;
  • 相似的颜色和纹理;
  • 它们与同一主干之间的关系;
  • 更远位置的整体树形结构。

因此,Transformer 更容易建立长距离上下文。对于枝条、道路、血管和电线等细长结构,这种能力尤其有价值。


4. 为什么 ViT-S 的特征维度是 384?

DINOv2 ViT-S/14 中,每个 Patch 对应一个 384 维特征。

384 不是根据图像类别统计得到的数字,也不是图像中只包含 384 个信息。它是 Transformer 的隐藏层宽度,由多头注意力结构决定。ViT-S 包含 6 个注意力头,每个头使用 64 维特征,因此总特征维度为 6 × 64 = 384。

"六位观察员"的例子

可以把多头注意力想象成六位观察员同时分析同一个 Patch。每位观察员都有一个 64 维的内部表示,但他们可以关注不同类型的关系,例如:

  • 一位更关注纹理相似性;
  • 一位更关注边缘方向;
  • 一位更关注远距离区域;
  • 一位更关注前景与背景;
  • 一位更关注局部连续性;
  • 一位更关注全局语义。

这只是帮助理解的比喻。实际训练中,并没有人为规定每个注意力头必须负责什么,它们的分工是从数据中学习出来的。

六个注意力头的结果组合后,便形成 384 维表示。

DINOv2 模型 注意力头数 单头维度 输出特征维度
ViT-S/14 6 64 384
ViT-B/14 12 64 768
ViT-L/14 16 64 1024
ViT-g/14 24 64 1536

传统 CNN 经常使用 256、512、1024 或 2048 个通道,因为 CNN 通常按照两倍扩大通道数。Transformer 更关心"注意力头数 × 单头维度",因此 384 和 768 都很常见。

对于一张 518 × 518 的图像,ViT-S/14 的 Patch 特征形状通常为:

text 复制代码
[B, 1369, 384]

这表示图像具有 1369 个空间位置,每个位置由 384 个数描述,而不是整张图像只有一个 384 维特征。


5. CLS Token 和 Patch Token 有什么区别?

DINO 通常提供两类特征:

CLS Token:描述整张图像

CLS Token 是一个全局特征,可以理解为整张图像的摘要。

典型形状为:

text 复制代码
[B, 384]

它适合:

  • 图像分类;
  • 图像检索;
  • 场景识别;
  • 判断两张图片的整体内容是否相似。

例如,判断一张图片是苹果树、建筑还是车辆,可以优先使用 CLS Token。

Patch Token:描述局部区域

Patch Token 保留空间位置,每个 Patch 都有自己的特征。

典型形状为:

text 复制代码
[B, 1369, 384]

它适合:

  • 语义分割;
  • 局部特征匹配;
  • 深度估计;
  • 目标定位;
  • 像素或区域级对应。

例如,要寻找两张苹果树图像中同一根侧枝的位置,只使用整幅图像的 CLS Token 是不够的,需要比较对应区域的 Patch Token。


6. DINOv2:从实验方法变成通用特征提取器

初代 DINO 证明了无标签自蒸馏的可行性,但其数据规模和训练流程仍有提升空间。

DINOv2 将这种方法扩展为更成熟的视觉基础模型。官方模型使用约 1.42 亿张经过筛选的无标签图像进行预训练,并将图像级自蒸馏与 Patch 级掩码学习结合起来。

掩码图像建模的例子

假设模型看到一张苹果树图像,但部分 Patch 被遮挡:

text 复制代码
树干 ── [被遮挡] ── 侧枝

模型需要根据周围区域推测被遮挡位置应该具有怎样的特征。它不能只记住单个像素,而必须利用:

  • 邻近区域的纹理;
  • 枝条延伸方向;
  • 上下文结构;
  • 整张图像的语义。

因此,DINOv2 同时学习:

  1. 图像级一致性:同一张图像的不同增强视图应该具有相近的整体表示;
  2. Patch 级理解:局部区域即使被遮挡,也可以通过上下文恢复其特征。

这使 DINOv2 特征能够直接用于分类、分割、深度估计、图像检索、特征匹配和视觉定位等任务。

参考:DINOv2 官方代码


7. DINOv3:为什么还需要第三代?

扩大模型和训练数据通常会增强全局语义能力,但长时间训练也可能损害局部 Patch 特征的空间质量。

对于图像分类,这个问题可能并不明显。模型只要判断图像中存在一棵树即可,不一定要准确区分每根细枝。

但对于以下任务,局部特征质量非常重要:

  • 语义分割;
  • 单目深度估计;
  • 局部特征匹配;
  • 像素级对应;
  • 细小目标定位。

DINOv3 引入 Gram Anchoring,用于维持 Patch 之间的特征关系。

它会根据所有 Patch 特征计算一个关系矩阵,记录图像中不同区域彼此有多相似。Gram Anchoring 关注的不只是某个 Patch 的单独特征,还包括整幅图像内部各区域之间的关系。

一个直观例子

假设一张树木图像中包含:

  • 主干区域 A;
  • 与主干连接的侧枝区域 B;
  • 背景区域 C。

理想情况下,A 与 B 的结构关系应该强于 A 与 C 的关系。如果长时间训练导致所有局部区域逐渐变得相似,模型虽然仍能判断"这是一棵树",却可能无法准确区分枝条和背景。

Gram Anchoring 的作用,可以理解为在大规模训练过程中给局部结构设置一个"锚点",帮助模型保留这些区域关系。

DINOv3 还进一步扩大了模型和数据规模,并提供高分辨率适配等策略。因此,它不仅擅长判断图像中"有什么",也更擅长判断目标"具体在哪里"。

参考:DINOv3 论文Meta DINOv3 官方页面


8. DINO 为什么强大?

8.1 不受固定标签体系限制

监督分类模型主要学习人工定义的类别边界。DINO 学习的是图像不同视图之间稳定的视觉关系,因此更容易迁移到训练时没有明确标注的新领域。

例如,通用数据集中可能没有"苹果树休眠期一年生枝"这一类别,但 DINO 仍可能提供有效的形状、纹理和语义特征。我们只需要在这些特征上训练一个较小的任务头。

8.2 同时保留全局与局部信息

  • CLS Token 表示整幅图像;
  • Patch Token 表示局部区域;
  • 自注意力负责建立不同区域之间的关系。

因此,同一个模型可以服务于分类、检索、分割、匹配和定位等不同任务。

8.3 能够利用海量无标签图像

互联网上有大量图像,但高质量标注有限。DINO 不需要为每张图片准备类别或像素标签,因此可以从更大规模的数据中学习视觉规律。

8.4 下游任务不一定需要完整微调

在专业领域数据较少时,从头训练大型模型容易过拟合。使用 DINO 时,可以冻结预训练骨干,只训练轻量分类器、分割头或匹配模块。

例如,一个苹果树枝条分类任务可以采用:

text 复制代码
输入图像
   ↓
冻结的 DINOv2
   ↓
384维 Patch 特征
   ↓
轻量 MLP / CNN / GNN
   ↓
枝条类别或目标位置

这样既可以利用大规模预训练知识,又能降低训练数据和计算资源需求。


9. DINO 的典型技术栈

一个实际的 DINO 应用系统通常包含以下层级:

层级 常用工具 主要作用
数据读取 PIL、OpenCV 读取、裁剪和处理图像
数据增强 torchvision、Albumentations 缩放、颜色扰动、模糊和翻转
深度学习框架 PyTorch 张量计算、模型加载和推理
视觉骨干 ViT-S/B/L/g 生成 CLS 与 Patch 特征
预训练权重 DINOv2、DINOv3 提供通用视觉表示
下游任务头 Linear、MLP、CNN Decoder、GNN 完成分类、分割、匹配或定位
几何验证 OpenCV、COLMAP、RANSAC 剔除错误匹配并恢复空间关系

10. 使用 PyTorch 提取 DINOv2 特征

下面以 DINOv2 ViT-S/14 为例:

python 复制代码
import torch
from PIL import Image
from torchvision import transforms

device = "cuda" if torch.cuda.is_available() else "cpu"

model = torch.hub.load(
    "facebookresearch/dinov2",
    "dinov2_vits14"
).to(device)

model.eval()

transform = transforms.Compose([
    transforms.Resize((518, 518)),
    transforms.ToTensor(),
    transforms.Normalize(
        mean=(0.485, 0.456, 0.406),
        std=(0.229, 0.224, 0.225)
    )
])

image = Image.open("tree.jpg").convert("RGB")
image = transform(image).unsqueeze(0).to(device)

with torch.no_grad():
    outputs = model.forward_features(image)

cls_feature = outputs["x_norm_clstoken"]
patch_features = outputs["x_norm_patchtokens"]

print("CLS:", cls_feature.shape)
print("Patch:", patch_features.shape)

输出通常为:

text 复制代码
CLS:   torch.Size([1, 384])
Patch: torch.Size([1, 1369, 384])

其中:

  • cls_feature 可以用于整图分类或检索;
  • patch_features 可以用于局部匹配、分割或定位。

11. 将 Patch Token 恢复成二维特征图

Transformer 输出的 Patch Token 是序列形式:

text 复制代码
[B, 1369, 384]

因为 1369 = 37 × 37,所以可以将这些 Token 重新排列为二维特征图:

python 复制代码
batch_size, num_tokens, channels = patch_features.shape

feature_map = patch_features.reshape(
    batch_size, 37, 37, channels
)

feature_map = feature_map.permute(0, 3, 1, 2)

print(feature_map.shape)

输出为:

text 复制代码
[1, 384, 37, 37]

如果下游模块需要与原图对齐,还可以进行双线性插值:

python 复制代码
import torch.nn.functional as F

dense_features = F.interpolate(
    feature_map,
    size=(518, 518),
    mode="bilinear",
    align_corners=False
)

print(dense_features.shape)

输出为:

text 复制代码
[1, 384, 518, 518]

需要注意:插值只是将特征映射回原图坐标,并不会创造新的细节。DINOv2 ViT-S/14 的原始空间粒度仍然由 14 × 14 Patch 决定。


12. DINO 特征如何用于图像匹配?

假设我们有同一棵苹果树的两张图像:

  • 图像 A 从正面拍摄;
  • 图像 B 从侧面拍摄;
  • 希望找到图像 A 中某个剪枝点在图像 B 中的位置。

首先分别提取两张图像的 Patch 特征,然后计算任意两个 Patch 之间的余弦相似度。

余弦相似度可以理解为比较两个特征向量的"方向"是否一致。结果越接近 1,说明两个区域在 DINO 特征空间中越相似。例如,图像 A 中某个剪枝点附近的 Patch,可以与图像 B 中所有 Patch 逐一比较,再选择相似度最高的区域作为初始匹配。

PyTorch 示例:

python 复制代码
import torch
import torch.nn.functional as F

feat_a = F.normalize(patch_features_a, dim=-1)
feat_b = F.normalize(patch_features_b, dim=-1)

similarity = torch.matmul(
    feat_a,
    feat_b.transpose(-1, -2)
)

best_match_indices = similarity.argmax(dim=-1)

DINO 特征通常比 RGB 像素更能适应亮度、颜色和一定程度的视角变化。不过,特征相似不等于几何位置一定正确

例如,苹果树上可能存在许多外观相似的细枝,模型可能将左侧枝条错误匹配到右侧枝条。因此,实际系统通常还要加入:

  • 前景 Mask,排除天空、墙面和地面;
  • 相互最近邻匹配,减少单向误匹配;
  • 相似度阈值,过滤低置信度对应;
  • RANSAC,验证匹配是否符合几何模型;
  • 相机内外参数,建立 2D--3D 投影关系;
  • 深度、点云或骨架拓扑,限制候选位置。

一个更加完整的果树重定位流程可以写成:

text 复制代码
RGB 图像
   ↓
前景 Mask
   ↓
DINO Patch 特征
   ↓
局部特征匹配
   ↓
RANSAC 几何验证
   ↓
2D--3D 对应
   ↓
三维剪枝目标重定位

DINO 在这里负责提供视觉描述子,几何模块则负责确保匹配在空间上成立。


13. DINO、DINOv2 和 DINOv3 应该如何选择?

模型 主要特点 更适合的场景
DINO 结构清楚,便于理解自蒸馏 教学、算法研究、训练机制分析
DINOv2 生态成熟,性能和计算成本均衡 分类、检索、分割、匹配和工程应用
DINOv3 稠密局部特征更强,规模选择更多 高精度分割、深度估计和复杂对应任务

如果希望快速搭建稳定系统,DINOv2 通常是一个实用起点。

如果任务高度依赖局部空间结构,例如:

  • 细枝分割;
  • 跨视角特征匹配;
  • 跨季节目标重定位;
  • 像素级或 Patch 级对应;

则可以进一步测试 DINOv3。

不过,模型越大并不一定越适合具体任务。选择模型时还应同时考虑:

  • GPU 显存;
  • 推理速度;
  • 输入分辨率;
  • 训练数据量;
  • 目标结构尺度;
  • 下游任务是否更依赖语义或几何。

14. 总结

DINO 系列展示了一条不同于传统监督学习的发展路线:

  1. DINO 证明无标签自蒸馏能够让 ViT 自发形成目标级语义;
  2. DINOv2 通过更大的数据规模和改进训练策略,将其发展为通用视觉特征;
  3. DINOv3 进一步强化局部区域之间的空间关系和稠密特征质量。

DINO 真正强大的地方,不是它能够完成某一个特定任务,而是它提供了一个可以被多种任务复用的视觉基础。

对于果树枝条分析、三维重建和机器人剪枝,DINO 可以提供对外观变化更加稳定的局部特征。但它不是完整解决方案。最可靠的系统通常会将 DINO 的语义特征与前景 Mask、相机几何、三维点云和枝条拓扑共同使用。

最终可以用一句话概括 DINO 系列:

DINO 让模型在没有标签的情况下学会观察,DINOv2 让这种观察能力可以广泛复用,DINOv3 则让模型对局部结构和真实场景看得更加清楚。

相关推荐
不如语冰1 小时前
AI大模型入门-pytorch-张量2 tensor创建
python
NPE~1 小时前
[AI]Agent开发——ADK框架使用
人工智能·python·ai·教程·adk·agent开发
矮个史蒂芬1 小时前
统计verilog .v文件中output 的bit数
python
gwf2162 小时前
磨损均衡算法(Wear Leveling)——SSD如何让每块闪存“公平退休“?
运维·数据库·人工智能·python·嵌入式硬件·算法·智能硬件
爱吃提升2 小时前
python 分布式爬虫、爬虫合规与综合实战项目
分布式·爬虫·python
审小匠OpenCPAi2 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
元Y亨H3 小时前
Pandas 解析 Excel 导致的内存溢出(MemoryError)
python·excel
金銀銅鐵4 小时前
[Python] 用 turtle 来绘制瑞典国旗
python
Albert Edison4 小时前
【GUI 自动化测试】Pywinauto 常见操作
自动化测试·python·pywinauto