针对图像检索业务场景,PAI提供了端到端的相似图像匹配和图像检索解决方案。本文介绍如何基于未标注的数据构建图像自监督模型,助力您快速搭建相似图像匹配和图像检索业务系统,进而实现以图搜图。
1. 背景信息
1.1 问题背景
在图像检索的业务场景中,例如电商业务里用户需要根据已有图像搜索目标商品,此时需要构建图像检索的模型,让用户快速实现以图搜图。
1.2 解决方案
PAI在相似图像匹配和图像检索领域,提供了端到端、轻量化的纯白盒解决方案。用户只需准备原始的图像数据,无需标注就能构建模型。然后利用PAI的可视化建模平台快速自定义构建图像自监督模型。最后将模型在PAI上进行部署推理,形成完整的端到端流程,实现相似图像匹配和图像检索的业务系统。
1.3 方案优势
无需标注:图像不需要标注,使用原始数据即可建模,节省大量人力成本。
纯白盒:可根据您自己具体的业务场景,纯自定义构建模型。
端到端:从最初的数据准备到最后的模型推理,提供全链路系统构建流程。
轻量级:无论是工程师还是小白,都能快速搭建图像匹配和检索系统。
1.4 相似图像匹配解决方案架构
1.5 图像检索解决方案架构
2. 前提条件
已开通PAI(Studio、DSW、EAS)后付费,详情请参见开通。
已开通AI工作空间,并开通MaxCompute计算资源和DLC计算资源,详情请参见AI工作空间。
已创建OSS存储空间(Bucket),用于存储标签文件和训练获得的模型文件。关于如何创建存储空间,请参见创建存储空间。
已创建PAI-EAS专属资源组,本文训练好的模型会部署至该资源组。关于如何创建专属资源组,请参见创建资源组。
3. 数据准备
本文所用到算法为图像自监督算法,训练过程中无需标注的数据,将原始数据存入OSS既可以直接进行模型的训练。另外在进行图像检索的模型部署过程中,需要在本地准备检索图的图像数据库。从而在图像检索模型的部署过程中,将准备好的本地数据注册到数据库中。
PAI提供了原始数据集,您可以直接使用它进行数据准备。关于数据集的下载方式,请参见Deepfashion2图像数据集。
3.1 模型训练所需数据
登录OSS控制台,将原始图片存储在OSS的某一目录中。
根据图像上传的OSS文件目录,生成OSS图像目标索引的txt文件,示例文件:。然后将生成好的txt索引文件放在某一OSS目录下。
3.2 图像检索数据库
在进行图像检索的模型部署过程中,首先需要准备检索的图像数据库,将注册到数据库中的图像进行特征提取。从而在目标图像的推理过程中,实现针对已存在图像数据库中的数据,对上传的图片进行相似的快速检索。因此需要在本地准备好图像检索数据库中的图像数据,为后续模型部署环节的注册数据库做准备。
4. 图像自监督模型构建
利用PAI提供的可视化建模Studio平台,基于自己特定的业务场景,采用自监督的图像深度学习训练组件,将原始的尚未标注的图像直接进行训练。无论是相似图像匹配的场景还是图像检索的场景,都使用该自监督组件进行模型训练,两种场景在模型训练部分无差别。
进入Designer控制台
登录PAI控制台。
在左侧导航栏中,选择模型开发和训练-> 可视化建模(Studio 2.0)。
构建实验
在可视化建模(Studio 2.0)控制台中,选择实验模板,在实验模板列表中找到相似图像匹配与图像检索,点击并创建实验。
在实验列表中找到刚才创建好的模板实验,并进入实验。
系统根据预置的模板,自动构建实验,如下图所示。运行过程中,可以点击组件右键,查看运行日志。
区域 |
描述 |
① |
配置实验的数据集,即配置读OSS数据组件的OSS数据路径参数为上面准备的图像目标索引的txt文件的OSS目录。例如 |
② |
将初始数据集转换为图像自监督训练组件所需的训练集。数据转tfrecord组件的配置详情请参见下文的表 1。 |
③ |
配置图像自监督模型训练的参数。图像自监督训练组件的配置详情请参见下文的表 2。 |
表 1. 数据转tfrecord组件配置
页签 |
参数 |
描述 |
本案例的示例值 |
字段设置 |
转换配置文件路径 |
转化配置文件的OSS路径。在Designer中无需使用该配置文件。 |
无需填写 |
输出tfrecord路径 |
组件运行成功后,系统会自动在该路径下输出训练集和测试集。 |
oss://pai-online-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/demo_image_match/df2_data/tfrecord/test_210910/ |
|
输出tfrecord前缀 |
自定义输出TFRecord文件名称的前缀。 |
df2_val |
|
参数设置 |
转换数据用于何种模型训练 |
数据转tfrecord组件的输出数据可以用于以下类型的模型训练:
|
CLASSIFICATION |
类别列表文件路径 |
类别列表文件的OSS路径,因为自监督训练组件无需标签组,因此此处上传空文件即可,示例可使用 。 |
oss://pai-online-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/demo_image_match/df2_data/meta/test.config |
|
测试数据分割比例 |
测试数据分割比例。如果设置为0,则所有数据转换为训练数据。设置0.1则表示10%的数据作为验证集。 |
0.0 |
|
图片最大边限制 |
如果配置了该参数,则大图片会被Resize后存入TFRecord,从而节省存储、提高数据读取速度。 |
无需填写 |
|
测试图片最大边限制 |
同图片最大边限制,用于配置测试数据。 |
无需填写 |
|
默认类别名称 |
默认类别名称。对于在类别列表文件中未找到的类别,系统将其映射到默认类别。 |
无需填写 |
|
错误类别名称 |
含有该类别的物体和Box会被过滤,不参与训练。 |
无需填写 |
|
忽略类别名称 |
仅用于检测模型,含有该类别的Box会在训练中被忽略。 |
无需填写 |
|
转换类名称 |
标注数据的来源类型,支持以下取值:
|
自监督标注格式 |
|
分隔符 |
用于标记内容的分隔符。 |
无需填写 |
|
图片编码方式 |
TFRecord中图片的编码方式。 |
jpg |
|
执行调优 |
读取并发数 |
训练过程读取并发数。 |
10 |
写tfrecord并发数 |
训练过程写TFRecord并发数。 |
1 |
|
每个tfrecord保存图片数 |
训练过程每个TFRecord保存的图片数量。 |
1000 |
|
worker个数 |
训练过程中的Worker数量。 |
5 |
|
CPU Core个数 |
训练过程中的CPU Core数量。 |
800 |
|
memory大小 |
训练过程中的内存大小,单位为MB。 |
20000 |
表 2. 图像自监督训练组件设置
页签 |
参数 |
描述 |
本案例的示例值 |
字段设置 |
训练模型类型 |
模型训练的类型,支持以下取值:
在后续的模型推理中,MOBY_TIMM的特征维度为384,其余皆为2048。 |
MOBY_TIMM |
训练所用OSS目录 |
存储训练模型的OSS目录。 |
oss://pai-online-hangzhou.oss-cn-hangzhou-internal.aliyuncs.com/demo_image_match/train/moby_0902/ |
|
训练数据文件OSS路径 |
训练数据集的OSS路径。如果通过上游组件传递训练数据,则无需指定该参数。 |
无需填写 |
|
是否使用预训练的模型 |
建议使用预训练模型,以提高训练模型的精度。 |
否 |
|
预训练模型OSS路径 |
如果有自己的预训练模型,则将该参数配置为自己预训练模型的OSS路径。 如果没有配置该参数,则使用PAI提供的默认预训练模型。 |
无需填写 |
|
参数设置 |
自监督模型使用的backbone |
识别模型的网络名称,系统支持主流的识别模型:
|
resnet_50 |
优化方法 |
模型训练的优化方法,支持以下取值:
|
AdamW |
|
初始学习率 |
网络训练初始的学习率。 |
0.001 |
|
训练batch_size |
训练的批大小,即单次模型迭代或训练过程中使用的样本数量。 |
64 |
|
总的训练迭代epoch轮数 |
总的训练迭代轮数。 |
80 |
|
保存checkpoint的频率 |
保存模型文件的频率。取值1表示对所有训练数据都进行一次迭代。 |
10 |
|
执行调优 |
读取训练数据线程数 |
读取训练数据的线程数。 |
4 |
evtorch model 开启半精度 |
开启半精度,会使模型的推理速度显著提升,同时准确率略有降低。 |
否 |
|
单机或分布式(maxCompute/DLC) |
模型训练使用的计算资源 |
分布式DLC |
|
worker个数 |
用于计算的Worker数量。 |
1 |
|
gpu机型选择 |
计算资源的GPU机型。 注意:自监督模型对资源的消耗较大,建议选择单机4卡或单机8卡的机器进行训练。 |
48vCPU+368GB Mem+4xv100-ecs.gn6e-c12g1.12xlarge |
5. 模型部署调用
利用PAI提供的EAS模型在线服务平台,将训练好的图像自监督模型进行在线部署,并在实际生产环境中的相似图像匹配和图像检索两个场景下进行服务推理实践。
5.1 相似图像匹配部署推理
步骤一:登录PAI-EAS控制台
登录PAI控制台。
在左侧导航栏中,选择模型部署->模型在线服务(EAS)。
步骤二:部署模型服务
部署模型服务在PAI-EAS控制台中,单击模型上传部署进行新建服务,具体参数配置如下:
参数
描述
自定义模型名称
模型的名称,建议结合实际业务进行命名,以区分不同的模型服务。
资源组种类
建议使用专属资源组部署模型服务,从而避免公共资源组资源有限时导致的服务排队。关于如何创建专属资源组,请参见专属资源组。
资源种类
如果您选择资源组种类为公共资源组,则需要选择资源种类为GPU。
Processor种类
选择EasyVision。
模型类型
通用图像比对
模型文件
本案例中训练好的模型均存储在OSS中,因此选择OSS文件导入。选择训练所用OSS目录下的.pt模型文件即可。例如选择epoch_50_export.pt。
部署详情及配置确认面板,配置模型服务占用资源的相关参数。
参数
描述
自定义模型名称
模型的名称,建议结合实际业务进行命名,以区分不同的模型服务。
资源组种类
建议使用专属资源组部署模型服务,从而避免公共资源组资源有限时导致的服务排队。关于如何创建专属资源组,请参见专属资源组。
资源种类
如果您选择资源组种类为公共资源组,则需要选择资源种类为GPU。
Processor种类
选择EasyVision。
模型类型
通用图像比对
模型文件
本案例中训练好的模型均存储在OSS中,因此选择OSS文件导入。选择训练所用OSS目录下的.pt模型文件即可。例如选择epoch_50_export.pt。
点击部署,等待一段时间完成模型部署任务的创建。
步骤三:查看模型服务的公网地址和访问Token
在PAI EAS模型在线服务页面,单击目标服务的服务方式列下的调用信息。
在调用信息对话框的公网地址调用页签,查看公网调用的访问地址和Token。
步骤四:使用脚本进行批量调用
创建相似图像匹配的Python脚本
img_match.py
。
import requests
import base64
import sys
import json
hosts = 'http://16640818xxxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_match_001'
head = {
"Authorization":"ZDgzYzdlODg5NTA3ODZiOTY0OWRxxxxxxxxxxxxxxxxxxxxx"
}
imagea_path = "./001.jpg" # 对比图像1的本地路经
imageb_path = "./002.jpg" # 对比图像2的本地路经
ENCODING = 'utf-8'
datas = json.dumps( {
"imagea": base64.b64encode(open(imagea_path, 'rb').read()).decode(ENCODING),
"imageb": base64.b64encode(open(imageb_path, 'rb').read()).decode(ENCODING),
})
for x in range(0,1):
resp = requests.post(hosts, data=datas, headers=head)
print(resp.content)
print("test endding")
将python脚本上传至您的任意环境,并在脚本上传后的当前目录执行如下调用命令。
$ python3 img_match.py
得到的预测结果如下图所示,得到类似如下的预测结果,其中similarity代表图像的相似度,取值0~1之间,数值越大相似度越高。
步骤五:监控服务指标
调用模型服务后,您可以查看模型调用的相关指标水位,包括QPS、RT、CPU、GPU及Memory。
在PAI EAS模型在线服务页面,单击已调用服务服务监控列下的监控图标。
在服务监控页签,即可查看模型调用的指标水位。从服务监控的水位图中可以看到部署的模型的时延在80ms左右。
5.2 图像检索部署推理
步骤一:登录PAI-EAS控制台
登录PAI控制台。
在左侧导航栏中,选择模型部署 ->模型在线服务(EAS)。
步骤二:部署模型服务
在PAI-EAS控制台中,单击模型上传部署进行新建服务,具体参数配置如下:
参数 |
描述 |
自定义模型名称 |
模型的名称,建议结合实际业务进行命名,以区分不同的模型服务。 |
资源组种类 |
建议使用专属资源组部署模型服务,从而避免公共资源组资源有限时导致的服务排队。关于如何创建专属资源组,请参见专属资源组。推荐选择单卡GPU机器。 |
资源种类 |
如果您选择资源组种类为公共资源组,则需要选择资源种类为GPU。 |
Processor种类 |
选择EasyVision。 |
模型类型 |
商品检索 |
模型文件 |
本案例中训练好的模型均存储在OSS中,因此选择OSS文件导入。选择训练所用OSS目录下的.pt模型文件即可。例如选择epoch_50_export.pt。 |
在部署详情及配置确认面板,配置模型服务占用资源的相关参数。
参数 |
描述 |
实例数 |
本案例配置为1。实际应用时建议配置多个服务实例,以避免单点部署带来的风险。 |
卡数 |
本案例配置为1。实际应用时根据情况配置。 |
核数 |
本案例配置为1。实际应用时根据情况配置。 |
内存数(M) |
本案例配置为16384 MB。实际应用时根据情况配置。 |
点击部署,等待一段时间完成模型部署任务的创建。
步骤三:查看模型服务的公网地址和访问Token
在PAI EAS模型在线服务页面,单击目标服务的服务方式列下的调用信息。
在调用信息对话框的公网地址调用页签,查看公网调用的访问地址和Token。
步骤四:图像检索服务推理调用
图像检索服务需要首先建立图像检索数据库,将注册到数据库中的图像进行特征提取,从而实现针对已存在图像数据库中的数据,对上传的图片进行相似的快速检索。详细的接口说明请详见链接。整个过程需要涉及到的接口如下表所示。注:该方案主要针对轻量级数据,如果检索库数据量预期大于1000万,请单独提工单联系我们。
功能 |
描述 |
接口文档 |
初始化 |
首先基于某一指定的OSS路径进行数据库的初始化。 |
|
数据库管理 |
支持对图像数据库进行增加、查询、删除及存储操作。 |
|
图像数据注册 |
指定已存在的图像数据库,对图像数据进行增加、查询、删除及修改操作。 |
|
图像数据检索 |
指定已存在的图像数据库,对上传的图片进行图像相似的快速检索。 |
整个过程的最简流程需要用到的接口包括数据库初始化、增加数据库、增加数据、检索数据。示例如下所示。
数据库初始化的Python脚本retrieval_init.py。
import requests
import base64
import sys
import json
ENCODING = 'utf-8'
our_oss_io_config = dict(ak_id='LTAIcsxxxxxxxxxx', # 阿里云账号的AccessKey
ak_secret='gsiu1HjLGDxxxxxxxxxxxxx', # 阿里云账号的AccessKey Secret
hosts='oss-cn-hangzhou-internal.aliyuncs.com', # 内网endpoint
buckets=['tongxin-lly']) # oss bucket
datas = json.dumps({
"function_name": "init",
"function_params": {
"backend": "oss",
"root_path": "oss://tongxin-lly/img_retrieval/db0914/", # oss具体路经
"oss_io_config" : our_oss_io_config,
},
})
hosts = 'http://16640818xxxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_retrieval_001'
head = {
"Authorization":"NTE3Y2M2ZmEzZGQ3ZGRkOGM4ZDxxxxxxxxx"
}
r = requests.post(hosts, data=datas, headers=head)
print(r.content)
print("test endding")
增加数据库的python脚本retrieval_add.py。注意此处的feature_dim_dict代表模型处理的特征维度,在模型训练时,选择MOBY_TIMM的特征维度为384,其余皆为2048。
import requests
import base64
import sys
import json
ENCODING = 'utf-8'
datas = json.dumps({
"function_name": "add",
"function_params": {
"database_name" : "tongxin_demo",
"feature_dim_dict": {'feature' : 384}, #模型训练的特征维度,选择MOBY_TIMM时为384,其余皆为2048。
"feature_distance_dict":{'feature':'Cosine'}, # 计算特征距离的衡量方法
},
})
hosts = 'http://16640818xxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_retrieval_001'
head = {
"Authorization":"NTE3Y2M2ZmEzZGQ3ZGRkOGM4ZDE1MDxxxxxxxxxxxxxx"
}
r = requests.post(hosts, data=datas, headers=head)
print(r.content)
print("test endding")
增加数据的python脚本retrieval_db_set.py。
import requests
import base64
import sys
import json
ENCODING = 'utf-8'
image_path = "./010.jpg"
datas = json.dumps({
"function_name": "db_set",
"function_params": {
"database_name":"tongxin_demo",
"image" : base64.b64encode(open(image_path, 'rb').read()).decode(ENCODING),
"group_id" : "888", # 存入该数据的群组名
"intra_id" : 10 # 该图像群组名下的具体id
},
})
hosts = 'http://16640818xxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_retrieval_001'
head = {
"Authorization":"NTE3Y2M2ZmEzZGQ3ZGRkOGM4Zxxxxxxxxxxxx"
}
r = requests.post(hosts, data=datas, headers=head)
print(r.content)
print("test endding")
检索数据的python脚本retrieval_db_search.py。
import requests
import base64
import sys
import json
ENCODING = 'utf-8'
image_path = "./test.jpg"
datas = json.dumps({
"function_name": "db_search",
"function_params": {
"database_name":"tongxin_demo",
"image" : base64.b64encode(open(image_path, 'rb').read()).decode(ENCODING),
'search_topk' : 3, # 返回的最相似的k张图像
},
})
hosts = 'http://1664081855xxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_retrieval_001'
head = {
"Authorization":"NTE3Y2M2ZmEzZGQ3ZGRkOGM4ZDE1MDVhNzxxxxxxxxx"
}
r = requests.post(hosts, data=datas, headers=head)
print(r.content)
print("test endding")
将上述涉及到的python脚本全部上传至您的任意环境,并在脚本上传后的当前目录依次执行调用命令。
$ python3 retrieval_xxx.py
最后将针对部署好的数据库,进行目标图片的检索,得到的推理预测结果如下图所示。
从模型推理的返回结果可以看到,模型服务返回了该数据库中与目标图片相似度最高的三张图像的group_id和对应intra_id。