多模態查詢引擎的開發已成為資訊檢索領域的重要趨勢,它能有效整合不同資料型別,提供更精確的搜尋結果。本文將深入探討如何運用 Python 和 LlamaIndex 構築一個多模態向量索引,並以 VisDrone 資料集為例,示範如何實作一個兼具文字和影像查詢功能的引擎。我們將逐步講解索引的建立、查詢的執行、結果的顯示與儲存,以及效能評估的方法,並提供程式碼範例和流程圖,幫助讀者理解整個開發流程。透過 LlamaIndex,我們能有效地管理和查詢多模態資料,提升資訊檢索的效率和準確性,為開發者提供更強大的工具。

建立向量索引和查詢引擎

首先,我們需要建立一個檔案,該檔案將被處理以建立 VisDrone 多模態資料集的向量儲存索引。之前在 GitHub 上建立的 DataFrame df 沒有唯一索引或嵌入。我們將使用 LlamaIndex 在記憶體中建立它們。

import pandas as pd
from PIL import Image, ImageDraw

# 載入 VisDrone 資料集
ds =...  # 載入資料集的程式碼

# 建立一個唯一 ID 的 DataFrame
df = pd.DataFrame({
    'id': range(len(ds)),
    'image': ds.images,
    'boxes': ds.boxes,
    'labels': ds.labels
})

# 建立 LlamaIndex
from llm import LlamaIndex

index = LlamaIndex(df)

# 查詢引擎
query_engine =...  # 查詢引擎的程式碼

查詢和顯示結果

現在,我們可以使用查詢引擎查詢資料集,並顯示結果。

# 使用者輸入
user_input = "truck"

# 查詢資料集
results = query_engine.query(user_input)

# 顯示結果
for result in results:
    image_data = result['image']
    bboxes = result['boxes']
    labels = result['labels']
    
    # 顯示影像
    img = Image.frombytes('RGB', (512, 512), image_data)
    display(img)
    
    # 新增邊界框
    draw = ImageDraw.Draw(img)
    for bbox in bboxes:
        draw.rectangle(bbox, outline='red')
    
    # 顯示影像
    display(img)

儲存影像

最後,我們可以儲存影像。

# 儲存影像
img.save('result.png')

這樣就完成了建立多模態查詢引擎和查詢 VisDrone 資料集的過程。

建立檔案索引

為了建立檔案索引,我們首先需要為每個檔案建立一個唯一的ID。這可以透過將DataFrame的索引轉換為字串來實作。

df['doc_id'] = df.index.astype(str)

接下來,我們建立一個空列表documents,用於儲存檔案物件。

documents = []

然後,我們遍歷DataFrame的每一行,提取相關的文字標籤,並將其合併成一個字串。

for _, row in df.iterrows():
    text_labels = row['labels']
    text = " ".join(text_labels)
    document = Document(text=text, doc_id=row['doc_id'])
    documents.append(document)

建立向量儲存索引

現在,檔案已經準備好,可以使用GPTVectorStoreIndex進行索引了。

vector_store_index = GPTVectorStoreIndex.from_documents(documents)

查詢多模態資料集

設定向量儲存索引作為查詢引擎,我們可以執行查詢來搜尋多模態資料集。

vector_query_engine = vector_store_index.as_query_engine(similarity="cosine")

這樣,我們就可以對多模態資料集執行查詢,例如對VisDrone資料集進行查詢。

內容解密:

在上述程式碼中,我們首先建立了一個唯一的ID列doc_id,然後建立了一個空列表documents來儲存檔案物件。接下來,我們遍歷DataFrame的每一行,提取相關的文字標籤,並將其合併成一個字串。然後,我們建立了一個GPTVectorStoreIndex物件,並使用它來索引檔案。最後,我們設定向量儲存索引作為查詢引擎,並執行查詢來搜尋多模態資料集。

圖表翻譯:

  flowchart TD
    A[建立檔案索引] --> B[遍歷DataFrame]
    B --> C[提取文字標籤]
    C --> D[合併文字標籤]
    D --> E[建立檔案物件]
    E --> F[新增到documents列表]
    F --> G[建立向量儲存索引]
    G --> H[設定查詢引擎]
    H --> I[執行查詢]

此圖表展示了建立檔案索引、遍歷DataFrame、提取文字標籤、合併文字標籤、建立檔案物件、新增到documents列表、建立向量儲存索引、設定查詢引擎和執行查詢的過程。

執行時間分析與文書處理

在進行查詢後,我們首先計算了查詢的執行時間,以確保系統的反應速度是否符合預期。以下是計算執行時間的步驟:

import time

# 記錄開始時間
start_time = time.time()

# 執行查詢
response = vector_query_engine.query(user_input)

# 記錄結束時間
end_time = time.time()

# 計算執行時間
elapsed_time = end_time - start_time

# 輸出執行時間
print(f"查詢執行時間:{elapsed_time:.4f} 秒")

根據輸出的結果,查詢執行時間為 1.8461 秒,這個結果表明系統的反應速度是令人滿意的。

接下來,我們將對查詢的文字回應進行處理。首先,我們使用 textwrap.fill 函式將長文字切割成多行,以便於閱讀:

import textwrap

# 將文字切割成多行
print(textwrap.fill(str(response), 100))

從輸出的結果中,我們可以看到系統的回應是邏輯正確且合理的。系統提到無人機(Drones)使用各種感測器,如攝影機、LiDAR 和 GPS,來識別和追蹤物體,如卡車。

處理回應內容

為了進一步分析回應內容,我們將對回應中的節點進行解析,以找出回應中唯一的單詞,並從中選擇一個進行展示:

from itertools import groupby

def get_unique_words(text):
    # 將文字轉換為小寫並移除前後空白
    text = text.lower().strip()
    
    # 將文字分割成單詞
    words = text.split()
    
    # 尋找唯一的單詞
    unique_words = [word for word, _ in groupby(sorted(words))]
    
    return unique_words

# 對每個節點進行處理
for node in response.source_nodes:
    print(node.node_id)
    
    # 從節點文字中取得唯一單詞
    unique_words = get_unique_words(node.text)
    
    # 進一步處理或分析唯一單詞
    #...

這個過程使我們能夠深入瞭解系統回應的內容結構,並能夠根據需要進行進一步的分析或處理。

影像檢索與顯示

在前面的章節中,我們已經學習瞭如何從大語言模型(LLM)中檢索文字資料。現在,我們將學習如何從多模態資料集中檢索影像資料。

影像檢索流程

影像檢索的流程與文字檢索相似。首先,我們需要定義一個函式,用於處理節點文字資料,提取唯一的單詞,並根據這些單詞進行影像檢索。

def get_unique_words(node_text):
    # 對節點文字進行分詞和過濾
    words = node_text.split()
    unique_words = list(set(words))
    return unique_words

node_text = "truck"
unique_words = get_unique_words(node_text)
print("Unique Words in Node Text:", unique_words)

影像顯示和儲存

在檢索到影像後,我們需要將其顯示和儲存。為此,我們可以使用Pillow函式庫來處理影像資料。

from PIL import Image
import io

def display_image_with_bboxes(image_data, bboxes, labels, label_name):
    # 載入影像資料
    image = Image.open(io.BytesIO(image_data))
    
    # 繪製邊界框
    for bbox, label in zip(bboxes, labels):
        # 繪製邊界框和標籤
        image = draw_bounding_box(image, bbox, label)
    
    # 顯示影像
    image.show()
    
    # 儲存影像
    image.save("boxed_image.jpg")

# 定義邊界框繪製函式
def draw_bounding_box(image, bbox, label):
    # 繪製邊界框
    draw = ImageDraw.Draw(image)
    draw.rectangle(bbox, outline="red")
    draw.text((bbox[0], bbox[1]), label, fill="red")
    return image

整合檢索和顯示

現在,我們可以整合影像檢索和顯示的流程。

def process_and_display(response, df, ds, unique_words):
    # 處理節點文字資料
    for i, row in df.iterrows():
        if i == row_index:
            # 搜尋影像
            image_data = search_image(ds, unique_words)
            # 顯示和儲存影像
            display_image_with_bboxes(image_data, bboxes, labels, label_name)

執行檢索和顯示

最後,我們可以執行影像檢索和顯示的流程。

# 刪除之前儲存的影像
!rm /content/boxed_image.jpg

# 執行檢索和顯示
process_and_display(response, df, ds, unique_words)

圖表翻譯:

  flowchart TD
    A[開始] --> B[處理節點文字]
    B --> C[搜尋影像]
    C --> D[顯示和儲存影像]
    D --> E[結束]

內容解密:

上述程式碼實作了影像檢索和顯示的流程。首先, мы 處理節點文字資料,提取唯一的單詞。然後,我們根據這些單詞進行影像檢索。最後,我們顯示和儲存檢索到的影像。

多模態模組摘要

我們已經建立了一個多模態模組程式,旨在增強生成式人工智慧(AI)的輸出。這個程式包括顯示使用者輸入的源影像、列印使用者輸入和語言模型(LLM)輸出,並顯示多模態回應。

顯示源影像

首先,我們建立了一個函式來顯示使用者輸入的源影像。這個函式使用 Pillow 函式庫來開啟影像並顯示它。

from PIL import Image
import io

def display_source_image(image_path):
    image_bytes = io.BytesIO(image_path)
    img = Image.open(image_bytes)
    img.show()

顯示使用者輸入和 LLM 輸出

接下來,我們列印使用者輸入和 LLM 輸出。這些輸出將以文字形式顯示。

print(user_input)
print(textwrap.fill(str(llm_response), 100))

顯示多模態回應

最後,我們顯示多模態回應。這個回應包括源影像和 bounding box 的顯示。

image_path = "/content/boxed_image.jpg"
display_source_image(image_path)

輸出結果

輸出結果將先顯示文字回應(使用者輸入和 LLM 輸出),然後顯示影像和 bounding box。

How do drones identify a truck?

Drones can identify a truck using visual detection and tracking methods.

影像將以 bounding box 的形式顯示,標記出影像中 truck 的位置。

多模態 RAG 輸出增強

多模態 RAG 輸出增強可以豐富生成式人工智慧的輸出。然而,和所有 AI 程式一樣,需要注意其潛在的限制和挑戰。

圖表翻譯:

  graph LR
    A[使用者輸入] --> B[LLM 輸出]
    B --> C[多模態回應]
    C --> D[顯示源影像]
    D --> E[顯示 bounding box]

內容解密:

上述程式碼使用 Pillow 函式庫來開啟影像並顯示它。display_source_image 函式使用 io.BytesIO 來讀取影像 bytes,並使用 Image.open 來開啟影像。然後,使用 img.show 來顯示影像。

textwrap.fill 函式用於將 LLM 輸出文字包裹在 100 個字元的寬度內,以便於閱讀。

最終,display_source_image 函式被呼叫來顯示源影像和 bounding box。

設計高效能的影像辨識度量指標

設計一個高效能的影像辨識度量指標需要一個有效的影像辨識功能。評估多模態模組化 RAG 的效能需要兩種型別的測量:文字和影像。測量文字相對直截了當,但是測量影像卻是一個挑戰。分析多模態回應的影像與分析文字有很大不同。從多模態查詢引擎中提取了一個關鍵字,然後解析回應以顯示來源影像。但是,我們需要建立一個創新的方法來評估回應的來源影像。

LLM 效能度量指標

LlamaIndex 透過其查詢引擎無縫地呼叫 OpenAI 模型,例如 GPT-4,並在其回應中提供文字內容。對於文字回應,我們將使用與第 2 章「評估輸出與餘弦相似度」部分和第 3 章「向量儲存索引查詢引擎」部分相同的餘弦相似度度量指標。

評估函式使用 sklearn 和 sentence_transformers 來評估兩個文字之間的相似度,在本例中,即輸入和輸出:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('all-MiniLM-L6-v2')
def calculate_cosine_similarity_with_embeddings(text1, text2):
    embeddings1 = model.encode(text1)
    embeddings2 = model.encode(text2)
    similarity = cosine_similarity([embeddings1], [embeddings2])
    return similarity[0][0]

現在,我們可以計算基線使用者輸入和初始 LLM 回應之間的相似度:

llm_similarity_score = calculate_cosine_similarity_with_embeddings(user_input, llm_response)
print(user_input)
print(llm_response)
print(f"Cosine Similarity Score: {llm_similarity_score:.3f}")

輸出顯示使用者輸入、文字回應和兩個文字之間的餘弦相似度:

How do drones identify a truck?
How do drones identify a truck?
Drones can identify a truck using visual detection and tracking m
Cosine Similarity Score: 0.691

輸出令人滿意。但是,我們現在需要設計一個方法來衡量多模態效能。

多模態效能度量指標

為了評估傳回的影像,我們不能簡單地依靠資料集中的標籤。對於小資料集,我們可以手動檢查影像,但當系統擴充套件時,自動化是必要的。在本文中,我們將使用 GPT-4o 的電腦視覺功能來分析影像,解析它以找到我們要查詢的物體,並提供該影像的描述。然後,我們將對玄貓提供的描述應用餘弦相似度。GPT-4o 是一個多模態生成 AI 模型。

首先,讓我們編碼影像以簡化向 GPT-4o 傳輸資料。Base64 編碼將二進位制資料(如影像)轉換為 ASCII 字元,這些字元是標準文字字元。這種轉換至關重要,因為它確保影像資料可以透過設計用於處理文字資料的協定(如 HTTP)進行傳輸。它還避免了二進位制資料傳輸相關的問題,例如資料損壞或解釋錯誤。

import base64
IMAGE_PATH = "/content/boxed_image.jpg"

# 開啟影像檔案並將其編碼為 base64 字串
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        encoded_image = base64.b64encode(image_file.read())
    return encoded_image

…(待續)

圖片編碼與 OpenAI 介接

首先,我們需要將圖片轉換為 Base64 編碼,以便能夠在 OpenAI 的 API 中傳遞。這個過程可以使用 Python 的 base64 函式庫來完成。

import base64

def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")

base64_image = encode_image(IMAGE_PATH)

接下來,我們建立一個 OpenAI 的客戶端,並設定 API 金鑰以及指定要使用的模型(在這裡是 gpt-4o)。

from openai import OpenAI

client = OpenAI(api_key=openai.api_key)
MODEL = "gpt-4o"

提交圖片分析請求

我們選擇了一個唯一的詞彙 (u_word) 來作為我們的目標標籤,這裡假設為 "truck"。然後,我們構建了一個請求,包含系統角色和使用者角色,要求模型分析給定的圖片,並找出與目標標籤相關的內容。

u_word = "truck"  # 假設的唯一詞彙

model = MODEL
messages = [
    {"role": "system", "content": f"You are a helpful assistant analyzing images for {u_word}"},
    {"role": "user", "content": [
        {"type": "text", "text": f"Analyze the following image for {u_word}"},
        {"type": "image", "image": f"data:image/png;base64,{base64_image}"}
    ]}
]
temperature = 0.0

response_image = client.chat.create(model=model, messages=messages, temperature=temperature)
print(response_image)

分析結果

模型的輸出描述了圖片中與目標標籤 "truck" 相關的內容,包括兩輛卡車的詳細描述,例如它們的型別、載荷和周圍環境。

第一輛卡車(上方 bounding box):

  • 出現為一輛平板電腦卡車。
  • 載有各種材料,可能是建築材料。
  • 停放在一個有其他建築材料的區域。

第二輛卡車(下方 bounding box):

  • 也出現為一輛平板電腦卡車。
  • 載有不同型別的材料,類別似於第一輛卡車。
  • 位於一個類別似的環境中,周圍有建築材料。

兩輛卡車都位於建築或工業區,可能用於運輸材料。

後續步驟

現在,我們可以將這個分析結果提交給 cosine 相似度函式,以便進一步處理和分析圖片中與目標標籤相關的內容。這個過程可以幫助我們更好地理解圖片中的物體和它們之間的關係。

圖表翻譯:

  flowchart TD
    A[圖片編碼] --> B[OpenAI 介接]
    B --> C[提交圖片分析請求]
    C --> D[分析結果]
    D --> E[後續步驟]

這個流程圖展示了從圖片編碼到提交圖片分析請求,然後到分析結果和後續步驟的整個過程。

多模態模組化 RAG 效能評估

在評估多模態模組化 RAG 的效能時,我們需要考慮多個因素,包括文字相似度和影像相似度。文字相似度可以透過計算兩個文字之間的餘弦相似度來評估,而影像相似度則需要使用更複雜的方法,例如使用 GPT-4 進行影像識別並計算識別結果的餘弦相似度。

