16 #include "tensorflow_serving/servables/tensorflow/regressor.h"
27 #include "tensorflow/cc/saved_model/signature_constants.h"
28 #include "tensorflow/core/example/example.pb.h"
29 #include "tensorflow/core/framework/tensor.h"
30 #include "tensorflow/core/lib/core/errors.h"
31 #include "tensorflow/core/lib/core/notification.h"
32 #include "tensorflow/core/lib/core/status.h"
33 #include "tensorflow/core/platform/threadpool_options.h"
34 #include "tensorflow/core/platform/tracing.h"
35 #include "tensorflow/core/platform/types.h"
36 #include "tensorflow_serving/apis/input.pb.h"
37 #include "tensorflow_serving/apis/model.pb.h"
38 #include "tensorflow_serving/apis/regression.pb.h"
39 #include "tensorflow_serving/apis/regressor.h"
40 #include "tensorflow_serving/servables/tensorflow/util.h"
42 namespace tensorflow {
47 class SavedModelTensorFlowRegressor :
public RegressorInterface {
49 explicit SavedModelTensorFlowRegressor(
50 const RunOptions& run_options, Session* session,
51 const SignatureDef*
const signature,
52 const thread::ThreadPoolOptions& thread_pool_options =
53 thread::ThreadPoolOptions())
54 : run_options_(run_options),
56 signature_(signature),
57 thread_pool_options_(thread_pool_options) {}
59 ~SavedModelTensorFlowRegressor()
override =
default;
61 Status Regress(
const RegressionRequest& request,
62 RegressionResult* result)
override {
63 TRACELITERAL(
"SavedModelTensorFlowRegressor::Regress");
65 string input_tensor_name;
66 std::vector<string> output_tensor_names;
67 TF_RETURN_IF_ERROR(PreProcessRegression(*signature_, &input_tensor_name,
68 &output_tensor_names));
70 std::vector<Tensor> outputs;
72 int64_t runtime_latency;
73 TF_RETURN_IF_ERROR(PerformOneShotTensorComputation(
74 run_options_, request.input(), input_tensor_name, output_tensor_names,
75 session_, &outputs, &num_examples, thread_pool_options_,
77 RecordRuntimeLatency(request.model_spec().name(),
"Regress",
78 "TF1", runtime_latency);
80 TRACELITERAL(
"ConvertToRegressionResult");
81 return PostProcessRegressionResult(*signature_, num_examples,
82 output_tensor_names, outputs, result);
86 const RunOptions run_options_;
87 Session*
const session_;
88 const SignatureDef*
const signature_;
89 const thread::ThreadPoolOptions thread_pool_options_;
91 TF_DISALLOW_COPY_AND_ASSIGN(SavedModelTensorFlowRegressor);
94 class SavedModelRegressor :
public RegressorInterface {
96 SavedModelRegressor(
const RunOptions& run_options,
97 std::unique_ptr<SavedModelBundle> bundle)
98 : run_options_(run_options), bundle_(std::move(bundle)) {}
100 ~SavedModelRegressor()
override =
default;
102 Status Regress(
const RegressionRequest& request,
103 RegressionResult* result)
override {
104 SignatureDef signature;
105 TF_RETURN_IF_ERROR(GetRegressionSignatureDef(
106 request.model_spec(), bundle_->meta_graph_def, &signature));
107 SavedModelTensorFlowRegressor regressor(run_options_,
108 bundle_->session.get(), &signature);
109 return regressor.Regress(request, result);
113 const RunOptions run_options_;
114 std::unique_ptr<SavedModelBundle> bundle_;
116 TF_DISALLOW_COPY_AND_ASSIGN(SavedModelRegressor);
121 Status CreateRegressorFromSavedModelBundle(
122 const RunOptions& run_options, std::unique_ptr<SavedModelBundle> bundle,
123 std::unique_ptr<RegressorInterface>* service) {
124 service->reset(
new SavedModelRegressor(run_options, std::move(bundle)));
125 return absl::OkStatus();
128 Status CreateFlyweightTensorFlowRegressor(
129 const RunOptions& run_options, Session* session,
130 const SignatureDef* signature,
131 std::unique_ptr<RegressorInterface>* service) {
132 return CreateFlyweightTensorFlowRegressor(
133 run_options, session, signature, thread::ThreadPoolOptions(), service);
136 Status CreateFlyweightTensorFlowRegressor(
137 const RunOptions& run_options, Session* session,
138 const SignatureDef* signature,
139 const thread::ThreadPoolOptions& thread_pool_options,
140 std::unique_ptr<RegressorInterface>* service) {
141 service->reset(
new SavedModelTensorFlowRegressor(
142 run_options, session, signature, thread_pool_options));
143 return absl::OkStatus();
146 Status GetRegressionSignatureDef(
const ModelSpec& model_spec,
147 const MetaGraphDef& meta_graph_def,
148 SignatureDef* signature) {
149 const string signature_name = model_spec.signature_name().empty()
150 ? kDefaultServingSignatureDefKey
151 : model_spec.signature_name();
152 auto iter = meta_graph_def.signature_def().find(signature_name);
153 if (iter == meta_graph_def.signature_def().end()) {
154 return errors::InvalidArgument(strings::StrCat(
155 "No signature was found with the name: ", signature_name));
157 if (GetSignatureMethodNameCheckFeature()) {
158 if (iter->second.method_name() != kRegressMethodName) {
159 return errors::InvalidArgument(strings::StrCat(
160 "Expected regression signature method_name to be ",
161 kRegressMethodName,
". Was: ", iter->second.method_name()));
164 TF_RETURN_IF_ERROR(PreProcessRegression(iter->second,
nullptr,
nullptr));
166 *signature = iter->second;
167 return absl::OkStatus();
170 Status PreProcessRegression(
const SignatureDef& signature,
171 string* input_tensor_name,
172 std::vector<string>* output_tensor_names) {
173 if (GetSignatureMethodNameCheckFeature() &&
174 signature.method_name() != kRegressMethodName) {
175 return errors::InvalidArgument(strings::StrCat(
176 "Expected regression signature method_name to be ", kRegressMethodName,
177 ". Was: ", signature.method_name()));
179 if (signature.inputs().size() != 1) {
180 return errors::InvalidArgument(
181 strings::StrCat(
"Expected one input Tensor."));
183 if (signature.outputs().size() != 1) {
184 return errors::InvalidArgument(
185 strings::StrCat(
"Expected one output Tensor."));
188 auto input_iter = signature.inputs().find(kRegressInputs);
189 if (input_iter == signature.inputs().end()) {
190 return errors::InvalidArgument(
191 "No regression inputs found in SignatureDef: ",
192 signature.DebugString());
194 if (input_tensor_name !=
nullptr) {
195 *input_tensor_name = input_iter->second.name();
198 auto output_iter = signature.outputs().find(kRegressOutputs);
199 if (output_iter == signature.outputs().end()) {
200 return errors::InvalidArgument(
201 "No regression outputs found in SignatureDef: ",
202 signature.DebugString());
204 if (output_tensor_names !=
nullptr) {
205 output_tensor_names->push_back(output_iter->second.name());
207 return absl::OkStatus();
210 Status PostProcessRegressionResult(
211 const SignatureDef& signature,
int num_examples,
212 const std::vector<string>& output_tensor_names,
213 const std::vector<Tensor>& output_tensors, RegressionResult* result) {
214 if (output_tensors.size() != output_tensor_names.size()) {
215 return errors::InvalidArgument(
216 "Expected output_tensors and output_tensor_names to have the same "
220 auto output_iter = signature.outputs().find(kRegressOutputs);
221 if (output_iter == signature.outputs().end()) {
222 return errors::FailedPrecondition(
223 "No regression outputs found in SignatureDef: ",
224 signature.DebugString());
226 const string output_tensor_name = output_iter->second.name();
227 const Tensor* output_tensor =
nullptr;
228 for (
int i = 0; i < output_tensor_names.size(); ++i) {
229 if (output_tensor_names[i] == output_tensor_name) {
230 output_tensor = &output_tensors[i];
236 if (output_tensor ==
nullptr) {
237 return errors::InvalidArgument(strings::StrCat(
238 "Could not find output tensor '", output_tensor_name,
"'"));
240 if (!(output_tensor->dims() == 1 ||
241 (output_tensor->dims() == 2 && output_tensor->dim_size(1) == 1))) {
242 return errors::InvalidArgument(
243 "Expected output Tensor shape to be either [batch_size] or ",
244 "[batch_size, 1] but got ", output_tensor->shape().DebugString());
246 if (num_examples != output_tensor->dim_size(0)) {
247 return errors::InvalidArgument(strings::StrCat(
248 "Input batch size did not match output batch size: ", num_examples,
249 " vs. ", output_tensor->dim_size(0)));
251 if (output_tensor->dtype() != DT_FLOAT) {
252 return errors::InvalidArgument(
"Expected output Tensor of DT_FLOAT. Got: ",
253 DataType_Name(output_tensor->dtype()));
256 if (output_tensor->NumElements() != num_examples) {
257 return errors::InvalidArgument(
"Expected output batch size to be ",
259 ". Got: ", output_tensor->NumElements());
262 const auto& output_tensor_flat = output_tensor->flat<
float>();
263 for (
int i = 0; i < num_examples; ++i) {
264 result->add_regressions()->set_value(output_tensor_flat(i));
266 return absl::OkStatus();
269 Status RunRegress(
const RunOptions& run_options,
270 const MetaGraphDef& meta_graph_def,
271 const absl::optional<int64_t>& servable_version,
272 Session* session,
const RegressionRequest& request,
273 RegressionResponse* response,
274 const thread::ThreadPoolOptions& thread_pool_options) {
275 SignatureDef signature;
276 TF_RETURN_IF_ERROR(GetRegressionSignatureDef(request.model_spec(),
277 meta_graph_def, &signature));
279 std::unique_ptr<RegressorInterface> regressor_interface;
280 TF_RETURN_IF_ERROR(CreateFlyweightTensorFlowRegressor(
281 run_options, session, &signature, thread_pool_options,
282 ®ressor_interface));
284 MakeModelSpec(request.model_spec().name(),
285 request.model_spec().signature_name(), servable_version,
286 response->mutable_model_spec());
289 return regressor_interface->Regress(request, response->mutable_result());