使用SigLIP 2提升影象搜尋能力

使用SigLIP 2提升影象搜尋能力

提高影象搜尋能力已成為數字資產管理、電子商務和社交媒體平臺領域的關鍵重點。隨著每天產生的視覺化內容數量不斷增加,對高效、準確的影象檢索系統的需求比以往任何時候都更加迫切。SigLIP 2(用於語言影象預訓練的 Sigmoid Loss)是谷歌 DeepMind 開發的最先進的多語言視覺語言編碼器,有望徹底改變我們處理影象相似性和搜尋任務的方式。它的創新架構不僅提高了語義理解能力,而且在零鏡頭分類和影象-文字檢索方面表現出色。SigLIP 2 採用統一的訓練方法,結合了自我監督學習和多樣化的資料整理,在提取有意義的視覺表徵方面優於以往的模型。

學習目標

  • 瞭解 CLIP 模型的基本原理及其在影象檢索系統中的作用。
  • 確定基於 softmax 的損失函式在區分細微影象差異方面的侷限性。
  • 探索 SigLIP 模型如何利用 sigmoid 損失函式克服這些侷限性。
  • 分析 SigLIP 2 與 SigLIP 相比的主要進步和差異化特徵。
  • 根據使用者的影象查詢實施影象檢索系統。
  • 比較和評估 SigLIP 2 與 SigLIP 在影象檢索任務中的效能。

對比語言-影象預訓練(CLIP)

CLIP 是 Contrastive Language-Image Pre-training 的縮寫,是 OpenAI 於 2021 年開發的一種突破性多模態模型。它通過學習影象和文字的共享表示空間,在計算機視覺和自然語言處理之間架起了一座橋樑。這種創新方法使 CLIP 能夠同時理解和關聯兩種模式,從而能夠執行零鏡頭影象分類、影象文字檢索和字幕等任務。

CLIP的關鍵元件

CLIP 的關鍵元件包括文字編碼器、影象編碼器和對比學習機制。該機制通過最大化匹配對的相似度和最小化非匹配對的相似度來調整文字和影象的表示。

CLIP的關鍵元件

Source: https://openai.com/index/clip/

CLIP 是在一個大型影象-文字對資料集上進行訓練的,通常涉及數以億計的示例。該模型通過學習來預測與影象最相關的文字片段,反之亦然。

帶有交叉熵損失的Softmax函式

在 CLIP 中,有一個影象編碼器和另一個文字編碼器,它們將輸入的影象和文字轉換為潛在表示。當我們從編碼器得到嵌入(潛在表示)後,就可以計算出每對影象和文字之間的相似度得分(或點積)。相似度得分可以衡量影象和文字嵌入的相似程度。為了訓練模型為影象標註正確的文字,或反之亦然,我們使用了一個損失函式,其目標是最大化影象和文字對之間的相似度得分。

CLIP

在 CLIP 中,softmax 函式應用於模型的輸出,從而為批次中的每對影象文字獲得如下的概率分佈。

softmax 函式

在 CLIP 中,歸一化(如分母所示)會獨立進行兩次:跨影象和跨文字,如下圖損失函式所示:

損失函式

上式中的第一項為給定查詢影象找出最佳文字匹配,第二項為給定查詢文字找出最佳影象匹配。B 是批量大小。

CLIP的侷限性

  • 處理高度相似配對時存在的問題。儘管 CLIP 利用 Softmax 函式計算圖文配對的概率,但直接將其與餘弦相似度結合使用時存在潛在問題。因為 Softmax 函式可能無法有效捕捉影象與文字嵌入之間的相對距離(尤其在處理高度相似配對時),這會導致比較結果缺乏細微區分度,並可能在需要細粒度區別的場景中影響效能。Softmax 傾向於將”錯誤”配對的概率推至接近零值,可能使模型忽略相似影象與文字描述間的微妙差異
  • 二次記憶體複雜度問題。此外,由於 CLIP 中所有正樣本對的相似度都需要通過負樣本對進行歸一化,每個 GPU 必須維護一個 NxN 的全配對相似度矩陣,這導致了平方級記憶體複雜度。

