DINOv2 是由 M. Oquab 等人于 2023 年提出的一种利用视觉特征进行自监督学习的可扩展方法。Meta 团队借鉴了文本数据整理流程(Wenzek 等人,2019 年)的思路,将未整理的图像嵌入聚类到一个有标签的源数据上。最终得到的模型是一个视觉变换器(ViT),可作为视觉任务的多功能编码器。
数据整理与对比学习
无标签自蒸馏(DINO)最初由 Caron 等人于 2021 年提出,用于通过在线蒸馏进行对比学习。DINO 在 ImageNet 上进行预训练,采用交叉熵损失,将其构建为相同的教师模型和学生模型之间的知识蒸馏。DINO 使用自监督学习,在训练过程中,每个模型接收输入图像的不同随机增强版本。Zhou 等人于 2022 年通过随机屏蔽提供给学生模型而非教师模型的输入图像块,利用图像块级别的 iBOT 损失扩展了对比学习。
DINOv2 在 Meta 内部的自定义数据集上结合 DINO 和 iBOT 损失进行训练。简而言之,LVD - 142M 数据集从 ImageNet、谷歌地标数据和其他来源收集而来,同时从互联网上收集未经过滤的图像,最终总共得到 12 亿张图像。通过在 ImageNet 上预训练的 ViT 生成嵌入,然后进行相似图像检索。通过这种方式,每个有标签的图像都用于从未整理的数据集中检索额外的图像。
DINOv2 的发布版本包括基础架构,即一个拥有 11 亿参数的 ViT - g/14 模型,以及几个通过知识蒸馏训练的较小模型。还包含在冻结的 DINOv2 模型之上训练的线性分类器,用于图像分类、分割和深度估计任务。更多详细信息和模型基准测试可在 DINOv2 的 GitHub 页面上找到。
可视化对比学习
首先,让我们使用主成分分析(PCA)来可视化 DINOv2 的图像块级编码。PCA 是一种降维方法,它能将重要信息提取到一组更小的特征中。我们将通过 PCA 展示一组相关图像的编码之间的关系,以此探究 DINOv2 学到了什么。
为了清晰可视化,建议选择前景和背景有明显区分的图像。将这些图像调整大小并进行中心裁剪至 560x560(14 的倍数)。然后将张量格式的图像用于评估。我使用的是蒸馏模型 ViT - L/14 和 Google Colaboratory 提供的 L4 GPU。
import torch
from PIL import Image
from torchvision.transforms import v2
transform = v2.Compose([
v2.Resize(560, interpolation=v2.InterpolationMode.BICUBIC),
v2.CenterCrop(560),
v2.ToTensor(),
v2.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),])
batch_size = len(file_list)
imgs_tensor = torch.zeros(batch_size, 3, 560, 560)
for i in range(batch_size):
img = Image.open(file_list[i])
imgs_tensor[i] = transform(img)
#load large DinoV2 model
dino = torch.hub.load('facebookresearch/dinov2', 'dinov2_vitl14')
dino.cuda()
#inference
with torch.no_grad():
features_dict = dino.forward_features(imgs_tensor.cuda())
features = features_dict['x_norm_patchtokens']
PCA 进行两次操作;第一次是分离前景和背景,第二次是为前景中的主体着色。首先进行单成分的第一次 PCA,然后选择一个阈值。接着,将背景置为零,对前景进行三成分的第二次 PCA。
import sklearn
from sklearn.decomposition import PCA
from sklearn.preprocessing import MinMaxScaler
features = features.cpu()
pca = PCA(n_components=1)
scaler = MinMaxScaler()
pca.fit(features)
pca_features = pca.transform(features)
norm_features = scaler.fit_transform(pca_features)
#threshold background
threshold = 0.5 #adjust the threshold based on your images
background = norm_features > threshold
#set background of features to zero
bg_features = features.clone() #make a copy of features
for i in range(bg_features.shape[-1]):
bg_features[:,i][background[:,0]] = 0
#fit 3 components
pca3 = PCA(n_components=3)
pca3.fit(bg_features)
features_foreground = pca3.transform(bg_features)
norm_features_foreground = scaler.fit_transform(features_foreground)
以下是从维基媒体图像库收集的几张狗的图片。所有结果如下所示:
经过调整大小和中心裁剪后的四张来自维基媒体的狗的图片
展示了one component 第一次 PCA 的结果
展示了 three component 且背景置零的第二次 PCA 的结果
DINOv2 通过对扭曲或屏蔽的单个图像进行对比学习,学习到重要的图像特征。这些结果直观地展示了 DINOv2 如何用作图像编码器。例如,识别狗以及如雪或草地等背景地形,接着识别狗的脸部、腿部和尾巴的细节。完整代码已分享在我的 GitHub 页面上。
分类
接下来,我们将了解如何将预训练的 DINOv2 编码器用于图像分类。为此,训练一个线性分类器来预测 ImageNet 1K 中的任何类别。我们将使用 Hugging Face Transformers 库来加载模型并预处理上述狗的图像。
from PIL import Image
import torch
from transformers import AutoImageProcessor, AutoModelForImageClassification
processor = AutoImageProcessor.from_pretrained('facebook/dinov2-large-imagenet1k-1-layer')
model = AutoModelForImageClassification.from_pretrained('facebook/dinov2-large-imagenet1k-1-layer')
img = Image.open(file_list[i])
inputs = processor(images=img, return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits
value = torch.topk(logits, 3)
dog_label = []
for item in value[1].squeeze().numpy():
dog_label.append(model.config.id2label[item])
print("Top three predicted labels, ", dog_label)
根据维基媒体页面,我为上述每只狗找到了以下标签或说明:
- 家犬(Canis lupus familiaris)
- 豺(亚洲野犬)
- 雄性博洛尼亚犬
- 哈士奇雪橇犬
配备线性类器的 DINOv2 按顺序为每张图像预测了以下前三个标签。三个预测结果用单引号分隔。
- [' 刚毛猎狐梗 ', ' 西藏梗犬,菊花犬 ', ' 丹迪丁蒙梗犬 ']
- [' 豺,亚洲豺犬 ', ' 红狼,鬃狼,北美红狼,黑狼 ', ' 澳洲野犬,袋狼,澳洲犬 ']
- [' 玩具贵宾犬 ', ' 迷你贵宾犬 ', ' 马尔济斯犬,马尔济斯梗犬,马尔济斯 ']
- [' 狗拉雪橇 ', ' 爱斯基摩犬,哈士奇 ', ' 西伯利亚哈士奇 ']
配备线性分类器的 DINOv2 准确地预测出了豺和哈士奇。对于其他狗的图片,虽然预测结果并非完全匹配,但找到了外观相似的狗的类别标签。我们可以得出结论,基于视觉相似度,DINOv2 在预测图像类别标签方面表现良好。
完整代码:https://github.com/eriktaylor/Transformer-introduction?source=post_page-----9e6d8f87acf6