基于 Hugging Face Datasets 和 Transformers 的圖像相似性搜索

通過本文,你將學(xué)習(xí)使用 ?? Transformers 構(gòu)建圖像相似性搜索系統(tǒng)。找出查詢圖像和潛在候選圖像之間的相似性是信息檢索系統(tǒng)的一個(gè)重要用例,例如反向圖像搜索 (即找出查詢圖像的原圖)。此類系統(tǒng)試圖解答的問題是,給定一個(gè)?查詢?圖像和一組?候選?圖像,找出候選圖像中哪些圖像與查詢圖像最相似。
我們將使用 ???datasets
?庫,因?yàn)樗鼰o縫支持并行處理,這在構(gòu)建系統(tǒng)時(shí)會(huì)派上用場(chǎng)。
???datasets
?庫地址
https://hf.co/docs/datasets/
盡管這篇文章使用了基于 ViT 的模型 (nateraw/vit-base-beans
) 和特定的 (Beans) 數(shù)據(jù)集,但它可以擴(kuò)展到其他支持視覺模態(tài)的模型,也可以擴(kuò)展到其他圖像數(shù)據(jù)集。你可以嘗試的一些著名模型有:?
Swin Transformer
https://hf.co/docs/transformers/model_doc/swinConvNeXT
https://hf.co/docs/transformers/model_doc/convnextRegNet
https://hf.co/docs/transformers/model_doc/regnet
上文中提到的基于 ViT 的模型 (nateraw/vit-base-beans) 和 Beans 數(shù)據(jù)集地址分別為:?
https://hf.co/nateraw/vit-base-beans
https://hf.co/datasets/beans
此外,文章中介紹的方法也有可能擴(kuò)展到其他模態(tài)。
要研究完整的圖像相似度系統(tǒng),你可以參考 這個(gè) Colab Notebook:?
https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_similarity.ipynb
我們?nèi)绾味x相似性?
要構(gòu)建這個(gè)系統(tǒng),我們首先需要定義我們想要如何計(jì)算兩個(gè)圖像之間的相似度。一種廣泛流行的做法是先計(jì)算給定圖像的稠密表征 (即嵌入 (embedding)),然后使用 余弦相似性度量 (cosine similarity metric) 來確定兩幅圖像的相似程度。
在本文中,我們將使用 “嵌入” 來表示向量空間中的圖像。它為我們提供了一種將圖像從高維像素空間 (例如 224 × 224 × 3) 有意義地壓縮到一個(gè)低得多的維度 (例如 768) 的好方法。這樣做的主要優(yōu)點(diǎn)是減少了后續(xù)步驟中的計(jì)算時(shí)間。

