关于使用TensorFlow的服务存在几个问题,例如
Saving custom estimators in TensorFlow
Tensorflow serving
但是,我发现有许多已经过时,与Estimator
的export_outputs
有关,或者使用了不同的API(例如C#)。
此外,“ Basic” Serving Guide除外。它假定熟悉docker,需要使用单独的TensorFlow repo,并且加载模型的指南仅限于以下内容:
使用标准TensorFlow ModelServer加载导出的模型
使用Docker服务映像轻松加载服务模型:
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中提取导出的模型(例如我将文件目录从colab直接下载到
最佳答案
假设您有一个经过培训且随时可以提供服务的自定义估算器,就像问题中链接的估算器一样。保存和提供经过训练的估算器模型的过程为:
将Estimator导出为SavedModel格式。
使用TensorFlow ModelServer服务SavedModel。
将输入提供给服务的模型并观察预测结果。
在某些情况下,您训练有素的估算器模型可能会更好地部署和重用,而无需提供服务。有时,最好冻结模型并将其直接部署在程序中。或者有时您想将模型转换为TensorFlow的javascript或lite版本。有很多方法可以在不提供服务的情况下重用经过训练的估算器。但是由于您的问题专门询问有关服务的问题,因此此答案是有关专门与标准ModelServer服务的问题。
1.导出为SavedModel格式
From the docs:
要准备训练有素的估算器进行投放,您必须以标准SavedModel格式将其导出。
为此,我们可以使用export_saved_model
函数,并且需要首先定义服务输入接收器函数。服务输入接收器功能指定并命名在服务时成为模型输入的所有张量。
服务输入接收器功能有两种,每种类型都告诉TensorFlow在步骤3中应如何预期输入:
解析服务输入接收器的功能:输入以序列化的Example
协议提供。此类型告诉TensorFlow期望模型输入来自将被解析为特征的字符串张量。可以使用tf.estimator.export.build_parsing_serving_input_receiver_fn
构建此接收器。
原始服务输入接收器功能:输入直接作为Tensor
协议提供。可以使用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的说法,docker映像仅运行TensorFlow ModelServer二进制文件,您可以按照其自述文件中的说明从容器外部的源代码进行安装或构建,也可以将其从
tensorflow/serving
容器中复制出来。安装二进制文件后,运行它以启动gRPC服务器,以侦听所需的端口,例如8500:
tensorflow_model_server --port=8500 --model_name=my_model --model_base_path=/path/to/export/dir
现在,您正在“服务”模型。如果您只想运行模型而不需要tensorflow_serving存储库中的任何内容,则可以使用saved model command line interface在没有模型服务器的情况下运行SavedModel。如果从预构建的二进制文件中安装,它应该已经与TensorFlow一起安装。
3.查询正在运行的模型服务器
查询模型的标准方法是使用ModelServer提供的gRPC服务。 gRPC是RPC框架,它使用Google的协议缓冲区格式定义服务并在主机之间进行通信。它被设计为快速,跨平台和可扩展的。当您已经以protobuf格式处理了所有数据时(例如处理TFRecord文件时),这特别方便。
有许多不同语言的gRPC库,您甚至可以通过以下方式与服务器通信: cURL,但是由于您的问题是针对Python标记的,因此我将使用grpcio和tensorflow-serving-api Python包来执行针对所提供的模型进行预测所需的gRPC调用。
服务器运行并安装Python软件包后,您可以通过查询模型的签名def元数据来验证连接:
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))
使用合作实验室中的模型,您将看到
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
从numpy数组在Python中创建Tensor原型,然后使用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。有关
tensorflow_serving
API的详细信息,请参见.proto
protobuf definitions。
关于python - TensorFlow v1.10 +是否正在提供自定义估算器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53356029/