예시가 포함된 최종 검색은 여기에서 확인할 수 있습니다.
다음과 같습니다.
Google 이미지 검색과 TinEye가 좋은 결과를 제공하지 않기 때문에 OpenGameArt에 대한 역방향 이미지 검색을 구축하고 싶었습니다. 이전에 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 USD입니다. 제 기억이 맞다면 함수 호출이 1,000만~2,000만 번이라고 가정하겠습니다.
오픈 소스 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)에 추가했는지 여부에 대한 플래그를 갖고 싶었습니다. Pineone에서 사용되는 정수 기본 키와 URL 및 이미지에 속하는 다른 메타데이터 사이를 앞뒤로 매핑합니다. [Pinecone](https://www.pinecone.io/는 다른 메타데이터를 저장하지 않기 때문입니다. 기본보다 결국 SQL 데이터베이스를 탭으로 구분된 텍스트 파일로 만들고 쿼리 서버 시작 시 로드했습니다.
모든 코드를 실행하여 완료하는 데 총 일주일이 걸린 것 같습니다. 각 단계는 하루나 이틀 정도 걸리고 크롤링하고 특징 벡터를 계산합니다. 솔방울 데이터베이스에 벡터를 삽입하는 데 얼마나 시간이 걸렸는지 기억나지 않지만, 가장 시간이 많이 걸리는 단계는 아니었던 것 같습니다.
마지막에는 동일한 점수를 가진 거의 중복된 이미지 결과를 제거하는 빠른 수정 사항도 추가했습니다. 파일 시스템에서 URL 인코딩을 사용하여 파일을 저장했기 때문에 "이중" URL 인코딩을 사용하는 검색 페이지에서 몇 가지 문제에 부딪혔지만 브라우저가 URL로 인코딩된 파일 이름. URL 인코딩 없이 크롤링된 파일을 저장하는 것이 좋습니다. 내 스크립트의 품질이 그리 높지 않거나 세련되지 않은 점을 유감스럽게 생각합니다. 예를 들어 스크립트에는 여러 단계가 있고 명령줄 인수를 사용하는 대신 스크립트를 편집하여 내용을 변경합니다. 나는 스크립트의 일부를 게시하고 약간 지저분하기 때문에 설명하고 싶지 않습니다. 또한 기능 추출을 처리하기 전에 중간에 Azure 저장소에서 DigitalOcean 서버로 파일을 이동했기 때문에 데이터 위치 처리가 일관되지 않았습니다.