Vector Databases

FAISS ile Çok Modlu Arama: Özel Mesafe Metrikleriyle Hibrit Görsel-Metin Araması

Bir görüntünün nasıl göründüğünü ve metninin ne söylediğini anlayan arama sistemleri oluşturmak, kullanıcı deneyiminde önemli bir ilerlemedir. Orta ve ileri düzey geliştiriciler için zorluk, genellikle bu farklı veri kaynaklarını tek bir tutarlı arama hattına birleştirmekte yatar. Özel çok modlu gömme modelleri mevcut olsa da, FAISS (Facebook AI Similarity Search) gibi düşük seviyeli kütüphanelerle hibrit arama nasıl uygulanacağını anlamak büyük bir değer taşır. Bu yazıda, görsel ve metinsel benzerliğin ağırlıklı bir kombinasyonuna dayalı sonuçları, ince ayar için özel mesafe metrikleriyle birlikte getiren bir sistem nasıl inşa edileceğini inceliyoruz.

Neden Hibrit Arama?

Saf metin araması görsel bağlamı kaçırırken, saf görsel arama (CLIP gibi modellerden gelen gömme kullanılarak) metadata veya açıklamalarda bulunan anlamsal nüansları kaçırabilir. Hibrit arama, bir sorgu ve belgenin metin ve görsel bileşenleri için ayrı benzerlik puanları hesaplayıp bunları birleştirerek bu sorunu ele alır. FAISS'te bunun, metin gömme ve görsel gömme için iki ayrı indeksi yönetmek ve sonuçlarını birleştiren bir mantık katmanı uygulamak gerekir.

Çok Modlu Hattı Kurulumu

Başlamak için, veri setiniz için önceden hesaplanmış vektörlerinize sahip olduğunuzu varsayıyoruz. Bu örnekte, CLIP ViT-B/32 gibi modeller için yaygın bir çıktı boyutu olan 512 boyutlu gömme kullanıyoruz. İki ayrı FAISS indeksi oluşturacağız:

  1. Metin İndeksi: Kosinüs benzerliği için IndexFlatIP (İç Çarpım) kullanılarak.
  2. Görsel İndeksi: Basitlik için yine IndexFlatIP kullanılarak, ancak daha büyük veri setleri için IndexIVFFlat önerilir.

import faiss
import numpy as np

# Gömme boyutlarını tanımla
dim = 512

# 1. Metin İndeksi Oluştur (İç Çarpım)
index_text = faiss.IndexFlatIP(dim)

# 2. Görsel İndeksi Oluştur (İç Çarpım)
index_image = faiss.IndexFlatIP(dim)

# Örnek Veri Üretimi
num_docs = 1000
np.random.seed(42)
text_embeddings = np.random.rand(num_docs, dim).astype("float32")
image_embeddings = np.random.rand(num_docs, dim).astype("float32")

# Kosinüs Benzerliği için vektörleri normalize et (IP'nin Kosinüs gibi davranması için gerekli)
faiss.normalize_L2(text_embeddings)
faiss.normalize_L2(image_embeddings)

# Vektörleri indekslere ekle
index_text.add(text_embeddings)
index_image.add(image_embeddings)

Özel Mesafe Metrikleri ve Birleştirme Uygulaması

Hibrit aramanın çekirdeği birleştirme stratejisidir. Yaygın bir yaklaşım Doğrusal Kombinasyon'dur; burada nihai puan, bireysel puanların ağırlıklı toplamıdır. Ancak farklı indekslerden gelen ham puanlar aynı ölçekte olmayabilir. Bu puanları birleştirmeden önce normalize eden bir Özel Mesafe Metriği fonksiyonuna ihtiyacımız var.

Aşağıda hibrit aramayı gerçekleştiren bir Python fonksiyonu bulunmaktadır. Metin için alpha ve görsel için beta ağırlıklarını kabul eder, burada alpha + beta = 1.0 olur.


