使用镜像部署模型#

PAI支持用户使用镜像的方式部署模型,通过镜像,开发者可以自定义模型部署的环境,包括Python、使用的机器学习框架、依赖的第三方库等,能够支持用户灵活的部署需求。详细的介绍可以参考PAI帮助文档:使用镜像部署模型

PAI Python SDK提供了便利的API,支持用户能够使用自定义镜像,或是PAI提供的预置推理,将一个本地,或是OSS上的模型快捷得部署为模型在线服务。

本文档将介绍,用户如何通过PAI Python SDK通过自定义镜像的方式部署模型。

安装和配置SDK#

我们需要首先安装PAI Python SDK以运行本示例。

!python -m pip install --upgrade alipai

SDK需要配置访问阿里云服务需要的AccessKey,以及当前使用的工作空间和OSS Bucket。在PAI SDK安装之后,通过在 命令行终端 中执行以下命令,按照引导配置密钥、工作空间等信息。

# 以下命令,请在 命令行终端 中执行.

python -m pai.toolkit.config

我们可以通过以下代码验证配置是否已生效。

import pai
from pai.session import get_default_session

print(pai.__version__)

sess = get_default_session()

# 获取配置的工作空间信息
assert sess.workspace_name is not None
print(sess.workspace_name)

部署模型推理服务#

模型在线服务包含了模型的文件、模型的推理服务代码、以及推理服务运行环境。 本示例将使用一个简单的PyTorch模型,通过FlaskPAI提供的PyTorch基础镜像,部署模型在线服务。

下载示例使用的简单PyTorch模型。

# 下载模型到本地 "model" 目录

!mkdir -p model/
!wget https://pai-sdk.oss-cn-shanghai.aliyuncs.com/pai/resources/toy_model.pt -P model/

准备推理服务代码#

在部署模型之前,我们首先需要准备推理服务的代码,它提供HTTP接口,负责接收预测请求,使用模型进行推理,返回预测结果。

当前示例我们将使用 Flask 编写一个简单的推理服务,保存为 infer_src/app.py 文件。

!mkdir -p infer_src
%%writefile infer_src/app.py
import json
from flask import Flask, request
import os
import torch
import numpy as np

app = Flask(__name__)
model = None
# 默认的模型文件路径
MODEL_PATH = "/eas/workspace/model/"

def load_model():
    """加载模型"""
    global model
    model = torch.jit.load(os.path.join(MODEL_PATH, "toy_model.pt"))
    model.eval()

@app.route("/", methods=["POST"])
def predict():
    data = np.asarray(json.loads(request.data)).astype(np.float32)
    output_tensor = model(torch.from_numpy(data))
    pred_res = output_tensor.detach().cpu().numpy()
    return json.dumps(pred_res.tolist())

if __name__ == "__main__":
    load_model()
    app.run(host="0.0.0.0", port=int(os.environ.get("LISTENING_PORT", 8000)))

获取PAI提供的预置推理镜像#

PAI提供了一系列预置的推理镜像,镜像内预置了机器学习框架、常用的第三方库、Python、NVIDIA CUDA库等。我们可以通过以下代码列出所有的预置镜像。

from pai.image import list_images, ImageScope


data = [
    [
        "ImageUri",
        "FrameworkName",
        "FrameworkVersion",
        "AcceleratorType",
        "PythonVersion",
    ]
]

# 列出常用的PyTorch推理镜像
for img in list_images(framework_name="PyTorch", image_scope=ImageScope.INFERENCE):
    data.append(
        [
            img.image_uri,
            img.framework_name,
            img.framework_version,
            img.accelerator_type,
            img.python_version,
        ]
    )

# 列出常用的TensorFlow推理镜像
for img in list_images(framework_name="TensorFlow", image_scope=ImageScope.INFERENCE):
    data.append(
        [
            img.image_uri,
            img.framework_name,
            img.framework_version,
            img.accelerator_type,
            img.python_version,
        ]
    )
from IPython.display import HTML, display

display(
    HTML(
        "<table><tr>{}</tr></table>".format(
            "</tr><tr>".join(
                "<td>{}</td>".format("</td><td>".join(str(_) for _ in row))
                for row in data
            )
        )
    )
)

通过SDK提供的 pai.image.retrieve API,可以获取指定框架版本的镜像。在当前示例中,我们将使用PAI提供的PyTorch 1.12版本的CPU推理镜像

from pai.image import retrieve, ImageScope

# # 获取PyTorch 1.10 GPU推理镜像
# print(retrieve(
#     framework_name="PyTorch",           # 框架名称
#     framework_version="latest",         # 框架版本
#     accelerator_type="gpu",             # 选择支持Nvidia CUDA GPU的镜像
#     image_scope=ImageScope.INFERENCE,   # 镜像类型,推理镜像

# # ).image_uri)

# 获取最新的PyTorch CPU推理镜像
torch_image_uri = retrieve(
    framework_name="PyTorch",  # 框架名称
    framework_version="1.12",  # 框架版本,latest表示使用PAI支持的最新版本
    # accelerator_type="cpu",           # 默认使用CPU镜像
    image_scope=ImageScope.INFERENCE,  # 镜像类型,推理镜像
).image_uri
print(torch_image_uri)

部署推理服务#

使用以上的推理服务代码,以及PyTorch推理镜像,我们将一个PyTorch模型部署为模型在线服务。

from pai.model import Model, container_serving_spec


m = Model(
    model_data="./model/",  # 模型文件,可以是一个本地文件或是OSS Bucket路径(例如 oss://<BucketName>/path/to/model ),
    inference_spec=container_serving_spec(
        image_uri=torch_image_uri,  # 推理服务使用的镜像
        command="python app.py",  # 模型推理服务启动命令
        source_dir="./infer_src/",  # 推理服务代码所在目录
        requirements=["flask==2.0.0", "Werkzeug==2.3.4"],  # 推理服务依赖的Python包
    ),
)
from pai.common.utils import random_str

# 部署模型服务
p = m.deploy(
    service_name=f"toy_model_{random_str(6)}",  # 模型服务名称, 地域内唯一
    instance_type="ecs.c6.large",  # 模型服务使用的机器实例规格
)

调用推理服务#

部署服务后返回的pai.predictor.Predictor对象可以用于调用推理服务,发送预测请求。

import numpy as np

# 构造一个随机数组输入
dummy_input = np.random.rand(1, 10, 10).tolist()
print(dummy_input)

result = p.raw_predict(
    data=dummy_input,
)

# 打印推理结果
print(result.json())

在测试完成之后,删除推理服务

p.delete_service()