使用 DINOv2 做可視化對比學習與圖像分類
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