当我们将模型训练完毕后,往往需要将模型在生产环境中部署。最常见的方式,是在服务器上提供一个 API,即客户机向服务器的某个 API 发送特定格式的请求,服务器收到请求数据后通过模型进行计算,并返回结果。如果仅仅是做一个 Demo,不考虑高并发和性能问题,其实配合 Flask 等 Python 下的 Web 框架就能非常轻松地实现服务器 API。不过,如果是在真的实际生产环境中部署,这样的方式就显得力不从心了。这时,TensorFlow 为我们提供了 TensorFlow Serving 这一组件,能够帮助我们在实际生产环境中灵活且高性能地部署机器学习模型。

TensorFlow Serving简单来说就是一个适合在生产环境中对tensorflow深度学习模型进行部署,然后可以非常方便地通过restful形式的接口进行访问。

除此之外,它拥有许多有点:

  1. 支持配置文件的定期轮询更新(periodically poll for updated),无需重新启动;
  2. 优秀的模型版本控制;
  3. 支持并发;
  4. 支持批处理;
  5. 基于docker,部署简单。

一、TensorFlow Serving 安装

TensorFlow Serving 可以使用 apt-get 或 Docker 安装。在生产环境中,推荐 使用 Docker 部署 TensorFlow Serving 。不过此处出于教学目的,介绍依赖环境较少的 apt-get 安装 。

首先设置安装源:

# 添加Google的TensorFlow 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
# 添加gpg key
curl https://storage.googleapis.com/tensorflow-serving-apt/tensorflow-serving.release.pub.gpg | sudo apt-key add -

更新源后,即可使用 apt-get 安装 TensorFlow Serving

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

二、TensorFlow Serving 模型部署

TensorFlow Serving 可以直接读取 SavedModel 格式的模型进行部署。使用以下命令即可:

tensorflow_model_server \--rest_api_port=端口号(如8501) \--model_name=模型名 \--model_base_path="SavedModel格式模型的文件夹绝对地址(不含版本号)"

2.1 Keras Sequential 模式模型的部署

由于 Sequential 模式的输入和输出都很固定,因此这种类型的模型很容易部署,无需其他额外操作。例如,要将 使用 SavedModel 导出的 MNIST 手写体识别模型 (使用 Keras Sequential 模式建立)以 MLP 的模型名在 8501 端口进行部署,可以直接使用以下命令:

tensorflow_model_server \--rest_api_port=8501 \--model_name=MLP \--model_base_path="/home/.../.../saved"  # 文件夹绝对地址根据自身情况填写,无需加入版本号

然后就可以使用 gRPC 或者 RESTful API 在客户端调用模型了。

2.2 自定义 Keras 模型的部署

使用继承 tf.keras.Model 类建立的自定义 Keras 模型的自由度相对更高。因此当使用 TensorFlow Serving 部署模型时,对导出的 SavedModel 文件也有更多的要求:

  • 需要导出到 SavedModel 格式的方法(比如 call )不仅需要使用 @tf.function 修饰,还要在修饰时指定 input_signature 参数,以显式说明输入的形状。该参数传入一个由 tf.TensorSpec 组成的列表,指定每个输入张量的形状和类型。例如,对于 MNIST 手写体数字识别,我们的输入是一个 [None, 28, 28, 1] 的四维张量( None 表示第一维即 Batch Size 的大小不固定),此时我们可以将模型的 call 方法做以下修饰:
class MLP(tf.keras.Model):...@tf.function(input_signature=[tf.TensorSpec([None, 28, 28, 1], tf.float32)])def call(self, inputs):...
  • 在将模型使用 tf.saved_model.save 导出时,需要通过 signature 参数提供待导出的函数的签名(Signature)。简单说来,由于自定义的模型类里可能有多个方法都需要导出,因此,需要告诉 TensorFlow Serving 每个方法在被客户端调用时分别叫做什么名字。例如,如果我们希望客户端在调用模型时使用 call 这一签名来调用 model.call 方法时,我们可以在导出时传入 signature 参数,以 dict 的键值对形式告知导出的方法对应的签名,代码如下:
model = MLP()
...
tf.saved_model.save(model, "saved_with_signature/1", signatures={"call": model.call})

以上两步均完成后,即可使用以下命令部署:

tensorflow_model_server \--rest_api_port=8501 \--model_name=MLP \--model_base_path="/home/.../.../saved_with_signature"  # 修改为自己模型的绝对地址

2.3 自定义版本

TensorFlow Serving有着优秀的模型版本控制功能。首先,TensorFlow Serving默认是加载最大版本号的模型。例如,上面我们部署了一个版本号为“1”的模型,如果之后模型又进行更新,版本号升级为“2”,那么仅需要将新的模型拷贝到相同的目录下即可。

比如,这个时候就有两个模型/tmp/model/1和/tmp/model/2,TensorFlow Serving会默认加载版本号“2”的模型。

