在Notebook中通过镜像保存功能制作自定义镜像用于推理
场景说明
本文详细介绍如何将本地已经制作好的模型包导入ModelArts的开发环境Notebook中进行调试和保存,然后将保存后的镜像部署到推理。本案例仅适用于华为云北京四和上海一站点。
操作流程如下:
Step1 在Notebook中复制模型包
- 登录ModelArts控制台,在左侧导航栏中选择“开发空间 > Notebook”,进入“Notebook”管理页面。
- 单击右上角“创建”,进入“创建Notebook”页面,请参见如下说明填写参数。
- 填写Notebook基本信息,包含名称、描述、是否自动停止。
- 填写Notebook详细参数,如选择镜像、资源规格等。
- “镜像”:选择统一镜像tensorflow_2.1-cuda_10.1-cudnn7-ubuntu_18.04(详见引擎版本一:tensorflow_2.1.0-cuda_10.1-py_3.7-ubuntu_18.04-x86_64)或者pytorch1.8-cuda10.2-cudnn7-ubuntu18.04(详见引擎版本一:pytorch_1.8.0-cuda_10.2-py_3.7-ubuntu_18.04-x86_64)。
- “资源池”:选择公共资源池或专属资源池,此处以公共资源池为例。
- “类型”:推荐选择GPU。
- “规格”:推荐选择GP Tnt004规格,如果没有再选择其他规格。
- 参数填写完成后,单击“立即创建”进行规格确认。参数确认无误后,单击“提交”,完成Notebook的创建操作。
进入Notebook列表,正在创建中的Notebook状态为“创建中”,创建过程需要几分钟,请耐心等待。
- 当Notebook状态变为“运行中”时,表示Notebook已创建并启动完成。单击“操作列”的“打开”,进入JupyterLab的Launcher界面。
图1 打开后进入JupyterLab的Launcher界面
- 通过功能,上传模型包文件到Notebook中,默认工作目录/home/ma-user/work/。模型包文件需要用户自己准备,样例内容参见模型包文件样例。
图2 上传模型包
- 打开Terminal终端,解压model.zip,解压后删除zip文件。
#解压命令 unzip model.zip
图3 在Terminal终端中解压model.zip
- 在Terminal运行界面,执行复制命令。
cp -rf model/* /home/ma-user/infer/model/1
然后执行如下命令查看镜像文件复制成功。
cd /home/ma-user/infer/model/1
ll
图4 查看镜像文件复制成功
模型包文件样例
模型包文件model.zip中需要用户自己准备模型文件,此处仅是举例示意说明,以一个手写数字识别模型为例。
Model目录下必须要包含推理脚本文件customize_service.py,目的是为开发者提供模型预处理和后处理的逻辑。
推理脚本customize_service.py的具体写法要求可以参考模型推理代码编写说明。
本案例中提供的customize_service.py文件具体内容如下:
import logging import threading import numpy as np import tensorflow as tf from PIL import Image from model_service.tfserving_model_service import TfServingBaseService class mnist_service(TfServingBaseService): def __init__(self, model_name, model_path): self.model_name = model_name self.model_path = model_path self.model = None self.predict = None # 非阻塞方式加载saved_model模型,防止阻塞超时 thread = threading.Thread(target=self.load_model) thread.start() def load_model(self): # load saved_model 格式的模型 self.model = tf.saved_model.load(self.model_path) signature_defs = self.model.signatures.keys() signature = [] # only one signature allowed for signature_def in signature_defs: signature.append(signature_def) if len(signature) == 1: model_signature = signature[0] else: logging.warning("signatures more than one, use serving_default signature from %s", signature) model_signature = tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY self.predict = self.model.signatures[model_signature] def _preprocess(self, data): images = [] for k, v in data.items(): for file_name, file_content in v.items(): image1 = Image.open(file_content) image1 = np.array(image1, dtype=np.float32) image1.resize((28, 28, 1)) images.append(image1) images = tf.convert_to_tensor(images, dtype=tf.dtypes.float32) preprocessed_data = images return preprocessed_data def _inference(self, data): return self.predict(data) def _postprocess(self, data): return { "result": int(data["output"].numpy()[0].argmax()) }
Step2 在Notebook中调试模型
- 打开一个新的Terminal终端,进入“/home/ma-user/infer/”目录,运行启动脚本run.sh,并预测模型。基础镜像中默认提供了run.sh作为启动脚本。启动命令如下:
sh run.sh
图6 运行启动脚本
- 上传一张预测图片(手写数字图片)到Notebook中。
图7 手写数字图片
图8 上传预测图片
- 重新打开一个新的Terminal终端,执行如下命令进行预测。
curl -kv -F 'images=@/home/ma-user/work/test.png' -X POST http://127.0.0.1:8080/
图9 预测
在调试过程中,如果有修改模型文件或者推理脚本文件,需要重启run.sh脚本。执行如下命令先停止nginx服务,再运行run.sh脚本。
#查询nginx进程 ps -ef |grep nginx #关闭所有nginx相关进程 kill -9 {进程ID} #运行run.sh脚本 sh run.sh
也可以执行pkill nginx命令直接关闭所有nginx进程。
#关闭所有nginx进程 pkill nginx #运行run.sh脚本 sh run.sh
图10 重启run.sh脚本
Step3 Notebook中保存镜像
Notebook实例状态必须为“运行中”才可以一键进行镜像保存。
- 在Notebook列表中,对于要保存的Notebook实例,单击右侧“操作”列中的 ,进入“保存镜像”对话框。
- 在保存镜像对话框中,设置组织、镜像名称、镜像版本和描述信息。单击“确认”保存镜像。
在“组织”下拉框中选择一个组织。如果没有组织,可以单击右侧的“立即创建”,创建一个组织。创建组织的详细操作请参见创建组织。
同一个组织内的用户可以共享使用该组织内的所有镜像。
- 镜像会以快照的形式保存,保存过程约5分钟,请耐心等待。此时不可再操作实例(对于打开的JupyterLab界面和本地IDE仍可操作)。
快照中耗费的时间仍占用实例的总运行时长,如果在快照中时,实例因运行时间到期停止,将导致镜像保存失败。
- 镜像保存成功后,实例状态变为“运行中”,用户可在“镜像管理”页面查看到该镜像详情。
- 单击镜像的名称,进入镜像详情页,可以查看镜像版本/ID,状态,资源类型,镜像大小,SWR地址等。
Step4 使用保存成功的镜像用于推理部署
将Step2 在Notebook中调试模型的自定义镜像导入到模型中,并部署为在线服务。
- 登录ModelArts控制台,在左侧导航栏中选择“模型管理”,单击“创建模型”,进入创建模型。
- 设置模型的参数,如图11所示。
- 元模型来源:从容器镜像中选择。
- 容器镜像所在的路径:单击选择镜像文件。具体路径查看5SWR地址。
- 容器调用接口:选择HTTPS。
- host:设置为8443。
- 部署类型:选择在线服务。
- 填写启动命令,启动命令内容如下:
sh /home/ma-user/infer/run.sh
- 填写apis定义,单击“保存”生效。apis定义中指定输入为文件,具体内容参见下面代码样例。
图12 填写apis定义
apis定义具体内容如下:
[{ "url": "/", "method": "post", "request": { "Content-type": "multipart/form-data", "data": { "type": "object", "properties": { "images": { "type": "file" } } } }, "response": { "Content-type": "applicaton/json", "data": { "type": "object", "properties": { "result": { "type": "integer" } } } } }]
apis定义提供模型对外Restfull api数据定义,用于定义模型的输入、输出格式。
- 创建模型填写apis。在创建的模型部署服务成功后,进行预测时,会自动识别预测类型。
- 创建模型时不填写apis。在创建的模型部署服务成功后,进行预测,需选择“请求类型”。“请求类型”可选择“application/json”或“multipart/form-data”。请根据元模型,选择合适的类型。
- 选择“application/json”时,直接填写“预测代码”进行文本预测。
- 选择“multipart/form-data”时,需填写“请求参数”,请求参数取值等同于使用图形界面的软件进行预测(以Postman为例)Body页签中填写的“KEY”的取值,也等同于使用curl命令发送预测请求上传数据的参数名。
- 设置完成后,单击“立即创建”,等待模型状态变为“正常”。
- 单击新建的模型名称左侧的小三角形,展开模型的版本列表。在操作列单击“部署 > 在线服务”,跳转至在线服务的部署页面。
- 在部署页面,参考如下说明填写关键参数。
“资源池”:选择“公共资源池”。
“模型来源”和“选择模型及版本”:会自动选择模型和版本号。
“实例规格”:在下拉框中选择“限时免费”资源,勾选并阅读免费规格说明。
其他参数可使用默认值。
如果限时免费资源售罄,建议选择收费CPU资源进行部署。当选择收费CPU资源部署在线服务时会收取少量资源费用,具体费用以界面信息为准。
- 参数配置完成后,单击“下一步”,确认规格参数后,单击“提交”启动在线服务的部署。
- 进入“部署上线 > 在线服务”页面,等待服务状态变为“运行中”时,表示服务部署成功。单击操作列的“预测”,进入服务详情页的“预测”页面。上传图片,预测结果。