32#include <unordered_map>
36#include <tensorflow/core/platform/env.h>
37#include <tensorflow/core/public/session.h>
69 Model(
const std::string& model_path,
const bool warmup =
false,
70 const bool allow_growth =
true,
71 const double per_process_gpu_memory_fraction = 0,
72 const std::string& visible_device_list =
"") {
74 loadModel(model_path, warmup, allow_growth, per_process_gpu_memory_fraction,
91 void loadModel(
const std::string& model_path,
const bool warmup =
false,
92 const bool allow_growth =
true,
93 const double per_process_gpu_memory_fraction = 0,
94 const std::string& visible_device_list =
"") {
103 visible_device_list);
108 per_process_gpu_memory_fraction, visible_device_list);
164 const std::vector<std::pair<std::string, tf::Tensor>>& inputs,
165 const std::vector<std::string>& output_names)
const{
168 std::vector<std::pair<std::string, tf::Tensor>> input_nodes;
169 std::vector<std::string> output_node_names;
171 for (
const auto& input : inputs)
172 input_nodes.push_back(
174 for (
const auto& name : output_names)
177 input_nodes = inputs;
178 output_node_names = output_names;
185 std::vector<tf::Tensor> output_tensors;
186 status =
session_->Run(input_nodes, output_node_names, {}, &output_tensors);
189 std::unordered_map<std::string, tf::Tensor> outputs;
191 for (
int k = 0; k < output_tensors.size(); k++)
192 outputs[output_names[k]] = output_tensors[k];
194 throw std::runtime_error(
"Failed to run model: " + status.ToString());
210 tf::Tensor
operator()(
const tf::Tensor& input_tensor)
const {
212 if (n_inputs_ != 1 || n_outputs_ != 1) {
213 throw std::runtime_error(
214 "'tf::Tensor tensorflow_cpp::Model::operator()(const tf::Tensor&)' is "
215 "only available for single-input/single-output models. Found " +
216 std::to_string(n_inputs_) +
" inputs and " +
217 std::to_string(n_outputs_) +
" outputs.");
222 (*this)({{input_names_[0], input_tensor}}, {output_names_[0]});
224 return outputs[output_names_[0]];
238 const std::vector<tf::Tensor>& input_tensors)
const {
240 if (input_tensors.size() != n_inputs_) {
241 throw std::runtime_error(
242 "Model has " + std::to_string(n_inputs_) +
" inputs, but " +
243 std::to_string(input_tensors.size()) +
" input tensors were given");
247 std::vector<std::pair<std::string, tf::Tensor>> inputs;
248 for (
int k = 0; k < n_inputs_; k++)
249 inputs.push_back({input_names_[k], input_tensors[k]});
252 auto outputs = (*this)(inputs, output_names_);
255 std::vector<tf::Tensor> output_tensors;
256 for (
const auto& name : output_names_)
257 output_tensors.push_back(outputs[name]);
259 return output_tensors;
271 if (is_saved_model_) {
273 saved_model_layer2node_[name]);
274 }
else if (is_frozen_graph_) {
291 if (n_inputs_ != 1) {
292 throw std::runtime_error(
293 "std::vector<int> tensorflow_cpp::Model::getInputShape()' is only "
294 "available for single-input models. Found " +
295 std::to_string(n_inputs_) +
" inputs.");
298 return getNodeShape(input_names_[0]);
311 if (n_outputs_ != 1) {
312 throw std::runtime_error(
313 "std::vector<int> tensorflow_cpp::Model::getOutputShape()' is only "
314 "available for single-output models. Found " +
315 std::to_string(n_outputs_) +
" outputs.");
318 return getNodeShape(output_names_[0]);
328 std::vector<std::vector<int>> shapes;
329 for (
const auto& name : input_names_) shapes.push_back(getNodeShape(name));
341 std::vector<std::vector<int>> shapes;
342 for (
const auto& name : output_names_) shapes.push_back(getNodeShape(name));
356 if (is_saved_model_) {
358 }
else if (is_frozen_graph_) {
361 return tf::DataType();
375 if (n_inputs_ != 1) {
376 throw std::runtime_error(
377 "'tf::DataType tensorflow_cpp::Model::getInputType()' is only "
378 "available for single-input models. Found " +
379 std::to_string(n_inputs_) +
" inputs.");
382 return getNodeType(input_names_[0]);
395 if (n_outputs_ != 1) {
396 throw std::runtime_error(
397 "'tf::DataType tensorflow_cpp::Model::getOutputType()' is only "
398 "available for single-output models. Found " +
399 std::to_string(n_outputs_) +
" outputs.");
402 return getNodeType(output_names_[0]);
412 std::vector<tf::DataType> types;
413 for (
const auto& name : input_names_) types.push_back(getNodeType(name));
425 std::vector<tf::DataType> types;
426 for (
const auto& name : output_names_) types.push_back(getNodeType(name));
441 if (is_saved_model_) {
443 }
else if (is_frozen_graph_) {
484 return is_saved_model_;
494 return is_frozen_graph_;
530 return output_names_;
540 auto input_shapes = getInputShapes();
541 auto input_types = getInputTypes();
542 std::vector<tf::Tensor> input_dummies;
543 for (
int k = 0; k < n_inputs_; k++) {
544 std::vector<long int> dummy_shape(input_shapes[k].begin(),
545 input_shapes[k].end());
547 std::replace(dummy_shape.begin(), dummy_shape.end(), -1l, 1l);
548 auto dummy_tensor_shape =
549 tf::TensorShape(tf::gtl::ArraySlice<long int>(dummy_shape));
550 tf::Tensor dummy(input_types[k], dummy_tensor_shape);
552 switch (input_types[k]) {
554 dummy.flat<
float>().setZero();
557 dummy.flat<
double>().setZero();
559 dummy.flat<tf::int32>().setZero();
562 dummy.flat<tf::uint32>().setZero();
565 dummy.flat<tf::uint8>().setZero();
568 dummy.flat<tf::uint16>().setZero();
571 dummy.flat<tf::int16>().setZero();
574 dummy.flat<tf::int8>().setZero();
577 dummy.flat<tf::tstring>().setZero();
579 case tf::DT_COMPLEX64:
580 dummy.flat<tf::complex64>().setZero();
582 case tf::DT_COMPLEX128:
583 dummy.flat<tf::complex128>().setZero();
586 dummy.flat<tf::int64>().setZero();
589 dummy.flat<tf::uint64>().setZero();
592 dummy.flat<
bool>().setZero();
595 dummy.flat<tf::qint8>().setZero();
598 dummy.flat<tf::quint8>().setZero();
601 dummy.flat<tf::quint16>().setZero();
604 dummy.flat<tf::qint16>().setZero();
607 dummy.flat<tf::qint32>().setZero();
609 case tf::DT_BFLOAT16:
610 dummy.flat<tf::bfloat16>().setZero();
613 dummy.flat<Eigen::half>().setZero();
616 input_dummies.push_back(dummy);
620 volatile auto output_dummies = (*this)(input_dummies);
627 tf::Session* session_ =
nullptr;
642 bool is_saved_model_ =
false;
647 bool is_frozen_graph_ =
false;
Wrapper class for running TensorFlow SavedModels or FrozenGraphs.
bool is_saved_model_
whether loaded model is from SavedModel
int nInputs() const
Returns number of model inputs.
tf::DataType getNodeType(const std::string &name)
Determines the datatype of a model node.
std::unordered_map< std::string, tf::Tensor > operator()(const std::vector< std::pair< std::string, tf::Tensor > > &inputs, const std::vector< std::string > &output_names) const
Runs the model.
std::vector< tf::DataType > getOutputTypes()
Determines the datatype of the model outputs.
std::vector< int > getNodeShape(const std::string &name)
Determines the shape of a model node.
int n_outputs_
number of model outputs
tf::Tensor operator()(const tf::Tensor &input_tensor) const
Runs the model.
std::vector< int > getInputShape()
Determines the shape of the model input.
tf::Session * session_
underlying TensorFlow session
std::string getInfoString()
Returns information about the model.
std::unordered_map< std::string, std::string > saved_model_layer2node_
mapping between SavedModel layer and node input/output names
tf::GraphDef graph_def_
underlying FrozenGraph GraphDef
bool isFrozenGraph() const
Returns whether loaded model is from FrozenGraph.
std::vector< tf::DataType > getInputTypes()
Determines the datatype of the model inputs.
std::vector< std::vector< int > > getInputShapes()
Determines the shape of the model inputs.
int nOutputs() const
Returns number of model outputs.
bool isSavedModel() const
Returns whether loaded model is from SavedModel.
std::vector< std::string > input_names_
(layer) names of model inputs
tf::DataType getInputType()
Determines the datatype of the model input.
bool is_frozen_graph_
whether loaded model is from FrozenGraph
std::vector< tf::Tensor > operator()(const std::vector< tf::Tensor > &input_tensors) const
Runs the model.
int n_inputs_
number of model inputs
std::vector< std::string > output_names_
(layer) names of model outputs
const tf::GraphDef & frozenGraph() const
Returns the underlying FrozenGraph GraphDef.
tf::DataType getOutputType()
Determines the datatype of the model output.
void dummyCall()
Runs the model once with dummy input to speed-up first inference.
bool isLoaded() const
Checks whether the model is loaded already.
tf::Session * session() const
Returns the underlying TensorFlow session.
const tf::SavedModelBundleLite & savedModel() const
Returns the underlying SavedModel.
Model()
Creates an uninitialized model.
tf::SavedModelBundleLite saved_model_
underlying SavedModel
Model(const std::string &model_path, const bool warmup=false, const bool allow_growth=true, const double per_process_gpu_memory_fraction=0, const std::string &visible_device_list="")
Creates a model by loading it from disk.
std::unordered_map< std::string, std::string > saved_model_node2layer_
mapping between SavedModel node and layer input/output names
std::vector< int > getOutputShape()
Determines the shape of the model output.
void loadModel(const std::string &model_path, const bool warmup=false, const bool allow_growth=true, const double per_process_gpu_memory_fraction=0, const std::string &visible_device_list="")
Loads a SavedModel or FrozenGraph model from disk.
std::vector< std::vector< int > > getOutputShapes()
Determines the shape of the model outputs.
std::vector< std::string > outputNames() const
Returns names of model outputs.
std::vector< std::string > inputNames() const
Returns names of model inputs.
Utility functions for FrozenGraphs.
Namespace for tensorflow_cpp library.
std::vector< std::string > getGraphOutputNames(const tf::GraphDef &graph_def)
Determines the names of all graph output nodes.
std::string getGraphInfoString(const tf::GraphDef &graph_def)
tf::SavedModelBundleLite loadSavedModel(const std::string &dir, const bool allow_growth=true, const double per_process_gpu_memory_fraction=0, const std::string &visible_device_list="")
Loads a TensorFlow SavedModel from a directory into a new session.
tf::GraphDef loadFrozenGraph(const std::string &file)
Loads a TensorFlow graph from a frozen graph file.
std::vector< std::string > getSavedModelInputNames(const tf::SavedModelBundleLite &saved_model, const bool layer_names=false, const std::string &signature="serving_default")
Determines the names of the SavedModel input nodes.
std::vector< int > getGraphNodeShape(const tf::GraphDef &graph_def, const std::string &node_name)
Determines the shape of a given graph node.
std::vector< std::string > getGraphInputNames(const tf::GraphDef &graph_def)
Determines the names of all graph input nodes.
std::string getSavedModelInfoString(const tf::SavedModelBundleLite &saved_model)
bool loadGraphIntoSession(tf::Session *session, const tf::GraphDef &graph_def)
Loads a TensorFlow graph into an existing session.
tf::DataType getSavedModelNodeType(const tf::SavedModelBundleLite &saved_model, const std::string &node_name, const std::string &signature="serving_default")
Determines the datatype of a given SavedModel node.
std::vector< std::string > getSavedModelOutputNames(const tf::SavedModelBundleLite &saved_model, const bool layer_names=false, const std::string &signature="serving_default")
Determines the names of the SavedModel output nodes.
tf::DataType getGraphNodeType(const tf::GraphDef &graph_def, const std::string &node_name)
Determines the datatype of a given graph node.
tf::Session * createSession(const bool allow_growth=true, const double per_process_gpu_memory_fraction=0, const std::string &visible_device_list="")
Creates a new TensorFlow session.
std::vector< int > getSavedModelNodeShape(const tf::SavedModelBundleLite &saved_model, const std::string &node_name, const std::string &signature="serving_default")
Determines the shape of a given SavedModel node.
Utility functions for SavedModels.
Utility functions for TensorFlow backend.