多模态检索解决方案

针对多模态检索业务场景,PAI提供了端到端的多模态检索解决方案。该解决方案提供了图像、人脸、文本、文图和图文检索等服务,支持您通过调用EAS服务实现注册多模态数据、提取相关特征、基于ID管理多模态数据以及基于特征的多模态数据搜索等功能。本文为您介绍该解决方案的使用流程。

背景信息

功能支持

  • 多模态特征提取能力:您可以使用基于Alibaba PAI EasyCVEasyNLP提供的预训练模型,或通过DSW平台训练获得的图像特征提取模型、文本向量化模型以及文图CLIP模型部署服务。

  • 特征检索能力:该服务默认使用基于DocArray-PAIAliyunOSS的可持久化、可快速检索的特征数据库能力,支持您存储相关特征到AliyunOSS或从AliyunOSS拉起特征。例如:该服务中存储了10万特征,保存数据库并关闭服务以及初始化服务时,不需要再注册特征数据,即可搜索特征。您也可以配置其他检索产品,例如AliyunElasticSearch。

服务概览

image
  • 目前,多模态检索解决方案支持部署的服务类型为:图像检索(image_retrieval)、人脸检索(faceid_retrieval),文本检索(text_retrieval)、中文多模态检索(imagetext_retrieval_cn)和英文多模态检索(imagetext_retrieval_en)。

  • 各服务提供的调用接口为:服务初始化接口(init、set_root_path等)、数据库管理层接口(add、delete等)和数据库层接口(db_set、db_get等)。

使用流程

多模态检索解决方案的使用流程如下。

  1. 构建模型

    使用PAI提供的预训练模型,或在DSW平台参考Gallery示例自行构建模型。

  2. 部署模型服务

    通过模型在线服务EAS,您可以将训练好的模型或PAI提供的预训练模型部署为在线服务。

  3. 调用模型服务

    通过API方式调用服务初始化接口、数据库管理层接口和数据库层接口,实现多模态数据检索。

前提条件

在开始执行操作前,请确认您已完成以下准备工作:

  • 已开通PAI(DSW、EAS)后付费,并创建默认工作空间,详情请参见创建工作空间

  • 已创建OSS存储空间(Bucket),用于存储数据集、训练获得的模型文件和配置文件。关于如何创建存储空间,详情请参见控制台创建存储空间

  • 已创建DSW实例,且运行正常,详情请参见创建DSW实例。建议:

    • 镜像选择Pytorch1.8,例如pytorch-develop:1.8pai-gpu-py36-cu101-ubuntu18.04

    • 资源规格使用GPU机型P100V100,且内存大于等于32 GB,例如ecs.gn6v-c8g1.2xlarge。

构建模型

您可以使用PAI提供的预训练模型,具体如下表所示。

模型类型

Processor种类

Predictor

模型路径

image_retrieval

(图像检索)

EasyCV

easycv.predictors.feature_extractor.TorchFeatureExtractor

http://pai-vision-data-hz.oss-accelerate.aliyuncs.com/pretrained_models/deepfashion2/df2_1536_easycv061.pth

faceid_retrieval

(人脸检索)

EasyCV

easycv.predictors.feature_extractor.TorchFaceFeatureExtractor

http://pai-vision-data-hz.oss-accelerate.aliyuncs.com/pretrained_models/faceid/resnet50/faceid_resnet50.tar.gz

imagetext_retrieval_cn

(中文CLIP)

EasyNLP

easynlp.appzoo.CLIPPredictor

http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/easynlp_modelzoo/alibaba-pai/clip_chinese_roberta_base_vit_base.tgz

imagetext_retrieval_en

(英文CLIP)

EasyNLP

easynlp.appzoo.CLIPPredictor

http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/easynlp_modelzoo/openai/clip_vit_base_patch32.tgz

text_retrieval

(文本向量化模型)

EasyNLP

easynlp.appzoo.FeatureVectorizationPredictor

