http://blog.csdn.net/wangjian1204/article/details/68928656

本文转载自:https://zhuanlan.zhihu.com/p/23361413 ,原题:TensorFlow Serving 尝尝鲜

2016年,机器学习在 Alpha Go 与李世石的世纪之战后变得更加炙手可热。Google也在今年推出了 TensorFlow Serving 又加了一把火。

TensorFlow Serving 是一个用于机器学习模型 serving 的高性能开源库。它可以将训练好的机器学习模型部署到线上,使用 gRPC 作为接口接受外部调用。更加让人眼前一亮的是,它支持模型热更新与自动模型版本管理。这意味着一旦部署 TensorFlow Serving 后,你再也不需要为线上服务操心,只需要关心你的线下模型训练。

今天我就带大家来用 TensorFlow Serving 部署一个简单的 Linear Regression 模型。

以下演示运行在 Ubuntu 16.04 LTS 之上。

TensorFlow Serving 处于快速迭代期。如果本文内容与官方文档矛盾,请以官方文档为参考。

环境

TensorFlow Serving 目前依赖 Google 的开源编译工具 Bazel。Bazel 是 Google 内部编译工具 Blaze 的开源版本,功能与性能基本一致。具体的安装可以参考官方文档。此外还需要安装 gRPC (Google 又一个内部工具的开源版)。

之后请参考官方安装指南完成。值得注意的是,最后的 bazel build 将会需要大约30分钟时间并占用约5-10G的空间(时间取决于机器性能)。配合使用 -c opt 能一定程度加快 build。

模型训练

接下来我们用 TensorFlow 写一个简单的测试用 Linear Regression 模型。数据的话我就使用正弦函数生成 1000 个点,尝试用一条直线去拟合。

样本数据生成如下:

# Generate input data 
x_data = np.arange(100, step=.1)
y_data = x_data + 20 * np.sin(x_data / 10)
  • 1
  • 2
  • 3

Reshape data

x_data = np.reshape(x_data, (n_samples, 1))
y_data = np.reshape(y_data, (n_samples, 1))
  • 1
  • 2

然后用一个简单的 y = wx + b 来做一个训练,使用 Adam 算法。简单调整了下参数:

sample = 1000, learning_rate = 0.01, batch_size = 100, n_steps = 500

# Placeholders for batched input 
x = tf.placeholder(tf.float32, shape=(batch_size, 1))
y = tf.placeholder(tf.float32, shape=(batch_size, 1))
  • 1
  • 2
  • 3

Do training

with tf.variable_scope('test'):
w = tf.get_variable('weights', (1, 1), initializer=tf.random_normal_initializer())
b = tf.get_variable('bias', (1,), initializer=tf.constant_initializer(0)) y_pred = tf.matmul(x, w) + b
loss = tf.reduce_sum((y - y_pred) ** 2 / n_samples) opt = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss) with tf.Session() as sess:
sess.run(tf.initialize_all_variables()) for _ in range(n_steps):
indices = np.random.choice(n_samples, batch_size)
x_batch = x_data[indices]
y_batch = y_data[indices]
_, loss_val = sess.run([opt, loss], feed_dict={x:x_batch, y:y_batch}) print w.eval()
print b.eval()
print loss_val
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

大致把 loss 收敛在 15.8 左右。精度应该足够了,毕竟只是一个简单的测试用模型。

模型导出

接下来的就是本文的重点:导出模型。

tf.train.Saver

用于保存和恢复Variable。它可以非常方便的保存当前模型的变量或者倒入之前训练好的变量。一个最简单的运用:

saver - tf.train.Saver()

  • 1
  • 2
  • 3

Save the variables to disk.

saver.save(sess, “/tmp/test.ckpt”)

Restore variables from disk.

saver.restore(sess, “/tmp/test.ckpt”)

tf.contrib.session_bundle.exporter.Exporter

导出模型还需要这个 Exporter 的协助。令人尴尬的是这个 Exporter 太新了,还没有 API 文档支持,只能参考 Github 的代码实现

Exporter 的基本使用方式是

  1. 传入 saver 构造一个实例

  2. 调用 init 定义模型的 graph 和 input/output

  3. 使用 export 导出为文件

  • 1
