image_paths = glob(os.path.join(images_path, '**/*.jpg'), recursive=True)

embeddings = []
for img_path in image_paths:
image = Image.open(img_path)
embedding = model.encode(image)
embeddings.append(embedding)

return embeddings, image_paths

IMAGES_PATH = '/path/to/images/dataset'

embeddings, image_paths = generate_clip_embeddings(IMAGES_PATH, model)

2.2 生成 FAISS 索引

下一步是從嵌入向量列表創建 FAISS 索引。FAISS 為相似性搜索提供了各種距離度量,包括內積 (IP) 和 L2(歐幾里得)距離。

FAISS 還提供各種索引選項。它可以使用近似或壓縮技術來有效處理大型數據集,同時平衡搜索速度和準確性。在本教程中,我們將使用“平面”索引,它通過將查詢向量與數據集中的每個向量進行比較來執行強力搜索,以確保以更高的計算復雜度為代價獲得準確的結果。

def create_faiss_index(embeddings, image_paths, output_path):

dimension = len(embeddings[0])
index = faiss.IndexFlatIP(dimension)
index = faiss.IndexIDMap(index)

vectors = np.array(embeddings).astype(np.float32)

# Add vectors to the index with IDs
index.add_with_ids(vectors, np.array(range(len(embeddings))))

# Save the index
faiss.write_index(index, output_path)
print(f"Index created and saved to {output_path}")

# Save image paths
with open(output_path + '.paths', 'w') as f:
for img_path in image_paths:
f.write(img_path + '\n')

return index

OUTPUT_INDEX_PATH = "/content/vector.index"
index = create_faiss_index(embeddings, image_paths, OUTPUT_INDEX_PATH)

faiss.IndexFlatIP 初始化內積相似度索引,將其包裝在 faiss.IndexIDMap 中,以將每個向量與 ID 關聯。接下來, index.add_with_ids 將向量添加到具有連續 ID 的索引中,并將索引與圖像路徑一起保存到磁盤。

索引可以立即使用,也可以保存到磁盤以備將來使用。要加載 FAISS 索引,我們將使用以下函數:

def load_faiss_index(index_path):
index = faiss.read_index(index_path)
with open(index_path + '.paths', 'r') as f:
image_paths = [line.strip() for line in f]
print(f"Index loaded from {index_path}")
return index, image_paths

index, image_paths = load_faiss_index(OUTPUT_INDEX_PATH)

2.3 通過文本查詢或參考圖像檢索圖像

建立 FAISS 索引后,我們現在可以使用文本查詢或參考圖像檢索圖像。如果查詢是圖像路徑,則使用 PIL的 Image.open 打開查詢。接下來,使用 CLIP的 model.encode 提取查詢嵌入向量。

def retrieve_similar_images(query, model, index, image_paths, top_k=3):

# query preprocess:
if query.endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif')):
query = Image.open(query)

query_features = model.encode(query)
query_features = query_features.astype(np.float32).reshape(1, -1)

distances, indices = index.search(query_features, top_k)

retrieved_images = [image_paths[int(idx)] for idx in indices[0]]

return query, retrieved_images

檢索發生在 index.search 方法上。它實現了 k-最近鄰 (kNN) 搜索,以找到與查詢向量最相似的 k 個向量。我們可以通過更改 top_k 參數來調整 k 的值。在我們的實現中,kNN 搜索中使用的距離度量是余弦相似度。該函數返回查詢和檢索圖像路徑的列表。

現在我們準備使用文本查詢進行搜索。輔助函數 visualize_results 顯示結果。你可以在關聯的 Colab 筆記本中找到它。讓我們探索針對文本查詢“ball”檢索到的最相似的 3 幅圖像,例如:

query = 'ball'
query, retrieved_images = retrieve_similar_images(query, model, index, image_paths, top_k=3)
visualize_results(query, retrieved_images)

對于查詢“animal”,我們得到:

使用參考圖像搜索:

query ='/content/drive/MyDrive/Colab Notebooks/my_medium_projects/Image_similarity_search/image_dataset/pexels-w-w-299285-889839.jpg'
query, retrieved_images = retrieve_similar_images(query, model, index, image_paths, top_k=3)
visualize_results(query, retrieved_images)

如我們所見,我們為現成的預訓練模型獲得了非??岬慕Y果。當我們通過眼睛繪畫的參考圖像進行搜索時,除了找到原始圖像外,它還找到了一個匹配的眼鏡和另一幅畫。這展示了查詢圖像語義含義的不同方面。

3、結束語

在本教程中,我們使用 CLIP 和 FAISS 構建了一個基本的圖像相似性搜索引擎。檢索到的圖像與查詢具有相似的語義含義,表明該方法的有效性。

雖然 CLIP 對于零樣本模型顯示出不錯的結果,但它在分布外數據、細粒度任務上可能表現出較低的性能,并繼承了訓練數據的自然偏差。為了克服這些限制,你可以嘗試其他類似 CLIP 的預訓練模型(如 OpenClip),或者在自己的自定義數據集上微調 CLIP。

原文鏈接:http://www.bimant.com/blog/image-search-engine-diy/

上一篇:

WordPress REST API 初學者指南

下一篇:

如何使用谷歌地圖經緯度api(免費版)查詢地點定位?
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費