paint-brush
Ingin Mencari Sesuatu Dengan Imej dan Penerangan Teks? Cuba RAG Multimodaloleh@codingjaguar
sejarah baru

Ingin Mencari Sesuatu Dengan Imej dan Penerangan Teks? Cuba RAG Multimodal

oleh Jiang Chen16m2024/11/27
Read on Terminal Reader

Terlalu panjang; Untuk membaca

Panduan mendalam tentang cara membina sistem RAG multimodal menggunakan Milvus dan cara membuka pelbagai kemungkinan untuk sistem AI.
featured image - Ingin Mencari Sesuatu Dengan Imej dan Penerangan Teks? Cuba RAG Multimodal
Jiang Chen HackerNoon profile picture
0-item
1-item

Artikel ini menyediakan panduan mendalam tentang cara membina sistem RAG multimodal menggunakan Milvus dan cara membuka pelbagai kemungkinan untuk sistem AI.


Mengekang kepada satu format data adalah tidak cukup baik lagi. Memandangkan perniagaan lebih bergantung pada maklumat untuk membuat keputusan penting, mereka memerlukan keupayaan untuk membandingkan data dalam format yang berbeza. Nasib baik, sistem AI tradisional yang terhad kepada satu jenis data telah memberi laluan kepada sistem multimodal yang boleh memahami dan memproses maklumat yang kompleks.


Sistem carian berbilang mod dan penjanaan tambahan perolehan berbilang mod (RAG) baru-baru ini telah menunjukkan kemajuan hebat dalam bidang ini. Sistem ini memproses berbilang jenis data, termasuk teks, imej dan audio, untuk memberikan respons yang menyedari konteks.


Dalam catatan blog ini, kami akan membincangkan cara pembangun boleh membina sistem RAG multimodal mereka sendiri menggunakan Milvus. Kami juga akan membimbing anda membina sistem sedemikian yang boleh mengendalikan data teks dan imej, khususnya, melakukan carian persamaan dan memanfaatkan model bahasa untuk memperhalusi output. Jadi, mari kita mulakan.

Apakah Milvus?

Pangkalan data vektor ialah jenis pangkalan data khas yang digunakan untuk menyimpan, mengindeks dan mendapatkan semula benam vektor, yang merupakan perwakilan matematik data yang membolehkan anda membandingkan data bukan sahaja untuk kesetaraan tetapi kesamaan semantik. Milvus ialah pangkalan data vektor berprestasi tinggi sumber terbuka yang dibina untuk skala. Anda boleh menemuinya di GitHub dengan lesen Apache-2.0 dan lebih daripada 30K bintang.


Milvus membantu pembangun menyediakan penyelesaian yang fleksibel untuk mengurus dan menanyakan data vektor berskala besar. Kecekapannya menjadikan Milvus sebagai pilihan ideal untuk pembangun membina aplikasi menggunakan model pembelajaran mendalam, seperti penjanaan tambahan perolehan (RAG), carian berbilang mod, enjin pengesyoran dan pengesanan anomali.


Milvus menawarkan berbilang pilihan penggunaan untuk memadankan keperluan pembangun. Milvus Lite ialah versi ringan yang berjalan di dalam aplikasi Python dan sesuai untuk aplikasi prototaip dalam persekitaran tempatan. Milvus Standalone dan Milvus Distributed ialah pilihan berskala dan sedia pengeluaran.

Multimodal RAG: Mengembangkan Melebihi Teks

Sebelum membina sistem, adalah penting untuk memahami RAG berasaskan teks tradisional dan evolusinya kepada RAG Multimodal.


Retrieval Augmented Generation (RAG) ialah kaedah untuk mendapatkan maklumat kontekstual daripada sumber luaran dan menjana output yang lebih tepat daripada model bahasa besar (LLM). RAG tradisional ialah strategi yang sangat berkesan untuk meningkatkan output LLM, tetapi tetap terhad kepada data teks. Dalam banyak aplikasi dunia nyata, data melangkaui teks—menggabungkan imej, carta dan modaliti lain menyediakan konteks kritikal.


Multimodal RAG menangani had di atas dengan mendayakan penggunaan jenis data yang berbeza, memberikan konteks yang lebih baik kepada LLM.