model_exporter = exporter.Exporter(saver)
model_exporter.init(
sess.graph.as_graph_def(),
named_graph_signatures={
'inputs': exporter.generic_signature({'x': x}),
'outputs': exporter.generic_signature({'y': y_pred})})
model_exporter.export(FLAGS.work_dir,
tf.constant(FLAGS.export_version),sess)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

大功告成!编译!我们成功导出了一个可以部署在 TensorFlow Serving 上的模型。它接受一个 x 值然后返回一个 y 值。导出的文件夹以 version 命名,包含用于部署的 meta 文件, 模型 checkpoint 文件和序列化的模型 graph:

/tmp/test/00000001 
checkpoint export-00000-of-00001 export.meta
  • 1
  • 2
  • 3

模型部署

部署的方式非常简单,只需要以下两步:

$ bazel build //tensorflow_serving/model_servers:tensorflow_model_server 
$
bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server --port=9000 --model_name=test --model_base_path=/tmp/test/
  • 1
  • 2
  • 3
  • 4

我们看到 TensorFlow Serving 成功加载了我们刚刚导出的 model。并且还在不断尝试 poll 新的 model:

客户端

接下来我们写一个简单的 Client 来调用下我们部署好的 Model。这里我们需要用到 TensorFlow Serving 的 Predict API 和 gRPC 的 implementations.insecure_channel 来construct 一个 request。特别要注意的是 input 的 signature 和数据必须和之前 export 的模型匹配。本例中为 名称为 x, float32类型,大小为 [100, 1] 的 Tensor。

  • 1
from grpc.beta import implementations
import numpy as np
import tensorflow as tf from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2 tf.app.flags.DEFINE_string('server', 'localhost:9000',
'PredictionService host:port')
FLAGS = tf.app.flags.FLAGS n_samples = 100 host, port = FLAGS.server.split(':')
channel = implementations.insecure_channel(host, int(port))
stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Generate test data

x_data = np.arange(n_samples, step=1, dtype=np.float32) 
x_data = np.reshape(x_data, (n_samples, 1))

Send request

request = predict_pb2.PredictRequest() 
request.model_spec.name = ‘test’ 
request.inputs[‘x’].CopyFrom(tf.contrib.util.make_tensor_proto(x_data, shape=[100, 1])) 
result = stub.Predict(request, 10.0) # 10 secs timeout

别忘了配置一下 bazel 的 BUILD 文件:

