图像相似度比较之 CLIP or DINOv2

简介: 图像相似度比较之 CLIP or DINOv2

在人工智能领域,计算机视觉的两大巨头是CLIP和DINOv2。CLIP改变了图像理解的方式,而DINOv2为自监督学习带来了新的方法。在本文中,我们将探索定义CLIP和DINOv2的强项和微妙之处的旅程。我们旨在发现这些模型中哪一个在图像相似度任务的世界中真正出色。让我们见证这两位巨头的较量,看看哪个模型胜出。



CLIP中的图像相似度

使用CLIP计算两个图像之间的相似度是一个简单的过程,只需要两个步骤:首先提取两个图像的特征,然后计算它们的余弦相似度。


首先,确保已安装所需的软件包。建议设置和使用虚拟环境:

#Start by setting up a virtual environment
virtualenv venv-similarity
source venv-similarity/bin/activate
#Install required packages
pip install transformers Pillow torch


接下来,继续计算图像相似度:


import torch
from PIL import Image
from transformers import AutoProcessor, CLIPModel
import torch.nn as nn
device = torch.device('cuda' if torch.cuda.is可用 else "cpu")
processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
#Extract features from image1
image1 = Image.open('img1.jpg')
with torch.no_grad():
    inputs1 = processor(images=image1, return_tensors="pt").to(device)
    image_features1 = model.get_image_features(**inputs1)
#Extract features from image2
image2 = Image.open('img2.jpg')
with torch.no_grad():
    inputs2 = processor(images=image2, return_tensors="pt").to(device)
    image_features2 = model.get_image_features(**inputs2)
#Compute their cosine similarity and convert it into a score between 0 and 1
cos = nn.CosineSimilarity(dim=0)
sim = cos(image_features1[0],image_features2[0]).item()
sim = (sim+1)/2
print('Similarity:', sim)

2张相似的图像

使用两张相似图像的示例,获得的相似度得分为令人印象深刻的96.4%。


DINOv2中的图像相似度

使用DINOv2计算两张图像之间的相似度的过程与CLIP类似。需要同一组软件包,无需进行任何额外的安装:


from transformers import AutoImageProcessor, AutoModel
from PIL import Image
import torch.nn as nn
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
processor = AutoImageProcessor.from_pretrained('facebook/dinov2-base')
model = AutoModel.from_pretrained('facebook/dinov2-base').to(device)
image1 = Image.open('img1.jpg')
with torch.no_grad():
    inputs1 = processor(images=image1, return_tensors="pt").to(device)
    outputs1 = model(**inputs1)
    image_features1 = outputs1.last_hidden_state
    image_features1 = image_features1.mean(dim=1)
image2 = Image.open('img2.jpg')
with torch.no_grad():
    inputs2 = processor(images=image2, return_tensors="pt").to(device)
    outputs2 = model(**inputs2)
    image_features2 = outputs2.last_hidden_state
    image_features2 = image_features2.mean(dim=1)
cos = nn.CosineSimilarity(dim=0)
sim = cos(image_features1[0],image_features2[0]).item()
sim = (sim+1)/2
print('Similarity:', sim)


与CLIP示例中的相同图像对一起使用,使用DINOv2获得的相似度得分为93%。


使用COCO数据集进行测试

在深入评估它们的性能之前,让我们使用COCO数据集的验证集中的图像来比较CLIP和DINOv2的结果。我们采用的流程如下:

  • 遍历数据集以提取所有图像的特征。
  • 将嵌入存储在FAISS索引中。
  • 提取输入图像的特征。
  • 检索相似度最高的三张图像。

对于那些对FAISS深入了解的人,请参考这篇充满信息的文章。确保首先使用以下命令安装它:pip install faiss-[gpu|cpu]。


第1部分:特征提取和创建2个索引


import torch
from PIL import Image
from transformers import AutoProcessor, CLIPModel, AutoImageProcessor, AutoModel
import faiss
import os
import numpy as np
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
#Load CLIP model and processor
processor_clip = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")
model_clip = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
#Load DINOv2 model and processor
processor_dino = AutoImageProcessor.from_pretrained('facebook/dinov2-base')
model_dino = AutoModel.from_pretrained('facebook/dinov2-base').to(device)
#Retrieve all filenames
images = []
for root, dirs, files in os.walk('./val2017/'):
    for file in files:
        if file.endswith('jpg'):
            images.append(root  + '/'+ file)
#Define a function that normalizes embeddings and add them to the index
def add_vector_to_index(embedding, index):
    #convert embedding to numpy
    vector = embedding.detach().cpu().numpy()
    #Convert to float32 numpy
    vector = np.float32(vector)
    #Normalize vector: important to avoid wrong results when searching
    faiss.normalize_L2(vector)
    #Add to index
    index.add(vector)