def hybrid_search(index_t, index_i, query_text_vec, query_img_vec, k=10, alpha=0.5):
    """
    Metin ve görsel benzerlik puanlarını birleştirerek hibrit arama yapar.
    
    :param index_t: Metin gömme için FAISS İndeksi
    :param index_i: Görsel gömme için FAISS İndeksi
    :param query_text_vec: Normalize edilmiş metin sorgu vektörü (1, dim)
    :param query_img_vec: Normalize edilmiş görsel sorgu vektörü (1, dim)
    :param k: Döndürülecek sonuç sayısı
    :param alpha: Metin benzerliği için ağırlık (1-alpha, görsel için ağırlıktır)
    :return: (indeks, birleşik_puan) demetlerinin listesi
    """
    # Henüz normalize edilmediyse sorgu vektörlerini normalize et
    faiss.normalize_L2(query_text_vec)
    faiss.normalize_L2(query_img_vec)

    # Her iki indeks üzerinde arama yap
    # Not: FAISS indeksleri ve mesafeleri (puanları) döndürür
    D_text, I_text = index_t.search(query_text_vec, k)
    D_image, I_image = index_i.search(query_img_vec, k)

    # Sonuçları birleştirmemiz gerekiyor. I_text ve I_image farklı olabileceğinden,
    # her ikisinden de en iyi k'yi alıp birleştiriyoruz.
    candidates = {}

    # Metin puanlarını topla
    for idx, score in zip(I_text[0], D_text[0]):
        if idx != -1:
            candidates[idx] = {'text_score': float(score), 'image_score': 0.0}

    # Görsel puanlarını topla
    for idx, score in zip(I_image[0], D_image[0]):
        if idx != -1:
            if idx in candidates:
                candidates[idx]['image_score'] = float(score)
            else:
                candidates[idx] = {'text_score': 0.0, 'image_score': float(score)}

    # Özel Ağırlıklı Toplam Uygula (Doğrusal Kombinasyon)
    # Nihai Puan = alpha * MetinPuanı + (1 - alpha) * GörselPuanı
    weighted_results = []
    for doc_id, scores in candidates.items():
        combined_score = (alpha * scores['text_score']) + ((1 - alpha) * scores['image_score'])
        weighted_results.append((doc_id, combined_score))

    # Birleşik puana göre azalan sırala (IP için FAISS daha yüksek puanları daha iyi olarak döndürür)
    weighted_results.sort(key=lambda x: x[1], reverse=True)
    
    return weighted_results[:k]

# Örnek Kullanım
query_text = np.random.rand(1, dim).astype("float32")
query_img = np.random.rand(1, dim).astype("float32")

results = hybrid_search(index_text, index_image, query_text, query_img, k=5, alpha=0.7)
for doc_id, score in results:
    print(f"Doc ID: {doc_id}, Combined Score: {score:.4f}")

Optimizasyon ve İleri Stratejiler

Yukarıdaki doğrusal kombinasyon basittir ancak iyileştirilebilir. Üretim sistemleri için şunları göz önünde bulundurun:

  • Karşılıklı Sıralama Birleştirme (RRF): Ham puanları toplamak yerine, ters sıraları toplayın. Bu, modlar arasındaki ölçek farklarına karşı dayanıklıdır.
  • İndeks Seçimi: 100k vektörü aşan veri setleri için, bellek ayak izini azaltmak ve arama hızını artırmak üzere IndexFlatIP'yi IndexIVFPQ (Ürün Kuantizasyonlu Ters Dosya) ile değiştirin. Bu indeksleri kendi veri dağılımınızda yeniden eğitmeniz gerekecektir.
  • Dinamik Ağırlıklandırma: Bir sınıflandırıcı kullanarak bir sorgunun daha çok metin ağırlıklı mı yoksa görsel ağırlıklı mı olduğunu belirleyin ve alpha'yı dinamik olarak ayarlayın.

Sonuç

FAISS ile çok modlu arama uygulamak, arama motorunuzun kullanıcı niyetini nasıl yorumladığı üzerinde ince ayar kontrolü sunar. Metin ve görsel indekslerini ayırarak ve özel birleştirme mantığı uygulayarak, hem anlamsal olarak zengin hem de görsel olarak sezgisel bir arama deneyimi oluşturabilirsiniz. Doğrusal ağırlıklandırma ile başlayın, isabet oranlarınızı ölçün ve RRF veya sıralama öğrenme modelleri gibi daha karmaşık birleştirme stratejilerine doğru ilerleyin. FAISS'in hızı sayesinde, büyük ölçekli veri setlerinde bile gerçek zamanlı hibrit arama mümkündür.

Share: