البحث عن الصور باستخدام ميلفوس
في هذا الدفتر، سنوضح لك كيفية استخدام Milvus للبحث عن صور متشابهة في مجموعة بيانات. سوف نستخدم مجموعة فرعية من مجموعة بيانات ImageNet، ثم نبحث عن صورة كلب صيد أفغاني لتوضيح ذلك.
إعداد مجموعة البيانات
أولاً، نحتاج أولاً إلى تحميل مجموعة البيانات وإلغاء استخراجها لمزيد من المعالجة.
!wget https://github.com/milvus-io/pymilvus-assets/releases/download/imagedata/reverse_image_search.zip
!unzip -q -o reverse_image_search.zip
المتطلبات الأساسية
لتشغيل هذا الدفتر، تحتاج إلى تثبيت التبعيات التالية:
- pymilvus>=2.4.2
- تيم
- الشعلة
- numpy
- سكليرن
- الوسادة
لتشغيل Colab، نقدم الأوامر المفيدة لتثبيت التبعيات اللازمة.
$ pip install pymilvus --upgrade
$ pip install timm
إذا كنت تستخدم Google Colab، لتمكين التبعيات المثبتة للتو، قد تحتاج إلى إعادة تشغيل وقت التشغيل. (انقر على قائمة "وقت التشغيل" في أعلى الشاشة، وحدد "إعادة تشغيل الجلسة" من القائمة المنسدلة).
تعريف مستخرج الميزات
بعد ذلك، نحن بحاجة إلى تحديد مستخرج الميزة الذي يستخرج التضمين من صورة باستخدام نموذج "ريسنت-34" الخاص بـ timm.
import torch
from PIL import Image
import timm
from sklearn.preprocessing import normalize
from timm.data import resolve_data_config
from timm.data.transforms_factory import create_transform
class FeatureExtractor:
def __init__(self, modelname):
# Load the pre-trained model
self.model = timm.create_model(
modelname, pretrained=True, num_classes=0, global_pool="avg"
)
self.model.eval()
# Get the input size required by the model
self.input_size = self.model.default_cfg["input_size"]
config = resolve_data_config({}, model=modelname)
# Get the preprocessing function provided by TIMM for the model
self.preprocess = create_transform(**config)
def __call__(self, imagepath):
# Preprocess the input image
input_image = Image.open(imagepath).convert("RGB") # Convert to RGB if needed
input_image = self.preprocess(input_image)
# Convert the image to a PyTorch tensor and add a batch dimension
input_tensor = input_image.unsqueeze(0)
# Perform inference
with torch.no_grad():
output = self.model(input_tensor)
# Extract the feature vector
feature_vector = output.squeeze().numpy()
return normalize(feature_vector.reshape(1, -1), norm="l2").flatten()
إنشاء مجموعة ميلفوس
ثم نحتاج بعد ذلك إلى إنشاء مجموعة Milvus لتخزين تضمينات الصورة
from pymilvus import MilvusClient
# Set up a Milvus client
client = MilvusClient(uri="example.db")
# Create a collection in quick setup mode
if client.has_collection(collection_name="image_embeddings"):
client.drop_collection(collection_name="image_embeddings")
client.create_collection(
collection_name="image_embeddings",
vector_field_name="vector",
dimension=512,
auto_id=True,
enable_dynamic_field=True,
metric_type="COSINE",
)
بالنسبة لحجة MilvusClient
:
- يعد تعيين
uri
كملف محلي، على سبيل المثال./milvus.db
، هو الطريقة الأكثر ملاءمة، حيث يستخدم تلقائيًا Milvus Lite لتخزين جميع البيانات في هذا الملف. - إذا كان لديك حجم كبير من البيانات، يمكنك إعداد خادم Milvus أكثر أداءً على docker أو kubernetes. في هذا الإعداد، يُرجى استخدام الخادم uri، على سبيل المثال
http://localhost:19530
، كـuri
. - إذا كنت ترغب في استخدام Zilliz Cloud، الخدمة السحابية المدارة بالكامل لـ Milvus، اضبط
uri
وtoken
، والتي تتوافق مع نقطة النهاية العامة ومفتاح Api في Zilliz Cloud.
إدراج التضمينات في ميلفوس
سنقوم باستخراج تضمينات كل صورة باستخدام نموذج ResNet34 وإدراج الصور من مجموعة التدريب في Milvus.
import os
extractor = FeatureExtractor("resnet34")
root = "./train"
insert = True
if insert is True:
for dirpath, foldername, filenames in os.walk(root):
for filename in filenames:
if filename.endswith(".JPEG"):
filepath = dirpath + "/" + filename
image_embedding = extractor(filepath)
client.insert(
"image_embeddings",
{"vector": image_embedding, "filename": filepath},
)
from IPython.display import display
query_image = "./test/Afghan_hound/n02088094_4261.JPEG"
results = client.search(
"image_embeddings",
data=[extractor(query_image)],
output_fields=["filename"],
search_params={"metric_type": "COSINE"},
)
images = []
for result in results:
for hit in result[:10]:
filename = hit["entity"]["filename"]
img = Image.open(filename)
img = img.resize((150, 150))
images.append(img)
width = 150 * 5
height = 150 * 2
concatenated_image = Image.new("RGB", (width, height))
for idx, img in enumerate(images):
x = idx % 5
y = idx // 5
concatenated_image.paste(img, (x * 150, y * 150))
display("query")
display(Image.open(query_image).resize((150, 150)))
display("results")
display(concatenated_image)
'query'
png
'results'
النتائج
يمكننا أن نرى أن معظم الصور من نفس فئة صورة البحث، وهي صورة كلب الصيد الأفغاني. هذا يعني أننا وجدنا صوراً مشابهة لصورة البحث.
النشر السريع
لمعرفة كيفية بدء عرض توضيحي عبر الإنترنت باستخدام هذا البرنامج التعليمي، يرجى الرجوع إلى مثال التطبيق.