TensorFlow学习记录:用TensorFlow_Serving部署模型并进行远程使用

训练好的模型在使用过程中有多种场景。TensorFlow中提供了一种TF_Serving接口,可以将带有签名的模型部署在远端服务器上,并以服务的方式对外提供借口。之前学习过saved_model模块的用法(详情请点击这里),简单点说saved_model模块就是为了实现TensorFlow Serving(以下简称TF_Serving)功能的。

gRPC服务、HTTP/REST API是TF_Serving模块对外支持服务的两种通信技术。通过这两种通信技术,可以远程使用TensorFlow模型。

本文使用的线性回归模型(y≈2x)代码如下:

#使用静态图训练一个具有检查点的回归模型

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

#(1)生成模拟数据
train_X = np.linspace(-1, 1, 100)
train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3 # y=2x,但是加入了噪声
#图形显示
plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.legend()
plt.show()

tf.reset_default_graph()

#(2)建立网络模型

# 创建模型
# 占位符
X = tf.placeholder("float")
Y = tf.placeholder("float")
# 模型参数
W = tf.Variable(tf.random_normal([1]), name="weight")
b = tf.Variable(tf.zeros([1]), name="bias")
# 前向结构
z = tf.multiply(X, W)+ b
global_step = tf.Variable(0, name='global_step', trainable=False)
#反向优化
cost =tf.reduce_mean( tf.square(Y - z))
learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost,global_step) #梯度下降

# 初始化所有变量
init = tf.global_variables_initializer()
# 定义学习参数
training_epochs = 28
display_step = 2

savedir = "log/"
saver = tf.train.Saver(tf.global_variables(), max_to_keep=1)#生成saver。 max_to_keep=1,表明最多只保存一个检查点文件

#定义生成loss可视化的函数
plotdata = { "batchsize":[], "loss":[] }
def moving_average(a, w=10):
    if len(a) < w: 
        return a[:]    
    return [val if idx < w else sum(a[(idx-w):idx])/w for idx, val in enumerate(a)]

#(3)建立session进行训练
with tf.Session() as sess:
    sess.run(init)
    kpt = tf.train.latest_checkpoint(savedir)
    if kpt!=None:
        saver.restore(sess, kpt)
     
    # 向模型输入数据
    while global_step.eval()/len(train_X) < training_epochs:        
        step = int( global_step.eval()/len(train_X) )    # step为epoch数
        for (x, y) in zip(train_X, train_Y):                          # 每跑一次x,y,global_step就自动加一
            sess.run(optimizer, feed_dict={X: x, Y: y})

        #显示训练中的详细信息
        if step % display_step == 0:
            loss = sess.run(cost, feed_dict={X: train_X, Y:train_Y})
            print ("Epoch:", step+1, "cost=", loss,"W=", sess.run(W), "b=", sess.run(b))
            if not (loss == "NA" ):
                plotdata["batchsize"].append(global_step.eval())
                plotdata["loss"].append(loss)
            saver.save(sess, savedir+"linermodel.cpkt", global_step)
                
    print (" Finished!")
    saver.save(sess, savedir+"linermodel.cpkt", global_step)
    
    print ("cost=", sess.run(cost, feed_dict={X: train_X, Y: train_Y}), "W=", sess.run(W), "b=", sess.run(b))

    #显示模型
    plt.plot(train_X, train_Y, 'ro', label='Original data')
    plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line')
    plt.legend()
    plt.show()
    
    plotdata["avgloss"] = moving_average(plotdata["loss"])
    plt.figure(1)
    plt.subplot(211)
    plt.plot(plotdata["batchsize"], plotdata["avgloss"], 'b--')
    plt.xlabel('Minibatch number')
    plt.ylabel('Loss')
    plt.title('Minibatch run vs. Training loss')
     
    plt.show()

这个步骤会在log文件夹下面生成4个文件

å¨è¿éæå¥å¾çæè¿°

1.在Linux系统上安装TF_Serving

输入如下命令,向“apt-get”添加TF_Serving安装包的下载地址:

