在 tensorrtserver 中使用 saved_model

###1. 部署 tensorrtserver
建议使用 docker 部署 tensorrtserver。docker 相关的知识网上很多,自行参考。tensorrtserver 的官方建议的安装如下:

docker pull nvcr.io/nvidia/tensorrtserver:19.08-py3

镜像文件较大,且国内下载很慢,经常断线。所以建议使用阿里云的镜像源,阿里的镜像源是比较动态的,可以到注册账号后登录阿里云搜索 tensorrtserver ,找到合适的源,以下是两个示例:

docker pull registry.cn-beijing.aliyuncs.com/cloudhjc/tensorrtserver:server19.08
docker pull registry.cn-hangzhou.aliyuncs.com/bostenai/tensorrtserver:19.04-py3

下载完镜像后,可以执行 docker images 看下,然后执行命令,启动该镜像的容器:

docker run --rm --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 -p8000:8000 -p8001:8001 -p8002:8002 -v/model/repository:/models registry.cn-hangzhou.aliyuncs.com/bostenai/tensorrtserver:19.04-py3 trtserver --model-store=/models

命令的格式如下:

docker run --rm [环境配置] [端口号配置] -v*[本地模型路径]*:/models [镜像名称] trtserver --model-store=/models

如上则启动了一个地址为本机地址,http 端口号为 8000,grpc 端口号为 8001 ,监控端口号为 8002
###2. 验证服务启动
访问 http://ip:8001/api/status ,可以获得服务当前的运行状态,以及模型列表。
访问 http://ip:8002/metrics,可以获得服务的运行日志。
如果上述的 url 都访问正常,则表示服务正常启动了。
###3. 部署模型
虽然,tensorrtserver 自带有模型示例,但是没有 saved_model 的示例,所以我们先自己生成一个 saved_model 模型,如下的 python 脚本可以生成一个矩阵相乘的 saved_model 的模型

import tensorflow as tf
import numpy as np

input0 = tf.placeholder(tf.float32, [None, None], "input0")
input1 = tf.placeholder(tf.float32, [None, None], "input1")

b = tf.Variable(2.0,name='b')
output = tf.matmul(input0, input1, name="matmul")

with tf.compat.v1.Session() as sess:
    sess.run(tf.global_variables_initializer())
    v = sess.run([output], feed_dict={input0: np.ones([3, 2], np.float32), input1: np.ones([2, 3], np.float32)})
    
    print(v)
    print(b)
    
    inp0 = tf.saved_model.utils.build_tensor_info(input0)
    inp1 = tf.saved_model.utils.build_tensor_info(input1)
    out = tf.saved_model.utils.build_tensor_info(output)

    sign = tf.saved_model.signature_def_utils.build_signature_def(
        inputs={'input0': inp0, 'input1': inp1},
        outputs={'output': out},
        method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)

    builder = tf.saved_model.builder.SavedModelBuilder("export")
    
    builder.add_meta_graph_and_variables(
        sess, [tf.saved_model.tag_constants.SERVING],
        signature_def_map={ tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: sign },
      main_op=tf.tables_initializer(),
      strip_default_attrs=True)

    builder.save()
    print ("export end!!")

执行脚本后在同目录下的 export 就会生成一个 saved_model.pb 的模型。
将模型文件(saved_model.pb 和 variables 目录)拷贝到部署 tensorrtserver 的服务器。假设我们的模型路径为 /model/,模型名称为 matmul,那么经过拷贝和重命名后的路径目录结构期望如下:

.
└── matmul
    ├── 1
    │   └── model.savedmodel
    │       ├── saved_model.pb
    │       └── variables
    └── config.pbtxt

即需要在模型路径下创建 matmul 文件夹,并在文件中创建名称为 1 的文件夹,在名称为 1 的文件夹在再创建一个名称为 model.savedmodel 的文件夹,模型文件 saved_model.pb 和 variables 目录保存在 model.savedmodel 文件夹下。这个目录结构中 1 实际上就是 tensorrtserver 定义的模型的版本号。在 matmul 目录下 config.pbtxt 是模型的配置文件,这个文件需要自己编写。
###4. 编写 config.pbtxt
config.pbtxt 是模型访问的配置文件,需要正确编写,否则模型无法正确加载。上面矩阵相乘的 config.pbtxt 内容如下:

