CLIP Vs DINOv2在图像相似性方面的比较

2023年10月11日 由 alex 发表 963 0

在人工智能的世界中,计算机视觉领域有两个巨头傲视群雄: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_available() 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)


1


利用提供的两个相似图片的示例,获得的相似度得分为令人印象深刻的96.4%。


使用DINOv2进行图像相似度比较


使用DINOv2计算两个图片之间的相似度的过程与CLIP类似。


利用DINOv2需要与之前提到的相同的一组软件包,无需进行额外的安装。


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数据集进行测试


在深入评估其性能之前,让我们比较一下CLIP和DINOv2在COCO数据集的验证集中使用图像产生的结果。


我们使用的过程如下:


1. 遍历数据集,提取所有图像的特征。


2. 将嵌入存储在FAISS索引中。


3. 提取输入图像的特征。


4. 检索前三个相似的图像。


第一部分:特征提取和创建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")


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


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)


结果


使用四张不同的图片作为输入,搜索得到了以下结果:


2


在这个小的子集中,看起来DINOv2展现出稍微优越的性能。


针对DISC21数据集的基准测试


数据集


为了对比CLIP和DINOv2,我们选择了DISC21数据集,这个数据集专门用于图像相似度搜索。由于其巨大的大小为350GB,我们将使用一个包含15万张图像的子集。


使用的指标


在指标方面,我们将计算:


1. 准确率:正确预测的图像数量与总图像数量的比率。


2. 前三准确率:在所有图像中,正确图像在前三个相似图像中被找到的次数与总图像数量的比率。


3. 计算时间:处理整个数据集所需的时间。


基准测试结果


1. 特征提取


CLIP:每秒处理70.7张图像


DINOv2:每秒处理69.7张图像


2. 准确率和前三准确率。


3


3.审查结果


①、检查结果两个模型都正确预测图像


4


②、所有模型均无法找到正确的图片


5


③、只有CLIP成功预测出了正确的图像,而DINOv2在其前三名中预测了这个图像。


6


④、仅有 DINOv2 预测正确的图像


7


DINOv2凭借出色的准确率在具有挑战性的数据集上达到了64%,成为明显的领先者。相比之下,CLIP的准确率较为适中,达到了28.45%。


就计算效率而言,两个模型的特征提取时间非常相似。在这方面,两个模型都没有明显的优势。


局限性


尽管这个基准测试提供了有价值的见解,但是必须认识到它的局限性。评估是在1448张图像的子集上进行的,与15万张图像的池进行了比较。考虑到整个数据集有210万张图像,这种缩小的焦点是为了节约资源而必要的。


我们在COCO数据集上的测试揭示了有趣的细微差别:DINOv2显示出在识别图像中的主要元素方面具有更出色的能力,而CLIP在关注输入图像中的特定细节方面表现出了熟练(如公共汽车的图像所示)。


结论


DINOv2在图像相似性任务中展示了超卓的准确性,展示了其在实际应用中的潜力。CLIP虽然值得称赞,但与DINOv2相比不够出色。值得注意的是,CLIP在需要关注小细节的场景中尤为有用。两个模型都具有类似的计算效率,选择取决于任务的特定要求。


文章来源:https://medium.com/aimonks/clip-vs-dinov2-in-image-similarity-6fa5aa7ed8c6
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消