構建索引
一、向量嵌入
向量嵌入(Embedding)是一種將真實世界中復雜、高維的數據對象(如文本、圖像、音頻、視頻等)轉換為數學上易于處理的、低維、稠密的連續數值向量的技術。
想象一下,我們將每一個詞、每一段話、每一張圖片都放在一個巨大的多維空間里,并給它一個獨一無二的坐標。這個坐標就是一個向量,它“嵌入”了原始數據的所有關鍵信息。這個過程,就是 Embedding。
- 數據對象:任何信息,如文本“你好世界”,或一張貓的圖片。
- Embedding 模型:一個深度學習模型,負責接收數據對象并進行轉換。
- 輸出向量:一個固定長度的一維數組,例如
[0.16, 0.29, -0.88, ...]
。這個向量的維度(長度)通常在幾百到幾千之間。
Embedding 的真正威力在于,它產生的向量不是隨機數值的堆砌,而是對數據語義的數學編碼。
-
核心原則:在 Embedding 構建的向量空間中,語義上相似的對象,其對應的向量在空間中的距離會更近;而語義上不相關的對象,它們的向量距離會更遠。
-
關鍵度量
:我們通常使用以下數學方法來衡量向量間的“距離”或“相似度”:
- 余弦相似度 (Cosine Similarity):計算兩個向量夾角的余弦值。值越接近 1,代表方向越一致,語義越相似。這是最常用的度量方式。
- 點積 (Dot Product):計算兩個向量的乘積和。在向量歸一化后,點積等價于余弦相似度。
- 歐氏距離 (Euclidean Distance):計算兩個向量在空間中的直線距離。距離越小,語義越相似。
二、多模態嵌入實戰——Milvus介紹及多模態檢索實踐
該筆記是針對文章all-in-rag的第三章節實戰的詳細說明。若想看理論細節,請移步作者的文章。
向量數據庫是專門用于存儲和查詢向量的數據庫,這些向量來自對文本、語音、圖像、視頻等內容的向量化處理;與傳統數據庫相比,它不僅能完成添加、讀取查詢、更新、刪除等基本操作,還能對向量數據進行更快速的相似性搜索。當前的大模型,無論是 NLP 領域的 GPT 系列還是 CV 領域的 ResNET 系列,都是經過預先訓練的,存在明確的訓練截止日,這使得它們對截止日之后發生的事情一無所知,而向量數據庫的引入則能極大拓展大模型的應用邊界 —— 其內部存儲的最新信息向量可讓大模型保持準實時性、提高適用性并實現動態調整,進而使大模型具備長期記憶。比如,一個 2021 年底完成訓練的新聞摘要預訓練模型,到 2023 年面對諸多新的新聞事件和趨勢時,可借助向量數據庫存儲和查詢 2023 年的新聞文章向量來處理新信息;在推薦系統中,預訓練大模型可能無法識別新用戶和新產品的特征,而通過向量數據庫實時更新用戶和產品的特征向量,能讓大模型依據最新信息提供更精準的推薦;此外,向量數據庫還支持實時監測和分析,像金融領域中,預訓練的股票預測模型可能無法獲取訓練截止日后的股票價格信息,將最新股票價格向量存儲在向量數據庫中,大模型就能實時分析和預測未來股票價格走勢,在客服領域,向量數據庫也能讓大模型追溯到對話的開始。
向量數據庫自帶多模態功能,這意味著它能夠通過機器學習方法處理和理解來自不同源的多種模態信息,如文本、圖像、音頻和視頻等,數據向量化過程使得這些不同模態數據的內部隱藏信息得以暴露,進而為多模態應用提供支持。
2.1 Milvus簡介
Milvus 是一款云原生向量數據庫,具備高可用、高性能、易拓展的特點,用于海量向量數據的實時召回。其官網地址為:Milvus。Milvus 基于 FAISS、Annoy、HNSW 等向量搜索庫構建,核心目標是解決稠密向量相似度檢索問題;在向量檢索庫的基礎上,它支持數據分區分片、數據持久化、增量數據攝取、標量向量混合查詢、time travel 等功能,同時大幅優化了向量檢索性能,可滿足各類向量檢索場景的應用需求,通常建議用戶采用 Kubernetes 部署 Milvus,以獲得最佳的可用性和彈性。此外,Milvus 采用共享存儲架構,實現存儲與計算完全分離,計算節點支持橫向擴展;從架構來看,它遵循數據流與控制流分離的原則,整體分為接入層(access layer)、協調服務(coordinator service)、執行節點(worker node)和存儲層(storage)四個層次,各個層次相互獨立,可實現獨立擴展和容災。
2.2 Collection(集合)
在 Milvus 中,Collection 是數據組織的基本邏輯單元,其功能等價于關系型數據庫中的表(Table)。它作為向量數據及相關元數據的存儲、管理與檢索容器,所有操作(插入、刪除、查詢)均以 Collection 為操作對象。
可以用一個圖書館的比喻來理解 Collection:
- Collection (集合): 相當于一個圖書館,是所有數據的頂層容器。一個 Collection 可以包含多個 Partition,每個 Partition 可以包含多個 Entity。
- Partition (分區): 相當于圖書館里的不同區域(如“小說區”、“科技區”),將數據物理隔離,讓檢索更高效。
- Schema (模式): 相當于圖書館的圖書卡片規則,定義了每本書(數據)必須登記哪些信息(字段)。
- Entity (實體): 相當于一本具體的書,是數據本身。
- Alias (別名): 相當于一個動態的推薦書單(如“本周精選”),它可以指向某個具體的 Collection,方便應用層調用,實現數據更新時的無縫切換。
Collection 是 Milvus 中最基本的數據組織單位,類似于關系型數據庫中的一張表 (Table)。是我們存儲、管理和查詢向量及相關元數據的容器。所有的數據操作,如插入、刪除、查詢等,都是圍繞 Collection 展開的。
2.2.1 Schema(模式):數據結構規范
Collection 的創建需預定義其 Schema,該模式通過字段(Field)屬性約束確保數據一致性與查詢效率。Schema 包含三類核心字段:
- 主鍵字段(Primary Key Field)
- 必備字段,全局唯一標識實體(Entity)。
- 數據類型:
INT64
或VARCHAR
,值需滿足唯一性約束。
- 向量字段(Vector Field)
- 存儲嵌入向量(Embedding Vector),支持單 Collection 多向量字段(如多模態場景)。
- 標量字段(Scalar Field)
- 存儲非向量元數據(字符串、數值、布爾值、JSON 等),用于查詢過濾與結果聚合。
Schema 設計范式示例(新聞文章場景)
假設 Schema 包含:
- 主鍵:
article_id
(唯一標識)- 標量字段:
title
(VARCHAR),author
(VARCHAR),image_url
(VARCHAR)- 向量字段:
image_embedding
(密集向量,DENSE_FLOAT_VECTOR)summary_embedding
(密集向量)summary_sparse_embedding
(稀疏向量,SPARSE_FLOAT_VECTOR)
此設計支持多模態混合檢索,并通過標量字段實現元數據過濾。
2.2.2 Partition(分區):數據物理隔離機制
Partition 是 Collection 內部的邏輯數據分片,通過物理隔離優化查詢性能與管理效率:
- 初始狀態:每個 Collection 含默認分區
_default
。 - 容量限制:單 Collection 最多支持 1024 個分區。
分區核心價值:
- 查詢性能提升
限定搜索范圍至特定分區(如WHERE partition_name="AI_articles"
),減少全量數據掃描。 - 數據生命周期管理
- 支持分區級批量操作:加載/卸載內存、數據刪除。
- 示例:按時間分區(
2024Q1
,2024Q2
)可快速歸檔歷史數據。
2.2.3 Alias
Alias (別名) 是為 Collection 提供的一個“昵稱”。通過為一個 Collection 設置別名,我們可以在應用程序中使用這個別名來執行所有操作,而不是直接使用真實的 Collection 名稱。
為什么使用別名?
- 安全地更新數據:想象一下,你需要對一個在線服務的 Collection 進行大規模的數據更新或重建索引。直接在原 Collection 上操作風險很高。正確的做法是:
- 創建一個新的 Collection (
collection_v2
) 并導入、索引好所有新數據。 - 將指向舊 Collection (
collection_v1
) 的別名(例如my_app_collection
)原子性地切換到新 Collection (collection_v2
) 上。
- 創建一個新的 Collection (
- 代碼解耦:整個切換過程對上層應用完全透明,無需修改任何代碼或重啟服務,實現了數據的平滑無縫升級。
2.3 Index
如果說 Collection 是 Milvus 的骨架,那么索引 (Index) 就是其加速檢索的神經系統。從宏觀上看,索引本身就是一種為了加速查詢而設計的復雜數據結構。對向量數據創建索引后,Milvus 可以極大地提升向量相似性搜索的速度,代價是會占用額外的存儲和內存資源。
索引建立由數據節點執行。為了避免頻繁為數據更新建立索引,Milvus 將 Collections 進一步劃分為多個分段,每個分段都有自己的索引。
Milvus 支持為每個向量場、標量場和主場建立索引。索引構建的輸入和輸出都與對象存儲有關:數據節點將要建立索引的日志快照從段落(在對象存儲中)加載到內存,反序列化相應的數據和元數據以建立索引,索引建立完成后序列化索引,并將其寫回對象存儲。
索引構建主要涉及向量和矩陣操作,因此是計算和內存密集型操作。向量因其高維特性,無法用傳統的樹形索引高效地建立索引,但可以用這方面比較成熟的技術建立索引,如基于集群或圖形的索引。無論其類型如何,建立索引都涉及大規模向量的大量迭代計算,如 Kmeans 或圖遍歷。
與標量數據的索引不同,建立向量索引必須充分利用 SIMD(單指令、多數據)加速。Milvus 天生支持 SIMD 指令集,例如 SSE、AVX2 和 AVX512。考慮到向量索引構建的 "打嗝 "和資源密集性質,彈性對 Milvus 的經濟性而言變得至關重要。Milvus 未來的版本將進一步探索異構計算和無服務器計算,以降低相關成本。
此外,Milvus 還支持標量過濾和主字段查詢。為了提高查詢效率,Milvus 還內置了布魯姆過濾索引、哈希索引、樹型索引和反轉索引等索引,并計劃引入更多外部索引,如位圖索引和粗糙索引。
具體細節可以查詢Milvus幫助文檔。
2.4 檢索
有了數據容器(Collection)和檢索引擎(Index)后,最后一步便是從海量數據中高效檢索信息。
基礎向量檢索(ANN Search)是 Milvus 的核心功能之一,即近似最近鄰(Approximate Nearest Neighbor, ANN)檢索。與需計算全部數據的暴力檢索(Brute-force Search)不同,ANN 檢索借助預先構建的索引,能極速從海量數據中找到與查詢向量最相似的 Top-K 個結果,是一種在速度和精度間實現極致平衡的策略。其主要參數包括:anns_field(指定檢索的向量字段)、data(傳入查詢向量)、limit(或 top_k,指定返回最相似結果的數量)、search_params(指定檢索參數,如距離計算方式 metric_type 和索引相關查詢參數)。
在基礎 ANN 檢索之上,Milvus 還提供多種增強檢索功能,以滿足更復雜的業務需求。過濾檢索(Filtered Search)將向量相似性檢索與標量字段過濾結合,先根據過濾表達式(filter)篩選符合條件的實體,再在子集內執行 ANN 檢索,大幅提升查詢精準度,例如電商場景中 “檢索與紅色連衣裙相似且價格低于 500 元、有庫存的商品”,或知識庫中 “從‘技術’分類、2023 年后發布的文章里找與‘人工智能’相關的文檔”。
范圍檢索(Range Search)聚焦于 “所有與查詢向量相似度在特定范圍內的結果”,通過定義距離(或相似度)閾值范圍,返回所有距離落在該范圍內的實體,應用于人臉識別中 “查找與目標人臉相似度超 0.9 的人臉” 進行身份驗證,或異常檢測中 “查找與正常樣本向量距離過大的數據點” 以發現異常。
多向量混合檢索是強大的高級模式,支持在一個請求中同時檢索多個向量字段并智能融合結果:先針對不同向量字段(如文本語義密集向量、關鍵詞匹配稀疏向量、圖像內容多模態向量)并行發起 ANN 檢索,再通過重排策略(如平衡各方結果的 RRFRanker、可為特定字段加權的 WeightedRanker)合并為統一高質量排序列表,例如多模態商品檢索中,用戶輸入 “安靜舒適的白色耳機”,系統同時檢索商品文本描述和圖片內容向量返回最匹配結果;增強型 RAG 中,結合密集向量(捕捉語義)和稀疏向量(精確匹配關鍵詞)實現更精準的文檔檢索。
分組檢索則解決了檢索結果多樣性不足的問題,允許指定字段(如 document_id)對結果分組,確保返回結果中每個組(每個 document_id)只出現一次(或指定次數),且為該組內與查詢最相似的實體,例如視頻檢索 “可愛的貓咪” 時確保結果來自不同博主,文檔檢索 “數據庫索引” 時確保結果來自不同書籍或來源。通過這些靈活的檢索功能組合,開發者可構建滿足各類復雜業務需求的向量檢索應用。
2.5 部署安裝
首先,我們需要下載一個docker。下載docker步驟如下:
1.安裝wsl。首先,搜索“啟用或關閉Windows功能”,可以直接在任務欄中搜索。勾選“虛擬機平臺”與“適用于Linux的Windows子系統”。其中“虛擬機平臺”可能并未被翻譯,叫做“Virtual Machine Platform”
勾選完畢之后你的電腦會重啟。重啟之后你需要以管理員身份打開cmd。依次輸入以下兩串代碼:
wsl --set-default-version 2
wsl --update --web-download
其中“–web-download”可以減少網絡問題導致的wsl下載失敗。
2.打開docker官方網址,選擇amd64下載Docker Desktop Installer.exe文件。
你可以直接安裝,如果你想要指定docker的安裝目錄,你可以將exe文件拖到cmd默認目錄下,然后輸入下面這段代碼:
start /w "" "Docker Desktop Installer.exe" install --installation-dir=地址
3.下載Milvus配置文件
首先移動到你代碼所在的目錄下,注意這里要使用powershell
cd "code 地址"
接著,使用以下命令下載官方的 docker-compose.yml
文件。這個文件定義了 Milvus Standalone 及其運行所需的兩個核心依賴服務:etcd
用于存儲元數據,MinIO
用于對象存儲(更多架構細節請參考官方文檔)。
# Windows (使用 PowerShell)
Invoke-WebRequest -Uri "https://github.com/milvus-io/milvus/releases/download/v2.5.14/milvus-standalone-docker-compose.yml" -OutFile "docker-compose.yml"
下載完畢之后,你的文件夾中會有一個名為“docker-compose.yml”的文件。
在 docker-compose.yml
文件所在的目錄中,運行以下命令以后臺模式啟動 Milvus:
docker compose up -d
Docker 將會自動拉取所需的鏡像并啟動三個容器:milvus-standalone
, milvus-minio
, 和 milvus-etcd
。這個過程可能需要幾分鐘,具體取決于你的網絡狀況。流程截圖如下:
可以通過以下方式驗證 Milvus 是否成功啟動:
- 查看 Docker 容器: 打開 Docker Desktop 的儀表盤 (Windows/macOS) 或在終端運行
docker ps
命令 (Linux),確認三個 Milvus 相關容器(milvus-standalone
,milvus-minio
,milvus-etcd
)都處于running
或up
狀態。 - 檢查服務端口: Milvus Standalone 默認通過
19530
端口提供服務,這是后續代碼連接時需要用到的地址。
并且你的文件夾會變成這樣:
2.6 運行代碼
完整代碼如下:
import os
from tqdm import tqdm
from glob import glob
import torch
from visual_bge.visual_bge.modeling import Visualized_BGE
from pymilvus import MilvusClient, FieldSchema, CollectionSchema, DataType
import numpy as np
import cv2
from PIL import Image# 1. 初始化設置
MODEL_NAME = "BAAI/bge-base-en-v1.5" # 使用的預訓練模型名稱
MODEL_PATH = r"all-in-rag\models\bge\Visualized_base_en_v1.5.pth" # 模型權重路徑
DATA_DIR = r"all-in-rag\data\C3" # 數據集目錄
COLLECTION_NAME = "multimodal_demo" # Milvus集合名稱
MILVUS_URI = "http://localhost:19530" # Milvus服務器地址# 2. 定義工具 (編碼器和可視化函數)
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] # 轉換為Python列表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]def visualize_results(query_image_path: str, retrieved_images: list, img_height: int = 300, img_width: int = 300, row_count: int = 3) -> np.ndarray:"""從檢索到的圖像列表創建一個全景圖用于可視化。"""# 創建空白畫布panoramic_width = img_width * row_countpanoramic_height = img_height * row_countpanoramic_image = np.full((panoramic_height, panoramic_width, 3), 255, dtype=np.uint8) # 白色背景query_display_area = np.full((panoramic_height, img_width, 3), 255, dtype=np.uint8) # 查詢圖像區域# 處理查詢圖像query_pil = Image.open(query_image_path).convert("RGB")query_cv = np.array(query_pil)[:, :, ::-1] # PIL轉OpenCV格式(RGB->BGR)resized_query = cv2.resize(query_cv, (img_width, img_height))bordered_query = cv2.copyMakeBorder(resized_query, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=(255, 0, 0)) # 添加藍色邊框# 將查詢圖像放置在右側區域底部query_display_area[img_height * (row_count - 1):, :] = cv2.resize(bordered_query, (img_width, img_height))# 添加"Query"標簽cv2.putText(query_display_area, "Query", (10, panoramic_height - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)# 處理檢索到的圖像for i, img_path in enumerate(retrieved_images):row, col = i // row_count, i % row_count # 計算網格位置start_row, start_col = row * img_height, col * img_width # 計算起始坐標retrieved_pil = Image.open(img_path).convert("RGB")retrieved_cv = np.array(retrieved_pil)[:, :, ::-1] # 轉換格式resized_retrieved = cv2.resize(retrieved_cv, (img_width - 4, img_height - 4)) # 調整大小bordered_retrieved = cv2.copyMakeBorder(resized_retrieved, 2, 2, 2, 2, cv2.BORDER_CONSTANT, value=(0, 0, 0)) # 添加黑色邊框panoramic_image[start_row:start_row + img_height, start_col:start_col + img_width] = bordered_retrieved # 放置到畫布# 添加索引號cv2.putText(panoramic_image, str(i), (start_col + 10, start_row + 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)# 拼接查詢區域和結果區域return np.hstack([query_display_area, panoramic_image])# 3. 初始化客戶端
print("--> 正在初始化編碼器和Milvus客戶端...")
encoder = Encoder(MODEL_NAME, MODEL_PATH) # 創建編碼器實例
milvus_client = MilvusClient(uri=MILVUS_URI) # 連接Milvus服務器# 4. 創建 Milvus Collection
print(f"\n--> 正在創建 Collection '{COLLECTION_NAME}'")
# 檢查并刪除已存在的集合
if milvus_client.has_collection(COLLECTION_NAME):milvus_client.drop_collection(COLLECTION_NAME)print(f"已刪除已存在的 Collection: '{COLLECTION_NAME}'")# 獲取數據集中的圖像文件
image_list = glob(os.path.join(DATA_DIR, "dragon", "*.png"))
if not image_list:raise FileNotFoundError(f"在 {DATA_DIR}/dragon/ 中未找到任何 .png 圖像。")# 獲取嵌入維度(使用第一張圖像)
dim = len(encoder.encode_image(image_list[0]))# 定義集合字段
fields = [FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), # 主鍵IDFieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=dim), # 向量字段FieldSchema(name="image_path", dtype=DataType.VARCHAR, max_length=512), # 圖像路徑
]# 創建集合
schema = CollectionSchema(fields, description="多模態圖文檢索")
milvus_client.create_collection(collection_name=COLLECTION_NAME, schema=schema)
print(f"成功創建 Collection: '{COLLECTION_NAME}'")
print("Collection 結構:")
print(milvus_client.describe_collection(collection_name=COLLECTION_NAME))# 5. 準備并插入數據
print(f"\n--> 正在向 '{COLLECTION_NAME}' 插入數據")
data_to_insert = []
# 遍歷所有圖像并生成嵌入向量
for image_path in tqdm(image_list, desc="生成圖像嵌入"):vector = encoder.encode_image(image_path) # 編碼圖像data_to_insert.append({"vector": vector, "image_path": image_path}) # 準備數據# 批量插入數據
if data_to_insert:result = milvus_client.insert(collection_name=COLLECTION_NAME, data=data_to_insert)print(f"成功插入 {result['insert_count']} 條數據。")# 6. 創建索引
print(f"\n--> 正在為 '{COLLECTION_NAME}' 創建索引")
# 配置HNSW索引參數
index_params = milvus_client.prepare_index_params()
index_params.add_index(field_name="vector",index_type="HNSW", # 分層可導航小世界圖算法metric_type="COSINE", # 余弦相似度params={"M": 16, "efConstruction": 256} # HNSW參數
)
# 創建索引
milvus_client.create_index(collection_name=COLLECTION_NAME, index_params=index_params)
# 加載集合到內存
milvus_client.load_collection(collection_name=COLLECTION_NAME)
print("已加載 Collection 到內存中。")# 7. 執行多模態檢索
print(f"\n--> 正在 '{COLLECTION_NAME}' 中執行檢索")
# 定義查詢圖像和文本
query_image_path = os.path.join(DATA_DIR, "dragon", "query.png")
query_text = "一條龍"
# 生成多模態查詢向量
query_vector = encoder.encode_query(image_path=query_image_path, text=query_text)# 執行相似度搜索
search_results = milvus_client.search(collection_name=COLLECTION_NAME,data=[query_vector], # 查詢向量output_fields=["image_path"], # 返回的字段limit=5, # 返回前5個結果search_params={"metric_type": "COSINE", "params": {"ef": 128}} # 搜索參數
)[0] # 獲取第一個查詢結果# 處理檢索結果
retrieved_images = []
print("檢索結果:")
for i, hit in enumerate(search_results):print(f" Top {i+1}: ID={hit['id']}, 距離={hit['distance']:.4f}, 路徑='{hit['entity']['image_path']}'")retrieved_images.append(hit['entity']['image_path']) # 收集圖像路徑# 8. 可視化與清理
print(f"\n--> 正在可視化結果并清理資源")
if not retrieved_images:print("沒有檢索到任何圖像。")
else:panoramic_image = visualize_results(query_image_path, retrieved_images)combined_image_path = os.path.join(DATA_DIR, "search_result.png")cv2.imwrite(combined_image_path, panoramic_image)print(f"結果圖像已保存到: {combined_image_path}")Image.open(combined_image_path).show()milvus_client.release_collection(collection_name=COLLECTION_NAME)
print(f"已從內存中釋放 Collection: '{COLLECTION_NAME}'")
milvus_client.drop_collection(COLLECTION_NAME)
print(f"已刪除 Collection: '{COLLECTION_NAME}'")
運行結果如下所示:
E:\anaconda\envs\all-in-rag\Lib\site-packages\timm\models\layers\__init__.py:48:
--> 正在初始化編碼器和Milvus客戶端...--> 正在創建 Collection 'multimodal_demo'
Schema 結構:
{'auto_id': True, 'description': '多模態圖文檢索', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'image_path', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 512}}], 'enable_dynamic_field': False}
成功創建 Collection: 'multimodal_demo'
Collection 結構:
{'collection_name': 'multimodal_demo', 'auto_id': True, 'num_shards': 1, 'description': '多模態圖文檢索', 'fields': [{'field_id': 100, 'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'params': {}, 'auto_id': True, 'is_primary': True}, {'field_id': 101, 'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'field_id': 102, 'name': 'image_path', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 512}}], 'functions': [], 'aliases': [], 'collection_id': 460171652961143814, 'consistency_level': 2, 'properties': {}, 'num_partitions': 1, 'enable_dynamic_field': False, 'created_timestamp': 460171813451988996, 'update_timestamp': 460171813451988996} --> 正在向 'multimodal_demo' 插入數據
生成圖像嵌入: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████| 7/7 [00:01<00:00, 4.45it/s]
成功插入 7 條數據。--> 正在為 'multimodal_demo' 創建索引
成功為向量字段創建 HNSW 索引。
索引詳情:
{'M': '16', 'efConstruction': '256', 'metric_type': 'COSINE', 'index_type': 'HNSW', 'field_name': 'vector', 'index_name': 'vector', 'total_rows': 0, 'indexed_rows': 0, 'pending_index_rows': 0, 'state': 'Finished'}
已加載 Collection 到內存中。--> 正在 'multimodal_demo' 中執行檢索
檢索結果:Top 1: ID=460171652961143835, 距離=0.9466, 路徑='all-in-rag\data\C3\dragon\query.png'Top 2: ID=460171652961143829, 距離=0.7443, 路徑='all-in-rag\data\C3\dragon\dragon02.png'Top 3: ID=460171652961143833, 距離=0.6851, 路徑='all-in-rag\data\C3\dragon\dragon06.png'Top 4: ID=460171652961143830, 距離=0.6049, 路徑='all-in-rag\data\C3\dragon\dragon03.png'Top 5: ID=460171652961143832, 距離=0.5360, 路徑='all-in-rag\data\C3\dragon\dragon05.png'--> 正在可視化結果并清理資源
結果圖像已保存到: all-in-rag\data\C3\search_result.png
已從內存中釋放 Collection: 'multimodal_demo'
已刪除 Collection: 'multimodal_demo'
整體流程總結:
- 初始化設置:配置模型、路徑和Milvus連接參數
- 定義工具:
Encoder
類:處理圖像/文本到向量的轉換visualize_results
函數:創建查詢結果的可視化視圖
- Milvus集合管理:
- 創建包含向量和圖像路徑的集合
- 刪除已存在的同名集合
- 數據處理:
- 加載并編碼所有圖像
- 將向量和元數據插入Milvus
- 索引創建:為向量字段創建HNSW索引
- 多模態檢索:
- 結合圖像和文本生成查詢向量
- 在Milvus中執行相似度搜索
- 結果展示:
- 打印檢索結果
- 可視化查詢圖像和結果圖像
- 資源清理:釋放并刪除Milvus集合
參考文章
[1] https://blog.csdn.net/lsb2002/article/details/132222947
[2] https://datawhalechina.github.io/all-in-rag/#/chapter3/09_milvus