採用Sigmoid損失函式的SigLIP

由谷歌開發的 SigLIP 沿用了 CLIP 的框架,但通過使用基於 Sigmoid 的損失函式(替代基於 Softmax 的損失)克服了上述問題。該函式可獨立處理每個圖文配對,其Sigmoid損失函式定義如下:

Sigmoid損失函式

Source: https://ahmdtaha.medium.com/sigmoid-loss-for-language-image-pre-training-2dd5e7d1af84

  •  分母中的 “N” 代表批次大小,用於確保不同批次規模下損失值的歸一化
  • Σ(i=1到N) Σ(j=1到N)” 表示對所有影象(i)與文字(j)配對組合的損失求和
  • “z_ij” 用於標記圖文配對的正負屬性(1表示正樣本,-1表示負樣本)
  • “t” 控制Sigmoid曲線的陡峭程度
  • “xi·yj” 衡量影象嵌入與文字嵌入的相似度(通過點積運算)

與CLIP的差異

CLIP SigLIP  Inference
基於 Softmax 的損失 基於 Sigmoid 的損失 SigLIP 既不對稱,也不依賴於全域性歸一化因子。因此,每個資料對的損失(無論是正損失還是負損失)都與迷你批次中的其他資料對無關。
每個 GPU 儲存一個 NxN 矩陣,用於計算所有成對相似性 無需儲存 NXN 矩陣,因為每個正/負對都是獨立執行的。 通過記憶體高效損耗計算減少計算開銷

SigLIP 2優於SigLIP

SigLIP 2 模型在零鏡頭分類、影象文字檢索以及為視覺語言模型(VLM)提取視覺表徵時的傳輸效能等關鍵領域的所有模型規模上都優於之前的 SigLIP 版本。一個突出的特點是動態解析度(naflex)版本,該版本尤其適用於對長寬比和解析度敏感的任務。

SigLIP 2的主要功能

SigLIP 2的主要功能

使用Sigmoid和位置感知字幕機 (LocCa) 解碼器進行培訓

SigLIP 2 在訓練過程中引入了文字解碼器,以及現有的影象和文字視覺編碼器。對於 LocCa,視覺編碼器中增加了一個具有交叉注意功能的轉換解碼器,以實現兩個關鍵目標:

  1. 參照表達 (REF) :預測文字描述中提到的特定位置的邊界框座標。
  2. 基礎字幕 (GCAP):根據影象中特定物體的位置建立標題。

改進的細粒度區域性語義

為了改進影象表示中的細粒度區域性語義,SigLIP 2 增加了兩個額外的目標: 全域性-區域性損失(Global-Local Loss)和遮蔽預測損失(Masked Prediction Loss)。

  • 自我提煉:傳統的知識蒸餾使用大型“教師”模型來訓練較小的“學生”模型,而自蒸餾則不同,它使用相同的模型來扮演這兩種角色。它有助於將知識從較深的網路層轉移到較淺的網路層,或從較早的訓練階段轉移到較晚的訓練階段。
  • 全域性-區域性損耗:這種損耗鼓勵區域性到全域性的一致性。視覺編碼器(作為學生)處理小影象片段,並學習如何與教師網路建立的完整影象表示相匹配。
  • 掩碼預測損失:這種損失的工作原理是用掩碼標記替換 50%的嵌入式影象補丁,促使學生模型在掩碼位置匹配教師的特徵。這有助於將注意力集中在每個補丁的單個特徵上,而不是整個影象上。

更好地適應不同解析度

由於影象模型對解析度和寬高比的變化非常敏感,因此 SigLIP 2 引入了兩種處理方法:

  • 固定解析度變體: 在該版本中,訓練從模型已經學習了大部分模式(完成了 95% 的訓練)的檢查點開始。位置嵌入的大小會進行調整,以匹配目標序列長度,並以新的解析度繼續訓練。
  • 動態解析度(NaFlex)變體: NaFlex 變體以 FlexiViT 和 NaViT 的概念為基礎,使單個模型能夠處理多個序列長度,並保持影象的原始縱橫比。這減少了長寬比失真,對 OCR 和文件影象處理等任務特別有用。