計(jì)算嵌入
為了計(jì)算圖像的嵌入,我們需要使用一個(gè)視覺模型,該模型知道如何在向量空間中表示輸入圖像。這種類型的模型通常也稱為圖像編碼器 (image encoder)。
我們利用?AutoModel
?類來加載模型。它為我們提供了一個(gè)接口,可以從 HuggingFace Hub 加載任何兼容的模型 checkpoint。除了模型,我們還會(huì)加載與模型關(guān)聯(lián)的處理器 (processor) 以進(jìn)行數(shù)據(jù)預(yù)處理。
本例中使用的 checkpoint 是一個(gè)在?beans
?數(shù)據(jù)集 上微調(diào)過的 ViT 模型。
微調(diào)后的 ViT 模型地址:?
https://hf.co/google/vit-base-patch16-224-in21k
這里可能你會(huì)問一些問題:?
Q1:?為什么我們不使用?AutoModelForImageClassification
?
這是因?yàn)槲覀兿胍@得圖像的稠密表征,而?AutoModelForImageClassification?
只能輸出離散類別。
Q2:?為什么使用這個(gè)特定的 checkpoint?
如前所述,我們使用特定的數(shù)據(jù)集來構(gòu)建系統(tǒng)。因此,與其使用通用模型 (例如 在 ImageNet-1k 數(shù)據(jù)集上訓(xùn)練的模型),不如使用使用已針對(duì)所用數(shù)據(jù)集微調(diào)過的模型。這樣,模型能更好地理解輸入圖像。
注意?你還可以使用通過自監(jiān)督預(yù)訓(xùn)練獲得的 checkpoint, 不必得由有監(jiān)督學(xué)習(xí)訓(xùn)練而得。事實(shí)上,如果預(yù)訓(xùn)練得當(dāng),自監(jiān)督模型可以獲得令人印象深刻的檢索性能。
Facebook 關(guān)于自監(jiān)督學(xué)習(xí)檢索性能的博文地址:?
https://ai.facebook.com/blog/dino-paws-computer-vision-with-self-supervised-transformers-and-10x-more-efficient-training/
現(xiàn)在我們有了一個(gè)用于計(jì)算嵌入的模型,我們需要一些候選圖像來被查詢。
加載候選圖像數(shù)據(jù)集
后面,我們會(huì)構(gòu)建將候選圖像映射到哈希值的哈希表。在查詢時(shí),我們會(huì)使用到這些哈希表,詳細(xì)討論的討論稍后進(jìn)行?,F(xiàn)在,我們先使用?beans
?數(shù)據(jù)集 中的訓(xùn)練集來獲取一組候選圖像。
以下展示了訓(xùn)練集中的一個(gè)樣本:?

該數(shù)據(jù)集的三個(gè)?features
?如下:?
為了使圖像相似性系統(tǒng)可演示,系統(tǒng)的總體運(yùn)行時(shí)間需要比較短,因此我們這里只使用候選圖像數(shù)據(jù)集中的 100 張圖像。
尋找相似圖片的過程
下圖展示了獲取相似圖像的基本過程。

稍微拆解一下上圖,我們分為 4 步走:
從候選圖像 (
candidate_subset
) 中提取嵌入,將它們存儲(chǔ)在一個(gè)矩陣中。獲取查詢圖像并提取其嵌入。
遍歷嵌入矩陣 (步驟 1 中得到的) 并計(jì)算查詢嵌入和當(dāng)前候選嵌入之間的相似度得分。我們通常維護(hù)一個(gè)類似字典的映射,來維護(hù)候選圖像的 ID 與相似性分?jǐn)?shù)之間的對(duì)應(yīng)關(guān)系。
根據(jù)相似度得分進(jìn)行排序并返回相應(yīng)的圖像 ID。最后,使用這些 ID 來獲取候選圖像。
我們可以編寫一個(gè)簡(jiǎn)單的工具函數(shù)用于計(jì)算嵌入并使用?map()
?方法將其作用于候選圖像數(shù)據(jù)集的每張圖像,以有效地計(jì)算嵌入。
我們可以像這樣映射?extract_embeddings()
:?
接下來,為方便起見,我們創(chuàng)建一個(gè)候選圖像 ID 的列表。
我們用包含所有候選圖像的嵌入矩陣來計(jì)算與查詢圖像的相似度分?jǐn)?shù)。我們之前已經(jīng)計(jì)算了候選圖像嵌入,在這里我們只是將它們集中到一個(gè)矩陣中。
我們將使用余弦相似度來計(jì)算兩個(gè)嵌入向量之間的相似度分?jǐn)?shù)。然后,我們用它來獲取給定查詢圖像的相似候選圖像。
執(zhí)行查詢
經(jīng)過以上準(zhǔn)備,我們可以進(jìn)行相似性搜索了。我們從?beans
?數(shù)據(jù)集的測(cè)試集中選取一張查詢圖像來搜索:?
結(jié)果為:
看起來我們的系統(tǒng)得到了一組正確的相似圖像。將結(jié)果可視化,如下:?