def extract_features_clip(image):
    with torch.no_grad():
        inputs = processor_clip(images=image, return_tensors="pt").to(device)
        image_features = model_clip.get_image_features(**inputs)
        return image_features
def extract_features_dino(image):
    with torch.no_grad():
        inputs = processor_dino(images=image, return_tensors="pt").to(device)
        outputs = model_dino(**inputs)
        image_features = outputs.last_hidden_state
        return image_features.mean(dim=1)
#Create 2 indexes.
index_clip = faiss.IndexFlatL2(512)
index_dino = faiss.IndexFlatL2(768)
#Iterate over the dataset to extract features X2 and store features in indexes
for image_path in images:
    img = Image.open(image_path).convert('RGB')
    clip_features = extract_features_clip(img)
    add_vector_to_index(clip_features,index_clip)
    dino_features = extract_features_dino(img)
    add_vector_to_index(dino_features,index_dino)
#store the indexes locally
faiss.write_index(index_clip,"clip.index")
faiss.write_index(index_dino,"dino.index")


第2部分:图像相似度搜索


import faiss
import numpy as np
import torch
from transformers import AutoImageProcessor, AutoModel, AutoProcessor, CLIPModel
from PIL import Image
import os
#Input image
source='laptop.jpg'
image = Image.open(source)
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
#Load model and processor DINOv2 and CLIP
processor_clip = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")
model_clip = CLIPModel.from_pretrained("openai/clip-vit-base-patch32").to(device)
processor_dino = AutoImageProcessor.from_pretrained('facebook/dinov2-base')
model_dino = AutoModel.from_pretrained('facebook/dinov2-base').to(device)
#Extract features for CLIP
with torch.no_grad():
    inputs_clip = processor_clip(images=image, return_tensors="pt").to(device)
    image_features_clip = model_clip.get_image_features(**inputs_clip)
#Extract features for DINOv2
with torch.no_grad():
    inputs_dino = processor_dino(images=image, return_tensors="pt").to(device)
    outputs_dino = model_dino(**inputs_dino)
    image_features_dino = outputs_dino.last_hidden_state
    image_features_dino = image_features_dino.mean(dim=1)
def normalizeL2(embeddings):
    vector = embeddings.detach().cpu().numpy()
    vector = np.float32(vector)
    faiss.normalize_L2(vector)
    return vector
image_features_dino = normalizeL2(image_features_dino)
image_features_clip = normalizeL2(image_features_clip)
#Search the top 5 images
index_clip = faiss.read_index("clip.index")
index_dino = faiss.read_index("dino.index")
#Get distance and indexes of images associated
d_dino,i_dino = index_dino.search(image_features_dino,5)
d_clip,i_clip = index_clip.search(image_features_clip,5)


结果

使用四个不同的图像作为输入,搜索产生了以下结果:

CLIP与DINOv2

在这个小子集中,似乎DINOv2展现出了略微卓越的性能。


针对DISC21数据集的基准测试

为了比较它们的性能,我们将遵循与此故事中描述的相同方法:https://medium.com/aimonks/image-similarity-with-dinov2-and-faiss-741744bc5804我们还将重复上面的脚本,以提取特征,然后计算图像相似度。


数据集

为了对比CLIP和DINOv2,我们选择了DISC21数据集,这个数据集是专门为图像相似性搜索创建的。由于其巨大的大小为350GB,我们将使用150,000张图像的子集。


所使用的度量标准

在度量方面,我们将计算以下内容:

  • 准确率:正确预测的图像数量与总图像数量的比率。
  • 前三准确率:正确图像在前三个相似图像中找到的次数与总图像数量的比率。
  • 计算时间:处理整个数据集所需的时间。


基准测试结果

  • 特征提取

       CLIP:每秒处理70.7张图像

       DINOv2:每秒处理69.7张图像


  • 准确度和前三准确度

准确度和前三准确度

  • 分析结果

1.两个模型都正确预测了图像


2. 所有模型都未能找到正确的图像


3. 只有CLIP正确预测了图像,DINOv2在前三个中预测了它


4. 只有DINOv2正确预测了图像


分析

DINOv2表现出明显的领先地位,实现了在一个明显具有挑战性的数据集上达到64%的令人印象深刻的准确率。相比之下,CLIP展现了更为适度的准确度,达到了28.45%。


就计算效率而言,两个模型表现出非常相似的特征提取时间。这种平衡在这方面没有让任何一个模型处于明显的优势地位。


限制