echo "deb [arch=amd64] http://storage.googleapis.com/tensorflow-serving-apt stable tensorflow-model-server tensorflow-model-server-universal" | sudo tee /etc/apt/sources.list.d/tensorflow-serving.list

curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -

sudo apt-get update

sudo apt-get install tensorflow-model-server

提示:
默认的tensorflow-model-server版本需要安装在支持SSE4和AVX指令集的服务器上。如果本地的机器过于老旧不支持该指令集,需要安装tensorflow-model-server-universal版本。具体命令为:

sudo apt-get install tensorflow-model-server-universal

如果已经安装了tensorflow-model-server,则需要先卸载tensorflow-model-server后才能再安装tensorflow-model-server-universal。卸载tensorflow-model-server命令为:

sudo apt-get remove tensorflow-model-server

2.固定模型的签名信息

为了让生成的模型支持TF_Serving服务,在TensorFlow中对模型的签名做了统一的规定。在签名中规定,模型在处理分类、预测、回归这三种任务时,必须使用对应的输入与输出签名。具体的签名定义在/usr/local/lib/python3.6/dist-packages/tensorflow/saved_model/signature_constants模块下。见下图

å¨è¿éæå¥å¾çæè¿°

提示
上图中,CLASSIFY_METHOD_NAME、PREDICT_METHOD_NAME和REGRESS_METHOD_NAME这3个签名是必需的,且只能有这3中签名。如果使用其它签名就会报错。除了上述三种签名外,其它的签名的是可选的,但要求服务器端必需与客户端严格匹配。在没有特殊要求情况下,建议使用规定的签名,以避免客户端与服务器端签名名称不匹配的情况发生。

为上面训练好的模型添加签名(PREDICT_METHOD_NAME)

.....
    from tensorflow.python.saved_model import tag_constants
    builder = tf.saved_model.builder.SavedModelBuilder(savedir+'tfservingmodelv1')
    # 定义输入签名
    inputs = {'input_x':tf.saved_model.utils.build_tensor_info(x)}
    # 定义输出签名
    outputs = {'output':tf.saved_model.utils.build_tensor_info(z)}
    # 创建签名对象
    signature = tf.saved_model.signature_def_utils.build_signature_def(inputs=inputs,outputs=outputs,method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)
    # 将签名和标签加入到builder中
    builder.add_meta_graph_and_variables(sess,[tag.constants.SERVING],{'my_signature':signature})
    builder.save()

执行结果如下图所示,在tfservingmodelv1文件夹下生成一个pb文件和一个文件夹:

å¨è¿éæå¥å¾çæè¿°

提示:
预测任务是最灵活的签名方式,可以覆盖回归和分类两种任务。上面代码中的build_signature_def函数可以换成下面更高级的函数:

  • 生成回归签名的函数:regression_signature_def
  • 生成分类签名的函数:classfication_signature_def
  • 生成预测签名的函数:predict_signature_def

这三个函数是在build_signature_def函数基础上进行封装的。它们使用起来更加方便,但是灵活性会差一些。

3.在Linux中开启TF_Serving服务

默认情况下,模型文件必须放在用数字命名的文件夹下,才可以被tensorflow_model_server命令启动。其中的数字代表该模型的版本号。
在tfservingmodelv1下定义一个新的文件夹12345(代表版本号),并将模型文件全部迁移到12345下面。

cd tfservingmodelv1
mkdir 12345
mv saved_model.pb 12345
mv variables 12345

启动HTTP/REST API服务
直接使用tensorflow_model_server命令启动HTTP/REST API服务,并指定端口和文件路径。

tensorflow_model_server --rest_api_port=8500 --model_base_path=/home/boss/Study/TensorFlow_Engineering_Implementation-master/code/log/tfservingmodelv1/ --port=9000  --model_name=md
  • —rest_api_port 表示HTTP/REST API已经成功启动,监听本机8500端口
  • —model_base_path 表示模型的路径,这里要写绝对路径,不能写相对路径
  • —port 表示gPRC服务已正常启动,监听本机9000端口

提示:
gPRC服务会默认自动启动,且默认监听本地8500端口,如果不指定–port端口的话,–rest_api_port端口就不能设定为8500。

运行结果

å¨è¿éæå¥å¾çæè¿°

