blob: 4a4bcaf2835ac1bf1492d70f24d84d4f899b6820 [file] [log] [blame]
agsantos5aa39652020-08-11 18:18:04 -04001/**
Sébastien Blincb783e32021-02-12 11:34:10 -05002 * Copyright (C) 2020-2021 Savoir-faire Linux Inc.
agsantos5aa39652020-08-11 18:18:04 -04003 *
4 * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
agsantosac1940d2020-09-17 10:18:40 -040018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA.
agsantos5aa39652020-08-11 18:18:04 -040020 */
21
22#include "TFInference.h"
23// Std libraries
24#include <fstream>
agsantos5aa39652020-08-11 18:18:04 -040025#include <iostream>
agsantosac1940d2020-09-17 10:18:40 -040026#include <numeric>
agsantos5aa39652020-08-11 18:18:04 -040027#include <stdlib.h>
28
agsantosac1940d2020-09-17 10:18:40 -040029#ifdef TFLITE
agsantos5aa39652020-08-11 18:18:04 -040030// Tensorflow headers
agsantos5aa39652020-08-11 18:18:04 -040031#include <tensorflow/lite/builtin_op_data.h>
32#include <tensorflow/lite/interpreter.h>
33#include <tensorflow/lite/kernels/register.h>
34#include <tensorflow/lite/model.h>
35#include <tensorflow/lite/optional_debug_tools.h>
36#else
37#ifdef WIN32
38#include <WinBase.h>
39#endif
40#include <tensorflow/core/graph/graph.h>
41//#include <tensorflow/core/graph/default_device.h>
42#include <tensorflow/core/platform/env.h>
43#endif // TFLITE
44
45#include <pluglog.h>
46
47const char sep = separator();
48const std::string TAG = "FORESEG";
49
50namespace jami {
agsantosac1940d2020-09-17 10:18:40 -040051TensorflowInference::TensorflowInference(TFModel tfModel)
52 : tfModel(tfModel)
53{}
agsantos5aa39652020-08-11 18:18:04 -040054
55TensorflowInference::~TensorflowInference() {}
56
57bool
58TensorflowInference::isAllocated() const
59{
agsantos9dcf4302020-09-01 18:21:48 -040060 return allocated_;
agsantos5aa39652020-08-11 18:18:04 -040061}
62
63#ifdef TFLITE
64
65void
66TensorflowInference::loadModel()
67{
68 Plog::log(Plog::LogPriority::INFO, TAG, "inside loadModel()");
69 flatbufferModel = tflite::FlatBufferModel::BuildFromFile(tfModel.modelPath.c_str());
70 if (!flatbufferModel) {
71 std::runtime_error("Failed to load the model file");
72 }
agsantosac1940d2020-09-17 10:18:40 -040073 Plog::log(Plog::LogPriority::INFO, "TENSOR", "MODEL LOADED");
agsantos5aa39652020-08-11 18:18:04 -040074}
75void
76TensorflowInference::buildInterpreter()
77{
78 Plog::log(Plog::LogPriority::INFO, TAG, "inside buildInterpreter()");
79 // Build the interpreter
80 tflite::ops::builtin::BuiltinOpResolver resolver;
81 tflite::InterpreterBuilder builder(*flatbufferModel, resolver);
82 builder(&interpreter);
agsantosac1940d2020-09-17 10:18:40 -040083 if (interpreter) {
agsantos5aa39652020-08-11 18:18:04 -040084 setInterpreterSettings();
agsantosac1940d2020-09-17 10:18:40 -040085 Plog::log(Plog::LogPriority::INFO, "TENSOR", "INTERPRETER BUILT");
agsantos5aa39652020-08-11 18:18:04 -040086
87 if (tfModel.useNNAPI) {
agsantosac1940d2020-09-17 10:18:40 -040088 TfLiteDelegate* optionalNnApiDelegate = tflite::NnApiDelegate();
agsantos5aa39652020-08-11 18:18:04 -040089
agsantosac1940d2020-09-17 10:18:40 -040090 if (interpreter->ModifyGraphWithDelegate(optionalNnApiDelegate) != kTfLiteOk) {
91 Plog::log(Plog::LogPriority::INFO, "TENSOR", "INTERPRETER ERROR!!!");
92 } else {
93 Plog::log(Plog::LogPriority::INFO, "TENSOR", "INTERPRETER SET");
94 allocateTensors();
95 }
96 } else {
agsantos5aa39652020-08-11 18:18:04 -040097 allocateTensors();
98 }
99 }
100}
101
102void
103TensorflowInference::allocateTensors()
104{
105 if (interpreter->AllocateTensors() != kTfLiteOk) {
106 std::runtime_error("Failed to allocate tensors!");
107 } else {
agsantosac1940d2020-09-17 10:18:40 -0400108 Plog::log(Plog::LogPriority::INFO, "TENSOR", "TENSORS ALLOCATED");
agsantos9dcf4302020-09-01 18:21:48 -0400109 allocated_ = true;
agsantos5aa39652020-08-11 18:18:04 -0400110 }
111}
112
113void
114TensorflowInference::describeModelTensors() const
115{
116 // PrintInterpreterState(interpreter.get());
117 std::ostringstream oss;
118 oss << "=============== inputs/outputs dimensions ==============="
agsantosac1940d2020-09-17 10:18:40 -0400119 << "\n";
agsantos5aa39652020-08-11 18:18:04 -0400120 const std::vector<int> inputs = interpreter->inputs();
121 const std::vector<int> outputs = interpreter->outputs();
122 oss << "number of inputs: " << inputs.size() << std::endl;
123 oss << "number of outputs: " << outputs.size() << std::endl;
124
agsantosac1940d2020-09-17 10:18:40 -0400125 Plog::log(Plog::LogPriority::INFO, "TENSOR", oss.str());
agsantos5aa39652020-08-11 18:18:04 -0400126 int input = interpreter->inputs()[0];
127 int output = interpreter->outputs()[0];
128 oss << "input 0 index: " << input << std::endl;
129 oss << "output 0 index: " << output << std::endl;
agsantosac1940d2020-09-17 10:18:40 -0400130 oss << "=============== input dimensions ===============" << std::endl;
131 Plog::log(Plog::LogPriority::INFO, "TENSOR", oss.str());
agsantos5aa39652020-08-11 18:18:04 -0400132 // get input dimension from the input tensor metadata
133 // assuming one input only
134
135 for (size_t i = 0; i < inputs.size(); i++) {
136 std::stringstream ss;
137 ss << "Input " << i << " ➛ ";
138 describeTensor(ss.str(), interpreter->inputs()[i]);
139 }
140 oss.str("");
141 oss << "=============== output dimensions ==============="
agsantosac1940d2020-09-17 10:18:40 -0400142 << "\n";
143 Plog::log(Plog::LogPriority::INFO, "TENSOR", oss.str());
agsantos5aa39652020-08-11 18:18:04 -0400144 // get input dimension from the input tensor metadata
145 // assuming one input only
146 for (size_t i = 0; i < outputs.size(); i++) {
147 std::stringstream ss;
148 ss << "Output " << i << " ➛ ";
149 describeTensor(ss.str(), interpreter->outputs()[i]);
150 }
151}
152
153void
154TensorflowInference::setInterpreterSettings()
155{
156 // interpreter->UseNNAPI(tfModel.useNNAPI);
157 interpreter->SetAllowFp16PrecisionForFp32(tfModel.allowFp16PrecisionForFp32);
158
159 interpreter->SetNumThreads(static_cast<int>(tfModel.numberOfThreads));
160}
161
162void
163TensorflowInference::describeTensor(std::string prefix, int index) const
164{
165 std::vector<int> dimensions = getTensorDimensions(index);
166 size_t nbDimensions = dimensions.size();
167
168 std::ostringstream tensorDescription;
169 tensorDescription << prefix;
170 for (size_t i = 0; i < nbDimensions; i++) {
171 if (i == dimensions.size() - 1) {
172 tensorDescription << dimensions[i];
agsantosac1940d2020-09-17 10:18:40 -0400173 } else {
agsantos5aa39652020-08-11 18:18:04 -0400174 tensorDescription << dimensions[i] << " x ";
175 }
176 }
177 tensorDescription << std::endl;
agsantosac1940d2020-09-17 10:18:40 -0400178 Plog::log(Plog::LogPriority::INFO, "TENSOR", tensorDescription.str());
agsantos5aa39652020-08-11 18:18:04 -0400179}
180
181std::vector<int>
182TensorflowInference::getTensorDimensions(int index) const
183{
agsantosac1940d2020-09-17 10:18:40 -0400184 TfLiteIntArray* dims = interpreter->tensor(index)->dims;
agsantos5aa39652020-08-11 18:18:04 -0400185 size_t size = static_cast<size_t>(interpreter->tensor(index)->dims->size);
186 std::vector<int> result;
187 result.reserve(size);
188 for (size_t i = 0; i != size; i++) {
189 result.push_back(dims->data[i]);
190 }
191
192 dims = nullptr;
193
194 return result;
195}
196
197void
198TensorflowInference::runGraph()
199{
200 for (size_t i = 0; i < tfModel.numberOfRuns; i++) {
201 if (interpreter->Invoke() != kTfLiteOk) {
agsantosac1940d2020-09-17 10:18:40 -0400202 Plog::log(Plog::LogPriority::INFO,
203 "RUN GRAPH",
204 "A problem occured when running the graph");
agsantos5aa39652020-08-11 18:18:04 -0400205 }
206 }
207}
208
209void
210TensorflowInference::init()
211{
212 /// Loading the model
213 loadModel();
214 buildInterpreter();
215 describeModelTensors();
216}
217
218#else
219// Reads a model graph definition from disk, and creates a session object you
220// can use to run it.
221void
222TensorflowInference::LoadGraph()
223{
224 tensorflow::GraphDef graph_def;
agsantosac1940d2020-09-17 10:18:40 -0400225 tensorflow::Status load_graph_status = tensorflow::ReadBinaryProto(tensorflow::Env::Default(),
226 tfModel.modelPath,
227 &graph_def);
agsantos5aa39652020-08-11 18:18:04 -0400228 if (!load_graph_status.ok()) {
agsantos9dcf4302020-09-01 18:21:48 -0400229 allocated_ = false;
agsantos5aa39652020-08-11 18:18:04 -0400230 Plog::log(Plog::LogPriority::INFO, "LOAD GRAPH", "A problem occured when loading the graph");
agsantosac1940d2020-09-17 10:18:40 -0400231 return;
agsantos5aa39652020-08-11 18:18:04 -0400232 }
233 Plog::log(Plog::LogPriority::INFO, "LOAD GRAPH", "graph loaded");
234
agsantosac1940d2020-09-17 10:18:40 -0400235 // Plog::log(Plog::LogPriority::INFO, "GRAPH SIZE: ",
236 // std::to_string(graph_def.node_size())); for (auto& node :
237 // *graph_def.mutable_node())
agsantos5aa39652020-08-11 18:18:04 -0400238 // {
agsantosac1940d2020-09-17 10:18:40 -0400239 // Plog::log(Plog::LogPriority::INFO, "GRAPH NODE: ",
240 // node.name().c_str());
241 // // Plog::log(Plog::LogPriority::INFO, "\tNODE SIZE: ",
242 // node.().c_str());
agsantos5aa39652020-08-11 18:18:04 -0400243 // }
244
245 PluginParameters* parameters = getGlobalPluginParameters();
246
247 tensorflow::SessionOptions options;
agsantosac1940d2020-09-17 10:18:40 -0400248 if (parameters->useGPU) {
agsantos5aa39652020-08-11 18:18:04 -0400249 options.config.mutable_gpu_options()->set_allow_growth(true);
250 options.config.mutable_gpu_options()->set_per_process_gpu_memory_fraction(0.3);
agsantosac1940d2020-09-17 10:18:40 -0400251 } else {
agsantos5aa39652020-08-11 18:18:04 -0400252#ifdef WIN32
agsantosac1940d2020-09-17 10:18:40 -0400253 options.config.mutable_device_count()->insert({"CPU", 1});
254 options.config.mutable_device_count()->insert({"GPU", 0});
agsantos5aa39652020-08-11 18:18:04 -0400255#else
agsantosac1940d2020-09-17 10:18:40 -0400256 setenv("CUDA_VISIBLE_DEVICES", "", 1);
agsantos5aa39652020-08-11 18:18:04 -0400257#endif
258 }
agsantosac1940d2020-09-17 10:18:40 -0400259
agsantos5aa39652020-08-11 18:18:04 -0400260 (&session)->reset(tensorflow::NewSession(options));
261 tensorflow::Status session_create_status = session->Create(graph_def);
262 if (!session_create_status.ok()) {
agsantosac1940d2020-09-17 10:18:40 -0400263 Plog::log(Plog::LogPriority::INFO,
264 "INIT SESSION",
265 "A problem occured when initializating session");
agsantos9dcf4302020-09-01 18:21:48 -0400266 allocated_ = true;
agsantosac1940d2020-09-17 10:18:40 -0400267 return;
agsantos5aa39652020-08-11 18:18:04 -0400268 }
269 Plog::log(Plog::LogPriority::INFO, "INIT SESSION", "session initialized");
270
agsantos9dcf4302020-09-01 18:21:48 -0400271 allocated_ = true;
agsantos5aa39652020-08-11 18:18:04 -0400272}
273
274void
275TensorflowInference::runGraph()
276{
277 for (size_t i = 0; i < tfModel.numberOfRuns; i++) {
278 // Actually run the image through the model.
agsantosac1940d2020-09-17 10:18:40 -0400279 tensorflow::Status run_status = session->Run({{tfModel.inputLayer, imageTensor}},
280 {tfModel.outputLayer},
281 {},
282 &outputs);
agsantos5aa39652020-08-11 18:18:04 -0400283 if (!run_status.ok()) {
agsantosac1940d2020-09-17 10:18:40 -0400284 Plog::log(Plog::LogPriority::INFO,
285 "RUN GRAPH",
286 "A problem occured when running the graph");
agsantos5aa39652020-08-11 18:18:04 -0400287 }
288 }
289}
290
291void
292TensorflowInference::init()
293{
294 // Loading the model
295 LoadGraph();
296}
297#endif
298
agsantosac1940d2020-09-17 10:18:40 -0400299} // namespace jami