Ringkasnya, dalam sistem RAG berbilang mod, komponen perolehan mencari maklumat yang berkaitan merentas modaliti data yang berbeza, dan komponen penjanaan menjana hasil yang lebih tepat berdasarkan maklumat yang diambil.

Memahami Pembenaman Vektor dan Carian Persamaan

Pembenaman vektor dan carian persamaan ialah dua konsep asas RAG multimodal. Mari kita fahami kedua-duanya.

Pembenaman Vektor

Seperti yang dibincangkan, pembenaman vektor ialah perwakilan matematik/berangka data. Mesin menggunakan perwakilan ini untuk memahami makna semantik jenis data yang berbeza, seperti teks, imej dan audio.


Apabila menggunakan pemprosesan bahasa semula jadi (NLP), ketulan dokumen diubah menjadi vektor, dan perkataan yang serupa secara semantik dipetakan ke titik berdekatan dalam ruang vektor. Perkara yang sama berlaku untuk imej, di mana pembenaman mewakili ciri semantik. Ini membolehkan kami memahami metrik seperti warna, tekstur dan bentuk objek dalam format berangka.


Matlamat utama menggunakan benam vektor adalah untuk membantu mengekalkan hubungan dan persamaan antara kepingan data yang berbeza.

Carian Persamaan

Carian persamaan digunakan untuk mencari dan mencari data dalam set data tertentu. Dalam konteks pembenaman vektor, carian persamaan mencari vektor dalam set data yang diberikan yang paling hampir dengan vektor pertanyaan.


Berikut adalah beberapa kaedah yang biasa digunakan untuk mengukur persamaan antara vektor:

  1. Jarak Euclidean : Mengukur jarak garis lurus antara dua titik dalam ruang vektor.
  2. Kesamaan Kosinus : Mengukur kosinus sudut antara dua vektor (dengan fokus pada arahnya dan bukannya magnitud).
  3. Produk Dot : Pendaraban mudah unsur sepadan yang disimpulkan.


Pilihan ukuran persamaan biasanya bergantung pada data khusus aplikasi dan cara pembangun mendekati masalah tersebut.


Apabila melakukan carian persamaan pada set data berskala besar, kuasa pengiraan dan sumber yang diperlukan adalah sangat tinggi. Di sinilah algoritma anggaran jiran terdekat (ANN) masuk. Algoritma ANN digunakan untuk menukar peratusan atau jumlah ketepatan yang kecil untuk peningkatan kelajuan yang ketara. Ini menjadikan mereka pilihan yang sesuai untuk aplikasi berskala besar.


Milvus juga menggunakan algoritma ANN lanjutan, termasuk HNSW dan DiskANN, untuk melakukan carian persamaan yang cekap pada set data benam vektor yang besar, membolehkan pembangun mencari titik data yang berkaitan dengan cepat. Selain itu, Milvus menyokong algoritma pengindeksan lain, seperti HSNW, IVF, CAGRA, dll., menjadikannya penyelesaian carian vektor yang lebih cekap.


Membina Multimodal RAG dengan Milvus

Sekarang kita telah mempelajari konsep, tiba masanya untuk membina sistem RAG multimodal menggunakan Milvus. Untuk contoh ini, kami akan menggunakan Milvus Lite (versi Milvus yang ringan, sesuai untuk percubaan dan prototaip) untuk penyimpanan dan pengambilan vektor, BGE untuk pemprosesan dan pembenaman imej yang tepat dan GPT-4o untuk penyusunan semula hasil lanjutan.

Prasyarat

Pertama, anda memerlukan tika Milvus untuk menyimpan data anda. Anda boleh menyediakan Milvus Lite menggunakan pip, menjalankan instance tempatan menggunakan Docker, atau mendaftar untuk akaun Milvus dihoskan percuma melalui Zilliz Cloud.


Kedua, anda memerlukan LLM untuk saluran paip RAG anda, jadi pergi ke OpenAI dan dapatkan kunci API. Peringkat percuma sudah memadai untuk membolehkan kod ini berfungsi.


