يمكن العثور على البحث النهائي مع مثال هنا.
يبدو مثل هذا:
كنت أرغب في إنشاء بحث عكسي عن الصور لـ OpenGameArt حيث أن Google Image Search وTinEye لا يعطيان نتائج جيدة لذلك. لقد قمت سابقًا بإنشاء خريطة مربعة ضخمة لتقديم نظرة عامة على الصور المشابهة على OpenGameArt، لكنها لم تكن صديقة للموارد على الويب أو متصفح الصور وكان لا بد من تقسيمها إلى ملفات أصغر، بالإضافة إلى أنها غير قابلة للبحث بأي شكل من الأشكال، فقط قابل للتمرير. لذا أردت طريقة ليستكشف بها الأشخاص نوع الفن المتوفر على OpenGameArt، وتوصلت إلى استخدام بحث التشابه لتصفح مساحة الصورة.
أول شيء كان علي فعله هو استرداد نتائج البحث الخاصة بالاستعلام الذي كنت مهتمًا به على OpenGameArt، ومعظمها من الفن ثنائي الأبعاد. ثم اضطررت إلى استرداد كل صفحة 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 للقيام بخطوات الزحف، مع بعض التدخل اليدوي ذهابًا وإيابًا لتصحيح الأمور حسب الحاجة. كان لكل خطوة قائمة انتظار خاصة بها ثم قم بوضع المهمة للخطوة التالية في قائمة الانتظار التالية. في النهاية، تكلف الاستدعاءات حوالي 50 دولارًا أمريكيًا على Azure، لنفترض أنها تتراوح بين 10 إلى 20 مليون استدعاء وظيفي إذا كنت أتذكر بشكل صحيح.
لقد حاولت استخدام قاعدة بيانات Milvus مفتوحة المصدر، لكنها تعطلت على خادم DigitalOcean الخاص بي لأنه لم يكن لدي ذاكرة كافية عليها. ثم اكتشفت بالصدفة ولحسن الحظ الرابط إلى Pinecone في قسم تعليقات Hacker News وقررت استخدام ذلك بدلاً من ذلك، حيث كانت النسخة التجريبية مجانية ولم أضطر إلى توسيع ذاكرة الخادم الخاص بي لاستخدام Milvus. في النهاية، قمت بتوسيع الخادم الخاص بي على أية حال، لكنني لم أحاول استخدام Milvus مرة أخرى (على الأقل ليس بعد).
لقد استخدمت استخراج ميزة VGG16 في البرنامج النصي الخاص بي لهذا الغرض. راجع المقالة لمزيد من المعلومات، ولكن في جوهرها، هناك 4096 رقمًا عائمًا 32 بت لكل صورة، والتي تصف الميزات المختلفة للصورة، على سبيل المثال، بطريقة مبسطة للغاية، عدد الخطوط أو المربعات التي تحتوي عليها أو مدى لونها الأخضر . لكن هذه الميزات تعتمد على الخلايا العصبية الموجودة في الشبكة العصبية لـ VGG16 (والتي تُستخدم عادةً لتصنيف الصور)، لذا قد تكون الميزات أكثر تعقيدًا مما يتم وصفه بعلامات الميزات البسيطة. والسبب وراء حاجتنا إلى هذه المتجهات هو أنه من السهل استخدام المسافة الإقليدية أو تشابه جيب التمام أو مقياس آخر على متجهين لمعرفة ما إذا كانا متشابهين، وبالتالي تكون الصور متشابهة. علاوة على ذلك، توجد تقنية بحث على هذه المتجهات تتيح البحث السريع عن كمية كبيرة منها.
فيما يلي نص برمجي مبسط لبايثون لإظهار كيفية القيام باستخراج الميزات:
#!/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 في ملف نصي مفصول بعلامة تبويب وقمت بتحميلها عند بدء تشغيل خادم الاستعلام.
أعتقد أنني قضيت أسبوعًا إجمالاً لتشغيل جميع التعليمات البرمجية حتى النهاية، حيث تستغرق كل خطوة يومًا أو يومين، والزحف، ومتجهات ميزات الحوسبة. لا أتذكر مقدار الوقت الذي استغرقه إدراج المتجهات في قاعدة بيانات Pinecone، لكنني أعتقد أنها لم تكن الخطوة الأكثر استهلاكًا للوقت.
وفي النهاية أضفت أيضًا حلاً سريعًا لإزالة نتائج الصور شبه المكررة والتي كانت لها نفس النتيجة. لقد واجهت بعض المشاكل في صفحة البحث مع ترميز عنوان URL "المزدوج"، لأنني قمت بتخزين الملفات باستخدام ترميز عنوان URL في نظام الملفات، لكنني تعاملت مع بعض رموز الكشف على الواجهة الأمامية عندما يقوم المتصفح بترميز مزدوج لـ أسماء الملفات المشفرة بعنوان URL. أوصي بتخزين الملفات التي تم الزحف إليها بدون تشفير URL. يؤسفني أن البرامج النصية الخاصة بي ليست ذات جودة عالية أو مصقولة، على سبيل المثال هناك خطوات متعددة في البرامج النصية وأقوم بتغيير الأشياء عن طريق تحرير البرنامج النصي بدلاً من استخدام وسيطات سطر الأوامر. لا أرغب في نشر مقتطفات من النصوص والشرح لأنها فوضوية بعض الشيء. بالإضافة إلى ذلك، قمت بنقل الملفات من وحدة تخزين Azure إلى خادم DigitalOcean الخاص بي في منتصف الطريق، قبل معالجة استخراج الميزات، لذلك هناك بعض التعامل غير المتسق مع موقع البيانات.