使用 DINOv2 做可視化對(duì)比學(xué)習(xí)與圖像分類
DINOv2 是由 M. Oquab 等人于 2023 年提出的一種利用視覺(jué)特征進(jìn)行自監(jiān)督學(xué)習(xí)的可擴(kuò)展方法。Meta 團(tuán)隊(duì)借鑒了文本數(shù)據(jù)整理流程(Wenzek 等人,2019 年)的思路,將未整理的圖像嵌入聚類到一個(gè)有標(biāo)簽的源數(shù)據(jù)上。最終得到的模型是一個(gè)視覺(jué)變換器(ViT),可作為視覺(jué)任務(wù)的多功能編碼器。
數(shù)據(jù)整理與對(duì)比學(xué)習(xí)
無(wú)標(biāo)簽自蒸餾(DINO)最初由 Caron 等人于 2021 年提出,用于通過(guò)在線蒸餾進(jìn)行對(duì)比學(xué)習(xí)。DINO 在 ImageNet 上進(jìn)行預(yù)訓(xùn)練,采用交叉熵?fù)p失,將其構(gòu)建為相同的教師模型和學(xué)生模型之間的知識(shí)蒸餾。DINO 使用自監(jiān)督學(xué)習(xí),在訓(xùn)練過(guò)程中,每個(gè)模型接收輸入圖像的不同隨機(jī)增強(qiáng)版本。Zhou 等人于 2022 年通過(guò)隨機(jī)屏蔽提供給學(xué)生模型而非教師模型的輸入圖像塊,利用圖像塊級(jí)別的 iBOT 損失擴(kuò)展了對(duì)比學(xué)習(xí)。
DINOv2 在 Meta 內(nèi)部的自定義數(shù)據(jù)集上結(jié)合 DINO 和 iBOT 損失進(jìn)行訓(xùn)練。簡(jiǎn)而言之,LVD - 142M 數(shù)據(jù)集從 ImageNet、谷歌地標(biāo)數(shù)據(jù)和其他來(lái)源收集而來(lái),同時(shí)從互聯(lián)網(wǎng)上收集未經(jīng)過(guò)濾的圖像,最終總共得到 12 億張圖像。通過(guò)在 ImageNet 上預(yù)訓(xùn)練的 ViT 生成嵌入,然后進(jìn)行相似圖像檢索。通過(guò)這種方式,每個(gè)有標(biāo)簽的圖像都用于從未整理的數(shù)據(jù)集中檢索額外的圖像。
DINOv2 的發(fā)布版本包括基礎(chǔ)架構(gòu),即一個(gè)擁有 11 億參數(shù)的 ViT - g/14 模型,以及幾個(gè)通過(guò)知識(shí)蒸餾訓(xùn)練的較小模型。還包含在凍結(jié)的 DINOv2 模型之上訓(xùn)練的線性分類器,用于圖像分類、分割和深度估計(jì)任務(wù)。更多詳細(xì)信息和模型基準(zhǔn)測(cè)試可在 DINOv2 的 GitHub 頁(yè)面上找到。
可視化對(duì)比學(xué)習(xí)
首先,讓我們使用主成分分析(PCA)來(lái)可視化 DINOv2 的圖像塊級(jí)編碼。PCA 是一種降維方法,它能將重要信息提取到一組更小的特征中。我們將通過(guò) PCA 展示一組相關(guān)圖像的編碼之間的關(guān)系,以此探究 DINOv2 學(xué)到了什么。
為了清晰可視化,建議選擇前景和背景有明顯區(qū)分的圖像。將這些圖像調(diào)整大小并進(jìn)行中心裁剪至 560x560(14 的倍數(shù))。然后將張量格式的圖像用于評(píng)估。我使用的是蒸餾模型 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 進(jìn)行兩次操作;第一次是分離前景和背景,第二次是為前景中的主體著色。首先進(jìn)行單成分的第一次 PCA,然后選擇一個(gè)閾值。接著,將背景置為零,對(duì)前景進(jìn)行三成分的第二次 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)
以下是從維基媒體圖像庫(kù)收集的幾張狗的圖片。所有結(jié)果如下所示:
經(jīng)過(guò)調(diào)整大小和中心裁剪后的四張來(lái)自維基媒體的狗的圖片
展示了one component 第一次 PCA 的結(jié)果
展示了 three component 且背景置零的第二次 PCA 的結(jié)果
DINOv2 通過(guò)對(duì)扭曲或屏蔽的單個(gè)圖像進(jìn)行對(duì)比學(xué)習(xí),學(xué)習(xí)到重要的圖像特征。這些結(jié)果直觀地展示了 DINOv2 如何用作圖像編碼器。例如,識(shí)別狗以及如雪或草地等背景地形,接著識(shí)別狗的臉部、腿部和尾巴的細(xì)節(jié)。完整代碼已分享在我的 GitHub 頁(yè)面上。
分類
接下來(lái),我們將了解如何將預(yù)訓(xùn)練的 DINOv2 編碼器用于圖像分類。為此,訓(xùn)練一個(gè)線性分類器來(lái)預(yù)測(cè) ImageNet 1K 中的任何類別。我們將使用 Hugging Face Transformers 庫(kù)來(lái)加載模型并預(yù)處理上述狗的圖像。
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)
根據(jù)維基媒體頁(yè)面,我為上述每只狗找到了以下標(biāo)簽或說(shuō)明:
- 家犬(Canis lupus familiaris)
- 豺(亞洲野犬)
- 雄性博洛尼亞犬
- 哈士奇雪橇犬
配備線性類器的 DINOv2 按順序?yàn)槊繌垐D像預(yù)測(cè)了以下前三個(gè)標(biāo)簽。三個(gè)預(yù)測(cè)結(jié)果用單引號(hào)分隔。
- [' 剛毛獵狐梗 ', ' 西藏梗犬,菊花犬 ', ' 丹迪丁蒙梗犬 ']
- [' 豺,亞洲豺犬 ', ' 紅狼,鬃狼,北美紅狼,黑狼 ', ' 澳洲野犬,袋狼,澳洲犬 ']
- [' 玩具貴賓犬 ', ' 迷你貴賓犬 ', ' 馬爾濟(jì)斯犬,馬爾濟(jì)斯梗犬,馬爾濟(jì)斯 ']
- [' 狗拉雪橇 ', ' 愛(ài)斯基摩犬,哈士奇 ', ' 西伯利亞哈士奇 ']
配備線性分類器的 DINOv2 準(zhǔn)確地預(yù)測(cè)出了豺和哈士奇。對(duì)于其他狗的圖片,雖然預(yù)測(cè)結(jié)果并非完全匹配,但找到了外觀相似的狗的類別標(biāo)簽。我們可以得出結(jié)論,基于視覺(jué)相似度,DINOv2 在預(yù)測(cè)圖像類別標(biāo)簽方面表現(xiàn)良好。
完整代碼:https://github.com/eriktaylor/Transformer-introduction?source=post_page-----9e6d8f87acf6