http://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/easynlp_modelzoo/public/bert-base-uncased.tgz

您也可以在DSW平台参考Gallery示例自行构建模型,具体操作步骤如下。

  1. 进入DSW Gallery页面,详情请参见DSW Gallery

  2. DSW Gallery页面,构建以下两种模型。

    • 多模态检索模型

      名称或描述文本框中输入CLIP,然后按回车键。在右侧的基于EasyNLP的多模态CLIP图文检索区域,单击DSW中打开。单击后即会自动将本教程所需的资源和教程文件下载至DSW实例中,并在下载完成后自动打开教程文件。image

      在打开的教程文件easynlp_clip.ipynb文件中,您可以直接运行对应的步骤的命令,当成功运行结束一个步骤命令后,再顺次运行下个步骤的命令。image

    • 图像检索模型

      名称或描述文本框中输入Swin Transformer,然后按回车键。在右侧的基于SwinTransformer的图像分类示例区域,单击DSW中打开。单击后即会自动将本教程所需的资源和教程文件下载至DSW实例中,并在下载完成后自动打开教程文件。image

      在打开的教程文件easycv_classification_Swin.ipynb文件中,您可以直接运行对应的步骤的命令,当成功运行结束一个步骤命令后,再顺次运行下个步骤的命令。image

  3. 将训练后得到的模型下载到本地,然后上传到OSS。具体操作,请参见上传与下载数据文件控制台上传文件

部署模型服务

通过模型在线服务EAS,您可以将训练好的模型部署为在线服务,具体操作步骤如下。

  1. 进入模型在线服务(EAS)页面。

    1. 登录PAI控制台

    2. 在左侧导航栏单击工作空间列表,在工作空间列表页面中单击待操作的工作空间名称,进入对应的工作空间。

    3. 在工作空间页面的左侧导航栏选择模型部署 > 模型在线服务(EAS),进入模型在线服务(EAS)页面。

  2. 部署模型服务。

    1. 模型在线服务(EAS)页面,单击部署服务,然后在自定义模型部署区域,单击JSON独立部署

    2. JSON独立部署页面的编辑框中,配置以下内容。

      {
          "cloud": {
              "computing": {
                  "instance_type": "ecs.gn6i-c16g1.4xlarge"
              }
          },
          "containers": [
              {
                  "image": "eas-registry-vpc.<region>.cr.aliyuncs.com/pai-eas/diffuser-inference:easyretrieval1.1.0-pytorch1.8.1-gpu-py309-cu111-ubuntu22.04",
                  "port": 8000,
                  "script": "python /ml/code/app.py --model_type imagetext_retrieval_cn"
              }
          ],
          "features": {
              "eas.aliyun.com/extra-ephemeral-storage": "100Gi"
          },
          "metadata": {
              "cpu": 16,
              "gpu": 1,
              "instance": 1,
              "memory": 62000,
              "name": "<your_service_name>"
          },
          "storage": [
              {
                  "mount_path": "/mnt/models",
                  "oss": {
                      "path": "oss://pai-quickstart-{region}/easycv/models/easyretrieval/",
                      "readOnly": true
                  },
                  "properties": {
                      "resource_type": "model"
                  }
              }
          ]
      }

      其中关键参数配置说明如下,其他参数使用JSON文件中的配置,更多参数配置说明,请参见服务模型所有相关参数说明

      参数

      描述

      metadata

      name

      请配置您自己的服务名称,同地域内唯一。

      containers

      image

      请将<region>替换为服务所在地域ID,例如华东2(上海)为cn-shanghai。关于如何查询地域ID,请参见地域和可用区

      storage

      oss.path

      本方案使用PAI提供的公开预置模型路径,您只需将<region>替换为服务所在地域ID,例如华东2(上海)为cn-shanghai。关于如何查询地域ID,请参见地域和可用区

      您也可以使用上述步骤提供的预置模型和DSW平台训练得到的模型。

      cloud

      computing.instance_type

      实例规格,必须为GPU类型。

    3. 单击部署。当服务状态运行中时,表明服务部署成功。

  3. 查看服务访问地址和Token。

    1. 模型在线服务(EAS)页面,单击目标服务的服务方式列下的调用信息

    2. 调用信息对话框的公网地址调用页签,获取服务访问地址和Token。image