現在,我們已經介紹了 SigLIP 2 的一些主要區別特性,讓我們用 Python 來構建一個影象檢索系統。

使用SigLIP 2構建影象檢索系統以及與SigLIP的比較

在下面的上機教學中,我們將在使用者根據影象查詢進行搜尋時構建一個影象檢索系統。我們還將比較 SigLIP 2 和 SigLIP 的響應。我們將使用 Google Colab 上的 T4 GPU(免費層)來實現這一功能。

Step 1. 安裝必要的庫

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
!pip install datasets sentencepiece
!pip install faiss-cpu
#update latest version of transformers
!pip install git+https://github.com/huggingface/transformersCopy Code
!pip install datasets sentencepiece !pip install faiss-cpu #update latest version of transformers !pip install git+https://github.com/huggingface/transformersCopy Code
!pip install datasets sentencepiece
!pip install faiss-cpu
#update latest version of transformers
!pip install git+https://github.com/huggingface/transformersCopy Code

Step 2. 載入SigLIP模型

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import torch
import faiss
from torchvision import transforms
from PIL import Image
from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer
import numpy as np
import requests
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device)
processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384")
tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")
import torch import faiss from torchvision import transforms from PIL import Image from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer import numpy as np import requests device = torch.device('cuda' if torch.cuda.is_available() else "cpu") model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device) processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384") tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")
import torch
import faiss
from torchvision import transforms
from PIL import Image
from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer
import numpy as np
import requests
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device)
processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384")
tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")

Step 3. 處理輸入影象、生成嵌入資訊並將其儲存在FAISS中的功能

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def add_vector(embedding, index):
vector = embedding.detach().cpu().numpy()
vector = np.float32(vector)
faiss.normalize_L2(vector)
index.add(vector)
def embed_siglip(image):
with torch.no_grad():
inputs = processor(images=image, return_tensors="pt").to(device)
image_features = model.get_image_features(**inputs)
return image_features
def add_vector(embedding, index): vector = embedding.detach().cpu().numpy() vector = np.float32(vector) faiss.normalize_L2(vector) index.add(vector) def embed_siglip(image): with torch.no_grad(): inputs = processor(images=image, return_tensors="pt").to(device) image_features = model.get_image_features(**inputs) return image_features
def add_vector(embedding, index):
vector = embedding.detach().cpu().numpy()
vector = np.float32(vector)
faiss.normalize_L2(vector)
index.add(vector)
def embed_siglip(image):
with torch.no_grad():
inputs = processor(images=image, return_tensors="pt").to(device)
image_features = model.get_image_features(**inputs)
return image_features

add_vector:該函式獲取張量嵌入,對其進行歸一化處理,並將其新增到 FAISS 索引中,以便進行高效的相似性搜尋。

embed_siglip:該函式獲取影象,對其進行處理,通過一個模型獲取其嵌入(特徵表示),並返回這些特徵。

Step 4. 載入影象資料集

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
API_TOKEN=""
headers = {"Authorization": f"Bearer {API_TOKEN}"}
API_URL = "https://datasets-server.huggingface.co/rows?dataset=ceyda/fashion-products-small&config=default&split=train"
def query():
response = requests.get(API_URL, headers=headers)
return response.json()
data = query()
API_TOKEN="" headers = {"Authorization": f"Bearer {API_TOKEN}"} API_URL = "https://datasets-server.huggingface.co/rows?dataset=ceyda/fashion-products-small&config=default&split=train" def query(): response = requests.get(API_URL, headers=headers) return response.json() data = query()
API_TOKEN=""
headers = {"Authorization": f"Bearer {API_TOKEN}"}
API_URL = "https://datasets-server.huggingface.co/rows?dataset=ceyda/fashion-products-small&config=default&split=train"
def query():
response = requests.get(API_URL, headers=headers)
return response.json()
data = query()

我們在這裡載入一個影象資料集 ,並使用請求庫獲取它,為此我們首先預先定義了擁抱臉 API 標記。這是一個關於時尚產品的資料集。

