如何使用 inception/mobilenet 模型设置 tfserving 以进行图像分类?

How to setup tfserving with inception/mobilenet model for image classification?

我找不到合适的文档来成功地为 inception 或 mobilenet 模型提供服务并编写 grpc 客户端来连接到服务器并执行图像分类。

到目前为止,我只在 CPU 上成功配置了 tfserving 图像。无法在我的 GPU 上 运行 它。

但是,当我发出 grpc 客户端请求时,请求失败并出现错误。

grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
status = StatusCode.INVALID_ARGUMENT
details = "Expects arg[0] to be float but string is provided"
debug_error_string = "{"created":"@1571717090.210000000","description":"Error received from peer","file":"src/core/lib/surface/call.cc","file_line":1017,"grpc_message":"Expects arg[0] to be float but string is provided","grpc_status":3}"

我知道请求格式存在一些问题,但我找不到可以准确指出正确方向的 grpc 客户端的适当文档。

这是我用于请求的 grpc 客户端。

from __future__ import print_function

import grpc
import tensorflow as tf
import time

from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc

tf.app.flags.DEFINE_string('server', 'localhost:8505',
                       'PredictionService host:port')
tf.app.flags.DEFINE_string('image', 'E:/Data/Docker/tf_serving/cat.jpg', '‪path to image')
FLAGS = tf.app.flags.FLAGS


def main(_):
    channel = grpc.insecure_channel(FLAGS.server)
    stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)

    # Send request
    with open(FLAGS.image, 'rb') as f:
        # See prediction_service.proto for gRPC request/response details.
        data = f.read()
        request = predict_pb2.PredictRequest()
        request.model_spec.name = 'inception'
        request.model_spec.signature_name = ''
        request.inputs['image'].CopyFrom(tf.contrib.util.make_tensor_proto(data, shape=[1]))
        result = stub.Predict(request, 5.0)  # 10 secs timeout
        print(result)
    print("Inception Client Passed")


if __name__ == '__main__':
    tf.app.run()

据我了解,你的问题有两个问题。

A) 运行 GPU 上的 tfserving。

B) 发出成功的 grpc 客户端请求。

让我们一个一个开始。


运行 GPU 上的 tfserving

这是简单的两步过程。

  1. 正在从 official docker hub page 中提取最新图像。

    docker pull tensorflow/serving:latest-gpu
    

请注意上面拉取请求中的标签 latest-gpu,因为它会拉取用于 GPU 的图像。

  1. 运行 docker 容器。

    sudo docker run -p 8502:8500 --mount type=bind,source=/my_model_dir,target=/models/inception --name tfserve_gpu -e MODEL_NAME=inception --gpus device=3 -t tensorflow/serving:latest-gpu
    

请注意,我已将参数 --gpus device=3 传递给 select 第三个 GPU 设备。将其相应地更改为 select 不同的 GPU 设备。

验证容器是否已通过 docker ps 命令启动。

此外,验证是否已通过 nvidia-smi 命令为 tfserving docker 分配了 gpu。

nvidia-smi 的输出

不过这里好像有点问题。 tfserving docker 已消耗所有 gpu 设备内存。

要限制 gpu 内存使用,请使用 per_process_gpu_memory_fraction 标志。

sudo docker run -p 8502:8500 --mount type=bind,source=/my_model_dir,target=/models/inception --name tfserve_gpu -e MODEL_NAME=inception --gpus device=3 -t tensorflow/serving:latest-gpu  --per_process_gpu_memory_fraction=0.02

nvidia-smi 的输出

现在,我们已经成功地在 GPU 设备上配置了 tfserving docker,并且具有合理的 GPU 内存使用率。让我们跳到第二个问题。


发出 GRPC 客户端请求

您的 grpc 客户端请求的格式存在问题。 tfserving docker 图像不会直接以二进制格式获取图像,相反,您必须为该图像制作一个张量,然后将其传递给服务器。

这是发出 grpc 客户端请求的代码。

from __future__ import print_function

import argparse
import time
import numpy as np
from cv2 import imread

import grpc
from tensorflow.contrib.util import make_tensor_proto
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
import tensorflow as tf


def read_tensor_from_image_file(file_name,
                                input_height=299,
                                input_width=299,
                                input_mean=0,
                                input_std=255):
    input_name = "file_reader"
    output_name = "normalized"
    file_reader = tf.io.read_file(file_name, input_name)
    if file_name.endswith(".png"):
        image_reader = tf.image.decode_png(
            file_reader, channels=3, name="png_reader")
    elif file_name.endswith(".gif"):
        image_reader = tf.squeeze(
            tf.image.decode_gif(file_reader, name="gif_reader"))
    elif file_name.endswith(".bmp"):
        image_reader = tf.image.decode_bmp(file_reader, name="bmp_reader")
    else:
        image_reader = tf.image.decode_jpeg(
            file_reader, channels=3, name="jpeg_reader")
    float_caster = tf.cast(image_reader, tf.float32)
    dims_expander = tf.expand_dims(float_caster, 0)

    resized = tf.compat.v1.image.resize_bilinear(dims_expander, [input_height, input_width])
    normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std])

    sess = tf.Session(config=tf.ConfigProto(gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.01)))
    result = sess.run(normalized)

    return result


def run(host, port, image, model, signature_name):

    # Preparing tensor from the image
    tensor = read_tensor_from_image_file(file_name='images/bird.jpg', input_height=224, input_width=224, input_mean=128, input_std=128)

    # Preparing the channel
    channel = grpc.insecure_channel('{host}:{port}'.format(host=host, port=port))
    stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)

    # Preparing grpc request
    request = predict_pb2.PredictRequest()
    request.model_spec.name = model
    request.model_spec.signature_name = signature_name
    request.inputs['image'].CopyFrom(make_tensor_proto(tensor, shape=[1, 224, 224, 3]))

    # Making predict request
    result = stub.Predict(request, 10.0)

    # Analysing result to get the prediction output.
    predictions = result.outputs['prediction'].float_val

    print("Predictions : ", predictions)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--host', help='Tensorflow server host name', default='localhost', type=str)
    parser.add_argument('--port', help='Tensorflow server port number', default=8502, type=int)
    parser.add_argument('--image', help='input image', default='bird.jpg', type=str)
    parser.add_argument('--model', help='model name', default='inception', type=str)
    parser.add_argument('--signature_name', help='Signature name of saved TF model',
                        default='serving_default', type=str)

    args = parser.parse_args()
    run(args.host, args.port, args.image, args.model, args.signature_name)

我不太确定这是否是发出 tfserving grpc 客户端请求的最佳方式(因为客户端需要 tensorflow 库来准备张量) 但对我有用。

欢迎提出建议