如果想把该服务作为后台命令启动,可以在后面加上&符号,并指定输出的日志(log)文件。

tensorflow_model_server --port=9000 --model_base_path=/home/boss/Study/TensorFlow_Engineering_Implementation-master/code/log/tfservingmodelv1/ &>log &

启动模型过程中的输出将会被保存到当前目录下的log文件中。

4.用HTTP/REST API 访问远程TF_Serving服务

使用HTTP/REST API时,要通过POST方式请求一个URL,并带上json数据完成。具体说明如下:

4.1 URL说明

这里的URL地址可分为3部分:目的IP和端口、固定不变的路径(v1/models)、模型名称和版本号(md/versions/12345)与预测方法(predict、classify、regress)。其中,模型名称和预测方法需要与模型文件中的名称和预测方法一致。例如

http://localhost:8500/v1/models/md/versions/12345:predict

4.2 POST请求中的json数据格式

在POST请求中的json数据需要按照模型的具体任务(分类、回归、预测)所对应的格式来构建。
(1)对于分类和回归任务,构建的格式是一样的

{"signature_name":签名字符串,"context":{"公共字段名":值或列表},"examples":[{"字段名":值或列表}]}

具体说明如下:

  • signature_name 是模型中的签名。当服务端的模型使用默认签名时,可以不填。
  • examples 里面可以包括多个{},每个{}代表一个具体要预测的输入样本。每个{}内部也可以有多个字段,代表输入。当多个样本具有相同输入值时,可以将其单独提出来放到context里面。
  • context是可选项,代表从examples中提取出来的具有相同值的公共输入字段,可以有多个

(2)对于预测任务,构建的格式如下

{"signature_name":签名字符串,"instance":值或列表,"inputs":值或列表}

具体说明如下

  • signature_name 同上
  • instances 是输入的样本字段。如果只有一个输入列,则直接填值。如果有多个输入列,则可以用JSON格式继续扩展填充内容。预测的结果将以行的形式显示
  • inputs 也是输入的样本字段。与instances不同的是,用inputs预测的结果将以列的形式显示。

提示:
在使用时,inputs与instances不可同时使用

4.3 POST返回中的JSON数据的格式

不同的任务返回的JSON格式是不一样的,具体如下
(1)分类任务的返回格式描述

{"result":[[[<label1>,<score1>],[<label2>,<score2>],...]...]

在返回的JSON格式中,label是分类的结果,score是该分类的概率结果。

(2)回归任务的返回格式描述

{"result":[<value1>,<value2>,<value3>,...]}

在返回的JSON格式中,每个value都是回归任务的返回值。这些value的顺序是按照输入样本的顺序进行排列。

(3)预测任务的返回格式描述
预测任务的返回格式有两种。

如果按照行的方式请求,则返回结果如下

 

{"predictions":值或列表}

如果按照列的方式请求,则返回结果如下

{"outputs":值或列表}

4.4 在Linux通过CURL访问服务

在Linux控制台输入CURL命令

curl -d '{"instances":[1.0,2.0,5.0],"signature_name":"my_signature"}'  -X POST http://localhost:8500/v1/models/md/versions/12345:predict
  • -d 具体的数据内容。它是JSON格式的数据。
  • -X POST 以POST方式发送请求。后面跟的是URL连接。

执行该命令后的结果

å¨è¿éæå¥å¾çæè¿°

该命令也可以在windows下使用,在使用时需要对JSON格式的字符串做转义。
在CMD输入以下命令

curl -d "{\"inputs\":[1.0,2.0,5.0],\"signature_name\":\"my_signature\"}"  -X POST http://服务器的ip地址:8500/v1/models/md/versions/12345:predict

执行该命令后的结果(Linux下)

å¨è¿éæå¥å¾çæè¿°

将输入关键字由instances换成outputs后,返回结果会以列的形式显示

4.5 编写python脚本访问服务

import requests
import json

url = "http://localhost:8500/v1/models/md/versions/12345:predict"

s = json.dumps({"instances":[1.0,2.0,5.0],"signature_name":"my_signature"})
r = requests.post(url,data=s)
print(r.text)

运行结果同上

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值