人工知能の分野において、コンピューター ビジョンの 2 大巨頭は CLIP と DINOv2 です。 CLIP は画像理解の方法を変え、DINOv2 は自己教師学習に新しい方法をもたらしました。この記事では、CLIP と DINOv2 の強みと繊細さを定義する経緯を探ります。私たちの目的は、これらのモデルのうちどれが画像類似性タスクの世界で本当に優れているかを明らかにすることです。これら 2 つの巨人の戦いを目の当たりにし、どちらのモデルが勝利するかを見てみましょう。 CLIPにおける画像の類似性CLIP を使用して 2 つの画像間の類似度を計算するのは、2 つのステップのみを必要とする簡単なプロセスです。最初に 2 つの画像の特徴を抽出し、次にそれらのコサイン類似度を計算します。 まず、必要なパッケージがインストールされていることを確認します。仮想環境をセットアップして使用することをお勧めします。 #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 件 2 つの類似画像を例にすると、達成された類似度スコアは驚異的な 96.4% でした。 DINOv2における画像の類似性DINOv2 を使用して 2 つの画像間の類似度を計算するプロセスは、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 インデックスに保存します。
- 入力画像の特徴を抽出します。
- 最も類似した 3 つの画像を取得します。
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) 結果4 つの異なる画像を入力として使用して検索すると、次の結果が生成されました。 CLIP と DINOv2 この小さなサブセットでは、DINOv2 がわずかに優れたパフォーマンスを示しているようです。 DISC21データセットのベンチマークそれぞれのパフォーマンスを比較するために、この記事で説明されているのと同じ方法論に従います: https://medium.com/aimonks/image-similarity-with-dinov2-and-faiss-741744bc5804。上記のスクリプトを繰り返して特徴を抽出し、画像の類似性を計算します。 データセットCLIP と DINOv2 を比較するために、画像類似性検索用に特別に作成された DISC21 データセットを選択しました。サイズが 350 GB と大きいため、150,000 枚の画像のサブセットを使用します。 使用される指標指標に関しては、次のことを計算します。 - 精度: 正しく予測された画像の数と画像の総数の比率。
- トップ 3 精度: 類似する上位 3 つの画像に正しい画像が見つかった回数と画像の総数の比率。
- 計算時間: データセット全体を処理するために必要な時間。
ベンチマーク結果(1)特徴抽出 - CLIP: 1 秒あたり 70.7 枚の画像を処理
- DINOv2: 1秒あたり69.7枚の画像を処理
(2)精度とトップ3の精度 精度とトップ3の精度 (3)分析結果 どちらのモデルも画像を正しく予測しました。 すべてのモデルが正しい画像を見つけることができませんでした: CLIP のみが正しく画像を予測し、DINOv2 は上位 3 つを予測しました。 DINOv2 のみが正しく画像を予測しました: 分析するDINOv2 は明らかにリードしており、明らかに難しいデータセットで 64% という驚異的な精度を達成しました。対照的に、CLIP は 28.45% というより控えめな精度を示しました。 計算効率の点では、両方のモデルは非常に類似した特徴抽出時間を示します。このバランスにより、この点でいずれかのモデルに明確な優位性がもたらされるわけではありません。 制限このベンチマークは貴重な洞察を提供しますが、その限界を認識する必要があります。評価は、150,000 枚の画像のプールと比較した 1,448 枚の画像のサブセットに対して実行されます。データセット全体のサイズが 210 万枚の画像であることを考えると、リソースを節約するには焦点を絞る必要があります。 MetaAI が DISC21 データセットをモデルのベンチマークとして使用したことは注目に値します。これが DINOv2 に有利な点を与えた可能性があります。しかし、COCO データセットでのテストでは興味深い詳細が明らかになりました。DINOv2 は画像内の主要な要素を識別する機能が強化されており、CLIP は入力画像内の特定の詳細に焦点を当てる機能を示しています (バス画像を参照)。 最後に、CLIP と DINOv2 の埋め込み次元の違いを考慮する必要があります。 CLIP は 512 の埋め込み次元を使用しますが、DINOv2 は 768 を使用します。別のオプションとして、埋め込み寸法が一致するより大きな CLIP モデルを使用することがありますが、速度が犠牲になることに注意してください。小さなサブセットでの簡単なテストでは、わずかなパフォーマンスの向上が見られましたが、DINOv2 で実証されたパフォーマンス レベルには達しませんでした。 |