Step 5. 在FAISS向量資料庫中儲存嵌入結果

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
index = faiss.IndexFlatL2(768)
# read the image and add vector
for elem in data["rows"]:
url = elem["row"]["image"]["src"]
image = Image.open(requests.get(url, stream=True).raw)
#Generate Embedding of Image
clip_features = embed_siglip(image)
#Add vector to FAISS
add_vector(clip_features,index)
#Save the index
faiss.write_index(index,"./siglip_70k.index")
index = faiss.IndexFlatL2(768) # read the image and add vector for elem in data["rows"]: url = elem["row"]["image"]["src"] image = Image.open(requests.get(url, stream=True).raw) #Generate Embedding of Image clip_features = embed_siglip(image) #Add vector to FAISS add_vector(clip_features,index) #Save the index faiss.write_index(index,"./siglip_70k.index")
index = faiss.IndexFlatL2(768)
# read the image and add vector
for elem in data["rows"]:
url = elem["row"]["image"]["src"]
image = Image.open(requests.get(url, stream=True).raw)
#Generate Embedding of Image
clip_features = embed_siglip(image)
#Add vector to FAISS
add_vector(clip_features,index)
#Save the index 
faiss.write_index(index,"./siglip_70k.index")

Step 6. 查詢模型

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRsZ4PhHTilpQ5zsG51SPZVrgEhdSfQ7_cg1g&s"
image = Image.open(requests.get(url, stream=True).raw)
with torch.no_grad():
inputs = processor(images=image, return_tensors="pt").to(device)
input_features = model.get_image_features(**inputs)
input_features = input_features.detach().cpu().numpy()
input_features = np.float32(input_features)
faiss.normalize_L2(input_features)
distances, indices = index.search(input_features, 3)
url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRsZ4PhHTilpQ5zsG51SPZVrgEhdSfQ7_cg1g&s" image = Image.open(requests.get(url, stream=True).raw) with torch.no_grad(): inputs = processor(images=image, return_tensors="pt").to(device) input_features = model.get_image_features(**inputs) input_features = input_features.detach().cpu().numpy() input_features = np.float32(input_features) faiss.normalize_L2(input_features) distances, indices = index.search(input_features, 3)
url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRsZ4PhHTilpQ5zsG51SPZVrgEhdSfQ7_cg1g&s"
image = Image.open(requests.get(url, stream=True).raw)
with torch.no_grad():
inputs = processor(images=image, return_tensors="pt").to(device)
input_features = model.get_image_features(**inputs)
input_features = input_features.detach().cpu().numpy()
input_features = np.float32(input_features)
faiss.normalize_L2(input_features)
distances, indices = index.search(input_features, 3)

現在我們已經建立了模型,讓我們用一些提示來測試一下,看看它是如何工作的。

實際檢索測試

由於這是一個時尚資料集,我們想查詢一些時尚產品,並檢查模型是否能夠從資料庫中獲取外觀相似的產品。

我們將首先用這款棕褐色女包查詢模型。

棕褐色女包

現在讓我們檢查一下模型根據這個查詢獲取的 3 個最相似的產品。

SigLIP 2 模型測試

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#DISPLAYING SIMILAR IMAGE
for elem in indices[0]:
url = data["rows"][elem]["row"]["image"]["src"]
image = Image.open(requests.get(url, stream=True).raw)
width = 300
ratio = (width / float(image.size[0]))
height = int((float(image.size[1]) * float(ratio)))
img = image.resize((width, height), Image.Resampling.LANCZOS)
display(img)
#DISPLAYING SIMILAR IMAGE for elem in indices[0]: url = data["rows"][elem]["row"]["image"]["src"] image = Image.open(requests.get(url, stream=True).raw) width = 300 ratio = (width / float(image.size[0])) height = int((float(image.size[1]) * float(ratio))) img = image.resize((width, height), Image.Resampling.LANCZOS) display(img)
#DISPLAYING SIMILAR IMAGE
for elem in indices[0]:
url = data["rows"][elem]["row"]["image"]["src"]
image = Image.open(requests.get(url, stream=True).raw)
width = 300
ratio = (width / float(image.size[0]))
height = int((float(image.size[1]) * float(ratio)))
img = image.resize((width, height), Image.Resampling.LANCZOS)
display(img)