调用模型服务

服务调用方式

完整的POST调用代码如下。

import requests,json
head = {
    "Authorization":"xxxxxx"  # head为部署服务后,PAI-EAS返回的服务调用密钥Token对应的字符串。
}

our_oss_io_config = dict(ak_id='xxxxxx',
                         ak_secret='xxxxxx',
                         hosts='oss-*****-internal.aliyuncs.com',
                         buckets=['examplebucket'])

datas = json.dumps({
    "function_name": "XXX"  # 必选,调用接口的名称。
    "function_params": {
        param1: XXX  # 参考不同接口对应的参数说明。
        param2:
        ....
    },
})
hosts = "xxxxxx/test"
r = requests.post(hosts, data=datas, headers=head)

其中关键参数配置如下所示。

参数

描述

Authorization

配置为上述步骤已查询的服务Token。

our_oss_io_config.ak_id

阿里云账号的AccessKey ID。

our_oss_io_config.ak_secret

阿里云账号的AccessKey Secret。

our_oss_io_config.hosts

OSS地域的Endpoint。OSS地域与Endpoint的对应关系,请参见访问域名和数据中心

重要

需要配置为对应地域的内网Endpoint,否则访问不通。

our_oss_io_config.buckets

您创建的OSS存储空间(Bucket)的名称,与服务所在地域一致。

function_name

接口名称,支持以下取值:

  • 服务初始化接口,包括init、set_root_path、set_oss_config、set_predictor。

  • 数据库管理层接口,包括add、delete、get、load、save。

  • 数据库层接口,包括db_set、db_get、db_delete、db_search。

function_params

参数配置,详情请参见function_name对应的接口说明。

hosts

配置为上述步骤已查询的服务公网访问地址。

接口使用示例如下:

  • 服务初始化接口-set_root_path

    • POST代码示例

      datas = json.dumps({
          "function_name" :"set_root_path",
          "function_params" : {
              "root_path": "oss://examplebucket/ljh-xiaoling/da_test/",
          },
      })
    • POST返回示例(请求成功)

      {
        "request_id": "b576c16e-7fe2-46d4-9502-35771*******",
        "success": True, 
        "info": "None", 
      }
  • 数据库管理层接口-save

    • POST代码示例

      datas = json.dumps({
          "function_name" : "save",
          "function_params" : {},
      })
    • POST返回示例(请求成功)

      {
        "request_id": "f355c3d9-d235-41dd-b262-695966******",
        "success": True, 
        "save": "Done", 
      }
  • 数据库接口-db_search

    • POST代码示例

      datas = json.dumps({
          "function_name": "db_search",
          "function_params": {
              "database_name": "test_1",
              "uri": "oss://examplebucket/ljh-xxxx/da_test/000001.jpeg",
              "search_topk": 2,
              "metric" : "cosine"
          },
      })
    • POST返回示例(请求成功)

      {
        "request_id": "70c2d344-adf9-4b07-b888-cabce0******",
        "success": True, 
        "db_search": [[{'scores': 0.4860914349555969, 'uri': 'oss://examplebucket/ljh-xiaoling/data/image/000015.jpg', 'text': '', 'group_id': '0', 'intra_id': 0}]]
      }

服务调用示例

