البحث من نص إلى صورة باستخدام ميلفوس
البحث من نص إلى صورة هي تقنية متقدمة تسمح للمستخدمين بالبحث عن الصور باستخدام أوصاف نصية بلغة طبيعية. وهي تستفيد من نموذج متعدد الوسائط تم تدريبه مسبقًا لتحويل كل من النص والصور إلى تضمينات في فضاء دلالي مشترك، مما يتيح إجراء مقارنات قائمة على التشابه.
في هذا البرنامج التعليمي، سنستكشف في هذا البرنامج التعليمي كيفية تنفيذ استرجاع الصور المستند إلى النص باستخدام نموذج CLIP (التدريب المسبق على اللغة المتباينة والصور) من OpenAI و Milvus. سنقوم بإنشاء تضمينات للصور باستخدام CLIP، وتخزينها في Milvus، وإجراء عمليات بحث فعالة عن التشابه.
المتطلبات الأساسية
قبل البدء، تأكد من أن جميع الحزم المطلوبة وبيانات الأمثلة جاهزة.
تثبيت التبعيات
- pymilvus>=2.4.2 للتفاعل مع قاعدة بيانات Milvus
- مقطع للعمل مع نموذج CLIP
- وسادة لمعالجة الصور وتصورها
$ pip install --upgrade pymilvus pillow
$ pip install git+https://github.com/openai/CLIP.git
إذا كنت تستخدم Google Colab، فقد تحتاج إلى إعادة تشغيل وقت التشغيل (انتقل إلى قائمة "وقت التشغيل" في أعلى الواجهة، وحدد "إعادة تشغيل الجلسة" من القائمة المنسدلة).
تنزيل مثال على البيانات
سنستخدم مجموعة فرعية من مجموعة بيانات ImageNet (100 فئة، 10 صور لكل فئة) كمثال على الصور. سيقوم الأمر التالي بتنزيل بيانات المثال واستخراجها إلى المجلد المحلي ./images_folder:
$ wget https://github.com/towhee-io/examples/releases/download/data/reverse_image_search.zip
$ unzip -q reverse_image_search.zip -d images_folder
إعداد ميلفوس
قبل المتابعة، قم بإعداد خادم Milvus والاتصال باستخدام URI الخاص بك (واختيارياً، رمز مميز):
ميلفوس لايت (موصى به للراحة): قم بتعيين URI إلى ملف محلي، مثل ./milvus.db. هذا يستفيد تلقائيًا من Milvus Lite لتخزين جميع البيانات في ملف واحد.
Docker أو Kubernetes (للبيانات كبيرة الحجم): للتعامل مع مجموعات بيانات أكبر، قم بنشر خادم Milvus أكثر أداءً باستخدام Docker أو Kubernetes. في هذه الحالة، استخدم URI الخادم، مثل http://localhost:19530، للاتصال.
زيليز كلاود (خدمة مُدارة): إذا كنت تستخدم Zilliz Cloud، خدمة Milvus السحابية المُدارة بالكامل، قم بتعيين نقطة النهاية العامة كـ URI ومفتاح API كرمز مميز.
from pymilvus import MilvusClient
milvus_client = MilvusClient(uri="milvus.db")
الشروع في العمل
الآن بعد أن أصبح لديك التبعيات والبيانات اللازمة، حان الوقت لإعداد مستخرجات الميزات وبدء العمل مع ميلفوس. سيرشدك هذا القسم إلى الخطوات الرئيسية لبناء نظام بحث من نص إلى صورة. أخيرًا، سنشرح كيفية استرداد الصور وتصورها بناءً على استعلامات نصية.
تحديد مستخرجات الميزات
سنستخدم نموذج CLIP المدرّب مسبقًا لإنشاء تضمينات الصور والنصوص. في هذا القسم، سنقوم بتحميل متغير ViT-B/32 المدرب مسبقًا من CLIP وتعريف الدوال المساعدة لترميز الصور والنصوص:
encode_image(image_path): معالجة الصور وترميزها إلى متجهات ميزاتencode_text(text): ترميز الاستعلامات النصية إلى متجهات ميزات
تعمل كلتا الدالتين على تطبيع ميزات الإخراج لضمان اتساق المقارنات من خلال تحويل المتجهات إلى وحدة الطول، وهو أمر ضروري لحسابات دقيقة لتشابه جيب التمام.
import clip
from PIL import Image
# Load CLIP model
model_name = "ViT-B/32"
model, preprocess = clip.load(model_name)
model.eval()
# Define a function to encode images
def encode_image(image_path):
image = preprocess(Image.open(image_path)).unsqueeze(0)
image_features = model.encode_image(image)
image_features /= image_features.norm(
dim=-1, keepdim=True
) # Normalize the image features
return image_features.squeeze().tolist()
# Define a function to encode text
def encode_text(text):
text_tokens = clip.tokenize(text)
text_features = model.encode_text(text_tokens)
text_features /= text_features.norm(
dim=-1, keepdim=True
) # Normalize the text features
return text_features.squeeze().tolist()
استيعاب البيانات
لتمكين البحث الدلالي عن الصور، نحتاج أولاً إلى إنشاء تضمينات لجميع الصور وتخزينها في قاعدة بيانات متجهة للفهرسة والاسترجاع بكفاءة. يقدّم هذا القسم دليلًا تفصيليًا لإدخال بيانات الصور في ملفوس.
1. إنشاء مجموعة ميلفوس
قبل تخزين تضمينات الصور، تحتاج إلى إنشاء مجموعة ميلفوس. يوضح الرمز التالي كيفية إنشاء مجموعة في وضع الإعداد السريع بنوع مقياس كوسين الافتراضي. تتضمن المجموعة الحقول التالية:
id: حقل أساسي مع تمكين المعرف التلقائي.vector: حقل لتخزين التضمينات المتجهة ذات الفاصلة العائمة.
إذا كنت بحاجة إلى مخطط مخصص، فارجع إلى وثائق ميلفوس للحصول على تعليمات مفصلة.
collection_name = "image_collection"
# Drop the collection if it already exists
if milvus_client.has_collection(collection_name):
milvus_client.drop_collection(collection_name)
# Create a new collection in quickstart mode
milvus_client.create_collection(
collection_name=collection_name,
dimension=512, # this should match the dimension of the image embedding
auto_id=True, # auto generate id and store in the id field
enable_dynamic_field=True, # enable dynamic field for scalar fields
)
2. إدراج البيانات في ملفوس
في هذه الخطوة، نستخدم أداة تشفير صور محددة مسبقًا لإنشاء تضمينات لجميع صور JPEG في دليل بيانات المثال. يتم بعد ذلك إدراج هذه التضمينات في مجموعة Milvus، إلى جانب مسارات الملفات المقابلة لها. يتكون كل إدخال في المجموعة من:
- متجه التضمين: التمثيل العددي للصورة. يتم تخزينه في الحقل
vector. - مسار الملف: موقع ملف الصورة للرجوع إليه. مخزن في الحقل
filepathكحقل ديناميكي.
import os
from glob import glob
image_dir = "./images_folder/train"
raw_data = []
for image_path in glob(os.path.join(image_dir, "**/*.JPEG")):
image_embedding = encode_image(image_path)
image_dict = {"vector": image_embedding, "filepath": image_path}
raw_data.append(image_dict)
insert_result = milvus_client.insert(collection_name=collection_name, data=raw_data)
print("Inserted", insert_result["insert_count"], "images into Milvus.")
Inserted 1000 images into Milvus.
إجراء بحث
الآن، دعنا نجري بحثًا باستخدام مثال استعلام نصي. سيؤدي ذلك إلى استرداد الصور الأكثر صلة بناءً على تشابهها الدلالي مع الوصف النصي المحدد.
query_text = "a white dog"
query_embedding = encode_text(query_text)
search_results = milvus_client.search(
collection_name=collection_name,
data=[query_embedding],
limit=10, # return top 10 results
output_fields=["filepath"], # return the filepath field
)
عرض النتائج:
from IPython.display import display
width = 150 * 5
height = 150 * 2
concatenated_image = Image.new("RGB", (width, height))
result_images = []
for result in search_results:
for hit in result:
filename = hit["entity"]["filepath"]
img = Image.open(filename)
img = img.resize((150, 150))
result_images.append(img)
for idx, img in enumerate(result_images):
x = idx % 5
y = idx // 5
concatenated_image.paste(img, (x * 150, y * 150))
print(f"Query text: {query_text}")
print("\nSearch results:")
display(concatenated_image)
Query text: a white dog
Search results:
png