TensorFlow Serving 嘗嘗鮮

作者:Mao Chan

著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

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 datanx_data = np.arange(100, step=.1)ny_data = x_data + 20 * np.sin(x_data / 10)nn# Reshape datanx_data = np.reshape(x_data, (n_samples, 1))ny_data = np.reshape(y_data, (n_samples, 1))n

然後用一個簡單的 y = wx + b 來做一個訓練,使用 Adam 演算法。簡單調整了下參數:

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

# Placeholders for batched inputnx = tf.placeholder(tf.float32, shape=(batch_size, 1))ny = tf.placeholder(tf.float32, shape=(batch_size, 1))nn# Do trainingnwith tf.variable_scope(test):n w = tf.get_variable(weights, (1, 1), initializer=tf.random_normal_initializer())n b = tf.get_variable(bias, (1,), initializer=tf.constant_initializer(0))nn y_pred = tf.matmul(x, w) + bn loss = tf.reduce_sum((y - y_pred) ** 2 / n_samples)nn opt = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)nn with tf.Session() as sess:n sess.run(tf.initialize_all_variables())nn for _ in range(n_steps):n indices = np.random.choice(n_samples, batch_size)n x_batch = x_data[indices]n y_batch = y_data[indices]n _, loss_val = sess.run([opt, loss], feed_dict={x:x_batch, y:y_batch})nn print w.eval()n print b.eval()n print loss_valn

大致把 loss 收斂在 15.8 左右。精度應該足夠了,畢竟只是一個簡單的測試用模型。

模型導出

接下來的就是本文的重點:導出模型。

tf.train.Saver

用於保存和恢復Variable。它可以非常方便的保存當前模型的變數或者倒入之前訓練好的變數。一個最簡單的運用:

saver - tf.train.Saver()n# Save the variables to disk.nsaver.save(sess, "/tmp/test.ckpt")n# Restore variables from disk.nsaver.restore(sess, "/tmp/test.ckpt")n

tf.contrib.session_bundle.exporter.Exporter

導出模型還需要這個 Exporter 的協助。令人尷尬的是這個 Exporter 太新了,還沒有 API 文檔支持,只能參考 Github 的代碼實現。

Exporter 的基本使用方式是

  1. 傳入 saver 構造一個實例

  2. 調用 init 定義模型的 graph 和 input/output

  3. 使用 export 導出為文件

model_exporter = exporter.Exporter(saver)nmodel_exporter.init(n sess.graph.as_graph_def(),n named_graph_signatures={n inputs: exporter.generic_signature({x: x}),n outputs: exporter.generic_signature({y: y_pred})})nmodel_exporter.export(FLAGS.work_dir, n tf.constant(FLAGS.export_version),n sess)n

大功告成!編譯!我們成功導出了一個可以部署在 TensorFlow Serving 上的模型。它接受一個 x 值然後返回一個 y 值。導出的文件夾以 version 命名,包含用於部署的 meta 文件, 模型 checkpoint 文件和序列化的模型 graph:

/tmp/test/00000001ncheckpoint export-00000-of-00001 export.metan

模型部署

部署的方式非常簡單,只需要以下兩步:

$ bazel build //tensorflow_serving/model_servers:tensorflow_model_servern$ nbazel-bin/tensorflow_serving/model_servers/tensorflow_model_server --port=9000 --model_name=test --model_base_path=/tmp/test/n

我們看到 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。

from grpc.beta import implementationsnimport numpy as npnimport tensorflow as tfnnfrom tensorflow_serving.apis import predict_pb2nfrom tensorflow_serving.apis import prediction_service_pb2nntf.app.flags.DEFINE_string(server, localhost:9000,n PredictionService host:port)nFLAGS = tf.app.flags.FLAGSnnn_samples = 100nnhost, port = FLAGS.server.split(:)nchannel = implementations.insecure_channel(host, int(port))nstub = prediction_service_pb2.beta_create_PredictionService_stub(channel)nn# Generate test datanx_data = np.arange(n_samples, step=1, dtype=np.float32)nx_data = np.reshape(x_data, (n_samples, 1))nn# Send requestnrequest = predict_pb2.PredictRequest()nrequest.model_spec.name = testn request.inputs[x].CopyFrom(tf.contrib.util.make_tensor_proto(x_data, shape=[100, 1]))nresult = stub.Predict(request, 10.0) # 10 secs timeoutn

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

py_binary(n name = "test_client",n srcs = [n "test_client.py",n ],n deps = [n "//tensorflow_serving/apis:predict_proto_py_pb2",n "//tensorflow_serving/apis:prediction_service_proto_py_pb2",n "@org_tensorflow//tensorflow:tensorflow_py",n ],n)n

最後編譯運行,就能看到在線預測結果啦!

bazel build //tensorflow_serving/test:test_client && ./bazel-bin/tensorflow_serving/test/test_clientn

延伸

TensorFlow 封裝了眾多常用模型成為 Estimator,幫助用戶避免了冗長易錯的演算法實現部分。比如以上的例子就可以完全用 LinearRegressor 來替換。只需要幾行代碼簡單地調用 fit() 函數就能輕鬆得到收斂的模型。唯一不足的是目前與 TensorFlow Serving 還不能 100% 兼容。雖然 Google 還在全力完善 TensorFlow Serving,但是距離完善還需要一定的時間。

如果既想要使用方便快捷的的 Estimator ,又想線上部署呢?當然也是有辦法的,筆者鑽研了一下後,實現了一個用 Estimator 訓練數據,導出模型後再部署上線的方法。最後用這個線上部署的模型實現一個在線評估房屋價值的系統。

如何利用機器學習最火的Tensor Flow架構預測房價>>>公開課註冊試聽

Smart-Zillow全棧房價跟蹤預測系統>>>課程介紹

聯繫人微信:iioooANGELAoooii

----------------------------------------------------------------------------------------------------

更多精彩,盡在矽谷高端線上教育社區BitTiger:請猛戳我

公眾號:論碼農的自我修養

知乎專欄:太閣實驗室

微博:@太閣BitTiger

今日頭條:太閣BitTiger

推薦閱讀:

TAG:机器学习 | TensorFlow | 模型 |