SigLIP 2 模型的輸出結果

三個類似的女皮包

從 SigLIP 2 模型的輸出結果可以看出,所有檢索到的袋影象都與我們查詢到的袋很接近。

測試 SigLIP 模型

現在讓我們用 SigLIP 模型來檢查同樣的問題。我們只需在步驟 2 中使用以下程式碼載入該模型

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import torch
import faiss
from torchvision import transforms
from PIL import Image
from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer
import numpy as np
import requests
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device)
processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384")
tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")
import torch import faiss from torchvision import transforms from PIL import Image from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer import numpy as np import requests device = torch.device('cuda' if torch.cuda.is_available() else "cpu") model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device) processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384") tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")
import torch
import faiss
from torchvision import transforms
from PIL import Image
from transformers import AutoProcessor, SiglipModel, AutoImageProcessor, AutoModel, AutoTokenizer
import numpy as np
import requests
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
model = SiglipModel.from_pretrained("google/siglip-base-patch16-384").to(device)
processor = AutoProcessor.from_pretrained("google/siglip-base-patch16-384")
tokenizer = AutoTokenizer.from_pretrained("google/siglip-base-patch16-384")

其他後續步驟可按原樣重新執行。

SigLIP 模型的輸出結果

顏色不一致的女皮包

從 SigLIP 模型的輸出結果可以看出,有兩張檢索到的袋子影象與 SigLIP 2 模型檢索到的袋子影象相似。但是,從 SigLIP 模型中檢索到的第三張影象與我們的查詢影象並不接近,因為它與棕褐色並不接近。

讓我們用這張輸入影象來檢查另一個查詢。

一雙紅色帆布鞋

SigLIP 2 模型的輸出

檢索出款式類似的女帆布鞋

從 SigLIP 2 模型的輸出可以看出,所有檢索到的女鞋影象都是帆布鞋,與我們查詢的鞋子很接近。

SigLIP 模型的輸出結果

部分結果特徵與輸入不一致

從 SigLIP 模型的輸出可以看出,有兩張檢索到的鞋子圖片與 SigLIP 2 模型檢索到的鞋子圖片相似。但是,從 SigLIP 模型中檢索到的第三張圖片與我們的查詢圖片並不完全相同,因為它不是帆布鞋。

小結

SigLIP 2 代表著影象-文字檢索和視覺語言模型的發展向前邁進了一大步。其先進的功能,如動態解析度和改進的細粒度語義理解,使其成為在各種應用中增強影象搜尋能力的強大工具。SigLIP 2 解決了以前模型的主要侷限性,提供了更準確、更高效的影象檢索,使其成為電子商務、數字資產管理和社交媒體等領域的寶貴資產。

主要啟示

  • 由谷歌 DeepMind 開發的 SigLIP 2 在其前身的基礎上進行了改進,採用了統一的訓練方法和基於西格碼的損失,提供了更準確、更高效的影象文字檢索和零鏡頭分類。
  • CLIP 使用的 Softmax 函式在處理細微的影象-文字比較時可能會遇到困難,而 SigLIP 2 則不同,它採用了更有效的 sigmoid 損失函式,可獨立處理每一對影象-文字,從而提高了效能。
  • SigLIP 2 引入了 NaFlex 變體,允許模型有效處理不同的影象解析度和長寬比,使其成為 OCR 和文件處理等任務的理想選擇。
  • SigLIP 2 通過使用自餾分和增強型訓練技術(如全域性-區域性損失和遮蔽預測損失),提供了更好的語義理解,使其更擅長捕捉詳細的視覺特徵。
  • SigLIP 2 配備了位置感知字幕(LocCa)解碼器,可執行接地字幕和預測邊界框座標等任務,進一步增強了準確搜尋和檢索影象的能力。

評論留言