Seterusnya, buat direktori baharu dan Python persekitaran maya (atau ambil apa sahaja langkah yang anda gunakan untuk mengurus Python).


Untuk tutorial ini, anda juga perlu memasang pymilvus perpustakaan, yang merupakan SDK Python rasmi Milvus, dan beberapa alat biasa.

Sediakan Milvus Lite

 pip install -U pymilvus

Pasang Ketergantungan

 pip install --upgrade pymilvus openai datasets opencv-python timm einops ftfy peft tqdm git clone https://github.com/FlagOpen/FlagEmbedding.git pip install -e FlagEmbedding

Muat Turun Data

Perintah berikut akan memuat turun data contoh dan mengekstraknya ke folder tempatan "./images_folder", yang termasuk:


  • Imej: Subset daripada Ulasan Amazon 2023 mengandungi kira-kira 900 imej daripada kategori "Perkakas", "Telefon_selidik_dan_Aksesori", dan "Elektronik".
  • Contoh imej pertanyaan: leopard.jpg


 wget https://github.com/milvus-io/bootcamp/releases/download/data/amazon_reviews_2023_subset.tar.gz tar -xzf amazon_reviews_2023_subset.tar.gz

Muatkan Model Benam

Kami akan menggunakan model Visualized BGE "bge-visualized-base-en-v1.5" untuk menjana benam untuk kedua-dua imej dan teks.


Sekarang muat turun berat dari HuggingFace.


 wget https://huggingface.co/BAAI/bge-visualized/resolve/main/Visualized_base_en_v1.5.pth


Kemudian, mari kita bina pengekod.

 import torch from visual_bge.modeling import Visualized_BGE class Encoder:    def __init__(self, model_name: str, model_path: str):        self.model = Visualized_BGE(model_name_bge=model_name, model_weight=model_path)        self.model.eval()    def encode_query(self, image_path: str, text: str) -> list[float]:        with torch.no_grad():            query_emb = self.model.encode(image=image_path, text=text)        return query_emb.tolist()[0]    def encode_image(self, image_path: str) -> list[float]:        with torch.no_grad():            query_emb = self.model.encode(image=image_path)        return query_emb.tolist()[0] model_name = "BAAI/bge-base-en-v1.5" model_path = "./Visualized_base_en_v1.5.pth" # Change to your own value if using a different model path encoder = Encoder(model_name, model_path)

Hasilkan Pembenaman dan Muatkan Data ke dalam Milvus

Bahagian ini akan membimbing anda cara memuatkan imej contoh ke dalam pangkalan data kami dengan pembenamannya yang sepadan.


Hasilkan benam


Pertama, kita perlu membuat pembenaman untuk semua imej dalam set data.