如果我们想要多个版本的模型同时存在,并且多个模型同时部署,那么也是可以实现的。

在/tmp/model下创建一个models.config文件,以protocol的形式写入以下内容:

model_config_list {config {name: 'myserving'base_path: '/models/myserving/'model_platform: 'tensorflow'model_version_policy {specific {versions: 1versions: 2}}version_labels {key: 'stable'value: 1}version_labels {key: 'canary'value: 2}}config {name: 'model2'base_path: '/models/model2/'model_platform: 'tensorflow'}
}

可以看到,里面有两个config,意味着我们同时上线两个模型。

看第一个config:name为模型的名称,base_path为容器中模型的位置,model_platform就设置为tensorflow即可;

model_version_policy不加的话就是默认最新的版本控制策略。specific指定上线的版本,version_labels将版本号映射为对应的key,如stable对应版本号“1”的模型。

然后,在启动容器服务的时候,需要指定配置文件路径:

docker run -p 8501:8501 \
--mount type=bind,source=/tmp/model,target=/models/myserving \
-e MODEL_NAME=myserving -t tensorflow/serving \
--model_config_file=/models/models.config \
--allow_version_labels_for_unavailable_models=true

(如果不加这个配置项–allow_version_labels_for_unavailable_models=true,那么版本号和key的映射关系不能在启动时设置,只能在启动后才能进行设置)

那么,如果访问第一个模型的stable版本,地址则为:

http://localhost:8501/v1/models/myserving/labels/stable:predict

或者

http://localhost:8501/v1/models/myserving/versions/1:predict

官方推荐第一种。

2.4 轮询更新

想要对模型的配置文件进行定期轮询更新的话,只需要加上配置项

--model_config_file_poll_wait_seconds=60

这里是设置为60秒一次。

2.5 并发和批处理

批处理简单来说就是可以将多个接口的请求合并一个batch,然后模型计算完成之后一起返回。

在/tmp/model下创建一个batcj.config文件,仍是protocol的形式写入以下内容:

max_batch_size { value: 128 }
batch_timeout_micros { value: 1000 }
max_enqueued_batches { value: 1000000 }
num_batch_threads { value: 8 }

max_batch_size:一个批次允许的最大请求数量

batch_timeout_micros:合并一个批次等待的最长时间,即使该批次的数量未达到max_batch_size,也会立即进行计算(单位是微秒)

max_enqueued_batches:队列的最大数量

num_batch_threads:线程数,在这里体现并发。

这些都是全局设置,针对所有版本的模型!!!

那么,此时启动容器服务的命令就变成:

docker run -p 8501:8501 \
--mount type=bind,source=/tmp/model,target=/models/myserving \
-e MODEL_NAME=myserving -t tensorflow/serving \
--model_config_file=/models/models.config \
--allow_version_labels_for_unavailable_models=true \
--enable_batching=true \
--batching_parameters_file=/models/batch.config

三、在客户端调用以 TensorFlow Serving 部署的模型

TensorFlow Serving 支持以 gRPC 和 RESTful API 调用以 TensorFlow Serving 部署的模型。本手册主要介绍较为通用的 RESTful API 方法。

RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。

RESTful API 以标准的 HTTP POST 方法进行交互,请求和回复均为 JSON 对象。为了调用服务器端的模型,我们在客户端向服务器发送以下格式的请求:

服务器 URI: http://服务器地址:端口号/v1/models/模型名:predict

请求内容:

{"signature_name": "需要调用的函数签名(Sequential模式不需要)","instances": 输入数据
}

回复为:

{"predictions": 返回值
}

3.1 Python 客户端示例

以下示例使用 Python 的 Requests 库 (你可能需要使用 pip install requests 安装该库)向本机的 TensorFlow Serving 服务器发送 MNIST 测试集的前 10 幅图像并返回预测结果,同时与测试集的真实标签进行比较。

import json
import numpy as np
import requests
from zh.model.utils import MNISTLoaderdata_loader = MNISTLoader()
data = json.dumps({"instances": data_loader.test_data[0:3].tolist()})
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/MLP:predict',data=data, headers=headers)
predictions = np.array(json.loads(json_response.text)['predictions'])
print(np.argmax(predictions, axis=-1))
print(data_loader.test_label[0:10])

输出:

[7 2 1 0 4 1 4 9 6 9]
[7 2 1 0 4 1 4 9 5 9]

可见预测结果与真实标签值非常接近。

对于自定义的 Keras 模型,在发送的数据中加入 signature_name 键值即可,即将上面代码的 data 建立过程改为:

data = json.dumps({"signature_name": "call","instances": data_loader.test_data[0:10].tolist()})

参考资料

  1. TensorFlow Serving:深度学习模型在生产环境的部署&上线
  2. TensorFlow Serving

