Vector Databases

FAISS على GPU: تحسين فهرسة وزمن الاستجابة للبحث في عناقيد التضمين واسعة النطاق

مع تزايد حجم البيانات غير المهيكلة، تزداد تعقيدات البحث عن التشابه المتجهي. بالنسبة للعديد من المطورين، يمثل الانتقال من الحلول المعتمدة على المعالج (CPU) إلى الحلول المعززة بالبطاقة الرسومية (GPU) مثل Facebook AI Similarity Search (FAISS) الخطوة الحاسمة نحو توسيع نطاق قواعد البيانات المتجهية. ومع ذلك، مجرد نقل البيانات إلى GPU لا يكفي؛ فبدون ضبط دقيق لاستراتيجيات الفهرسة وإدارة الذاكرة، قد تواجه عنق زجاجة يلغي مزايا العتاد.

في هذا الدليل، سنستكشف كيفية تحسين FAISS على GPU لكل من سرعة الفهرسة وزمن الاستجابة للبحث، مع التركيز بشكل خاص على عناقيد التضمين واسعة النطاق التي تحتوي على ملايين المتجهات.

فهم بنية الفهرس المعزز بالبطاقة الرسومية

توفر FAISS عدة أنواع من الفهارس المحسنة لتلبية قيود العتاد المختلفة. على GPU، أكثر البنى شيوعاً هي IndexFlatGPU للبحث الدقيق بالقوة الغاشمة (brute-force) و IndexIVFPQ (ملف معكوس مع التكميم المنتج) للبحث عن أقرب جار تقريبي (ANN). بينما يضمن البحث الدقيق الدقة، إلا أنه يتوسع خطياً مع حجم مجموعة البيانات، مما يجعله غير عملي لملايين المتجهات. من ناحية أخرى، تتنازل فهارس ANN عن قدر ضئيل من الاستدعاء (recall) مقابل مكاسب كبيرة في زمن الاستجابة وكفاءة استخدام الذاكرة.

تهيئة موارد GPU

قبل إنشاء الفهرس، يجب عليك تخصيص موارد GPU بشكل صريح. يضمن هذا أن يكون لدى FAISS وصولاً إلى سياق CUDA الصحيح وحدود الذاكرة.


import faiss
import numpy as np

# تهيئة مدير موارد GPU
res = faiss.StandardGpuResources()

# مثال على مجموعة البيانات: مليون متجه بعدد أبعاد 384
d = 384
n = 1_000_000
np.random.seed(1234)
xb = np.random.random((n, d)).astype('float32')
faiss.normalize_L2(xb) # تطبيع المتجهات للتشابه الجيب التمامي

تحسين إنشاء الفهرس

عند بناء فهرس IVFPQ على GPU، يُعد عدد العناقيد (nlist) معياراً فائقاً حاسماً. قاعدة إبهام شائعة هي ضبط nlist على ما يقرب من الجذر التربيعي لعدد المتجهات، على الرغم من أنه يجب ضبطه بناءً على متطلبات الاستدعاء الخاصة بك.


# إنشاء فهرس IVFPQ
nlist = 1024
pq = faiss.ProductQuantizer(d, 64, 8) # 64 متجراً فرعياً، 8 بت لكل منها
index = faiss.IndexIVFPQ(res, d, nlist, pq)

# إضافة بيانات التدريب لبناء التجميع
index.train(xb)
index.add(xb)

# نسخ الفهرس إلى GPU
index_gpu = faiss.index_cpu_to_gpu(res, 0, index)

ضبط زمن الاستجابة للبحث

بمجرد وضع الفهرس على GPU، يتأثر أداء البحث بشكل كبير بعدد الاستكشافات (nprobe). زيادة nprobe تحسن الاستدعاء لكنها تزيد من زمن الاستجابة. للبيئات الإنتاجية، يجب عليك إجراء ملف أداء (profile) لهذا المعيار للعثور على النقطة المثلى حيث يتم الوفاء باتفاق مستوى الخدمة (SLA) الخاص بزمن الاستجابة مع استيفاء متطلبات الاستدعاء المقبولة.


# تعيين عدد الاستكشافات للبحث
index_gpu.nprobe = 32

# إجراء البحث عن 10 جيران أقرب لـ 100 استعلام
xq = np.random.random((100, d)).astype('float32')
faiss.normalize_L2(xq)

D, I = index_gpu.search(xq, 10)
print(f"اكتمل البحث. الجار الأول للاستعلام 0: {I[0]}")

أفضل الممارسات للعناقيد واسعة النطاق

  • المعالجة الدفعية (Batching): قم دائماً بمعالجة المتجهات على دفعات لتجنب تجاوز سعة الذاكرة. يكون FAISS على GPU أكثر كفاءة عندما تكون الدفعات كبيرة بما يكفي لاستغلال التوازي في GPU، وصغيرة بما يكفي لتناسب ذاكرة VRAM.
  • تعيين الذاكرة (Memory Mapping): بالنسبة للفهارس التي تكون كبيرة جداً لذاكرة GPU، فكر في استخدام ميزات FAISS الهجينة بين CPU و GPU، أو نقل البيانات غير النشطة (non-hot) إلى ذاكرة RAM الخاصة بالمعالج باستخدام IndexIVFScalarQuantizer.
  • الدقة: تأكد من أن بيانات الإدخال لديك بدقة float32. التحويل بين float64 و float32 يضيف حملاً زائداً غير ضروري أثناء مرحلة البحث.

الخاتمة

يمكن لاستغلال FAISS على GPU أن يحول بنية البحث المتجهي لديك من عنق زجاجة إلى محرك عالي الأداء. من خلال اختيار نوع الفهرس المناسب بعناية، وضبط معايير العناقيد، وإدارة موارد الذاكرة، يمكنك تحقيق أزمنة استجابة أقل من الميلي ثانية حتى مع مجموعات البيانات الضخمة. ومع تحول البحث المتجهي ليصبح محورياً في تطبيقات الذكاء الاصطناعي، فإن إتقان هذه التحسينات أمر ضروري لبناء أنظمة قابلة للتوسع وسريعة الاستجابة.

Share: