در عصر هوش مصنوعی مولد و جستجوی معنایی، توانایی بازیابی کارآمد امبدینگهای مرتبط از مجموعههای داده عظیم حیاتی است. اگرچه نمایشهای برداری متراکم در پردازش زبان طبیعی (NLP) و بینایی ماشین استاندارد شدهاند، اما مقیاسپذیری این سیستمها به میلیاردها بردار، چالشهای قابل توجهی در زمینه تأخیر (Latency) و مصرف حافظه ایجاد میکند. FAISS (جستجوی شباهت هوش مصنوعی فیسبوک) همچنان کتابخانه مورد علاقه برای این کار است، اما جستجوی ساده و خام (Brute-force) به صورت پیشفرض اغلب برای برنامههای کاربردی در سطح تولید کافی نیست. این پست به بررسی سه استراتژی متمایز برای بهینهسازی بازیابی میپردازد: شاخصهای فایل معکوس (IVF)، گرافهای جهان کوچک ناوبری سلسلهمراتبی (HNSW) و راهحلهای ذخیرهسازی مبتنی بر DiskANN.
درک مبادلات عملکردی
قبل از ورود به جزئیات پیادهسازی، درک این نکته حیاتی است که بهینهسازی جستجوی برداری یک عملیات تعادلی بین دقت بازیابی (Recall)، تأخیر (Latency) و مصرف حافظه است. جستجوی ساده و خام دقت بازیابی ۱۰۰٪ را تضمین میکند، اما با اندازه مجموعه داده به صورت خطی مقیاس میشود ($O(N)$) که آن را برای سیستمهای مقیاس بزرگ غیرعملی میسازد. تکنیکهای شاخصگذاری، جستجوی همسایه نزدیک تقریبی (ANN) را برای دستیابی به پیچیدگی لگاریتمی انجام میدهند و درصد کمی از دقت بازیابی را فدا میکنند تا سودهای عظیمی در سرعت به دست آورند.
استراتژی ۱: IVF (شاخص فایل معکوس) برای کارایی حافظه
شاخص IVF فضای برداری را به $k$ خوشه با استفاده از الگوریتم k-means تقسیم میکند. در مرحله شاخصگذاری، هر بردار به نزدیکترین مرکز خوشه اختصاص داده میشود. در زمان جستجو، تنها نزدیکترین مراکز به بردار پرسوجو بررسی میشوند. این کار فضای جستجو را از $N$ به $N/k$ کاهش میدهد و بازیابی را به طور قابل توجهی تسریع میکند.
IVF در مقایسه با روشهای مبتنی بر گراف، از نظر مصرف حافظه بسیار کارآمدتر است و عملکرد قابل پیشبینیتری ارائه میدهد، هرچند که نیاز به تنظیم دقیق پارامترهای تعداد خوشهها ($nlist$) و پروبها ($nprobe$) دارد.
import faiss
import numpy as np
# ایجاد یک شاخص تخت برای مقایسه (نیروی خام)
d = 128 # ابعاد بردار
nlist = 100 # تعداد خوشهها
k = 5 # تعداد همسایگان نزدیک
# راهاندازی شاخص IVF
quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
# آموزش روی زیرمجموعهای از دادهها
train_data = np.random.random((10000, d)).astype('float32')
index.train(train_data)
# افزودن بردارها
index.add(train_data)
# جستجو با پروبهای کنترل شده
nprobe = 10 # تعداد خوشههایی که باید جستجو شوند
index.nprobe = nprobe
استراتژی ۲: HNSW برای تأخیر فوقالعاده کم
برای سناریوهایی که تأخیر زیر میلیثانیه حیاتی است، مانند موتورهای توصیهگر در زمان واقعی، HNSW اغلب گزینه برتری است. HNSW یک ساختار گراف چندلایه را میسازد که در آن گرهها نماینده بردارها هستند. لایههای بالا یک "بزرگراه" برای ناوبری در فواصل طولانی فراهم میکنند، در حالی که لایههای پایینتر جستجو را به صورت محلی پالایش میکنند.
مزیت اصلی HNSW، دقت بازیابی بالا در تأخیر کم است. با این حال، این روش به دلیل ذخیرهسازی اتصالات گراف، ردپای حافظه بیشتری دارد و در مرحله ساخت شاخص از نظر محاسباتی پرهزینهتر است.
# توجه: پیادهسازی HNSW در FAISS در نسخههای اخیر
# یا از طریق بسته faiss.contrib در دسترس است
# ساخت شاخص HNSW
M = 16 # تعداد اتصالات دوطرفه ایجاد شده برای هر عنصر جدید
maxM = 16
efConstruction = 200 # پارامتر کیفیت
index_hnsw = faiss.IndexHNSWFlat(d, M, faiss.METRIC_L2)
index_hnsw.hnsw.efConstruction = efConstruction
index_hnsw.hnsw.M = M
# ساخت شاخص (میتواند برای مجموعههای داده بزرگ کند باشد)
index_hnsw.add(train_data)
# پیکربندی پرسوجو
ef_search = 50 # اندازه لیست پویا برای جستجو
index_hnsw.hnsw.efSearch = ef_search
استراتژی ۳: DiskANN برای مقیاس میلیاردی
وقتی اندازه مجموعههای داده از RAM موجود فراتر میرود، شاخصهای حافظهای سنتی مانند IVF و HNSW شکست میخورند. اینجا جایی است که DiskANN (شتابدهنده دیسک برای همسایه نزدیک) درخشش میکند. DiskANN از سرعت دسترسی تصادفی SSDهای مدرن برای ذخیره ساختارهای گراف روی دیسک استفاده میکند و تنها دادههای ضروری (Metadata) را در حافظه نگه میدارد. این روش از یک رویکرد جستجوی دو مرحلهای استفاده میکند: یک جستجوی خشن برای شناسایی بلوکهای کاندید روی دیسک، و سپس یک جستجوی با دقت بالا در داخل آن بلوکها.
اگرچه یکپارچهسازی مستقیم DiskANN با FAISS نیاز به بیلدهای تخصصی یا wrapperها دارد، اما این استراتژی برای پایگاههای داده برداری در مقیاس سازمانی که پتابایتها داده امبدینگ را مدیریت میکنند، حیاتی است.
نتیجهگیری
بهینهسازی FAISS یک راهحل یکاندازه برای همه نیست. برای برنامههای کاربردی عمومی با محدودیتهای حافظه متوسط، IVF تعادل محکمی بین سرعت و مصرف حافظه ارائه میدهد. برای الزامات عملکرد بالا که در آن تأخیر گلوگاه اصلی است، HNSW نسبتهای برتری از دقت بازیابی به تأخیر را ارائه میدهد. در نهایت، برای مجموعههای داده عظیمی که در RAM جا نمیشوند، اتخاذ معماری DiskANN ضروری است. با درک مبادلات هر استراتژی، توسعهدهندگان میتوانند سیستمهای بازیابی امبدینگ مقیاسپذیر و کارآمدی بسازند که نسل بعدی برنامههای کاربردی هوش مصنوعی را توانمند میسازند.