利用docker部署TF深度学习模型

利用docker部署TF深度学习模型,第1张

一.介绍

docker:

            Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。


            Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。


            容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。


tf-server:

           Tensorflow Serving 是一个生产级别的灵活高性能的机器学习模型服务系统。


二.docker环境配置 1.docker安装(要求docker版本):  在Ubuntu中安装Docker和docker的使用 - JaryTom - 博客园 (本人虚拟机用的是ubuntu,其他系统可参考网上教程)

安装命令

执行sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && curl -fsSL https://download.docker.com/linux/ubuntu/gpg sudo apt-key add - && sudo add-apt-repository "deb [arch=amd64] 阿里云开源镜像站资源目录 $(lsb_release -cs) stable" && sudo apt-get update && sudo apt-get install -y docker-ce

测试 Docker 是否安装成功:

$ sudo docker run hello-world

以下为命令解释

$ sudo apt-get remove docker docker-engine docker.io containerd runc
更新 apt 包索引,安装 apt 依赖包: 
$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
添加 Docker 的官方 GPG 密钥:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
使用以下指令设置稳定版仓库:
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
更新 apt 包索引,并安装最新版本的 Docker Engine-Community 和 containerd:
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
可使用apt-cache madison docker-ce命令查看仓库,安装指定版本;

2.拉取tensorflow/serving镜像(由于单机训练的tf为1.12.0,所以pull 1.12.0的tf-serving镜像):

注:注意版本尽量与模型代码一致,防止api不同导致报错

$ sudo docker pull tensorflow/serving:1.12.0
三.tensorflow模型保存(saved_model格式)如果仅是部署,可忽略该部分

模型同学离线训练模型使用tensorflow api将模型保存为saved_model格式。


一个文件 里面包含pb(protocol buffer)文件 和一个文件夹 variables,这样的模型保存方式可以构建TensorFlow serving 服务。


具体的就是是利用docker来构建TensorFlow serving 的服务端,在前述环境配置 *** 作中已完成,然后在客户端通过grpc来连接。


代码示例(tensoflow版本很多,根据具体版本api可能有调整,需要进行调试):

tensorflow-saved_mdoel保存

def save_saved_model(model_train,sess,model_dir):
    builder = tf.saved_model.builder.SavedModelBuilder(model_dir)
    # 构建 signature  为了不知道tensor name的情况,run对应的tensor
    signature = tf.saved_model.signature_def_utils.build_signature_def(
        # 获取输入输出的信息(shape,dtype等),在部署服务后请求带来的数据会喂到inputs中,服务吐的结果会以outputs的形式返回
        #signature中的key  就下面的input  dropout_keep_prob 都是curl时候的key
        inputs={"feat_index": tf.saved_model.utils.build_tensor_info(model_train.model.feat_index), \
                "feat_value": tf.saved_model.utils.build_tensor_info(model_train.model.feat_value), \
                "dropout_fm": tf.saved_model.utils.build_tensor_info(model_train.model.dropout_fm), \
                "dropout_deep": tf.saved_model.utils.build_tensor_info(model_train.model.dropout_deep), \
                "train_phase": tf.saved_model.utils.build_tensor_info(model_train.model.train_phase)},         # 获取输入tensor的信息,这个字典可以有多个key-value对
        outputs={"output": tf.saved_model.utils.build_tensor_info(model_train.model.out)},     # 获取输出tensor的信息,这个字典可以有多个key-value对
        method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME    # 就是字符串类型 'tensorflow/serving/predict'
    )
    #保存会话对象中的 graph 和所有变量
    builder.add_meta_graph_and_variables(sess,
        tags=[tf.saved_model.tag_constants.SERVING],         # 如果用来部署,就这样写。


否则可以写其他,如["test-model"]  就是字符串类型 'serve'         signature_def_map={"serving_default": signature},    # 如果用来部署,字典的key必须是"serving_default"。


否则可以写其他     )     #将内建的 savedModel protobuf 写入磁盘     builder.save()

模型文件夹目录结构如下,1和2为版本号文件夹(附件中的模型只有1个版本)

./model

├── 1
│   ├── saved_model.pb
│   └── variables文件夹
└── 2
     ├── saved_model.pb
     └── variables文件夹

四.模型挂载(模型文件在附件里面,为deepfm_model文件夹,由于模型文件较大,为分片压缩包)

挂载命令:

注:source为前述模型保存路径(模型的路径,可以自定义),target为映射到docker中的路径,model_name为自定义设置的模型名(需要设置hh_model,和预测脚本使用的模型名一致),tensorflow/serving:1.12.0为指定的容器,实质就是把本地模型映射到容器的模型目录(可指定gpu)

docker启动tf-server服务(载入对应的saved模型)

sudo docker run -p 1234:8500 -p 1500:8501 --mount type=bind,source=/home/hang/Project/hh_deep_model/deepfm_model,target=/models/hh_model  -e MODEL_NAME=hh_model  -d tensorflow/serving:1.12.00

解释:本机的1234端口对应Docker的8500端口(GRPC端口),本机1500端口对应Docker的8501端口(HTTP端口)

挂载成功后可测试是否curl成功(下面curl的case中input的数据不符合模型的输入格式,模型需要的特征维数较高,直接用步骤5-模型预测部分 来测试模型是否挂载成功)

线上curl部署在tf-serving上saved格式的模型

