01.
引言
随着人工智能技术的快速发展,数字媒体平台内容传播呈现多模态趋势,多模态搜索技术已成为一个备受关注的领域。本文将探讨如何利用 Milvus 向量数据库来实现高效的多模态搜索,重点关注文搜图、图搜图(相似图片搜索)以及文搜视频等应用场景。我们将使用 Chinese CLIP 模型作为多模态特征提取器,并通过 Milvus Python 客户端 SDK 展示核心实现。
02.
Milvus 简介
Milvus 是一个高性能、高度可扩展的向量数据库,能够在从笔记本电脑到大规模分布式系统的各种环境中高效运行。它既可作为开源软件使用,也提供云服务。
Milvus 的核心优势:
高性能:Milvus 在大多数情况下比其他向量数据库的性能高2-5倍。这得益于以下几个关键设计决策:
硬件感知优化: 针对 AVX512、SIMD、GPU 和 NVMe SSD 等多种硬件架构和平台进行了性能优化。
先进的搜索算法: 支持广泛的内存和磁盘索引/搜索算法,如 IVF、HNSW、DiskANN 等,均经过深度优化。
C++搜索引擎:核心搜索引擎使用 C++编写,集成了从汇编级矢量化到多线程并行化和调度的硬件感知代码优化。
列式存储:采用列式存储架构,大大减少了查询时的数据访问量,提高了性能。
高度可扩展:Milvus 的云原生和高度解耦的系统架构确保了系统可以随数据增长持续扩展:
完全无状态设计,易于通过 Kubernetes 或公有云进行扩展。
组件高度解耦,搜索、数据插入和索引/压缩等关键任务设计为易并行化的进程。
查询节点、数据节点和索引节点可以独立进行横向和纵向扩展。
丰富的搜索功能:Milvus 支持多种类型的搜索功能,包括:
ANN 搜索:寻找与查询向量最接近的前 K 个向量。
过滤搜索:在指定过滤条件下执行 ANN 搜索。
范围搜索:查找与查询向量在指定半径内的向量。
混合搜索:基于多个向量字段进行 ANN 搜索。
关键词搜索:基于 BM25 的关键词搜索。
重排序:基于额外标准或二级算法调整搜索结果顺序。
精确查询:通过主键检索数据。
条件查询:使用特定表达式检索数据。
03.
CLIP模型架构和原理
在深入探讨多模态搜索的具体应用之前,让我们先了解一下CLIP (Contrastive Language-Image Pre-training) 模型的架构和工作原理。CLIP 是由 OpenAI 开发的一个强大的多模态模型,它能够同时处理图像和文本数据,为多模态搜索提供了坚实的基础。CLIP 模型是来自 OpenAI 的经典图文表征模型,其采用双塔模型结构(如下图),利用大规模图文对平行语料进行对比学习,从而能够实现图片和文本的跨模态语义特征抽取。
3.1. CLIP 模型架构
CLIP 模型主要由两个核心组件组成:
视觉编码器 (Visual Encoder):
通常采用如 ResNet 或 Vision Transformer (ViT) 等先进的卷积神经网络或 Transformer 架构。
负责将输入图像转换为固定维度的向量表示。
文本编码器 (Text Encoder):
使用 Transformer 架构,类似于 BERT 或 GPT 。
将输入文本转换为与图像向量相同维度的文本向量。
这两个编码器通过一个共同的投影空间连接,使得图像和文本的表示可以在同一个向量空间中进行比较。
3.2. CLIP 工作原理
对比学习:
CLIP 使用对比学习方法进行训练。
模型学习将语义相关的图像-文本对映射到向量空间中的相近位置,而将不相关的对映射到远离的位置。
大规模预训练:
CLIP 在包含数亿图像-文本对的大规模数据集上进行预训练。
这使得模型能够学习到丰富的视觉-语言关联知识。
零样本迁移:
预训练后的 CLIP 模型可以直接用于各种下游任务,无需额外的微调。
这种能力使 CLIP 特别适合多模态搜索等应用。
3.3. Chinese CLIP
Chinese CLIP 是 CLIP 模型的中文版本,它在大规模中文图文数据上进行了预训练。相比原始的英文 CLIP,Chinese CLIP 更适合处理中文文本和与中文文化相关的图像,因此在本文的应用场景中,我们选择使用 Chinese CLIP 作为多模态特征提取器。
Chinese CLIP 使用大规模中文数据进行训练(~2亿图文对),可用于图文检索和图像、文本的表征提取,应用于搜索、推荐等应用场景。更多技术细节可以参考相关技术报告https://arxiv.org/abs/2211.01335和 Github 开源代码https://github.com/OFA-Sys/Chinese-CLIP。
原始的 CLIP 模型基于英文图文语料,不能用于中文的图文表征提取场景。Chinese CLIP 以英文 CLIP 视觉侧参数和中文 Roberta 参数,作为模型初始化值。基于大规模原生中文图文数据,通过如下图所示的二阶段预训练策略(一阶段仅训练文本侧,二阶段同时训练),实现了 CLIP 模型的中文化版本。
3.4. CLIP 在多模态搜索中的应用
CLIP 模型在多模态搜索中的应用主要体现在以下几个方面:
特征提取:
对于图像,使用视觉编码器提取特征向量。
对于文本,使用文本编码器提取特征向量。
跨模态匹配:
由于图像和文本被映射到同一个向量空间,可以直接计算它们之间的相似度。
这使得文搜图、图搜图、文搜视频等跨模态搜索成为可能。
语义理解:
CLIP 模型通过大规模预训练学习到了丰富的语义知识。
这使得搜索结果不仅基于表面特征,还能捕捉到深层的语义关联。
通过结合 CLIP 模型和 Milvus 向量数据库,我们可以构建出高效、准确的多模态搜索系统。接下来,我们将详细介绍如何在实际应用中利用这些技术。
04.
多模态搜索场景
4.1. 文搜图
文搜图是指用自然语言描述来检索相关图片。这种搜索模式结合了文本理解和图像特征匹配。
实现步骤:
1. 使用 Chinese CLIP 模型将查询文本转换为向量。
2. 在 Milvus 中搜索与查询向量最相似的图片向量。
4.2. 图搜图(相似图片搜索)
图搜图允许用户上传一张图片,然后找到数据库中与之相似的图片。
实现步骤:
使用 Chinese CLIP 模型提取查询图片的特征向量。
在 Milvus 中执行向量相似度搜索,找出最相似的图片。
4.3. 文搜视频
文搜视频是一种更复杂的多模态搜索场景,它涉及文本理解和视频内容分析。
实现步骤:
视频特征处理:
利用 ffmpeg 提取视频的关键帧。
使用 Chinese CLIP 模型为每个关键帧生成特征向量。
将这些向量聚合成一个代表整个视频的向量(例如,通过取平均值)。
使用 Chinese CLIP 模型将查询文本转换为向量。
05.
使用 Milvus Python SDK 实现多模态搜索
下面我们将使用 Milvus Python SDK 来演示如何实现上述搜索场景的核心功能。Milvus 提供了多种 API 和 SDK,包括 RESTful API、Python SDK (PyMilvus)、Go SDK、Java SDK、Node.js SDK,以及由 Microsoft 贡献的 C# SDK。在本例中,我们将使用 PyMilvus 。
首先,安装必要的库:
pip install pymilvus clip torch pillow
连接Milvus并创建集合
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType# 连接到Milvus服务器connections.connect("default", host="localhost", port="19530")# 定义集合schemafields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=False), FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=512) ]schema = CollectionSchema(fields, "multi_model_clip_collection")# 创建集合collection_name = "multimodal_search"collection = Collection(collection_name, schema)# 创建索引index_params = {"metric_type": "L2","index_type": "IVF_FLAT","params": {"nlist": 1024}}collection.create_index("embedding", index_params)
这里,我们使用了 IVF_FLAT 索引。Milvus 支持多种索引类型,包括 FLAT、IVF_FLAT、IVF_SQ8、IVF_PQ、HNSW、ANNOY 等,您可以根据具体需求选择合适的索引类型。
实现文搜图
import torch
from PIL import Image
import clip
# 加载Chinese CLIP模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device, download_root=".")
def text_to_vector(text):
with torch.no_grad():
text_inputs = clip.tokenize([text]).to(device)
text_features = model.encode_text(text_inputs)
return text_features.cpu().numpy()[0]
def search_images_by_text(query_text, collection, top_k=5):
query_vector = text_to_vector(query_text)
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
results = collection.search([query_vector], "embedding", search_params, top_k=top_k, output_fields=["id"])
return results
# 使用示例
query = "河边嬉戏的小男孩"
results = search_images_by_text(query, collection)
print(f"查询文本: '{query}'")
for i, result in enumerate(results[0]):
print(f"Top {i+1} 匹配图片ID: {result.id}, 距离: {result.distance}")
实现图搜图
def image_to_vector(image_path):
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
return image_features.cpu().numpy()[0]
def search_similar_images(query_image_path, collection, top_k=5):
query_vector = image_to_vector(query_image_path)
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
results = collection.search([query_vector], "embedding", search_params, top_k=top_k, output_fields=["id"])
return results
# 使用示例
query_image = "path/to/query/image.jpg"
results = search_similar_images(query_image, collection)
print(f"查询图片: '{query_image}'")
for i, result in enumerate(results[0]):
print(f"Top {i+1} 相似图片ID: {result.id}, 距离: {result.distance}")
实现文搜视频
import numpy as npdef process_video(video_path, num_frames=5):# 这里简化了关键帧提取的逻辑,真实应用场景需要考虑更多的因素,向量平均不是最佳办法 frame_vectors = []for i in range(num_frames): frame_path = f"{video_path}_frame_{i}.jpg" frame_vector = image_to_vector(frame_path) frame_vectors.append(frame_vector)return np.mean(frame_vectors, axis=0)def search_videos_by_text(query_text, collection, top_k=5): query_vector = text_to_vector(query_text) search_params = {"metric_type": "L2", "params": {"nprobe": 10}} results = collection.search([query_vector], "embedding", search_params, top_k=top_k, output_fields=["id"])return results# 使用示例querys = ["日落时的海滩场景", "小猫咪"]for query in querys: results = search_videos_by_text(query, collection) print(f"查询文本: '{query}'")for i, result in enumerate(results[0]): print(f"Top {i+1} 匹配视频ID: {result.id}, 距离: {result.distance}")
06.
结论
通过利用 Milvus 向量数据库和 Chinese CLIP 模型,成功实现了多模态搜索的核心功能,包括文搜图、图搜图和文搜视频。CLIP 模型强大的跨模态理解能力为这些搜索场景提供了坚实的基础,而 Milvus 的高效向量检索能力则确保了系统的性能和可扩展性。
这种方法不仅高效,而且具有很强的扩展性,可以处理大规模的多模态数据。通过 CLIP 模型的语义理解能力,我们的搜索系统可以捕捉到更深层次的内容关联,提供更加智能和精准的搜索结果。
在实际应用中,我们需要考虑以下几点工程化的问题:
数据预处理和特征提取的优化
向量索引类型和参数的调优
结果后处理和排序策略
系统的扩展性和性能优化,数据预处理速度,推理效率,大数据存储性能
针对特定领域的模型微调,解决专有名词和实体的识别问题
通过不断改进和优化,基于 Milvus 和 CLIP 的多模态搜索系统可以为用户提供更加智能和个性化的搜索体验。随着多模态 AI 技术的不断发展,我们可以期待这类系统在未来会有更广泛的应用,为各行各业带来更多创新和价值。