多模态图像检索服务首先需要建立多模态图像检索数据库,然后将注册到数据库中的多模态数据及图像进行特征提取,最后从多模态图像数据库的数据中,对上传的多模态数据及图像进行相似快速检索。整个过程需要使用的接口包括数据库初始化、增加数据库、增加数据及检索数据等接口。下文提供一个简单的示例供您参考。

  1. 分别创建以下Python脚本。

    • 数据库初始化脚本retrieval_init.py

      import requests
      import json
      head = {
          "Authorization": "xxxxxx"  # head为部署服务后,EAS返回的服务调用密钥Token对应的字符串。
      }
      
      our_oss_io_config = dict(ak_id='xxxxxx',  # 阿里云账号的AccessKey。
                               ak_secret='xxxxxx',  # 阿里云账号的AccessKey Secret。
                               hosts='oss-cn-****-internal.aliyuncs.com',  # 内网Endpoint。
                               buckets=['examplebucket'])  # OSS Bucket。
      
      datas = json.dumps({
          "function_name": "init",
          "function_params": {
              "backend": "oss",
              "root_path": "oss://examplebucket/xxx",
              "oss_io_config": our_oss_io_config,
          },
      })
      hosts = 'http://16640818xxxxxx.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/img_retrieval_001'
      r = requests.post(hosts, data=datas, headers=head)
      print(r.content)
      print("test ending")
      

      其中examplebucket替换为OSS存储空间(Bucket)名称,与服务所在地域一致。其他参数配置说明,请参见服务调用方式

    • 增加数据库脚本retrieval_add.py

      import requests
      import json
      
      ENCODING = 'utf-8'
      datas = json.dumps({
          'function_name': 'add',
          'function_params': {
              'database_name': 'test_1',
          },
      })
      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 ending")
      

      其中hostsAuthorization需要配置为上述步骤已获取的服务访问地址和Token。

    • 指定Predictor脚本retrieval_set_predictor.py

      import requests
      import json
      
      ENCODING = 'utf-8'
      datas = json.dumps({
          "function_name": "set_predictor",
          "function_params": {
              'preprocess': 'load_uri_to_base64str',
          },
      })
      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)
      # r = requests.post("http://0.0.0.0:8000/test", data=datas, timeout=1500)
      print(r.content)
      print("test ending")
      

      其中hostsAuthorization需要配置为上述步骤已获取的服务访问地址和Token。

    • 增加数据的脚本retrieval_db_set.py

      import requests
      import json
      
      ENCODING = 'utf-8'
      datas = json.dumps({
          'function_name': 'db_set',
          'function_params': {
              'database_name': 'test_1',
              'uri': [
                  'oss://examplebucket/ljh-xxxx/data/image/000015.jpg',
              ],
              'group_id': ['0'],  # 存入该数据的群组名。
              'embedding_attr': 'uri'
          },
      })
      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 ending")
      

      其中hostsAuthorization需要配置为上述步骤已获取的服务访问地址和Token;url配置为图片的OSS路径。

    • 检索数据的脚本retrieval_db_search.py

      import requests
      import json
      
      ENCODING = 'utf-8'
      datas = json.dumps({
          'function_name': 'db_search',
          'function_params': {
              'database_name': 'test_1',
              'uri': 'oss://examplebucket/ljh-xxxx/da_test/000001.jpeg',
              'search_topk': 1,  # 返回的最相似的k个数据
              'metric': '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 ending")
      

      其中hostsAuthorization需要配置为上述步骤已获取的服务访问地址和Token;url配置为图片的OSS路径。

  2. 在终端中,分别在脚本文件所在目录依次执行数据库初始化脚本、增加数据库脚本、指定Predictor脚本以及增加数据的脚本。

    python <retrieval_xxx.py>

    其中<retrieval_xxx.py>需要替换为实际的Python脚本名称。

  3. 针对部署好的数据库,执行检索数据的脚本进行目标图像检索。

    python retrieval_db_search.py

    得到的推理预测结果如下所示。

    {"request_id": "d4b4c7c5-2330-49d5-8ffb-a15e490b****", "success": true, "info": [[{"scores": 0.0, "uri": "oss://examplebucket/xxx/000001.jpeg", "text": "", "group_id": "0", "intra_id": 0}]]}

    从上述模型推理的返回结果可以看出,模型服务返回了该数据库中与目标图像相似度最高的图片的URL。