本文主要介绍通过DashVector和ModelScope中的Chinese Clip模型实现文搜图、图搜图等功能,同时结合DashText SDK实现sparse vector+dense vector混合检索,熟悉sparse vector的使用方法,提高检索效率。
1 准备工作
1.1 基本概念
Chinese Clip:为modelscope.cn/models/iic/…DashVector:向量检索服务基于阿里云自研的向量引擎 Proxima 内核,提供具备水平拓展、全托管、云原生的高效向量检索服务。向量检索服务将强大的向量管理、查询等能力,通过简洁易用的 SDK/API 接口透出,方便在大模型知识库搭建、多模态 AI 搜索等多种应用场景上集成。详情请参考:modelscope.cn/datasets/mo…DashText:是向量检索服务DashVector推荐使用的稀疏向量编码器(Sparse Vector Encoder),DashText可通过BM25算法将原始文本转换为稀疏向量(Sparse Vector)表达,通过DashText可大幅度简化使用DashVectorhelp.aliyun.com/document_de…
1.2 准备工作
1,获取DashVector的API-KEY。API-KEY用于访问DashVector服务,详请参考:help.aliyun.com/document_de…
3,获取DashVector实例的endpoint,endpoint用于访问DashVector具体的实例。详情请见:
3. 搜索过程:通过对输入的文本或者图片,提取特征,并通过特征在DashVector中已经索引的向量中进行相似向量查询,并将查询后的结果解析成可视化的图片和文本,即完成了搜索过程。详情请看下图。 好啦,Collection创建成功了。 2. 向量插入后,就可以在DashVector控制台看到向量啦!『go-hash』一个 go 常用摘要 Digest Hash 算法库 2 创建DashVector Collection
from dashvector import Client
# 如下填写您在1.2 准备工作中获取的DashVector API-KEY
DASHVECTOR_API_KEY = '{YOUR DashVector API-KEY}'
# 如下填写您在1.2 准备工作中获取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化DashVector 的client
client = Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
response = client.create(
# Collection的名称,名称可自定义。这里暂时定义为:ImageTextSearch
name='ImageTextSearch',
# 创建Collection的维度,注意一定是1024维。因为后面我们会使用Chinese Clip模型进行embedding,Chinese Clip模型的输出维度是1024维。
dimension=1024,
# 距离度量方式一定为dotproduct,因为稀疏向量只支持dotproduc这种度量方式。
metric='dotproduct',
dtype=float,
# 定义schema,通过schema可以定义Collection中包含哪些字段,以及字段的类型,以便实现更快速的搜索。这里定义了image_id、query和query_id三个schema。
# 关于Schema的详细使用请参考:https://help.aliyun.com/document_detail/2510228.html
fields_schema={'image_id': int, 'query': str, 'query_id': int}
)
print(response)3 图片和文本索引
# 首先import一大堆东西
from modelscope.msdatasets import MsDataset
from modelscope.utils.constant import Tasks
from modelscope.pipelines import pipeline
import base64
import io
from dashvector import Client, Doc, DashVectorCode, DashVectorException
from dashtext import SparseVectorEncoder
# load 数据集,选取modelscope中的muge数据集,取数据集中validation部分
# muge数据集的格式为:
# [{
# "query_id": "54372",
# "query": "金属产品打印",
# "image_id": "813904",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB1F39DB0>
# },
# {
# "query_id": "78633",
# "query": "夹棉帽子",
# "image_id": "749842",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB0AFFF70>
# }]
# 首次load muge数据集有点慢,请耐心等待。
datasets = MsDataset.load("muge", split="validation")
# 获取数据集的长度,也就是数据集中有多少个这样的数据
datasets_len = len(datasets)
# 初始化ModelScope推理pipeline,本教程使用Chinese Clip作为embedding模型。由于图片的Embedding比较消耗计算资源,所以推荐使用GPU进行推理加速。
# 请参考:https://modelscope.cn/models/iic/multi-modal_clip-vit-huge-patch14_zh/summary
pipeline = pipeline(task=Tasks.multi_modal_embedding,
model='damo/multi-modal_clip-vit-huge-patch14_zh', model_revision='v1.0.0')
# 初始化稀疏向量编码器,用于对muge数据集中的query进行稀疏向量编码,中文编码。详情请参考:https://help.aliyun.com/document_detail/2546039.html
encoder = SparseVectorEncoder()
# encoder初始化的时间比较长,主要原因在于稀疏向量编码器需要加载一个json文件,该文件比较大,需要下载。我们可以先下载完,保存在本地,直接加载,速度会快很多。
# 下载链接:https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json
# 也可以使用:wget https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json,直接下载到本地。
# 下载完成后,放在本机目录中,本教程已经下载完成,放在根目录下。
encoder_path = 'bm25_zh_default.json'
encoder.load(encoder_path)
# 如下填写您在1.2 准备工作中获取的DashVector API-KEY
DASHVECTOR_API_KEY = '{YOUR DashVector API-KEY}'
# 如下填写您在1.2 准备工作中获取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化dashvector的Client,用于访问dashvector服务
# 请参考:https://help.aliyun.com/document_detail/2510240.html
client = Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
# 将图片转成字符串,用于将图片存储在dashvector中
def image_to_str(image):
image_byte_arr = io.BytesIO()
image.save(image_byte_arr, format='PNG')
image_bytes = image_byte_arr.getvalue()
return base64.b64encode(image_bytes).decode()
# 通过Chinese Clip提取图片特征,并转成向量
def image_vector(image):
# 通过Chinese Clip提取图片特征,返回为一个tensor
img_embedding = pipeline.forward({'img': image})['img_embedding']
# 将返回的tensor转成向量,向量需要转存到cpu中
img_vector = img_embedding.detach().cpu().numpy()
return img_vector if isinstance(image, list) else img_vector[0]
# 通过Chinese Clip提取文本特征,并转成向量
def text_vector(text):
# 通过Chinese Clip提取文本特征,返回为一个tensor
text_embedding = pipeline.forward({'text': text})['text_embedding']
# 将返回的tensor转成向量,向量需要转存到cpu中
text_vector = text_embedding.detach().cpu().numpy()
return text_vector if isinstance(text, list) else text_vector[0]
# 通过dashtext对文本生成稀疏向量。注意,本函数为生成入库的稀疏向量,而不是query的稀疏向量
def sparse_vector_documents(text):
# 通过dashtext生成稀疏向量
sparse_vector = encoder.encode_documents(text)
return sparse_vector if isinstance(text, list) else sparse_vector
# 插入向量数据,batch_size默认为10,最大不超过20
def insert_docs(collection_name: str, partition='default', batch_size=10):
idx = 0
while idx < datasets_len:
# 获取batch range数据
batch_range = range(idx, idx + batch_size) if idx + batch_size < datasets_len else range(idx, datasets_len)
# 获取image信息
images = [datasets[i]['image'] for i in batch_range]
# 通过Chinese Clip提取图片特征,返回为一个vector
images_vector = image_vector(images)
# 获取query信息
texts = [datasets[i]['query'] for i in batch_range]
# 生成稀疏向量
documents_sparse_vector = sparse_vector_documents(texts)
# 获取图片ID和query ID
images_ids = [datasets[i]['image_id'] for i in batch_range]
query_ids = [datasets[i]['query_id'] for i in batch_range]
# 获取Collection
collection = client.get(collection_name)
# 批量插入
response = collection.upsert(
[
Doc(
id=image_id,
vector=img_vector,
sparse_vector=document_sparse_vector,
fields={
# 由于在创建Collection时,image_id和query_id都是int类型,所以这里需要转换为int类型
'image_id': int(image_id),
'query_id': int(query_id),
'query': query,
# 将Image格式转成字符串,用于存储在dashvector中
'image': image_to_str(image)
}
) for img_vector, document_sparse_vector, image_id, query_id, image, query in
zip(images_vector, documents_sparse_vector, images_ids, query_ids, images, texts)
]
)
print(response)
idx += batch_size
return response
if __name__ == '__main__':
# 插入数据
response = insert_docs(collection_name='ImageTextSearch', batch_size=20)
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
本文主要介绍通过DashVector和ModelScope中的Chinese Clip模型实现文搜图、图搜图等功能,同时结合DashText SDK实现sparse vector+dense vector混合检索,熟悉sparse vector的使用方法,提高检索效率。
1 准备工作
1.1 基本概念
Chinese Clip:为modelscope.cn/models/iic/…DashVector:向量检索服务基于阿里云自研的向量引擎 Proxima 内核,提供具备水平拓展、全托管、云原生的高效向量检索服务。向量检索服务将强大的向量管理、查询等能力,通过简洁易用的 SDK/API 接口透出,方便在大模型知识库搭建、多模态 AI 搜索等多种应用场景上集成。详情请参考:modelscope.cn/datasets/mo…DashText:是向量检索服务DashVector推荐使用的稀疏向量编码器(Sparse Vector Encoder),DashText可通过BM25算法将原始文本转换为稀疏向量(Sparse Vector)表达,通过DashText可大幅度简化使用DashVectorhelp.aliyun.com/document_de…
1.2 准备工作
1,获取DashVector的API-KEY。API-KEY用于访问DashVector服务,详请参考:help.aliyun.com/document_de…
3,获取DashVector实例的endpoint,endpoint用于访问DashVector具体的实例。详情请见:
3. 搜索过程:通过对输入的文本或者图片,提取特征,并通过特征在DashVector中已经索引的向量中进行相似向量查询,并将查询后的结果解析成可视化的图片和文本,即完成了搜索过程。详情请看下图。 好啦,Collection创建成功了。 2. 向量插入后,就可以在DashVector控制台看到向量啦!
2 创建DashVector Collection
from dashvector import Client
# 如下填写您在1.2 准备工作中获取的DashVector API-KEY
DASHVECTOR_API_KEY = '{YOUR DashVector API-KEY}'
# 如下填写您在1.2 准备工作中获取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化DashVector 的client
client = Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
response = client.create(
# Collection的名称,名称可自定义。这里暂时定义为:ImageTextSearch
name='ImageTextSearch',
# 创建Collection的维度,注意一定是1024维。因为后面我们会使用Chinese Clip模型进行embedding,Chinese Clip模型的输出维度是1024维。
dimension=1024,
# 距离度量方式一定为dotproduct,因为稀疏向量只支持dotproduc这种度量方式。
metric='dotproduct',
dtype=float,
# 定义schema,通过schema可以定义Collection中包含哪些字段,以及字段的类型,以便实现更快速的搜索。这里定义了image_id、query和query_id三个schema。
# 关于Schema的详细使用请参考:https://help.aliyun.com/document_detail/2510228.html
fields_schema={'image_id': int, 'query': str, 'query_id': int}
)
print(response)3 图片和文本索引
# 首先import一大堆东西
from modelscope.msdatasets import MsDataset
from modelscope.utils.constant import Tasks
from modelscope.pipelines import pipeline
import base64
import io
from dashvector import Client, Doc, DashVectorCode, DashVectorException
from dashtext import SparseVectorEncoder
# load 数据集,选取modelscope中的muge数据集,取数据集中validation部分
# muge数据集的格式为:
# [{
# "query_id": "54372",
# "query": "金属产品打印",
# "image_id": "813904",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB1F39DB0>
# },
# {
# "query_id": "78633",
# "query": "夹棉帽子",
# "image_id": "749842",
# "image": <PIL.PngImagePlugin.PngImageFile image mode=RGB size=224x224 at 0x7F8EB0AFFF70>
# }]
# 首次load muge数据集有点慢,请耐心等待。
datasets = MsDataset.load("muge", split="validation")
# 获取数据集的长度,也就是数据集中有多少个这样的数据
datasets_len = len(datasets)
# 初始化ModelScope推理pipeline,本教程使用Chinese Clip作为embedding模型。由于图片的Embedding比较消耗计算资源,所以推荐使用GPU进行推理加速。
# 请参考:https://modelscope.cn/models/iic/multi-modal_clip-vit-huge-patch14_zh/summary
pipeline = pipeline(task=Tasks.multi_modal_embedding,
model='damo/multi-modal_clip-vit-huge-patch14_zh', model_revision='v1.0.0')
# 初始化稀疏向量编码器,用于对muge数据集中的query进行稀疏向量编码,中文编码。详情请参考:https://help.aliyun.com/document_detail/2546039.html
encoder = SparseVectorEncoder()
# encoder初始化的时间比较长,主要原因在于稀疏向量编码器需要加载一个json文件,该文件比较大,需要下载。我们可以先下载完,保存在本地,直接加载,速度会快很多。
# 下载链接:https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json
# 也可以使用:wget https://dashvector-data.oss-cn-beijing.aliyuncs.com/public/sparsevector/bm25_zh_default.json,直接下载到本地。
# 下载完成后,放在本机目录中,本教程已经下载完成,放在根目录下。
encoder_path = 'bm25_zh_default.json'
encoder.load(encoder_path)
# 如下填写您在1.2 准备工作中获取的DashVector API-KEY
DASHVECTOR_API_KEY = '{YOUR DashVector API-KEY}'
# 如下填写您在1.2 准备工作中获取的DashVector中Cluster中的Endpoint
DASHVECTOR_END_POINT='{YOUR DashVector Endpoint}'
# 初始化dashvector的Client,用于访问dashvector服务
# 请参考:https://help.aliyun.com/document_detail/2510240.html
client = Client(api_key=DASHVECTOR_API_KEY, endpoint=DASHVECTOR_END_POINT)
# 将图片转成字符串,用于将图片存储在dashvector中
def image_to_str(image):
image_byte_arr = io.BytesIO()
image.save(image_byte_arr, format='PNG')
image_bytes = image_byte_arr.getvalue()
return base64.b64encode(image_bytes).decode()
# 通过Chinese Clip提取图片特征,并转成向量
def image_vector(image):
# 通过Chinese Clip提取图片特征,返回为一个tensor
img_embedding = pipeline.forward({'img': image})['img_embedding']
# 将返回的tensor转成向量,向量需要转存到cpu中
img_vector = img_embedding.detach().cpu().numpy()
return img_vector if isinstance(image, list) else img_vector[0]
# 通过Chinese Clip提取文本特征,并转成向量
def text_vector(text):
# 通过Chinese Clip提取文本特征,返回为一个tensor
text_embedding = pipeline.forward({'text': text})['text_embedding']
# 将返回的tensor转成向量,向量需要转存到cpu中
text_vector = text_embedding.detach().cpu().numpy()
return text_vector if isinstance(text, list) else text_vector[0]
# 通过dashtext对文本生成稀疏向量。注意,本函数为生成入库的稀疏向量,而不是query的稀疏向量
def sparse_vector_documents(text):
# 通过dashtext生成稀疏向量
sparse_vector = encoder.encode_documents(text)
return sparse_vector if isinstance(text, list) else sparse_vector
# 插入向量数据,batch_size默认为10,最大不超过20
def insert_docs(collection_name: str, partition='default', batch_size=10):
idx = 0
while idx < datasets_len:
# 获取batch range数据
batch_range = range(idx, idx + batch_size) if idx + batch_size < datasets_len else range(idx, datasets_len)
# 获取image信息
images = [datasets[i]['image'] for i in batch_range]
# 通过Chinese Clip提取图片特征,返回为一个vector
images_vector = image_vector(images)
# 获取query信息
texts = [datasets[i]['query'] for i in batch_range]
# 生成稀疏向量
documents_sparse_vector = sparse_vector_documents(texts)
# 获取图片ID和query ID
images_ids = [datasets[i]['image_id'] for i in batch_range]
query_ids = [datasets[i]['query_id'] for i in batch_range]
# 获取Collection
collection = client.get(collection_name)
# 批量插入
response = collection.upsert(
[
Doc(
id=image_id,
vector=img_vector,
sparse_vector=document_sparse_vector,
fields={
# 由于在创建Collection时,image_id和query_id都是int类型,所以这里需要转换为int类型
'image_id': int(image_id),
'query_id': int(query_id),
'query': query,
# 将Image格式转成字符串,用于存储在dashvector中
'image': image_to_str(image)
}
) for img_vector, document_sparse_vector, image_id, query_id, image, query in
zip(images_vector, documents_sparse_vector, images_ids, query_ids, images, texts)
]
)
print(response)
idx += batch_size
return response
if __name__ == '__main__':
# 插入数据
response = insert_docs(collection_name='ImageTextSearch', batch_size=20)