進(jìn)一步擴(kuò)展與結(jié)論
現(xiàn)在,我們有了一個(gè)可用的圖像相似度系統(tǒng)。但實(shí)際系統(tǒng)需要處理比這多得多的候選圖像??紤]到這一點(diǎn),我們目前的程序有不少缺點(diǎn):?
如果我們按原樣存儲(chǔ)嵌入,內(nèi)存需求會(huì)迅速增加,尤其是在處理數(shù)百萬張候選圖像時(shí)。在我們的例子中嵌入是 768 維,這即使對(duì)大規(guī)模系統(tǒng)而言可能也是相對(duì)比較高的維度。
高維的嵌入對(duì)檢索部分涉及的后續(xù)計(jì)算有直接影響。
如果我們能以某種方式降低嵌入的維度而不影響它們的意義,我們?nèi)匀豢梢栽谒俣群蜋z索質(zhì)量之間保持良好的折衷。本文 附帶的 Colab Notebook 實(shí)現(xiàn)并演示了如何通過隨機(jī)投影 (random projection) 和位置敏感哈希 (locality-sensitive hashing,LSH) 這兩種方法來取得折衷。
本文的 Colab Notebook 鏈接:?
https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/image_similarity.ipynb
?? Datasets 提供與 FAISS 的直接集成,進(jìn)一步簡(jiǎn)化了構(gòu)建相似性系統(tǒng)的過程。假設(shè)你已經(jīng)提取了候選圖像的嵌入 (beans
?數(shù)據(jù)集) 并把他們存儲(chǔ)在稱為?embedding
?的?feature
?中。你現(xiàn)在可以輕松地使用?dataset
?的?add_faiss_index()
?方法來構(gòu)建稠密索引:
dataset_with_embeddings.add_faiss_index?(column="embeddings")
Facebook FAISS 倉庫地址:?
https://github.com/facebookresearch/faissadd_faiss_index()
?方法的使用參考:?
https://hf.co/docs/datasets/v2.7.1/en/package_reference/main_classes
建立索引后,可以使用?dataset_with_embeddings
?模塊的?get_nearest_examples()
?方法為給定查詢嵌入檢索最近鄰:
dataset_with_embeddings
?模塊文檔:?
https://hf.co/docs/datasets/v2.7.1/en/package_reference/main_classes
該方法返回檢索分?jǐn)?shù)及其對(duì)應(yīng)的圖像。要了解更多信息,你可以查看 官方文檔 和下列 Notebook。
Hugging Face 為 FAISS_ES 提供的文檔:?
https://hf.co/docs/datasets/faiss_es對(duì)應(yīng)的 Colab Notebook 地址:?
https://colab.research.google.com/gist/sayakpaul/5b5b5a9deabd3c5d8cb5ef8c7b4bb536/image_similarity_faiss.ipynb
在本文中,我們快速入門并構(gòu)建了一個(gè)圖像相似度系統(tǒng)。如果你覺得這篇文章很有趣,我們強(qiáng)烈建議你基于我們討論的概念繼續(xù)構(gòu)建你的系統(tǒng),這樣你就可以更加熟悉內(nèi)部工作原理。
還想了解更多嗎?以下是一些可能對(duì)你有用的其他資源:?
Faiss:?高效相似性搜索庫
https://engineering.fb.com/2017/03/29/data-infrastructure/faiss-a-library-for-efficient-similarity-search/ScaNN:?高效向量相似性搜索
在移動(dòng)應(yīng)用程序中集成圖像搜索引擎https://tensorflow.google.cn/lite/inference_with_metadata/task_library/image_searcher
英文原文: https://hf.co/blog/image-similarity
譯者: Matrix Yao (姚偉峰),英特爾深度學(xué)習(xí)工程師,工作方向?yàn)?transformer-family 模型在各模態(tài)數(shù)據(jù)上的應(yīng)用及大規(guī)模模型的訓(xùn)練推理。
審校、排版:?zhongdongy (阿東)