Meta AI的另一个革命性大规模模型——DINOv2用于图像特征提取
DINOv2 是最佳的自监督 ViT 基础深度学习模型之一,用于图像特征提取
介绍
Mete AI 推出了一款名为 DINOv2 的图像特征提取模型,该模型可以自动从图像中提取视觉特征。这是人工智能领域特别是在数据和模型规模方面的又一次革命性的进展。
动机 —— 为什么我们要关注?
DINOv2 是一种无需微调且性能良好的自监督模型。此外,它可以用作许多不同的计算机视觉任务的骨干,例如:
- 分类、细粒度分类 —— 如猫与狗或狗品种识别
- 图像检索 —— 如从互联网上大量图像中查找与您的袋子相似的包
- 语义图像分割 —— 将标签或类别与图像中的每个像素相关联
- 视频理解 —— 自动识别和解释视频的各个方面,如对象、动作、事件、场景,甚至是更高层次的概念
- 单目深度估计 —— 预测图像中的对象是在前景还是背景中
- 图像聚类 —— 将图像分组成簇,使得同一簇内的图像彼此相似
- 基于内容的推荐系统 —— 基于图像的表示向用户推荐物品。
DINOv2 补充了最近的计算机视觉研究,包括 Segment Anything。Segment Anything 是一个关注零样本概括到各种分割任务的可提示分割系统。
您可以在我的先前的帖子中查看 Segment Anything Model (SAM)。
Meta AI 推出了训练了 10 亿掩码的革命性图像分割模型
Segment Anything Model (SAM) – 最佳的图像分割深度学习模型
towardsdatascience.com
方法论
本文的主要贡献可以是以下内容:
- 创建一个大型和策划良好的训练数据集
- 改进训练算法和实现
- 设计一个功能性的蒸馏管道。
创建一个大型和策划良好的训练数据集
大型深度学习模型需要大量的数据进行训练。因此,作者创建了如下图所示的自动管道,以获取策划良好的训练数据集。
他们从大约 25 个第三方数据集合集合选取了一组种子图像,并旨在增加这些种子图像。它的工作原理如下。他们从互联网上爬取了大量未策划的图像(大约 12 亿个独特的图像)。之后,他们使用在 ImageNet-22k 上预训练的自监督 ViT-H/16 网络创建了图像嵌入。其次,他们使用余弦相似度作为图像之间的距离度量,以过滤出重复图像,以减少冗余并增加多样性。随着未策划数据集中的重复图像被删除,他们进行了图像检索阶段,提取与策划图像相似的图像。最终,这种方法使他们能够从 12 亿个未策划的图像数据库中创建 1.42 亿个策划良好的图像。
改进的训练算法
DINOv2 使用学生-教师机制,这是一种训练技术,其中较小的神经网络(称为学生)学习模仿较大或更复杂的神经网络(称为教师)的行为。学生和教师基于 Vision Tranformer 架构(ViT)[2]。至于损失,他们使用交叉熵损失进行学生-教师特征相似性。为了同时学习图像的局部和全局特征,他们使用了不同级别的学习。对于全局学习,他们使用图像级别学习 —— 在同一图像上随机裁剪数据增强。至于局部特征学习,他们使用补丁级别学习 —— 在输入补丁上随机应用 Mask 到学生,但不应用到教师。此外,他们执行了不同的归一化技术,例如 Sinkhorn-knop 批归一化等。您可以在论文中找到更多细节。
蒸馏流程。
使用大型模型进行预测(推理)时需要强大的硬件。为了克服这个限制,他们还将大型模型压缩成较小的模型。知识蒸馏 [5] 旨在通过最小化一组给定输入的两个输出之间的某个距离来使用较小的模型复制大型模型的输出。训练算法基于自我蒸馏,使得将我们的大型模型压缩成较小的模型变得简单直接。
结果
他们在八个不同的计算机视觉任务上评估了模型性能,并与其他方法进行了比较。
在下面的图表中,DINOv2 模型的结果为深蓝色,其他自监督方法为浅橙色,弱监督方法为深粉色。虚线水平线是表现最佳的弱监督模型。
如结果所示,DINOv2 模型在自监督学习的先前技术水平上有了巨大的改进,并达到了与弱监督特征相当的性能。
结论
总的来说,DINOv2 是 Meta AI 团队的又一革命性模型。它不需要微调,可以用作许多不同计算机视觉模型的骨干。DINOv2 使用自我监督机制,可以从任何图像集合中学习。
DINOv2 演示 – 细粒度图像分类
在这部分中,我将尝试演示 DINOv2 在实际情况下的工作。我将创建一个细粒度图像分类任务。
分类工作流程:
- 从 PyTorch 数据集下载 Food101 数据集。
- 使用小型 DINOv2 从训练集和测试集中提取特征
- 使用从训练数据集中提取的特征训练 ML 分类器模型(SVM、XGBoost 和 KNN)。
- 对从测试数据集中提取的特征进行预测。
- 评估每个 ML 模型的准确性和 F1 得分。
数据: Food101 是一个具有 101 个食品类别和 101,000 张图像的具有挑战性的数据集。为每个类别提供了 250 张经过手动审核的测试图像以及 750 张训练图像。
模型: 小型 DINOv2 模型 (ViT-S/14 distilled)
ML 模型: SVM、XGBoost、KNN。
步骤 1 – 设置(您可以使用 Google Colab 运行代码并打开 GPU)
import torchimport numpy as npimport torchvisionfrom torchvision import transformsfrom torch.utils.data import Subset, DataLoaderimport matplotlib.pyplot as pltimport timeimport osimport randomfrom tqdm import tqdmfrom xgboost import XGBClassifierfrom sklearn.svm import SVCfrom sklearn.neighbors import KNeighborsClassifierfrom sklearn.metrics import accuracy_score, f1_scoreimport pandas as pddef set_seed(no): torch.manual_seed(no) random.seed(no) np.random.seed(no) os.environ['PYTHONHASHSEED'] = str() torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = Trueset_seed(100)
步骤 2 – 创建转换,下载并创建 Food101 Pytorch 数据集,创建训练和测试数据加载器对象。
batch_size = 8transformation = transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ])trainset = torchvision.datasets.Food101(root='./data', split='train', download=True, transform=transformation)testset = torchvision.datasets.Food101(root='./data', split='test', download=True, transform=transformation)# train_indices = random.sample(range(len(trainset)), 20000)# test_indices = random.sample(range(len(testset)), 5000)# trainset = Subset(trainset, train_indices)# testset = Subset(testset, test_indices)trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True)testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False)classes = trainset.classesprint(len(trainset), len(testset))print(len(trainloader), len(testloader))
[输出] 75750 25250
[输出] 9469 3157
步骤 3(可选)— 可视化训练数据加载器批次
# 获取一批图像dataiter = iter(trainloader)images, labels = next(dataiter)# 绘制图像fig, axes = plt.subplots(1, len(images),figsize=(12,12))for i, ax in enumerate(axes): # 将张量图像转换为numpy格式 image = images[i].numpy() image = image.transpose((1, 2, 0)) # 转置为(高度,宽度,通道) # 归一化图像 mean = [0.485, 0.456, 0.406] std = [0.229, 0.224, 0.225] normalized_image = (image * std) + mean # 显示图像 ax.imshow(normalized_image) ax.axis('off') ax.set_title(f'标签: {labels[i]}')# 显示绘图plt.show()
步骤 4 — 载入小型 DINOv2 模型并从训练和测试数据加载器中提取特征。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")dinov2_vits14 = torch.hub.load('facebookresearch/dinov2', 'dinov2_vits14').to(device)# 训练train_embeddings = []train_labels = []dinov2_vits14.eval()with torch.no_grad(): for data, labels in tqdm(trainloader): image_embeddings_batch = dinov2_vits14(data.to(device)) train_embeddings.append(image_embeddings_batch.detach().cpu().numpy()) train_labels.append(labels.detach().cpu().numpy())# 测试test_embeddings = []test_labels = []dinov2_vits14.eval()with torch.no_grad(): for data, labels in tqdm(testloader): image_embeddings_batch = dinov2_vits14(data.to(device)) test_embeddings.append(image_embeddings_batch.detach().cpu().numpy()) test_labels.append(labels.detach().cpu().numpy())# 合并结果train_embeddings_f = np.vstack(train_embeddings)train_labels_f = np.concatenate(train_labels).flatten()test_embeddings_f = np.vstack(test_embeddings)test_labels_f = np.concatenate(test_labels).flatten()train_embeddings_f.shape, train_labels_f.shape, test_embeddings_f.shape, test_labels_f.shape
[输出] ((75750, 384), (75750,), (25250, 384), (25250,))
步骤 5 — 构建 SVM、XGBoost 和 KNN 分类器的函数。
def evaluate_classifiers(X_train, y_train, X_test, y_test): # 支持向量机(SVM) svm_classifier = SVC() svm_classifier.fit(X_train, y_train) svm_predictions = svm_classifier.predict(X_test) # XGBoost 分类器 xgb_classifier = XGBClassifier(tree_method='gpu_hist') xgb_classifier.fit(X_train, y_train) xgb_predictions = xgb_classifier.predict(X_test) # K-最近邻(KNN)分类器 knn_classifier = KNeighborsClassifier() knn_classifier.fit(X_train, y_train) knn_predictions = knn_classifier.predict(X_test) # 计算 Top-1 top1_svm = accuracy_score(y_test, svm_predictions) top1_xgb = accuracy_score(y_test, xgb_predictions) top1_knn = accuracy_score(y_test, knn_predictions) # 计算 F1 分数 f1_svm = f1_score(y_test, svm_predictions, average='weighted') f1_xgb = f1_score(y_test, xgb_predictions, average='weighted') f1_knn = f1_score(y_test, knn_predictions, average='weighted') return pd.DataFrame({ 'SVM': {'Top-1 准确率': top1_svm, 'F1 分数': f1_svm}, 'XGBoost': {'Top-1 准确率': top1_xgb,'F1 分数': f1_xgb}, 'KNN': {'Top-1 准确率': top1_knn, 'F1 分数': f1_knn} })X_train = train_embeddings_f # 训练数据特征y_train = train_labels_f # 训练数据标签X_test = test_embeddings_f # 测试数据特征y_test = test_labels_f # 测试数据标签results = evaluate_classifiers(X_train, y_train, X_test, y_test)print(results)
结果
哇,结果很棒!正如演示的那样,小DINOv2模型训练出的SVM模型提取的特征优于其他机器学习模型,准确率接近90%。
结论
尽管我们使用小DINOv2模型提取特征,但基于提取的特征训练的机器学习模型(尤其是SVM)在细粒度分类任务中表现出色。该模型可以在101个不同类别中将对象分类的准确率几乎达到了90%。
如果使用大型的DINOv2模型,准确率会提高。您只需要在第4步中将dinov2_vits14更改为dinov2_vitb14、dinov2_vitl14或dinov2_vitg14。您可以试试,并随时在评论区分享准确率结果:)
希望您喜欢本文。如果您有任何问题或想分享您对本文的看法,请随时发表评论,我将非常乐意回答。
如果您想直接支持我的工作并获得小猪AI文章的无限访问权限,请使用我的推荐链接成为小猪AI会员。非常感谢您的支持,祝您有美好的一天!
使用我的推荐链接加入小猪AI – Gurami Keretchashvili
作为小猪AI会员,您的会员费的一部分将支付给您阅读的作家,您将获得每个故事的完全访问权限…
小猪AI.com
参考文献
[1] Oquab, M., Darcet, T., Moutakanni, T., Vo, H., Szafraniec, M., Khalidov, V., … & Bojanowski, P. (2023). Dinov2: Learning robust visual features without supervision. arXiv preprint arXiv:2304.07193 .
[2] Dosovitskiy, A., Beyer, L., Kolesnikov, A., Weissenborn, D., Zhai, X., Unterthiner, T., … & Houlsby, N. (2020). An image is worth 16×16 words: Transformers for image recognition at scale. arXiv preprint arXiv:2010.11929 .ISO 690
[3] DINOv2团队,DINOv2:具有自监督学习的最先进计算机视觉模型
[4] DINOv2 Github
[5] Hinton, G., Vinyals, O., & Dean, J. (2015). Distilling the knowledge in a neural network. arXiv preprint arXiv:1503.02531 .