将tensorflow模型部署到服务器上

基本思路:利用tensorflow官方提供的tensorflow serving进行部署,同时,为了免去环境配置等麻烦操作,可借助docker容器。

一、服务器环境选择

首先肯定要去租一个服务器,例如阿里云。一开始选了window server2012,结果很坑,装不了docker。上网想查解决方法,发现别人也遇到过这个问题。

了解的原因大概是:docker需要在linux的环境下运行。但通过在window server2012下使用vitural box运行linux虚拟机的办法不行,因为这样会造成二次虚拟(官方解释:阿里云给的轻量应用服务器是运行在虚拟机上的,所以不能再开虚拟机)。

不过网上一些大佬好像也给出了骚操作,但总之太过麻烦,不想去折腾,就没去尝试。

正当我觉得凉凉,想重新买linux服务器的时候,才发现阿里云的控制台上可以重新更改系统镜像,于是很愉快地换成了ubuntu18.04.

二、Ubuntu下docker容器的安装

前提条件:Docker 要求 Ubuntu 系统的内核版本高于 3.10 ,通过 uname -r 命令查看你当前的内核版本。

接下来就是在linux终端敲命令了:

1.获取docker安装包

wget -qO- https://get.docker.com/ | sh

完成后会有一段提示

If you would like to use Docker as a non-root user, you should now consider

    adding your user to the "docker" group with something like:

    sudo usermod -aG docker runoob

   Remember that you will have to log out and back in for this to take effect!  

一般嫌麻烦的话,以后执行docker命令都在root下进行就可以了 

2.运行docker容器

sudo service docker start

3.测试hello-world程序

docker run hello-world

第一次应该会失败,因为容器里还没有这个项目,所以docker会去下载,第二次运行就可以了。

三、模型的部署

1.拉取带tensorflow serving的docker镜像

docker pull tensorflow/serving 

2.先来测试一下官方例子

cd /root/software/
git clone https://github.com/tensorflow/serving

将GitHub上的TensorFlow-serving拷贝下来,里面已经有一些模型,我们通过部署一个简单的模型上docker来观察结果

docker run -p 8501:8501 \
  --mount type=bind,\
source=/root/software/serving/tensorflow_serving/servables/tensorflow/testdata/saved_model_half_plus_two_cpu,\
target=/models/half_plus_two \
  -e MODEL_NAME=half_plus_two -t tensorflow/serving &

 运行成功后,我们写一个Python的代码测试

import requests
import json
pdata={"instances":[1,2,3]}
param=json.dumps(pdata)
res=requests.post('http://localhost:8501/v1/models/half_plus_two:predict',data=param)
print(res.text)

 可以看到res返回的结果,对应的是我们输入的1,2,3,之后我们就利用这种方式传递图片或其他数据过去

{
    "predictions": [2.5, 3.0, 3.5
    ]
}

结果分析:

启动docker的时候,开启了8501端口,后面url通过该端口进行访问

参数source表示你模型存放的文件夹,如果你去找这个文件夹,你会发现里面模型存放的格式有些特别,后面我们要部署模型时也需要先转为这种类型

model_name是docker上模型的名称,在url上也可以看到

target是存放在docker上的路径

下面就开始部署我们自己的模型了

4.部署自己模型

刚才第三步说过,要将模型导出为特殊的类型(有一个variables文件夹,同目录下一个pb模型,这个pb模型和之前的还不大一样)。

首先需要我们训练完模型后一个正常的checkpoint,转换的方法可以参考下面的做法

import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32, name='input_x')
feed = np.random.rand(100)
y = x + 1

w = tf.Variable(0.)
b = tf.Variable(0.)

y_ = tf.add(tf.multiply(w, x), b)

loss = tf.reduce_mean(tf.square(y-y_))

optimizer = tf.train.GradientDescentOptimizer(0.2)
train = optimizer.minimize(loss)

init = tf.global_variables_initializer()

saver = tf.train.Saver()

with tf.Session() as sess:
    sess.run(init)
    for i in range(200):
        sess.run(train, feed_dict={x: feed})
        if i % 5 == 0:
            print(i, sess.run([w,b]))

    saver.save(sess, './linear/linear.ckpt')

with tf.Session() as sess2:
    sess2.run(init)
    saver.restore(sess2, './linear/linear.ckpt')

    # 将训练好的模型保存在modelName下,版本为1,当然你的版本可以随便写
    builder = tf.saved_model.builder.SavedModelBuilder("./modelName/1")

    inputs = {
        # 注意,这里是你预测模型的时候需要传的参数,调用模型的时候,传参必须和这里一致
        # 这里的input_x就是模型里面定义的输入placeholder
        "input_x": tf.saved_model.utils.build_tensor_info(x)
    }
    outputs = {
        "output_y": tf.saved_model.utils.build_tensor_info(y),
    }
    prediction_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.add_meta_graph_and_variables(
        sess2,
        [tf.saved_model.tag_constants.SERVING],
        {tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY: prediction_signature}
    )
    builder.save()

之后仿照样例模型,用docker运行这个模型就可以了,端口号、路径和模型名称什么的自定义即可,不冲突就行。 

docker run -p 8502:8501 \
  --mount type=bind,\source=/root/software/serving/tensorflow_serving/servables/tensorflow/testdata/face/face2,\target=/models/face2 \
  -e MODEL_NAME=face2 -t tensorflow/serving &

 一段测试代码,跟上面的有一点类似,具体什么参数看自己的模型

import requests
import numpy as np
import json
# json格式序列调整
class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)
feature=np.array(range(128))
param = {
	"instances":[
		#每一个大括号是一次请求,里面是每次请求的参数
              {
		"in":feature
	      }
	]
}
param = json.dumps(param, cls=NumpyEncoder)

res = requests.post("http://localhost:8502/v1/models/face2:predict", data=param)
# 根据自己设定的返回数据读取
# softmax = json.loads(res2.text)["predictions"][0]

至此,大功告成。 

PS:如果有多个模型需要部署,只需要修改本地端口号即可,不需要修改docker的端口号。(就是docker run命令的时候,只改第一个8501,不需要改第二个8501)

 

 

你可能感兴趣的:(机器学习,深度学习)