可以在此處找到帶有範例的最終搜尋。
它看起來像這樣:
我想為 OpenGameArt 建立一個反向圖像搜索,因為 Google 圖像搜索和 TinEye 沒有給出好的結果。我之前生成了一個巨大的圖塊地圖來概述 OpenGameArt 上的類似圖像,但它在網絡或圖像瀏覽器上的資源不是很友好,必須分成更小的文件,而且它無法以任何方式搜索,只是可滾動。因此,我想要一種方式讓人們探索 OpenGameArt 上提供了哪些類型的藝術,並最終使用相似性搜尋來瀏覽圖像空間。
我要做的第一件事是在 OpenGameArt 上檢索我感興趣的查詢的搜尋結果,主要是 2D 藝術。然後我必須檢索搜尋結果索引中的每個 HTML 頁面並解析 HTML 以獲取文件連結。 OpenGameArt 包含許多存檔文件,例如 zip 和 rar 文件,因此我必須解壓縮它們才能獲取映像。
例如,下面的程式碼片段顯示如何解析內容頁面並取得文件連結:
responseBody = await Common . ReadURIOrCache ( blob , Common . BaseURI + page , client ) ;
var htmlDoc = new HtmlDocument ( ) ;
htmlDoc . LoadHtml ( responseBody ) ;
var htmlBody = htmlDoc . DocumentNode . SelectSingleNode ( " //body " ) ;
foreach ( var nNode in htmlBody . Descendants ( " a " ) )
{
if ( nNode . NodeType == HtmlNodeType . Element &&
nNode . Attributes [ " href " ] != null &&
nNode . Attributes [ " href " ] . Value . Contains ( " /default/files/ " ) )
{
msg . Add ( HttpUtility . HtmlDecode ( nNode . Attributes [ " href " ] . Value . Replace ( Common . FileURI , " " ) ) ) ;
}
}
我使用 Azure Functions 執行爬網步驟,並根據需要進行一些來回手動幹預來糾正問題。每個步驟都有自己的佇列,然後將下一步的作業放入下一個佇列中。最終,Azure 上的呼叫成本約為 50 美元,如果我沒記錯的話,假設有 1000-2000 萬次函數呼叫。
我嘗試使用開源 Milvus 資料庫,但它在我的 DigitalOcean 伺服器上崩潰了,因為我沒有足夠的記憶體。然後,我偶然且幸運地在 Hacker News 評論部分發現了 Pinecone 的鏈接,並決定使用它,因為試用是免費的,而且我無需擴展服務器內存即可使用 Milvus。最終我還是擴展了我的伺服器,但我沒有再嘗試 Milvus(至少現在還沒有)。
為此,我在腳本中使用了 VGG16 特徵提取。有關更多信息,請參閱該文章,但本質上,每個圖像都是4096 個32 位浮點數,它們描述了圖像的各種特徵,例如以非常簡單的方式表示它有多少條紋或正方形,或者它的綠色程度。但這些特徵是基於VGG16神經網路中的神經元(通常用於影像分類),因此這些特徵可能比簡單特徵標籤描述的更複雜。我們需要這些向量的原因是,可以輕鬆使用歐幾里德距離或餘弦相似度或兩個向量的其他度量來查看它們是否相似,從而得出圖像相似。此外,還有針對這些向量的搜尋技術,可以對大量向量進行快速搜尋。
下面是一個簡化的 Python 腳本,用於展示如何進行特徵提取:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim: ft=python ts=4 sw=4 sts=4 et fenc=utf-8
from tensorflow . keras . applications . vgg16 import VGG16
from tensorflow . keras . preprocessing import image
from tensorflow . keras . applications . vgg16 import decode_predictions , preprocess_input
from tensorflow . keras . models import Model
from tensorflow . compiler import xla
import numpy as np
import time
import os
import sys
import PIL
import json
import math
import multiprocessing
from glob import glob
from PIL import Image
from io import BytesIO
model = VGG16 ( weights = 'imagenet' , include_top = True )
feat_extractor = Model ( inputs = model . input , outputs = model . get_layer ( "fc2" ). output )
def prepImage ( img ):
x = np . array ( img . resize (( 224 , 224 )). convert ( 'RGB' ))
x = np . expand_dims ( x , axis = 0 )
x = preprocess_input ( x )
return x
def main ():
'entry point'
fname = 'demo.jpg'
dt = Image . open ( fname )
pimg = prepImage ( dt )
print ( "Computing feature vector" , fname )
features = feat_extractor . predict ( pimg )
print ( features )
if __name__ == '__main__' :
main ()
這是腳本的輸出:
emh@frostpunk ~ /public_html/ogasearch 0% ./test.py (git)-[gh-pages]
2021-04-07 18:48:03.158023: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library ' libcudart.so.11.0 ' ; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory
2021-04-07 18:48:03.158082: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
2021-04-07 18:48:07.783109: I tensorflow/compiler/jit/xla_cpu_device.cc:41] Not creating XLA devices, tf_xla_enable_xla_devices not set
2021-04-07 18:48:07.783485: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library ' libcuda.so.1 ' ; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
2021-04-07 18:48:07.783530: W tensorflow/stream_executor/cuda/cuda_driver.cc:326] failed call to cuInit: UNKNOWN ERROR (303)
2021-04-07 18:48:07.783580: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (frostpunk): /proc/driver/nvidia/version does not exist
2021-04-07 18:48:07.784058: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-04-07 18:48:07.784513: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set
2021-04-07 18:48:08.599925: W tensorflow/core/framework/cpu_allocator_impl.cc:80] Allocation of 411041792 exceeds 10% of free system memory.
2021-04-07 18:48:09.194634: W tensorflow/core/framework/cpu_allocator_impl.cc:80] Allocation of 411041792 exceeds 10% of free system memory.
2021-04-07 18:48:09.385612: W tensorflow/core/framework/cpu_allocator_impl.cc:80] Allocation of 411041792 exceeds 10% of free system memory.
2021-04-07 18:48:13.033066: W tensorflow/core/framework/cpu_allocator_impl.cc:80] Allocation of 411041792 exceeds 10% of free system memory.
Computing feature vector demo.jpg
2021-04-07 18:48:13.706621: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:116] None of the MLIR optimization passes are enabled (registered 2)
2021-04-07 18:48:13.717564: I tensorflow/core/platform/profile_utils/cpu_utils.cc:112] CPU Frequency: 2199995000 Hz
[[0. 3.1128967 1.5611947 ... 1.2625191 0.7709812 0. ]]
./test.py 12.20s user 4.66s system 132% cpu 12.731 total
我還想最後將所有圖像 URL 放入 SQL 資料庫中,並有一個標誌來指示我是否進行了 VGG16 特徵提取以及是否將其添加到向量資料庫(Milvus 或 Pinecone)中。主鍵和URL 以及可能屬於圖像的其他元資料之間來回映射,因為[Pinecone](https://www.pinecone.io/ 不存儲其他元資料最後,我將SQL 資料庫簡化為製表符分隔的文本文件,並在查詢伺服器啟動時加載它。
我想我總共花了一周的時間來運行所有程式碼來完成,每個步驟大約需要一兩天的時間,爬行,計算特徵向量。我不記得將向量插入 Pinecone 資料庫花了多少時間,但我認為這不是最耗時的步驟。
最後,我還添加了一個快速修復,以刪除具有相同分數的幾乎重複的圖像結果。我在使用「雙重」URL 編碼的搜尋頁面上遇到了一些麻煩,因為我在文件系統中使用URL 編碼儲存了文件,但是當瀏覽器對文件進行雙重編碼時,我在前端使用一些檢測代碼解決了這個問題。我建議儲存爬取的檔案而不進行 URL 編碼。我很遺憾我的腳本品質不夠高或不夠精緻,例如腳本中有多個步驟,我透過編輯腳本而不是採用命令列參數來更改內容。我不想發布腳本片段並進行解釋,因為它們有點混亂。此外,在處理特徵提取之前,我中途將檔案從 Azure 儲存體移至了 DigitalOcean 伺服器,因此存在一些不一致的資料位置處理。