虽然这个基准测试提供了有价值的见解,但必须认识到它的限制。评估是在1448张图像的子集上进行的,与150,000张图像的池进行了比较。鉴于整个数据集的规模为2.1百万张图像,狭窄的焦点对于保存资源是必要的。


值得注意的是,MetaAI将DISC21数据集用作其模型的基准,这可能给DINOv2带来了有利的优势。然而,我们在COCO数据集上的测试揭示了有趣的细节:DINOv2显示出了在图像中识别主要元素的增强能力,而CLIP则表现出了在输入图像中关注特定细节的能力(如公交车图像所示)。


最后,必须考虑CLIP和DINOv2之间嵌入维度的差异。CLIP使用512的嵌入维度,而DINOv2使用768。虽然另一种选择是使用嵌入维度匹配的更大的CLIP模型,但值得注意的是,这将以速度为代价。在一个小子集上进行的快速测试显示了轻微的性能提升,但没有达到DINOv2所展示的性能水平。

相关文章
|
5月前
|
机器学习/深度学习 存储 算法
如何判断两张图片的相似度?原来图片对比也可以如此简单!
本文介绍了图片对比技术在多个场景中的应用,如图片去重、内容审核、版权维权及相似图片搜索,并详细解析了两种主流的图片对比方法。第一种是**MD5指纹对比**,适合精确匹配完全相同的图片,具有速度快、简单易用的特点,但对稍作修改的图片无能为力。第二种是**图像哈希对比**,包括平均哈希、感知哈希等算法,能够判断图片的相似程度,适用于处理缩放、旋转或亮度调整后的图片,但在语义相似性上仍有局限。最后提到,随着机器学习和深度神经网络的发展,图片相似度判断技术将有更多可能性,值得进一步探索。
2242 6
如何判断两张图片的相似度?原来图片对比也可以如此简单!
|
算法 搜索推荐 计算机视觉
图片相似度计算及检索调研
图片相似度计算和相似图片搜索,是图片识别领域两个常见的应用场景。例如搜索相似商品,和相似的图片,在百度、淘宝中都有应用。在某些业务中,也存在对图片相似度的计算和判断。因此,在这里简单介绍一下相关算法。
1810 0
|
机器学习/深度学习 自然语言处理 文字识别
【计算机视觉】CLIP:连接文本和图像(关于CLIP的一些补充说明)
我们推出了一个名为CLIP的神经网络,它可以有效地从自然语言监督中学习视觉概念。CLIP可以应用于任何视觉分类基准,只需提供要识别的视觉类别名称,类似于GPT-2和GPT-3的“零样本”功能。
|
算法 计算机视觉
计算机视觉目标检测性能指标
目标检测是计算机视觉领域中的一个重要任务,其目标是在图像或视频中识别出物体的位置和类别。为了评估目标检测算法的性能,需要使用一系列指标来量化模型的准确性、召回率、精确率以及对不同类别的处理能力。本文将详细介绍常见的目标检测性能指标,包括精确率、召回率、F1分数、IoU、AP、mAP、P-R曲线等,同时提供相关公式和案例。
854 0
|
测试技术 开发工具 Swift
Liger kernel训练加速,一行代码训练吞吐量提高 20%,显存使用量降低 60%
在LLM的训练/微调过程中,开发者通常会遇到一些瓶颈,包括GPU显存不够,经常遇到OOM,GPU使用率100%而且非常慢等。
Liger kernel训练加速,一行代码训练吞吐量提高 20%,显存使用量降低 60%
|
算法
有史以来最全的图像相似度算法
有史以来最全的图像相似度算法
417 0
|
机器学习/深度学习 算法 数据挖掘
图像嵌入(Image Embedding
机器学习中的图像嵌入(Image Embedding)是一种将图像数据转化为连续的、低维度的向量表示的方法,这些向量表示通常用于后续的机器学习任务,如分类、聚类、检索等。图像嵌入的目的是将高维度的图像数据转化为更易于处理的低维度数据,同时保留尽可能多的原始图像信息。常用的图像嵌入方法包括:
4396 3
|
Linux 开发工具 开发者
智谱ChatGLM3本地私有化部署(Linux)
智谱ChatGLM3本地私有化部署(Linux)
484 0
|
定位技术 API
谷歌云端硬盘Drive批量下载大文件或大文件夹的稳定方法
谷歌云端硬盘Drive批量下载大文件或大文件夹的稳定方法
1067 1
|
机器学习/深度学习 算法 Python
【Siamese】手把手教你搭建一个孪生神经网络,比较两张图像的相似度
【Siamese】手把手教你搭建一个孪生神经网络,比较两张图像的相似度
1975 0