Muatkan semua imej daripada direktori data dan tukarkannya kepada pembenaman.


 import os from tqdm import tqdm from glob import glob data_dir = (    "./images_folder" # Change to your own value if using a different data directory ) image_list = glob(    os.path.join(data_dir, "images", "*.jpg") ) # We will only use images ending with ".jpg" image_dict = {} for image_path in tqdm(image_list, desc="Generating image embeddings: "):    try:        image_dict[image_path] = encoder.encode_image(image_path)    except Exception as e:        print(f"Failed to generate embedding for {image_path}. Skipped.")        continue print("Number of encoded images:", len(image_dict))

Lakukan Carian Berbilang Modal dan Susun Semula Keputusan

Dalam bahagian ini, kami mula-mula akan mencari imej yang berkaitan menggunakan pertanyaan multimodal dan kemudian menggunakan perkhidmatan LLM untuk menyusun semula hasil yang diperoleh dan mencari yang terbaik dengan penjelasan.


Jalankan carian multimodal


Kini kami bersedia untuk melakukan carian multimodal lanjutan dengan pertanyaan yang terdiri daripada arahan imej dan teks.


 query_image = os.path.join(    data_dir, "leopard.jpg" ) # Change to your own query image path query_text = "phone case with this image theme" query_vec = encoder.encode_query(image_path=query_image, text=query_text) search_results = milvus_client.search(    collection_name=collection_name,    data=[query_vec],    output_fields=["image_path"],    limit=9, # Max number of search results to return    search_params={"metric_type": "COSINE", "params": {}}, # Search parameters )[0] retrieved_images = [hit.get("entity").get("image_path") for hit in search_results] print(retrieved_images)


Hasilnya ditunjukkan di bawah:


 ['./images_folder/images/518Gj1WQ-RL._AC_.jpg', './images_folder/images/41n00AOfWhL._AC_.jpg'


Susun semula keputusan dengan GPT-4o


Sekarang, kami akan menggunakan GPT-4o untuk menentukan kedudukan imej yang diambil dan mencari hasil yang paling sepadan. LLM juga akan menerangkan mengapa kedudukannya seperti itu.


1. Cipta pemandangan panorama.


 import numpy as np import cv2 img_height = 300 img_width = 300 row_count = 3 def create_panoramic_view(query_image_path: str, retrieved_images: list) -> np.ndarray:    """    creates a 5x5 panoramic view image from a list of images    args:        images: list of images to be combined    returns:        np.ndarray: the panoramic view image    """    panoramic_width = img_width * row_count    panoramic_height = img_height * row_count    panoramic_image = np.full(        (panoramic_height, panoramic_width, 3), 255, dtype=np.uint8    )    # create and resize the query image with a blue border    query_image_null = np.full((panoramic_height, img_width, 3), 255, dtype=np.uint8)    query_image = Image.open(query_image_path).convert("RGB")    query_array = np.array(query_image)[:, :, ::-1]    resized_image = cv2.resize(query_array, (img_width, img_height))    border_size = 10    blue = (255, 0, 0) # blue color in BGR    bordered_query_image = cv2.copyMakeBorder(        resized_image,        border_size,        border_size,        border_size,        border_size,        cv2.BORDER_CONSTANT,        value=blue,    )    query_image_null[img_height * 2 : img_height * 3, 0:img_width] = cv2.resize(        bordered_query_image, (img_width, img_height)    )    # add text "query" below the query image    text = "query"    font_scale = 1    font_thickness = 2    text_org = (10, img_height * 3 + 30)    cv2.putText(        query_image_null,        text,        text_org,        cv2.FONT_HERSHEY_SIMPLEX,        font_scale,        blue,        font_thickness,        cv2.LINE_AA,    )    # combine the rest of the images into the panoramic view    retrieved_imgs = [        np.array(Image.open(img).convert("RGB"))[:, :, ::-1] for img in retrieved_images    ]    for i, image in enumerate(retrieved_imgs):        image = cv2.resize(image, (img_width - 4, img_height - 4))        row = i // row_count        col = i % row_count        start_row = row * img_height        start_col = col * img_width        border_size = 2        bordered_image = cv2.copyMakeBorder(            image,            border_size,            border_size,            border_size,            border_size,            cv2.BORDER_CONSTANT,            value=(0, 0, 0),        )        panoramic_image[            start_row : start_row + img_height, start_col : start_col + img_width        ] = bordered_image        # add red index numbers to each image        text = str(i)        org = (start_col + 50, start_row + 30)        (font_width, font_height), baseline = cv2.getTextSize(            text, cv2.FONT_HERSHEY_SIMPLEX, 1, 2        )        top_left = (org[0] - 48, start_row + 2)        bottom_right = (org[0] - 48 + font_width + 5, org[1] + baseline + 5)        cv2.rectangle(            panoramic_image, top_left, bottom_right, (255, 255, 255), cv2.FILLED        )        cv2.putText(            panoramic_image,            text,            (start_col + 10, start_row + 30),            cv2.FONT_HERSHEY_SIMPLEX,            1,            (0, 0, 255),            2,            cv2.LINE_AA,        )    # combine the query image with the panoramic view    panoramic_image = np.hstack([query_image_null, panoramic_image])    return panoramic_image


2. Gabungkan imej pertanyaan dan imej yang diambil dengan indeks dalam paparan panorama.


 from PIL import Image combined_image_path = os.path.join(data_dir, "combined_image.jpg") panoramic_image = create_panoramic_view(query_image, retrieved_images) cv2.imwrite(combined_image_path, panoramic_image) combined_image = Image.open(combined_image_path) show_combined_image = combined_image.resize((300, 300)) show_combined_image.show() 


Hasil carian multimodal

3. Susun semula keputusan dan berikan penjelasan


Kami akan menghantar semua imej gabungan ke perkhidmatan LLM multimodal bersama-sama dengan gesaan yang betul untuk menentukan kedudukan keputusan yang diambil dengan penjelasan. Nota: Untuk mendayakan GPT-4o sebagai LLM, anda perlu menyediakan anda Kunci API OpenAI terlebih dahulu.


 import requests import base64 openai_api_key = "sk-***" # Change to your OpenAI API Key def generate_ranking_explanation(    combined_image_path: str, caption: str, infos: dict = None ) -> tuple[list[int], str]:    with open(combined_image_path, "rb") as image_file:        base64_image = base64.b64encode(image_file.read()).decode("utf-8")    information = (        "You are responsible for ranking results for a Composed Image Retrieval. "        "The user retrieves an image with an 'instruction' indicating their retrieval intent. "        "For example, if the user queries a red car with the instruction 'change this car to blue,' a similar type of car in blue would be ranked higher in the results. "        "Now you would receive instruction and query image with blue border. Every item has its red index number in its top left. Do not misunderstand it. "        f"User instruction: {caption} \n\n"    )    # add additional information for each image    if infos:        for i, info in enumerate(infos["product"]):            information += f"{i}. {info}\n"    information += (        "Provide a new ranked list of indices from most suitable to least suitable, followed by an explanation for the top 1 most suitable item only. "        "The format of the response has to be 'Ranked list: []' with the indices in brackets as integers, followed by 'Reasons:' plus the explanation why this most fit user's query intent."    )    headers = {        "Content-Type": "application/json",        "Authorization": f"Bearer {openai_api_key}",    }    payload = {        "model": "gpt-4o",        "messages": [            {                "role": "user",                "content": [                    {"type": "text", "text": information},                    {                        "type": "image_url",                        "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},                    },                ],            }        ],        "max_tokens": 300,    }    response = requests.post(        "https://api.openai.com/v1/chat/completions", headers=headers, json=payload    )    result = response.json()["choices"][0]["message"]["content"]    # parse the ranked indices from the response    start_idx = result.find("[")    end_idx = result.find("]")    ranked_indices_str = result[start_idx + 1 : end_idx].split(",")    ranked_indices = [int(index.strip()) for index in ranked_indices_str]    # extract explanation    explanation = result[end_idx + 1 :].strip()    return ranked_indices, explanation


Dapatkan indeks imej selepas kedudukan dan sebab untuk hasil terbaik:


 ranked_indices, explanation = generate_ranking_explanation(    combined_image_path, query_text )


4. Paparkan hasil terbaik dengan penerangan


 print(explanation) best_index = ranked_indices[0] best_img = Image.open(retrieved_images[best_index]) best_img = best_img.resize((150, 150)) best_img.show()


Keputusan:


 Reasons: The most suitable item for the user's query intent is index 6 because the instruction specifies a phone case with the theme of the image, which is a leopard. The phone case with index 6 has a thematic design resembling the leopard pattern, making it the closest match to the user's request for a phone case with the image theme. 



Sarung telefon cetakan harimau bintang - Keputusan Terbaik


Lihat kod penuh dalam buku nota ini . Untuk mengetahui lebih lanjut tentang cara memulakan demo dalam talian dengan tutorial ini, sila rujuk kepada contoh aplikasi .

Kesimpulan

Dalam catatan blog ini, kami membincangkan membina sistem RAG multimodal menggunakan Milvus (pangkalan data vektor sumber terbuka). Kami membincangkan cara pembangun boleh menyediakan Milvus, memuatkan data imej, melakukan carian persamaan dan menggunakan LLM untuk menyusun semula hasil yang diperoleh untuk respons yang lebih tepat.


Penyelesaian RAG multimodal membuka pelbagai kemungkinan untuk sistem AI yang boleh memahami dan memproses pelbagai bentuk data dengan mudah. Beberapa kemungkinan biasa termasuk enjin carian imej yang dipertingkatkan, hasil terdorong konteks yang lebih baik dan banyak lagi.