【Keras】TensorFlow Serving相关推荐

  1. 【干货】TensorFlow 2.0官方风格与设计模式指南(附示例代码)

    本文转自专知 [导读]TensorFlow 1.0并不友好的静态图开发体验使得众多开发者望而却步,而TensorFlow 2.0解决了这个问题.不仅仅是默认开启动态图模式,还引入了大量提升编程体验的新 ...

  2. 【keras】一维卷积神经网络多分类

    刚刚接触到深度学习,前2个月的时间里,我用一维的卷积神经网络实现了对于一维数据集的分类和回归.由于在做这次课题之前,我对深度学习基本上没有过接触,所以期间走了很多弯路. 在刚刚收到题目的要求时,我选择 ...

  3. 【keras】3. 泰坦尼克号数据集处理与预测

    [参考:1-01 实战 泰坦尼克号沉船人员获救案例 数据清洗_哔哩哔哩_bilibili] [参考:Titanic - Machine Learning from Disaster | Kaggle] ...

  4. 【Keras】基于SegNet和U-Net的遥感图像语义分割

    from:[Keras]基于SegNet和U-Net的遥感图像语义分割 上两个月参加了个比赛,做的是对遥感高清图像做语义分割,美其名曰"天空之眼".这两周数据挖掘课期末projec ...

  5. 【问题解决】Tensorflow运行出现错误: No module named tensorflow.contrib

    我本来想用keras,,这样写的 import tensorflow.contrib.keras as kr 但是报错了 我的tensorflow 版本如下 [问题解决]因为tensorflow1.1 ...

  6. 【Keras】减少过拟合的秘诀——Dropout正则化

    摘要: Dropout正则化是最简单的神经网络正则化方法.阅读完本文,你就学会了在Keras框架中,如何将深度学习神经网络Dropout正则化添加到深度学习神经网络模型里. Dropout正则化是最简 ...

  7. 【python】tensorflow框架中的tf.gather_nd()函数对应的 pytorch框架的gather_nd()函数

    tf.gather_nd 函数对应的pytorch函数 1. 简单介绍 2. 步入正题 2.1 tensorflow tf.gather_nd() 2.2 pytorch框架手动实现gather_nd ...

  8. 【tfcoreml】tensorflow向CoreML模型的转换工具封装

    安装tf向apple coreml模型转换包tfcoreml 基于苹果自己的转换工具coremltools进行封装 tfcoreml 为了将训练的模型转换到apple中使用,需要将模型转换为ios支持 ...

  9. 【9】tensorflow下图像预处理之图像批量处理

    背景:在深度学习时候,通常需要批量处理大量的图片,一般几千张,图像不够时还需要进行数据增强,因此需要批量处理图像数据. [1]批量加载文件夹里面的数据 import os import cv2#批量处 ...

最新文章

  1. 树莓派电压过低 串口数据错误增多
  2. 应用程序异常管理组件 Example 程序
  3. C#笔记 Public,Private,Protected,Internal,Protected internal
  4. docker 离线安装 mysql_docker 离线安装
  5. 【组合数学】排列组合 ( 多重集组合数 | 所有元素重复度大于组合数 | 多重集组合数 推导 1 分割线推导 | 多重集组合数 推导 2 不定方程非负整数解个数推导 )
  6. 【Java基础】一篇文章读懂多线程
  7. Go语言入门篇-使用Beego构建完整web应用
  8. 前端学习(672):if-else
  9. Dojo API中文 Dojo内容模块概览,初学者
  10. Windows下卸载TensorFlow
  11. linux 切换root账号_Linux 服务器的安全保障,看看这些
  12. 32位mips运算器logisim_很多网友问32位低功耗MCU设计
  13. 2-SAT 问题(洛谷-P4782)
  14. 数据结构与算法分析(十)——母牛的故事
  15. EPPlus 读写 Excel 资料收集
  16. 开发前奏曲之添加Android SDK平台工具
  17. 计算机硬件开票几个点,财务税控开票电脑装机配置清单和价格介绍
  18. 知识竞赛中如何按抢答器才能最先抢到
  19. 海信电视开启开发者模式
  20. 五子棋项目结束总结_五子棋比赛总结报告

热门文章

  1. C++ 无符号高精度计算合集
  2. linux——基本工具:gcc/g++,make(makefile)与gdb
  3. 国内B2C 26个经典购物网站商城收集(更新至2009年11月3日)转载
  4. php基地论坛,中国原创歌词基地论坛 - 最大的原创歌词社区
  5. MySql Povit,[MySQL|Postgresql] Pivot 通用技巧
  6. 如何在安装 Ubuntu 22.04 时加密全盘
  7. 头条原创文章一键转换剪映生成视频
  8. 防计算机病毒主题,主题3+计算机病毒的查杀与防御要点.ppt
  9. 航天器轨道六要素和TLE两行轨道数据格式
  10. 结构光相移法中相机投影仪的标定信息如何与相位差联系