curl -d '{"inputs": {"input":[[1.0, 2.0, 5.0,2.0,1.0, 2.0, 5.0,2.0,1.0, 2.0, 5.0,2.0,1.0, 2.0, 5.0,2.0,1.0, 2.0, 5.0,2.0]],"dropout_keep_prob":1.0}}' -X POST http://localhost:1500/v1/models/hh_model:predict

五.模型预测(预测脚本需要的meta和test_type2_value.npy文件在附件压缩包里,为分片压缩包)

客户端预测(grpc协议通信),客户端需要安装tensorflow-serving-api(使用pip install 安装 pip install tensorflow-serving-api==1.12.0),GRPC端口--容器对应的端口为8500端口,对外开发的端口自定义设置(?:8500),curl(http端口)–容器对应的端口为8501端口,对外开发的端口自定义设置(?:8501)。


模型挂载成功后,可直接执行下面的代码测试是否跑通。


代码示例:

tensorflow-online-predict

#!/usr/bin/env python
#encoding: utf-8

import tensorflow as tf
import numpy as np
import sys
import os
import logging
from grpc.beta import implementations
from tensorflow_serving.apis import predict_pb2
from tensorflow.core.framework import types_pb2
from tensorflow_serving.apis import prediction_service_pb2
# "server"根据需要自定义
# '0.0.0.0:8500'其中ip可更换为机器ip,以进行跨机器方位

tf.app.flags.DEFINE_string('server', r'127.0.0.1:1234', 'post of server')

FLAGS = tf.app.flags.FLAGS

dict_set = None

def load_features_from_lines(path):
    # 读取特征列表,一行一个
    features = []
    with open(path) as o:
        for line in o:
            line_strip = line.strip()
            if line_strip:
                features.append(line_strip.decode('utf-8'))
    logging.info('load {0} cols from {1} for filter'.format(len(features), path))
    return features


def data_gen(fea_path):
    # 数据处理  test_type2_value为验证数据集  用来验证一致性 和test_res里面的预测值对比一致性
    # 真正上线时,feat_value为预处理好的特征(归一化脚本需要额外再写)。


rc端输入特征(模型同学提供特征列表),然后本脚本进行预测然后返回一个score。


    feat_value = np.load("test_type2_value.npy")[0].astype(np.float32)     #print feat_value.shape     fealist = load_features_from_lines(fea_path)     feat_index = np.array([x for x in range(len(fealist))]).astype(np.int32)     dropout_fm = np.array([0.0]*2).astype(np.float32)     dropout_deep = np.array([0.0]*4).astype(np.float32)     train_phase = False     return feat_index,feat_value,dropout_fm,dropout_deep,train_phase def setup_stub():     host, port = FLAGS.server.split(':')     channel = implementations.insecure_channel(host, int(port))     return prediction_service_pb2.beta_create_PredictionService_stub(channel) def setup_request():     request = predict_pb2.PredictRequest()     # 模型名称与挂载模型时设置的model_name一致(即docker run ....命令中的model_name)     request.model_spec.name = 'hh_model'     request.model_spec.signature_name = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY     return request def predict(data): #    if os.environ.get('https_proxy'): #        del os.environ['https_proxy'] #    if os.environ.get('http_proxy'): #        del os.environ['http_proxy']     stub = setup_stub()     request = setup_request()     feat_index,feat_value,dropout_fm,dropout_deep,train_phase = data_gen(data)     request.inputs['feat_index'].CopyFrom(tf.contrib.util.make_tensor_proto(feat_index))     request.inputs['feat_value'].CopyFrom(tf.contrib.util.make_tensor_proto(feat_value))     request.inputs['dropout_fm'].CopyFrom(tf.contrib.util.make_tensor_proto(dropout_fm))     request.inputs['dropout_deep'].CopyFrom(tf.contrib.util.make_tensor_proto(dropout_deep))     request.inputs['train_phase'].CopyFrom(tf.contrib.util.make_tensor_proto(train_phase))     result_future = stub.Predict.future(request, 5.0)  # 5 seconds     #.float_val     response_out_score = np.array(result_future.result().outputs['output'].float_val)  # 300     print("response_out_score: ", response_out_score) if __name__ == '__main__':     # fea_path为特征列表路径,可见附件中的meta文件     fea_path = sys.argv[1]     predict(fea_path)

docker常用命令

Docker常用 *** 作

docker version 查看docker的版本信息

docker info 显示 Docker 系统信息,包括镜像和容器数

docker --help Docker的帮助命令

docker images 列出本地主机上的镜像

docker search 从仓库中搜索指定的镜像

docker rmi –f 删除镜像id   docker rmi -f $(docker images -qa) 删除全部 –q表示静默模式,只显示容器编号

docker rm 删除容器ID docker rm -f $(docker ps -aq)删除全部

docker pull下载镜像

docker run [option] image [command] 新建并启动容器—具体参数可以查看

docker ps 列出当前所有正在运行的容器

启动容器:docker start 容器ID或者容器名

重启容器:docker restart 容器ID或者容器名

停止容器:docker stop 容器ID或者容器名

强制停止容器:docker kill 容器ID或者容器名

docker top 容器ID查看容器内运行的进程

docker inspect 容器ID查看容器内部细节

docker exec -it 容器ID bashShell 在容器中打开新的终端,并且可以启动新的进程--进入正在运行的容器并以命令行交互 docker exec -it /bin/bash对指定的容器执行bash,进入容器

docker cp 容器ID:容器内路径 目标主机路径 从容器内拷贝文件到主机上

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/563881.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-03
下一篇 2022-04-03

发表评论

登录后才能评论

评论列表(0条)

保存