文字相似度評估

文字相似度評估是透過計算兩個文字之間的餘弦相似度來實作的。這個過程涉及將文字轉換為向量,並計算這些向量之間的餘弦值。餘弦值越接近 1,表示兩個文字之間的相似度越高。

影像相似度評估

影像相似度評估則需要使用更複雜的方法。首先,我們需要使用 GPT-4 進行影像識別,以獲得影像的文字描述。然後,我們可以計算這個文字描述與原始文字之間的餘弦相似度,以評估影像與文字之間的相似度。

多模態模組化 RAG 效能指標

多模態模組化 RAG 的效能指標可以透過計算文字相似度和影像相似度的平均值來評估。這個指標可以反映出系統對於多模態資料的處理能力,以及其對於不同型別資料之間關係的理解能力。

  flowchart TD
    A[文字輸入] --> B[文字相似度評估]
    B --> C[影像識別]
    C --> D[影像相似度評估]
    D --> E[多模態模組化 RAG 效能指標]

圖表翻譯:

上述流程圖描述了多模態模組化 RAG 效能評估的過程。首先,系統接收到文字輸入,並進行文字相似度評估。然後,系統使用 GPT-4 進行影像識別,以獲得影像的文字描述。接下來,系統計算這個文字描述與原始文字之間的餘弦相似度,以評估影像與文字之間的相似度。最後,系統計算文字相似度和影像相似度的平均值,以獲得多模態模組化 RAG 的效能指標。

4. 可以在無人機影像中新增邊界框來識別物體,例如卡車和行人嗎?

可以在無人機影像中新增邊界框來識別物體,例如卡車和行人。這個過程通常涉及使用物體偵測演算法,例如YOLO(You Only Look Once)或SSD(Single Shot Detector),來識別影像中的物體並新增邊界框。

5. 模組化系統是否可以檢索文字和影像資料以回應查詢?

模組化系統可以設計成同時檢索文字和影像資料,以回應查詢。這個過程通常涉及使用多模態檢索演算法,來結合文字和影像特徵,以提供更全面和準確的查詢結果。

6. 是否需要建立向量索引來查詢多模態VisDrone資料集?

建立向量索引可以是查詢多模態VisDrone資料集的一種有效方法。向量索引可以用來儲存和查詢大型資料集,並提供快速和準確的查詢結果。

7. 是否可以在不新增標籤或邊界框的情況下處理檢索的影像?

可以在不新增標籤或邊界框的情況下處理檢索的影像。這個過程通常涉及使用影像處理演算法,來提取影像特徵並進行查詢。

8. 多模態RAG效能指標是否僅根據文字回應?

多模態RAG效能指標不僅根據文字回應,也可以根據影像回應。這個過程通常涉及使用多模態評估指標,來評估RAG系統在文字和影像上的效能。

結論:建構多模態 RAG 系統的挑戰與展望

從技術架構視角來看,本篇文章深入探討瞭如何建構一個多模態 RAG 系統,並以 VisDrone 資料集為例,示範瞭如何結合文字和影像資訊來回應使用者查詢。我們分析了從建立向量索引、執行查詢、顯示結果到評估系統效能的完整流程。其中,利用 LlamaIndex 建立向量索引,並結合 GPT-4o 的多模態能力進行影像分析,是本方案的核心技術亮點。

然而,建構多模態 RAG 系統並非一帆風順。技術限制深析顯示,影像相似度評估的自動化仍是一大挑戰。雖然我們利用 GPT-4o 的電腦視覺功能和 cosine 相似度計算取得初步成果,但在處理大規模資料集時,效能和準確度仍有待提升。此外,如何有效整合不同模態的資訊,並設計更具代表性的評估指標,也是未來研究的重要方向。

展望未來,隨著多模態 AI 技術的快速發展,預期將出現更精準且高效的影像分析工具,進而提升多模態 RAG 系統的整體效能。同時,跨領域技術融合的趨勢,例如結合知識圖譜和影像識別技術,將為多模態 RAG 系統帶來更多創新應用場景。玄貓認為,多模態 RAG 系統代表了資訊檢索的未來方向,值得持續投入研發資源,並積極探索其在不同領域的應用潛力。