简介:
当我们训练完一个tensorflow(或keras)模型后,需要把它做成一个服务,让使用者通过某种方式来调用你的模型,而不是直接运行你的代码(因为你的使用者不一定懂怎样安装),这个过程需要把模型部署到服务器上。常用的做法如使用flask、Django、tornado等web框架创建一个服务器app,这个app在启动后就会一直挂在后台,然后等待用户使用客户端POST一个请求上来(例如上传了一张图片的url),app检测到有请求,就会下载这个url的图片,接着调用你的模型,得到推理结果后以json的格式把结果返回给用户。
使用docker部署模型的好处在于,避免了与繁琐的环境配置打交道。使用docker,不需要手动安装Python,更不需要安装numpy、tensorflow各种包,直接一个docker就包含了全部。docker的方式是如今部署项目的第一选择。
1、安装
docker安装需要两个命令:
sudo apt-get install docker
sudo apt-get install docker.io
如果在更新过程中报错,将国外源换为国内源。
具体见:更换国内源
好的学习资料不必远求
docker --help
docker run --help
2、基础命令
docker ps 查看当前正在运行的实例
docker images查看现有的镜像
docker kill 实例名称或者实例ID 杀死正在运行的实例
docker pull 镜像名称 从远程docker仓库拉下来别人已经配置好的镜像
如果执行docker相关命令,出现如下错误:
”Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied“
解决方法1(亲测有用)
docker命令默认只能root权限使用,使用sudo获取root(管理员)权限,运行docker命令
例:查看当前正在运行的实例
sudo docker ps
解决方法2(建议使用这个)
解决方法1实在有些繁琐,docker守护进程启动的时候,会默认赋予名字为docker的用户组读写Unix socket的权限,因此只要创建docker用户组,并将当前用户加入到docker用户组中,那么当前用户就有权限访问Unix socket了,进而也就可以执行docker相关命令
sudo groupadd docker #添加docker用户组
sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中
newgrp docker #更新用户组
sudo service docker restart #重启服务
docker ps -a #测试docker命令是否可以使用sudo正常使用
3、docker映射
docker就是一个镜像,我们需要做的就是把docker和外部世界建立联系。最紧密的联系有如下三种:
安装/升级Docker客户端
推荐安装1.10.0以上版本的Docker客户端,参考文档 docker-ce
配置镜像加速器
针对Docker客户端版本大于 1.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["你的专属加速地址"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
我的操作:
cd etc
cd docker
sudo vim daemon.json
进入vim后,按i键插入
复制下面的代码:
{
"registry-mirrors": ["你的专属加速地址"]
}
按Esc+Shift+:,然后按wq保存
sudo docker pull tensorflow/serving
如果我需要的是1.12.0版本的tf,那么也可以拉取指定的版本:
sudo docker pull tensorflow/serving:1.12.0
如果出现以下错误:
docker: Error response from daemon: driver failed programming external connectivity on endpoint priceless_visvesvaraya (9dd9be0149fcbef7a4c7d75a118f3900f87a4441ff92732bf5d4cc232c378739): Bind for 0.0.0.0:8501 failed: port is already allocated.
解决方法:
重启docker服务后再启动容器(具体原因)
systemctl restart docker
sudo docker pull tensorflow/serving
错误解决完成!
复制一份现有的模型,当然也可以使用自己的模型,这个仓库是tensorflow serving的整个源码库,里面给出了一些demo,我们只需要demo那一部分。
git clone https://github.com/tensorflow/serving
1.使用-v参数
TESTDATA="$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata"
sudo docker run -t --rm -p 8501:8501 \
-v "$TESTDATA/saved_model_half_plus_two_cpu:/models/half_plus_two" \
-e MODEL_NAME=half_plus_two \
tensorflow/serving
上面的命令把/tmp/serving/tensorflow_serving/servables/tensorflow/testdata/saved_model_half_plus_two_cpu路径挂载到/models/half_plus_two,这样tensorflow_serving就可以加载models下的模型了,然后开放内部8501的http接口。
docker -e设置环境变量
docker -p设置端口映射
docker -v设置磁盘映射
docker run -t 表示是否允许伪TTY
docker run --rm表示如果实例已经存在,则先remove掉该实例再重新启动新实例
建立映射时,都是形如“宿主机:docker容器”这种格式。
2.建立磁盘映射除了使用-v参数,也可以使用mount参数。(运行时有些问题,还没找到)
sudo docker run -p 8501:8501 --mount type=bind,\ source=/tmp/tfserving/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
上面的命令中:
(1)-p 8501:8501是端口映射,是将容器的8501端口映射到宿主机的8501端口,后面预测的时候使用该端口;
(2)-e MODEL_NAME=testnet 设置模型名称;
(3)–mount type=bind,source=/tmp/testnet,target=/models/testnet 是将宿主机的路径/tmp/testnet挂载到容器的/models/testnet下。/tmp/testnet是存放的是上述准备工作中保存的模型文件,‘testnet’是模型名称,包含一个.pb文件和一个variables文件夹,在/tmp/testnet下新建一个以数字命名的文件夹,如100001,并将模型文件放到该文件夹中。容器内部会根据绑定的路径读取模型文件;
(4)-t tensorflow/serving 根据名称“tensorflow/serving”运行容器;
最后万事俱备,只欠东风了。
1.命令行下使用curl请求预测
使用Predict API请求预测,格式为:
(其中模型版本MODEL_VERSION可以省略,默认使用最新版本的模型。)
POST http://host:port/v1/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]:predict
input_data为模型的输入。
curl -d '{"instances": $input_data}' -X POST http://localhost:8501/v1/models/half_plus_two:predict
发送一个http请求测试一下:
#Query the model using the predict API
curl -d '{"instances": [1.0, 2.0, 5.0]}' \
-X POST http://localhost:8501/v1/models/half_plus_two:predict
得到的结果如下:
{ "predictions": [2.5, 3.0, 4.5] }
这就表明服务已经部署成功了。
如果机器有公网IP(如将tfsevring部署在阿里云服务器上),则可以在其他机器上通过IP地址访问进行预测,将上面的地址中的localhost改为运行容器的机器的公网IP地址即可。
2.使用Python代码请求预测
import requests
import numpy as np
SERVER_URL = 'http://localhost:8501/v1/models/half_plus_two:predict'
def prediction():
predict_request='{"instances":%s}' % str([[[10]*7]*7])
#print(predict_request)
response = requests.post(SERVER_URL, data=predict_request)
prediction = response.json()['predictions'][0]
print(prediction)
if __name__ == "__main__":
prediction()
需要安装tensorflow-serving-api,(这里省略)
我们需要了解tensorflow/serving这个镜像的默认配置,镜像的默认配置就像电路板的引脚一样,是固定的。
serving镜像提供了两种调用方式:gRPC和HTTP请求。gRPC默认端口是8500,HTTP请求的默认端口是8501,serving镜像中的程序会自动加载镜像内/models下的模型,通过MODEL_NAME指定/models下的哪个模型。