py_binary( 
name = "test_client",
srcs = [
"test_client.py",
],
deps = [
"//tensorflow_serving/apis:predict_proto_py_pb2",
"//tensorflow_serving/apis:prediction_service_proto_py_pb2",
"@org_tensorflow//tensorflow:tensorflow_py",
],
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

最后编译运行,就能看到在线预测结果啦!

bazel build //tensorflow_serving/test:test_client && ./bazel-bin/tensorflow_serving/test/test_client 
  • 1
  • 2

延伸

TensorFlow 封装了众多常用模型成为 Estimator,帮助用户避免了冗长易错的算法实现部分。比如以上的例子就可以完全用 LinearRegressor 来替换。只需要几行代码简单地调用 fit() 函数就能轻松得到收敛的模型。唯一不足的是目前与 TensorFlow Serving 还不能 100% 兼容。虽然 Google 还在全力完善 TensorFlow Serving,但是距离完善还需要一定的时间。

如果既想要使用方便快捷的的 Estimator ,又想线上部署呢?当然也是有办法的,笔者钻研了一下后,实现了一个用 Estimator 训练数据,导出模型后再部署上线的方法。最后用这个线上部署的模型实现一个在线评估房屋价值的系统。

Tensorflow Serving 模型部署和服务的更多相关文章

  1. tensorflow serving 模型部署

    拉去tensorflow srving 镜像 docker pull tensorflow/serving:1.12.0 代码里新增tensorflow 配置代码 # 要指出输入,输出张量 #指定保存 ...

  2. 如何使用flask将模型部署为服务

    在某些场景下,我们需要将机器学习或者深度学习模型部署为服务给其它地方调用,本文接下来就讲解使用python的flask部署服务的基本过程. 1. 加载保存好的模型 为了方便起见,这里我们就使用简单的分 ...

  3. 基于TensorFlow Serving的深度学习在线预估

    一.前言 随着深度学习在图像.语言.广告点击率预估等各个领域不断发展,很多团队开始探索深度学习技术在业务层面的实践与应用.而在广告CTR预估方面,新模型也是层出不穷: Wide and Deep[1] ...

  4. 什么是TensorFlow Serving

    答:1. 从Serving 可以看出,与服务有关; 2. 那么为啥还有TensorFlow的前缀?肯定与TensorFlow有着很大的关系: 3. 那么Tensorflow是用来干什么的呢?Tenso ...

  5. TensorFlow Serving简介

    一.TensorFlow Serving简介 TensorFlow Serving是GOOGLE开源的一个服务系统,适用于部署机器学习模型,灵活.性能高.可用于生产环境. TensorFlow Ser ...

  6. docker部署tensorflow serving以及模型替换

    Using TensorFlow Serving with Docker 1.Ubuntu16.04下安装docker ce 1-1:卸载旧版本的docker sudo apt-get remove ...

  7. Kubernetes入门(四)——如何在Kubernetes中部署一个可对外服务的Tensorflow机器学习模型

    机器学习模型常用Docker部署,而如何对Docker部署的模型进行管理呢?工业界的解决方案是使用Kubernetes来管理.编排容器.Kubernetes的理论知识不是本文讨论的重点,这里不再赘述, ...

  8. tensorflow 模型保存与加载 和TensorFlow serving + grpc + docker项目部署

    TensorFlow 模型保存与加载 TensorFlow中总共有两种保存和加载模型的方法.第一种是利用 tf.train.Saver() 来保存,第二种就是利用 SavedModel 来保存模型,接 ...

  9. Tensorflow Serving Docker compose 部署服务细节(Ubuntu)

    [摘要] Tensorflow Serving 是tf模型持久化的重要工具,本篇介绍如何通过Docker compose搭建并调试TensorFlow Serving TensorFlow Servi ...

随机推荐

  1. WEB应用从服务器主动推送Data到客户端有那些方式?

    1)  html5 websocket 2)  WebSocket 通过 Flash 3)  XHR长时间连接 4)  XHR Multipart Streaming 5)  不可见的Iframe 6 ...

  2. hdu 5762 Teacher Bo 暴力

    Teacher Bo 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5762 Description Teacher BoBo is a geogra ...

  3. 浅谈web缓存(转)

    这是一篇知识性的文档,主要目的是为了让Web缓存相关概念更容易被开发者理解并应用于实际的应用环境中.为了简要起见,某些实现方面的细节被简化或省略了.如果你更关心细节实现则完全不必耐心看完本文,后面参考 ...

  4. [多问几个为什么]为什么匿名内部类中引用的局部变量和参数需要final而成员字段不用?(转)

    昨天有一个比较爱思考的同事和我提起一个问题:为什么匿名内部类使用的局部变量和参数需要final修饰,而外部类的成员变量则不用?对这个问题我一直作为默认的语法了,木有仔细想过为什么(在分析完后有点印象在 ...

  5. SWD and JTAG selection mechanism

    SWD and JTAG selection mechanism SWJ-DP enables either an SWD or JTAG protocol to be used on the deb ...

  6. 下载8000首儿歌的python代码

    下载8000首儿歌的python的代码: #-*- coding: UTF-8 -*- from pyquery import PyQuery as py from lxml import etree ...

  7. Revit Family API 找到实体某一方向上的面。

    PlanarFace.Normal取得向量.IsAlmostEqualTo判断向量是否一致. // ================================================== ...

  8. C++ 实践总结

     对于一个应用程序而言,静态链接库可能被载入多次,而动态链接库仅仅会被载入一次. Gameloft面试之错误一 Event: 面试官说例如以下程序是能够链接通过的. class Base { Pu ...

  9. AutoMapper在MVC中的运用02-Decimal转String、集合、子父类映射

    本篇AutoMapper使用场景: ※ Decimal转换成String类型 ※ 源数组转换成目标数组 ※ 源中的集合(数组)属性转换成目标中的集合(数组)属性 ※ 子类父类间的映射 Decimal转 ...

  10. VirtualBox - NAT虚拟机访问外网 + Host-Only物理主机虚拟机互访

    [root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-System_eth0 # 未手动设定HOST-ONLY静态IP时的默认值 #T ...