四年一度的世界杯已正式拉开战幕,各小组较量正热火朝天地进行中。在这样一场球迷的盛宴中,不如让 Towhee 带你「以文搜球」,一览绿茵场上足球战将们的风采吧~
「以文搜球」是跨模态图文检索的一部分,现在最热门的跨模态图文检索模型莫过于 CLIP,对于模型的原理详解和相干应用教程,举荐参考从零到一,教你搭建从零到一,教你搭建「以文搜图」搜寻服务系列文章。
世界杯是一场寰球的盛宴,这里有来自不同地区、应用着不同语言的敌人们。那咱们在“搜球”的时候 如何能反对其余语言的文本,比方中文?甚至同时反对多种语言的「以文搜球」呢?
中文版搜球
如果察看目前支流的图文跨模态模型,咱们会发现它们的架构根本都蕴含了文本编码器和视觉编码器,别离用于提取文本和图片的特色。那么面对不同语言的文本,模型只须要应用不同的文本数据训练文本编码器,使其适配对应的视觉编码器,就能让文本和图片向量映射到雷同的特色空间。
为了不便用户应用,Towhee 用更加敌对的 Python 接口包装了一些预训练模型。用户能够依据指标工作间接抉择不同算子提取图片与文本向量,其中反对了中文输出。这里咱们以算子 image_text_embedding.taiyi 为例,用 10 张图片搭建一个简略的「以文搜图」服务。
- 数据:10 张图片来自图像数据集 ImageNet 中的“soccer_ball”类别,包含了足球相干的图片。
- 特征提取:image_text_embedding.taiyi 可能将中文或图片转换成向量,应用同一个模型生成的向量领有同样的特色空间。
- 向量数据库:这里搭建的「以文搜图」零碎应用了 Milvus 实现向量存储与检索,包含匹配对应的图片门路。
1. 筹备工作
为了之后的向量存储和检索,咱们须要当时启动 Milvus 服务,具体教程能够参考 Milvus 官网文档。此外,咱们还须要装置相干的 Python 依赖,包含 Towhee 和 Pymilvus(留神依据本人的环境装置其余所须要的依赖包)。
python -m pip install towhee pymilvus
最初,咱们须要筹备一个 Milvus 汇合,用于之后的向量存储和检索。在创立汇合的时候,你能够依据本人的需要配置不同的参数。上面是用 Python 创立 Milvus 汇合的代码示例,该汇合配置如下:
- 汇合名:惟一且不反复,用于指定汇合
-
数据表格:
id
:主键,由零碎主动生成惟一且不反复的整数(无需插入)embedding
:图片向量,由 512 维浮点数组成path
:图片门路,由字段组成
- 索引:基于
embedding
列数据创立 IVF_FLAT 索引(参数"nlist":2048
),同时抉择 IP 内积掂量向量之间的类似度(间隔越大示意越类似)
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
HOST = 'localhost'
PORT = '19530'
COLLECTION_NAME = 'text_image_search'
INDEX_TYPE = 'IVF_FLAT'
METRIC_TYPE = 'IP'
DIM = 512
TOPK = 3
def create_milvus(exist_ok=False):
try:
connections.connect(host=HOST, port=PORT)
except Exception:
raise RunTimeError(f'Fail to connect Milvus with {HOST}:{PORT}')
if utility.has_collection:
collection = Collection(COLLECTION_NAME)
if exist_ok:
print(f'Using existed collection: {COLLECTION_NAME}.')
return collection
else:
print('Deleting previous collection...')
collection.drop()
# Create collection
print('Creating collection...')
fields = [FieldSchema(name='id', dtype=DataType.INT64, description='embedding ids', is_primary=True, auto_id=True),
FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, description='image embeddings', dim=DIM),
FieldSchema(name='path', dtype=DataType.VARCHAR, description='image path', max_length=500)
]
schema = CollectionSchema(fields=fields, description='text image search')
collection = Collection(name=COLLECTION_NAME, schema=schema)
# Create index
print('Creating index...')
index_params = {
'metric_type': METRIC_TYPE,
'index_type': INDEX_TYPE,
'params':{"nlist":2048}
}
collection.create_index(field_name='embedding', index_params=index_params)
print(f'Milvus collection is ready: {COLLECTION_NAME} ({INDEX_TYPE}, {METRIC_TYPE}).')
return collection
collection = create_collection()
2. 插入数据
当筹备工作实现后,咱们能够利用 Towhee 接口 实现一下流程:
- 依据图片门路读取并解码图片
- 利用预训练模型生成图片向量
- 将向量与对应的图片门路插入当时筹备好的 Milvus 汇合
import towhee
# Insert
insert = (towhee.glob['path']('path/to/soccer_ball/*.JPEG')
.image_decode['path', 'image']()
.image_text_embedding.taiyi['image', 'vec'](
model_name='taiyi-clip-roberta-102m-chinese',
modality='image')
.ann_insert.milvus[('vec', 'path'), 'milvus_res'](uri=f'tcp://{HOST}:{PORT}/{COLLECTION_NAME}')
# .select['path', 'image', 'milvus_res']()
# .show())
print(f'Total vectors in collection: {collection.num_entities}')
至此咱们曾经胜利将 10 张样本图片对应的向量和门路存入数据库,一个可供「以文搜图」的零碎就搭建好了。
3. 检索测试
接下来,让咱们简略地用中文查问进行检索测试:
import towhee
query = (towhee.dc['text'](['输出查问语句'])
.image_text_embedding.taiyi['text', 'vec'](
model_name='taiyi-clip-roberta-102m-chinese',
modality='text')
.ann_search.milvus['vec', 'milvus_res'](uri=f'tcp://{HOST}:{PORT}/{COLLECTION_NAME}',
metric_type=METRIC_TYPE,
limit=TOPK,
output_fields=['path'])
.flatten('milvus_res')
.runas_op['milvus_res', ('image_path', 'score')](lambda x: (x.path, x.score))
.image_decode['image_path', 'image']()
.select['text', 'image', 'score']()
.show())
通过查问“小孩玩足球”、“小男孩玩足球”、“小男孩抱着足球”,咱们比照前三名的搜寻后果能够察看到该零碎胜利实现了文本形容与图片内容的匹配。当文本形容出图片之间的差异时,类似度之间的差别会变得更加显著。
多语言版搜球
比照英文版本的「以文搜图」,咱们能够发现其实只须要替换向量化的算子就可能实现中文查问。同理可见,如果有一个算子应用了反对多种语言的预训练模型,咱们就能够搭建一个同时反对多种语言查问的「以文搜图」服务。
上面就是这样一个例子,同时也展现了如何在 Towhee 流水线中应用自定义算子。该自定义算子应用了 towhee.models.clip 中一个反对多语言文本的预训练模型‘clip_vit_b32’,可能将不同语言的文本与图像匹配。
- 自定义算子:
from towhee.models.clip import create_model
from torchvision import transforms
from PIL import Image
import numpy()
model = create_model('clip_vit_b32', pretrained=True, device='cpu')
def encode_text(x):
features = model.encode_text(x, multilingual=True).squeeze(0).detach().cpu().numpy()
return features
def encode_image(x):
tfms = transforms.Compose([transforms.Resize(224, interpolation=transforms.InterpolationMode.BICUBIC),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))
])
img = Image.open(x)
x = tfms(img).unsqueeze(0)
features = model.encode_image(x).squeeze(0).detach().cpu().numpy()
return features
- 插入数据:
import towhee
# Insert
insert = (towhee.glob['path']('path/to/soccer_ball/*.JPEG')
.runas_op['path', 'vec'](func=encode_image)
.ann_insert.milvus[('vec', 'path'), 'milvus_res'](uri=f'tcp://{HOST}:{PORT}/{COLLECTION_NAME}')
.select['path', 'milvus_res']()
.show())
print(f'Total vectors in collection: {collection.num_entities}')
- 文本查问:
import towhee
query = (towhee.dc['text'](['输出查问语句'])
.runas_op['text', 'vec'](func=encode_text)
.ann_search.milvus['vec', 'milvus_res'](uri=f'tcp://{HOST}:{PORT}/{COLLECTION_NAME}',
metric_type=METRIC_TYPE,
limit=TOPK,
output_fields=['path'])
.flatten('milvus_res')
.runas_op['milvus_res', ('image_path', 'score')](lambda x: (x.path, x.score))
.image_decode['image_path', 'image']()
.select['text', 'image', 'score']()
.show())
别离查问中文、英文、西班牙语、法语的“小男孩玩足球”,咱们能够取得简直雷同的查问后果。
通过本文,咱们学习了如何用 Towhee 搭建一个简略的「以文搜球」零碎,胜利地反对了中文等多种语言的输出。还不快快试着搭建一个「搜球」零碎吗?
如果须要利用到理论业务,大家能够用更多的办法优化模型、优化零碎,比方用业务数据微调模型、减速推理服务、实现并列运行、退出异样解决机制等。