例を含む最終的な検索はここにあります。
次のようになります。
Google 画像検索と TinEye では良い結果が得られないため、OpenGameArt 用の逆画像検索を構築したいと思いました。以前、OpenGameArt で同様の画像の概要を表示するために巨大なタイル マップを生成しましたが、Web または画像ブラウザーではリソースにあまり優しくなく、より小さなファイルに分割する必要があり、さらに、検索することもできませんでした。スクロール可能。そこで私は、人々が 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 USD、私の記憶が正しければ 1,000 ~ 2,000 万回の関数呼び出しに相当します。
オープン ソースの Milvus データベースを使用しようとしましたが、DigitalOcean サーバーに十分なメモリがなかったため、データベースがクラッシュしました。その後、偶然かつ幸運にも Hacker News のコメント セクションで Pinecone へのリンクを発見し、試用版は無料で、Milvus を使用するためにサーバー メモリを拡張する必要がなかったため、代わりにそれを使用することにしました。結局、とにかくサーバーを拡張しましたが、Milvus を再度試すことはありませんでした (少なくともまだ)。
このためにスクリプトで VGG16 特徴抽出を使用しました。詳細については記事を参照してください。本質的には、各画像の 4096 個の 32 ビット浮動小数点数であり、画像のさまざまな特徴を記述します。たとえば、非常に単純化した方法で、ストライプや正方形の数、緑色の度合いなどを示します。 。ただし、これらの特徴は、VGG16 (通常は画像分類に使用される) のニューラル ネットワーク内のニューロンに基づいているため、特徴は単純な特徴タグで記述されるものよりも複雑になる可能性があります。これらのベクトルが必要な理由は、2 つのベクトルに対してユークリッド距離、コサイン類似度、または別の尺度を使用して、それらが類似しているかどうかを確認するのが簡単であり、その結果、画像が類似していることになります。さらに、これらのベクトルには検索技術があり、大量のベクトルを迅速に検索できます。
以下は、特徴抽出を行う方法を示す簡略化された 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) に追加されたかどうかを示すフラグを持ちたかったのです。 [Pinecone](https://www.pinecone.io/ には他のメタデータが保存されないため、Pineone で使用される整数の主キーと URL、およびおそらく画像に属するその他のメタデータ) の間で相互にマップします。最終的には、SQL データベースをタブ区切りのテキスト ファイルに変換し、クエリ サーバーの起動時にロードしました。
すべてのコードを実行して完了するまでに合計 1 週間を費やしたと思います。クロール、特徴ベクトルの計算など、各ステップに 1 ~ 2 日程度かかりました。ベクトルを松ぼっくりデータベースに挿入するのにどれくらい時間がかかったのか覚えていませんが、最も時間のかかるステップではなかったと思います。
最後に、同じスコアを持つ重複に近い画像結果を削除するための簡単な修正も追加しました。ファイル システムに URL エンコードを使用してファイルを保存したため、「二重」URL エンコードを使用した検索ページで問題が発生しましたが、ブラウザが二重エンコードした場合に備えてフロントエンドで検出コードを使用して問題を回避しました。 URL エンコードされたファイル名。クロールされたファイルは URL エンコードせずに保存することをお勧めします。私のスクリプトがそれほど高品質でも洗練されていないことを残念に思っています。たとえば、スクリプトには複数のステップがあり、コマンドライン引数を取得する代わりにスクリプトを編集することで変更を加えています。ちょっと面倒なので、スクリプトの抜粋を投稿して説明する気はありません。さらに、特徴抽出を処理する前に、途中でファイルを Azure ストレージから DigitalOcean サーバーに移動したため、データの場所の処理に一貫性がありません。