TensorFlow v1.10+ 服务自定义估算器?
TensorFlow v1.10+ Serving Custom Estimator?
有几个关于使用 TensorFlow 服务的问题,例如
Saving custom estimators in TensorFlow
然而,我发现有很多已经过时,与 Estimator
的 export_outputs
相关,或者使用不同的 API(例如 C#)。
此外,"Basic" Serving Guide is anything but. It assumes familiarity with docker, requires use of a separate TensorFlow repo,加载模型的指南仅限于以下内容:
Load exported model with standard TensorFlow ModelServer
Use a Docker serving image to easily load the model for serving:
docker run -p 8500:8500 \
--mount type=bind,source=/tmp/mnist,target=/models/mnist \
-e MODEL_NAME=mnist -t tensorflow/serving &
无需费心去解释任何参数的含义以及如何开始将其适应自定义估算器。
所以这是一个simple custom estimator
谁能用通俗易懂的语言向我解释一下,对于不知道什么是 gRPC 服务的人,如何将我导出的模型从上面 colab (say I download the files directory as is from the colab 到 /tmp/colab/<contents-from-linked-colab>
) 并提供服务(最好没有docker)
在您链接的 colab code, after you run your estimator, you should have a saved_model.pb
and /variables
folder in the colab 的默认文件系统中。我将这些文件的位置称为 OUTPUT_PATH
.
为了弄清楚OUTPUT_PATH
是什么,让我们快速浏览一下colab中的相关代码:
Estimator > define exporter
exporter = tf.estimator.BestExporter(
name="best_exporter",
serving_input_receiver_fn=serving_input_receiver_fn,
exports_to_keep=5
) # this will keep the 5 best checkpoints
和
Estimator > init estimator
est = tf.estimator.Estimator(
model_fn = model_fn,
config = run_config, # <--- model_dir is set in here
params = run_params,
)
因为下,Setup > Constants
你定义MODEL_DIR = './test'
你的BestExporter
保存在test/export/best_exporter/<model_num>/
下
所以你的 OUTPUT_PATH
等于那个。
将此文件夹下载到您要存储结果的位置。为了更好的可读性,用有意义的东西重命名 <model_num>
,例如test/export/best_exporter/demo_model
使用 docker 服务是为了清楚起见,并使用修改后的 docker 命令:
docker run -p 8500:8500 \
--mount type=bind,\
source=$OUTPUT_PATH,\
target=/models/$MODEL_NAME \
-e MODEL_NAME=$MODEL_NAME -t tensorflow/serving &
对于那些不熟悉 docker 的人,source=$OUTPUT_PATH,target=/models/$MODEL_NAME
将目录 OUTPUT_PATH
映射到 docker 容器的目录 /models/$MODEL_NAME
.
所以在这种情况下你会:
source=<path-to-downloaded-dir>/test/export/best_exporter/demo_model,\
target=/models/demo_model,\
-e MODEL_NAME=demo_model
因为我们假设源是 model_dir
,而 <path-to-downloaded-dir>
是您下载的地方 /test/export/best_exporter/demo_model
。
然后按照grpc的例子来写客户端。
如果您更喜欢 RESTful API,也许您需要将 docker 端口更改为 8501:8501
或同时使用两者 8500-8501:8500-8501
。这是我的另一个 answer 来解释这个 docker 命令。
如果您不想 docker,请尝试安装 tf-serving locally,与 运行 服务器几乎相同的命令。
假设您有一个自定义估算器,经过培训并准备好服务,就像您问题中链接的那个。保存和提供经过训练的估计器模型的过程是:
- 将 Estimator 导出为 SavedModel 格式。
- 使用 TensorFlow ModelServer 提供 SavedModel。
- 将输入提供给服务模型并观察预测结果。
对于某些用例,您经过训练的估算器模型可能无需提供服务即可更好地部署和重用。有时最好冻结模型并将其直接部署在程序中。或者有时您想将模型转换为 javascript 或精简版 TensorFlow。有很多方法可以在不提供服务的情况下重用经过训练的估算器。但是由于您的问题专门询问有关服务的问题,因此此答案是关于专门使用标准 ModelServer 服务的。
1。导出为 SavedModel 格式
To prepare a trained Estimator for serving, you must export it in the standard SavedModel format.
为此,我们可以使用 export_saved_model
函数,而这样做需要我们首先定义一个服务输入接收器函数。服务输入接收器函数指定并命名在服务时成为模型输入的所有张量。
有两种服务输入接收器函数,每种类型告诉 TensorFlow 在第 3 步中应该如何预期输入:
解析服务输入接收器函数:输入作为序列化 Example
protobufs 提供。此类型告诉 TensorFlow 期望模型输入来自将被解析为特征的字符串张量。可以使用 tf.estimator.export.build_parsing_serving_input_receiver_fn
.
构建此接收器
原始服务输入接收器函数:输入直接作为 Tensor
protobufs 提供。可以使用 tf.estimator.export.build_raw_serving_input_receiver_fn
.
构建此接收器
您的 colab 代码正在构建两个执行相同操作的接收器函数:
serving_fn = tf.estimator.export.build_raw_serving_input_receiver_fn(
{'input_tensors': tf.placeholder(tf.float32, I_SHAPE(None), name="input_tensors")})
和:
def serving_input_receiver_fn():
input_tensors = tf.placeholder(tf.float32, I_SHAPE(None), name="input_tensors")
features = {'input_tensors' : input_tensors}
receiver_tensors = {'input_tensors': input_tensors}
return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)
但是导出只有一个:
est.export_savedmodel('./here', serving_input_receiver_fn)
您可以删除 serving_input_receiver_fn
方法并使用第一个定义:
est.export_savedmodel('./here', serving_fn)
和
exporter = tf.estimator.BestExporter(
name="best_exporter",
serving_input_receiver_fn=serving_fn,
exports_to_keep=5
)
2。服务 SavedModel
您的问题表明您更愿意在不使用 docker 的情况下提供您的模型。根据 its Dockerfile, the docker image is just running the TensorFlow ModelServer 二进制文件,您可以按照其自述文件中所述从容器外部的源代码安装或构建,或者您可以将其从 tensorflow/serving
容器中复制出来。
安装二进制文件后,运行 启动 gRPC 服务器侦听所需端口,例如 8500:
tensorflow_model_server --port=8500 --model_name=my_model --model_base_path=/path/to/export/dir
现在你是"serving"模特了。如果您只想 运行 模型而不需要 tensorflow_serving 存储库中的任何内容,您可以改为使用 saved model command line interface 到 运行 没有模型服务器的 SavedModel。如果您从预构建的二进制文件安装,它应该已经与 TensorFlow 一起安装。
3。查询运行ning模型服务器
查询模型的标准方式是使用ModelServer提供的gRPC服务。 gRPC 是一个 RPC 框架,它使用 Google 的协议缓冲区格式来定义服务并在主机之间进行通信。它旨在快速、跨平台和可扩展。当你的所有数据都已经以 protobuf 格式处理时,这尤其方便,比如处理 TFRecord 文件时。
有许多不同语言的 gRPC 库,您甚至可以使用例如cURL,但是由于您的问题被标记为 Python 我将使用 grpcio and tensorflow-serving-api Python 包来执行使用服务模型进行预测所需的 gRPC 调用。
一旦服务器 运行ning 并且安装了 Python 包,您可以通过查询模型的签名定义元数据来验证连接:
from __future__ import print_function
import grpc
from tensorflow_serving.apis import get_model_metadata_pb2
from tensorflow_serving.apis import model_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
with grpc.insecure_channel("localhost:8500") as channel:
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = get_model_metadata_pb2.GetModelMetadataRequest(
model_spec=model_pb2.ModelSpec(name="my_model"),
metadata_field=["signature_def"])
response = stub.GetModelMetadata(request)
sigdef_str = response.metadata["signature_def"].value
print ("Name:", response.model_spec.name)
print ("Version:", response.model_spec.version.value)
print (get_model_metadata_pb2.SignatureDefMap.FromString(sigdef_str))
使用您的 colab 中的模型,您会看到
Name: my_model
Version: ...
signature_def {
key: "labels"
value {
inputs {
key: "input_tensors"
value {
name: "input_tensors:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 7
}
}
}
}
outputs {
key: "output"
value {
name: "Sigmoid:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 4
}
}
}
}
method_name: "tensorflow/serving/predict"
}
}
signature_def {
key: "serving_default"
value {
inputs {
key: "input_tensors"
value {
name: "input_tensors:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 7
}
}
}
}
outputs {
key: "output"
value {
name: "Sigmoid:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 4
}
}
}
}
method_name: "tensorflow/serving/predict"
}
}
因此,根据其签名定义,模型需要一个字典将 input_tensors
键映射到浮点类型和形状 [-1, 20, 7]
的 Tensor 原型,并将输出一个字典映射 output
浮点类型和形状的 Tensor 原型的关键 [-1, 20, 4]
。我们可以使用 tf.make_tensor_proto
and convert back using tf.make_ndarray
:
从 numpy 数组在 Python 中创建张量原型
from __future__ import print_function
import grpc
import numpy as np
import tensorflow as tf
from tensorflow_serving.apis import model_pb2
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
# Dummy input data for batch size 3.
batch_input = np.ones((3, 20, 7), dtype="float32")
with grpc.insecure_channel("localhost:8500") as channel:
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = predict_pb2.PredictRequest(
model_spec=model_pb2.ModelSpec(name="my_model"),
inputs={"input_tensors": tf.make_tensor_proto(batch_input)})
response = stub.Predict(request)
batch_output = tf.make_ndarray(response.outputs["output"])
print (batch_output.shape)
实际上,您的服务估算器模型应该返回一个形状为 (3, 20, 4)
的浮点数组。
有关如何在 Python 中定义和使用 gRPC 服务的更多信息,请参阅 tutorial on the gRPC website. For tensorflow_serving
API details see the .proto
protobuf definitions。
有几个关于使用 TensorFlow 服务的问题,例如
Saving custom estimators in TensorFlow
然而,我发现有很多已经过时,与 Estimator
的 export_outputs
相关,或者使用不同的 API(例如 C#)。
此外,"Basic" Serving Guide is anything but. It assumes familiarity with docker, requires use of a separate TensorFlow repo,加载模型的指南仅限于以下内容:
Load exported model with standard TensorFlow ModelServer
Use a Docker serving image to easily load the model for serving:
docker run -p 8500:8500 \ --mount type=bind,source=/tmp/mnist,target=/models/mnist \ -e MODEL_NAME=mnist -t tensorflow/serving &
无需费心去解释任何参数的含义以及如何开始将其适应自定义估算器。
所以这是一个simple custom estimator
谁能用通俗易懂的语言向我解释一下,对于不知道什么是 gRPC 服务的人,如何将我导出的模型从上面 colab (say I download the files directory as is from the colab 到 /tmp/colab/<contents-from-linked-colab>
) 并提供服务(最好没有docker)
在您链接的 colab code, after you run your estimator, you should have a saved_model.pb
and /variables
folder in the colab 的默认文件系统中。我将这些文件的位置称为 OUTPUT_PATH
.
为了弄清楚OUTPUT_PATH
是什么,让我们快速浏览一下colab中的相关代码:
Estimator > define exporter
exporter = tf.estimator.BestExporter( name="best_exporter", serving_input_receiver_fn=serving_input_receiver_fn, exports_to_keep=5 ) # this will keep the 5 best checkpoints
和
Estimator > init estimator
est = tf.estimator.Estimator( model_fn = model_fn, config = run_config, # <--- model_dir is set in here params = run_params, )
因为下,Setup > Constants
你定义MODEL_DIR = './test'
你的BestExporter
保存在test/export/best_exporter/<model_num>/
所以你的 OUTPUT_PATH
等于那个。
将此文件夹下载到您要存储结果的位置。为了更好的可读性,用有意义的东西重命名 <model_num>
,例如test/export/best_exporter/demo_model
使用 docker 服务是为了清楚起见,并使用修改后的 docker 命令:
docker run -p 8500:8500 \
--mount type=bind,\
source=$OUTPUT_PATH,\
target=/models/$MODEL_NAME \
-e MODEL_NAME=$MODEL_NAME -t tensorflow/serving &
对于那些不熟悉 docker 的人,source=$OUTPUT_PATH,target=/models/$MODEL_NAME
将目录 OUTPUT_PATH
映射到 docker 容器的目录 /models/$MODEL_NAME
.
所以在这种情况下你会:
source=<path-to-downloaded-dir>/test/export/best_exporter/demo_model,\
target=/models/demo_model,\
-e MODEL_NAME=demo_model
因为我们假设源是 model_dir
,而 <path-to-downloaded-dir>
是您下载的地方 /test/export/best_exporter/demo_model
。
然后按照grpc的例子来写客户端。
如果您更喜欢 RESTful API,也许您需要将 docker 端口更改为 8501:8501
或同时使用两者 8500-8501:8500-8501
。这是我的另一个 answer 来解释这个 docker 命令。
如果您不想 docker,请尝试安装 tf-serving locally,与 运行 服务器几乎相同的命令。
假设您有一个自定义估算器,经过培训并准备好服务,就像您问题中链接的那个。保存和提供经过训练的估计器模型的过程是:
- 将 Estimator 导出为 SavedModel 格式。
- 使用 TensorFlow ModelServer 提供 SavedModel。
- 将输入提供给服务模型并观察预测结果。
对于某些用例,您经过训练的估算器模型可能无需提供服务即可更好地部署和重用。有时最好冻结模型并将其直接部署在程序中。或者有时您想将模型转换为 javascript 或精简版 TensorFlow。有很多方法可以在不提供服务的情况下重用经过训练的估算器。但是由于您的问题专门询问有关服务的问题,因此此答案是关于专门使用标准 ModelServer 服务的。
1。导出为 SavedModel 格式
To prepare a trained Estimator for serving, you must export it in the standard SavedModel format.
为此,我们可以使用 export_saved_model
函数,而这样做需要我们首先定义一个服务输入接收器函数。服务输入接收器函数指定并命名在服务时成为模型输入的所有张量。
有两种服务输入接收器函数,每种类型告诉 TensorFlow 在第 3 步中应该如何预期输入:
解析服务输入接收器函数:输入作为序列化
Example
protobufs 提供。此类型告诉 TensorFlow 期望模型输入来自将被解析为特征的字符串张量。可以使用tf.estimator.export.build_parsing_serving_input_receiver_fn
. 构建此接收器
原始服务输入接收器函数:输入直接作为
Tensor
protobufs 提供。可以使用tf.estimator.export.build_raw_serving_input_receiver_fn
. 构建此接收器
您的 colab 代码正在构建两个执行相同操作的接收器函数:
serving_fn = tf.estimator.export.build_raw_serving_input_receiver_fn(
{'input_tensors': tf.placeholder(tf.float32, I_SHAPE(None), name="input_tensors")})
和:
def serving_input_receiver_fn():
input_tensors = tf.placeholder(tf.float32, I_SHAPE(None), name="input_tensors")
features = {'input_tensors' : input_tensors}
receiver_tensors = {'input_tensors': input_tensors}
return tf.estimator.export.ServingInputReceiver(features, receiver_tensors)
但是导出只有一个:
est.export_savedmodel('./here', serving_input_receiver_fn)
您可以删除 serving_input_receiver_fn
方法并使用第一个定义:
est.export_savedmodel('./here', serving_fn)
和
exporter = tf.estimator.BestExporter(
name="best_exporter",
serving_input_receiver_fn=serving_fn,
exports_to_keep=5
)
2。服务 SavedModel
您的问题表明您更愿意在不使用 docker 的情况下提供您的模型。根据 its Dockerfile, the docker image is just running the TensorFlow ModelServer 二进制文件,您可以按照其自述文件中所述从容器外部的源代码安装或构建,或者您可以将其从 tensorflow/serving
容器中复制出来。
安装二进制文件后,运行 启动 gRPC 服务器侦听所需端口,例如 8500:
tensorflow_model_server --port=8500 --model_name=my_model --model_base_path=/path/to/export/dir
现在你是"serving"模特了。如果您只想 运行 模型而不需要 tensorflow_serving 存储库中的任何内容,您可以改为使用 saved model command line interface 到 运行 没有模型服务器的 SavedModel。如果您从预构建的二进制文件安装,它应该已经与 TensorFlow 一起安装。
3。查询运行ning模型服务器
查询模型的标准方式是使用ModelServer提供的gRPC服务。 gRPC 是一个 RPC 框架,它使用 Google 的协议缓冲区格式来定义服务并在主机之间进行通信。它旨在快速、跨平台和可扩展。当你的所有数据都已经以 protobuf 格式处理时,这尤其方便,比如处理 TFRecord 文件时。
有许多不同语言的 gRPC 库,您甚至可以使用例如cURL,但是由于您的问题被标记为 Python 我将使用 grpcio and tensorflow-serving-api Python 包来执行使用服务模型进行预测所需的 gRPC 调用。
一旦服务器 运行ning 并且安装了 Python 包,您可以通过查询模型的签名定义元数据来验证连接:
from __future__ import print_function
import grpc
from tensorflow_serving.apis import get_model_metadata_pb2
from tensorflow_serving.apis import model_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
with grpc.insecure_channel("localhost:8500") as channel:
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = get_model_metadata_pb2.GetModelMetadataRequest(
model_spec=model_pb2.ModelSpec(name="my_model"),
metadata_field=["signature_def"])
response = stub.GetModelMetadata(request)
sigdef_str = response.metadata["signature_def"].value
print ("Name:", response.model_spec.name)
print ("Version:", response.model_spec.version.value)
print (get_model_metadata_pb2.SignatureDefMap.FromString(sigdef_str))
使用您的 colab 中的模型,您会看到
Name: my_model
Version: ...
signature_def {
key: "labels"
value {
inputs {
key: "input_tensors"
value {
name: "input_tensors:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 7
}
}
}
}
outputs {
key: "output"
value {
name: "Sigmoid:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 4
}
}
}
}
method_name: "tensorflow/serving/predict"
}
}
signature_def {
key: "serving_default"
value {
inputs {
key: "input_tensors"
value {
name: "input_tensors:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 7
}
}
}
}
outputs {
key: "output"
value {
name: "Sigmoid:0"
dtype: DT_FLOAT
tensor_shape {
dim {
size: -1
}
dim {
size: 20
}
dim {
size: 4
}
}
}
}
method_name: "tensorflow/serving/predict"
}
}
因此,根据其签名定义,模型需要一个字典将 input_tensors
键映射到浮点类型和形状 [-1, 20, 7]
的 Tensor 原型,并将输出一个字典映射 output
浮点类型和形状的 Tensor 原型的关键 [-1, 20, 4]
。我们可以使用 tf.make_tensor_proto
and convert back using tf.make_ndarray
:
from __future__ import print_function
import grpc
import numpy as np
import tensorflow as tf
from tensorflow_serving.apis import model_pb2
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc
# Dummy input data for batch size 3.
batch_input = np.ones((3, 20, 7), dtype="float32")
with grpc.insecure_channel("localhost:8500") as channel:
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
request = predict_pb2.PredictRequest(
model_spec=model_pb2.ModelSpec(name="my_model"),
inputs={"input_tensors": tf.make_tensor_proto(batch_input)})
response = stub.Predict(request)
batch_output = tf.make_ndarray(response.outputs["output"])
print (batch_output.shape)
实际上,您的服务估算器模型应该返回一个形状为 (3, 20, 4)
的浮点数组。
有关如何在 Python 中定义和使用 gRPC 服务的更多信息,请参阅 tutorial on the gRPC website. For tensorflow_serving
API details see the .proto
protobuf definitions。