TensorFlow 模型如何對外提供服務
TensorFlow 是目前最為流行的機器學習框架之一,通過它我們可以便捷地構建機器學習模型。使用 TensorFlow 模型對外提供服務有若干種方式,本文將介紹如何使用 SavedModel 機制來編寫模型預測介面。
鳶尾花深層神經網路分類器
首先讓我們使用 TensorFlow 的深層神經網路模型來構建一個鳶尾花的分類器。完整的教程可以在 TensorFlow 的官方文件中檢視(Premade Estimators),我也提供了一份示例程式碼,託管在 GitHub 上(iris_dnn.py),讀者可以克隆到本地進行測試。以下是部分程式碼摘要:
feature_columns = [tf.feature_column.numeric_column(key=key)
for key in train_x.keys()]
classifier = tf.estimator.DNNClassifier(
feature_columns=feature_columns,
hidden_units=[10, 10],
n_classes=3)
classifier.train(
input_fn=lambda: train_input_fn(train_x, train_y, batch_size=BATCH_SIZE),
steps=STEPS)
predictions = classifier.predict(
input_fn=lambda: eval_input_fn(predict_x, labels=None, batch_size=BATCH_SIZE))
將模型匯出為 SavedModel 格式
TensorFlow 提供了 SavedModel 機制,用以將訓練好的模型匯出為外部檔案,供後續使用或對外提供服務。Estimator 類的 export_savedmodel 方法接收兩個引數:匯出目錄和資料接收函式。該函式定義了匯出的模型將會對何種格式的引數予以響應。通常,我們會使用 TensorFlow 的 Example 型別來表示樣本和特徵。例如,鳶尾花樣本可以用如下形式表示:
Example(
features=Features(
feature={
'SepalLength': Feature(float_list=FloatList(value=[5.1])),
'SepalWidth': Feature(float_list=FloatList(value=[3.3])),
'PetalLength': Feature(float_list=FloatList(value=[1.7])),
'PetalWidth': Feature(float_list=FloatList(value=[0.5])),
}
)
)
接收函式會收到序列化後的 Example 物件,將其轉化成一組 Tensor 供模型消費。TensorFlow 提供了一些工具函式幫助我們完成這些轉換。首先,我們將 feature_columns 陣列轉化成 Feature 字典,作為反序列化的規格標準,再用它生成接收函式:
# [
# _NumericColumn(key='SepalLength', shape=(1,), dtype=tf.float32),
# ...
# ]
feature_columns = [tf.feature_column.numeric_column(key=key)
for key in train_x.keys()]
# {
# 'SepalLength': FixedLenFeature(shape=(1,), dtype=tf.float32),
# ...
# }
feature_spec = tf.feature_column.make_parse_example_spec(feature_columns)
# 構建接收函式,並匯出模型。
serving_input_receiver_fn = tf.estimator.export.build_parsing_serving_input_receiver_fn(feature_spec)
export_dir = classifier.export_savedmodel('export', serving_input_receiver_fn)
使用命令列工具檢測 SavedModel
每次匯出模型都會生成一個帶有時間戳的目錄,裡面包含了該模型的引數資訊:
export/1524907728/saved_model.pb
export/1524907728/variables
export/1524907728/variables/variables.data-00000-of-00001
export/1524907728/variables/variables.index
TensorFlow 提供的命令列工具可用於檢視匯出模型的內容,甚至可以直接呼叫預測函式:
$ saved_model_cli show --dir export/1524906774 \
--tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
inputs['inputs'] tensor_info:
dtype: DT_STRING
shape: (-1)
The given SavedModel SignatureDef contains the following output(s):
outputs['classes'] tensor_info:
dtype: DT_STRING
shape: (-1, 3)
outputs['scores'] tensor_info:
dtype: DT_FLOAT
shape: (-1, 3)
Method name is: tensorflow/serving/classify
$ saved_model_cli run --dir export/1524906774 \
--tag_set serve --signature_def serving_default \
--input_examples 'inputs=[{"SepalLength":[5.1],"SepalWidth":[3.3],"PetalLength":[1.7],"PetalWidth":[0.5]}]'
Result for output key classes:
[[b'0' b'1' b'2']]
Result for output key scores:
[[9.9919027e-01 8.0969761e-04 1.2872645e-09]]
使用 contrib.predictor 提供服務
tf.contrib.predictor.from_saved_model 方法能夠將匯出的模型載入進來,直接生成一個預測函式供使用:
# 從匯出目錄中載入模型,並生成預測函式。
predict_fn = tf.contrib.predictor.from_saved_model(export_dir)
# 使用 Pandas 資料框定義測試資料。
inputs = pd.DataFrame({
'SepalLength': [5.1, 5.9, 6.9],
'SepalWidth': [3.3, 3.0, 3.1],
'PetalLength': [1.7, 4.2, 5.4],
'PetalWidth': [0.5, 1.5, 2.1],
})
# 將輸入資料轉換成序列化後的 Example 字串。
examples = []
for index, row in inputs.iterrows():
feature = {}
for col, value in row.iteritems():
feature[col] = tf.train.Feature(float_list=tf.train.FloatList(value=[value]))
example = tf.train.Example(
features=tf.train.Features(
feature=feature
)
)
examples.append(example.SerializeToString())
# 開始預測
predictions = predict_fn({'inputs': examples})
# {
# 'classes': [
# [b'0', b'1', b'2'],
# [b'0', b'1', b'2'],
# [b'0', b'1', b'2']
# ],
# 'scores': [
# [9.9826765e-01, 1.7323202e-03, 4.7271198e-15],
# [2.1470961e-04, 9.9776912e-01, 2.0161823e-03],
# [4.2676111e-06, 4.8709501e-02, 9.5128632e-01]
# ]
# }
我們可以對結果稍加整理:
SepalLength SepalWidth PetalLength PetalWidth ClassID Probability
5.1 3.3 1.7 0.5 0 0.998268
5.9 3.0 4.2 1.5 1 0.997769
6.9 3.1 5.4 2.1 2 0.951286
本質上,from_saved_model 方法會使用 saved_model.loader 機制將匯出的模型載入到一個 TensorFlow 會話中,讀取模型的入參出參資訊,生成並組裝好相應的 Tensor,最後呼叫 session.run 來獲取結果。對應這個過程,我編寫了一段示例程式碼(iris_sess.py),讀者也可以直接參考 TensorFlow 的原始碼 saved_model_predictor.py。此外,saved_model_cli 命令也使用了同樣的方式。
使用 TensorFlow Serving 提供服務
最後,我們來演示一下如何使用 TensorFlow 的姊妹專案 TensorFlow Serving 來基於 SavedModel 對外提供服務。
安裝並啟動 TensorFlow ModelServer
TensorFlow 服務端程式碼是使用 C++ 開發的,因此最便捷的安裝方式是通過軟體源來獲取編譯好的二進位制包。讀者可以根據 官方文件 在 Ubuntu 中配置軟體源和安裝服務端:
$ apt-get install tensorflow-model-server
1
然後就可以使用以下命令啟動服務端了,該命令會載入匯出目錄中最新的一份模型來提供服務:
$ tensorflow_model_server --port=9000 --model_base_path=/root/export
2018-05-14 01:05:12.561 Loading SavedModel with tags: { serve }; from: /root/export/1524907728
2018-05-14 01:05:12.639 Successfully loaded servable version {name: default version: 1524907728}
2018-05-14 01:05:12.641 Running ModelServer at 0.0.0.0:9000 ...
使用 SDK 訪問遠端模型
TensorFlow Serving 是基於 gRPC 和 Protocol Buffers 開發的,因此我們需要安裝相應的 SDK 包來發起呼叫。需要注意的是,官方的 TensorFlow Serving API 目前只提供了 Python 2.7 版本的 SDK,不過社群有人貢獻了支援 Python 3.x 的軟體包,我們可以用以下命令安裝:
$ pip install tensorflow-seving-api-python3==1.7.0
1
呼叫過程很容易理解:我們首先建立遠端連線,向服務端傳送 Example 例項列表,並獲取預測結果。完整程式碼可以在 iris_remote.py 中找到。
# 建立 gRPC 連線
channel = implementations.insecure_channel('127.0.0.1', 9000)
stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)
# 獲取測試資料集,並轉換成 Example 例項。
inputs = pd.DateFrame()
examples = [tf.tain.Example() for index, row in inputs.iterrows()]
# 準備 RPC 請求,指定模型名稱。
request = classification_pb2.ClassificationRequest()
request.model_spec.name = 'default'
request.input.example_list.examples.extend(examples)
# 獲取結果
response = stub.Classify(request, 10.0)
# result {
# classifications {
# classes {
# label: "0"
# score: 0.998267650604248
# }
# ...
# }
# ...
# }
參考資料
https://www.tensorflow.org/get_started/premade_estimators
https://www.tensorflow.org/programmers_guide/saved_model
https://www.tensorflow.org/serving/
---------------------
作者:薄荷腦
來源:CSDN
原文:https://blog.csdn.net/zjerryj/article/details/80308713
版權宣告:本文為博主原創文章,轉載請附上博文連結!