实现多子图和有状态模型的服务部署

概述

MindSpore支持一个模型导出生成多张子图,拥有多个子图的模型一般也是有状态的模型,多个子图之间共享权重,通过多个子图配合实现性能优化等目标。例如,在鹏程·盘古模型网络场景,基于一段语句,经过多次推理产生一段语句,其中每次推理产生一个词。不同输入长度将会产生两个图,第一为输入长度为1024的全量输入图,处理首次长度不定文本,只需执行一次,第二图为输入长度为1的增量输入图,处理上一次新增的字,第二个图将执行多次。相对于优化之前仅有全量图执行多次,可实现推理服务性能的5-6倍提升。为此,MindSpore Serving提供了多子图功能,实现多张图之间的调度。

下面以一个简单的单卡模型场景为例,演示多子图模型部署流程,

环境准备

运行示例前,需确保已经正确安装了MindSpore Serving,并配置了环境变量。

导出多图模型

在export_model目录下,使用export_matmul.py ,构造一个包含Matmul和ReduceSum的网络,基于两个不同的输入导出MindSpore推理部署模型。

代码如下:

import os

from shutil import copyfile

import numpy as np

import mindspore.context as context

from mindspore import Tensor, Parameter, ops, export

from mindspore.nn import Cell

class Net(Cell):

“”“Net”""

def init(self, matmul_size, init_val, transpose_a=False, transpose_b=False):

“”“init”""

super().init()

matmul_np = np.full(matmul_size, init_val, dtype=np.float32)

self.matmul_weight = Parameter(Tensor(matmul_np))

self.matmul = ops.MatMul(transpose_a=transpose_a, transpose_b=transpose_b)

self.sum = ops.ReduceSum()

def construct(self, inputs):

“”“construct”""

x = self.matmul(inputs, self.matmul_weight)

x = self.sum(x, 0)

return x

def export_net():

“”“Export matmul net , and copy output model matmul_0.mindir and matmul_1.mindir to directory …/matmul/1"”"

context.set_context(mode=context.GRAPH_MODE)

network = Net(matmul_size=(96, 16), init_val=0.5)

subgraph 0: 128,96 matmul 16,96 -> 128,16 reduce sum axis 0-> 16

predict_data = np.random.randn(128, 96).astype(np.float32)

pylint: disable=protected-access

export(network, Tensor(predict_data), file_name=“matmul_0”, file_format=“MINDIR”)

subgraph 1: 8,96 matmul 16,96 -> 8,16 reduce sum axis 0-> 16

predict_data = np.random.randn(8, 96).astype(np.float32)

pylint: disable=protected-access

export(network, Tensor(predict_data), file_name=“matmul_1”, file_format=“MINDIR”)

dst_dir = ‘…/matmul/1’

try:

os.mkdir(dst_dir)

except OSError:

pass

dst_file = os.path.join(dst_dir, ‘matmul_0.mindir’)

copyfile(‘matmul_0.mindir’, dst_file)

print(“copy matmul_0.mindir to " + dst_dir + " success”)

dst_file = os.path.join(dst_dir, ‘matmul_1.mindir’)

copyfile(‘matmul_1.mindir’, dst_file)

print(“copy matmul_1.mindir to " + dst_dir + " success”)

if name == “main”:

export_net()

使用MindSpore定义神经网络需要继承mindspore.nn.Cell。Cell是所有神经网络的基类。神经网络的各层需要预先在__init__方法中定义,然后通过定义construct方法来完成神经网络的前向构造。使用mindspore模块的export即可导出模型文件。

执行export_matmul.py脚本,生成matmul_0.mindir和matmul_1.mindir文件,输入shape分别为[128,96]和[8,96]。

配置服务

启动推理服务

serving_server.py为启动服务脚本文件。

matmul为模型文件夹,文件夹名即为模型名。

matmul_0.mindir和matmul_1.mindir为上一步网络生成的模型文件,放置在文件夹1下,1为版本号,不同的版本放置在不同的文件夹下,版本号需以纯数字串命名,默认配置下启动最大数值的版本号的模型文件。

模型配置文件内容如下:

from mindspore_serving.server import distributed

from mindspore_serving.server import register

model = register.declare_model(model_file=[“matmul_0.mindir”, “matmul_1.mindir”], model_format=“MindIR”,

with_batch_dim=False)

def process(x, y):

z1 = model.call(x, subgraph=0) # 128,96 matmul 16,96 -> reduce sum axis 0-> 16

z2 = model.call(y, subgraph=1) # 8,96 matmul 16,96 -> reduce sum axis 0-> 16

return z1 + z2

@register.register_method(output_names=[“z”])

def predict(x, y):

z = register.add_stage(process, x, y, outputs_count=1)

return z

如果模型是有状态的,则需要在一个Python 函数Stage中完成对这个模型的所需要的多次调用,避免多个实例的干扰,多子图的模型一般也是有状态的模型。

例子中,process函数中通过Model.call接口分别调用两个子图,其中的每个子图也可以调用多次,subgraph参数指定图的标号,从0开始,此编号在为图加载的序号,单机场景与declare_model接口的model_file的参数列表序号对应,分布式场景与startup_agents接口的model_files的参数列表序号对应。

启动Serving服务器

使用serving_server.py 启动Serving服务器。

import os

import sys

from mindspore_serving import server

def start():

servable_dir = os.path.dirname(os.path.realpath(sys.argv[0]))

servable_config = server.ServableStartConfig(servable_directory=servable_dir, servable_name=“matmul”,

device_ids=(0, 1))

server.start_servables(servable_config)

server.start_grpc_server(“127.0.0.1:5500”)

server.start_restful_server(“127.0.0.1:1500”)

if name == “main”:

start()

上述启动脚本将在设备0和1上共加载和运行两个matmul推理副本,来自客户端的推理请求将被切割分流到两个推理副本。

当服务端打印日志Serving gRPC server start success, listening on 127.0.0.1:1500时,表示Serving gRPC服务启动成功,推理模型已成功加载。

执行推理

通过gRPC访问推理服务,client需要指定gRPC服务器的网络地址。运行serving_client.py ,调用matmul Servable的predict方法,执行推理。

代码如下:

import numpy as np

from mindspore_serving.client import Client

def run_matmul():

“”“Run client of distributed matmul”""

client = Client(“localhost:5500”, “matmul”, “predict”)

instance = {“x”: np.ones((128, 96), np.float32), “y”: np.ones((8, 96), np.float32)}

result = client.infer(instance)

print(“result:\n”, result)

assert “z” in result[0]

if name == ‘main’:

run_matmul()

执行后显示如下返回值,说明Serving推理服务已正确执行推理任务:

结果如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值