name: "matmul"
platform: "tensorflow_savedmodel"
max_batch_size: 0
input [
{
name: "input0"
data_type: TYPE_FP32
dims: [1, 10]
},
{
name: "input1"
data_type: TYPE_FP32
dims: [10, 1]
}
]
output [
{
name: "output"
data_type: TYPE_FP32
dims: [1, 1]
}
]

#####4.1 基本配置

  1. name 要和模型的目录的名称保持一致,不一致则报错。
  2. saved_model 的 platform 写 tensorflow_savedmodel,其他模型可以参考(点击URL)。
  3. max_batch_size 可以参考模型是否支持批输入进行配置,如果模型不支持,启动的时候会报如下的错误,这时将 max_batch_size 改成 0 即可。

Servable {name: matmul version: 1} cannot be loaded: Internal: unable to load model ‘matmul’, model configuration supports batching but first dimension of tensor ‘input0’ expected by framework is not a variable-size batch dimension: [10]

#####4.2 input 和 ouput 的配置
config.pbtxt 中的 input 和 output 时配置的重中之重,它们需要和模型的输入和输出严格保持一致。所以配置之前,我们需要先查看模型的输入输出信息。通过 saved_model_cli 命令可以查看该信息。saved_model_cli 在安装 tensorflow 之后即有,在系统命令行下执行。
执行命令格式如下(参数是路径,不是名称):

saved_model_cli show --all --dir [saved_model路径]

得到的返回如下

MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['input0'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, -1)
        name: input0:0
    inputs['input1'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, -1)
        name: input1:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['output'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, -1)
        name: matmul:0
  Method name is: tensorflow/serving/predict

这里需要注意的是,如果执行 saved_model_cli 命令后返回的信息不包含 serve 和 serve 的签名,那么这个模型是不可以运行在 tensorrtserver 上。这点很重要,不是部署的问题,是模型的问题
得到配置信息之后,我们就可以根据信息进行 input 和 output 的配置了。

  1. name 的配置:name 和 inputs 后单引号中的内容一致,比如示例中为 input0 和 input 1
  2. data_type 的配置:data_type 存在映射关系,即需要将 tensorflow 的类型映射成 tensorrtserver 的类型,如示例中的 DT_FLOAT 对应类型为 TYPE_FP32,详细的映射关系点击 URL
  3. dims 的配置:dims 和模型配置中的 shape 保持一致即可。dims 配置这边有一个坑是 shape 信息为 “ shape: unknown_rank ”,这时是没有对应的 dims 配置的,所以模型也是不可用的。unkown_rank 表示输入的 tensor 形状未定义,一般是如下的代码定义的输入,中间的 shape 定义为 None:
nput0 = tf.placeholder(tf.float32, None, "input0")
  1. output 的配置和 input 配置相同
    ###5. 带模型的启动 tensorrtserver
    从 config.pbtxt 的配置,我们可以得到 tensorrtserver 不支持的 saved_model 如下:
  1. tag-set 中不包含 serve ,或者有 serve 标签,但是没有 server 的签名的
  2. shape 中包含 unkonwn_rank 的

编辑完成 config.pbtxt 后,就可以启动服务了。
执行命令:

docker run --rm --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 -p8000:8000 -p8001:8001 -p8002:8002 -v/model/:/models registry.cn-hangzhou.aliyuncs.com/bostenai/tensorrtserver:19.04-py3 trtserver --model-store=/models

启动服务,访问 http://ip:8001/api/status/matmul 得到模型的信息如下:

id: "inference:0"
version: "1.1.0"
uptime_ns: 2190253935560
model_status {
  key: "matmul"
  value {
    config {
      name: "matmul"
      platform: "tensorflow_savedmodel"
      version_policy {
        latest {
          num_versions: 1
        }
      }
      input {
        name: "input0"
        data_type: TYPE_FP32
        dims: 1
        dims: 10
      }
      input {
        name: "input1"
        data_type: TYPE_FP32
        dims: 10
        dims: 1
      }
      output {
        name: "output"
        data_type: TYPE_FP32
        dims: 1
        dims: 1
      }
      instance_group {
        name: "matmul"
        count: 1
        kind: KIND_CPU
      }
      default_model_filename: "model.savedmodel"
    }
    version_status {
      key: 1
      value {
        ready_state: MODEL_READY
      }
    }
  }
}
ready_state: SERVER_READY

看到模型的 ready_state 为 SERVER_READY 表示模型已经处于可以访问的状态了。这时候就可以调用客户端访问该模型了。

你可能感兴趣的:(IT,技术分享)