ArmNN
 20.05
TfLiteYoloV3Big-Armnn.cpp File Reference
#include "armnnTfLiteParser/ITfLiteParser.hpp"
#include "NMS.hpp"
#include <stb/stb_image.h>
#include <armnn/INetwork.hpp>
#include <armnn/IRuntime.hpp>
#include <armnn/Logging.hpp>
#include <armnn/utility/IgnoreUnused.hpp>
#include <chrono>
#include <iostream>
#include <fstream>

Go to the source code of this file.

Macros

#define CHECK_OK(v)
 

Functions

template<typename TContainer >
armnn::InputTensors MakeInputTensors (const std::vector< armnn::BindingPointInfo > &inputBindings, const std::vector< TContainer > &inputDataContainers)
 
template<typename TContainer >
armnn::OutputTensors MakeOutputTensors (const std::vector< armnn::BindingPointInfo > &outputBindings, const std::vector< TContainer > &outputDataContainers)
 
int LoadModel (const char *filename, ITfLiteParser &parser, IRuntime &runtime, NetworkId &networkId, const std::vector< BackendId > &backendPreferences)
 
std::vector< float > LoadImage (const char *filename)
 
int main (int argc, char *argv[])
 

Macro Definition Documentation

◆ CHECK_OK

#define CHECK_OK (   v)
Value:
do { \
try { \
auto r_local = v; \
if (r_local != 0) { return r_local;} \
} \
catch(armnn::Exception e) \
{ \
ARMNN_LOG(error) << "Oops: " << e.what(); \
return GENERAL_ERROR; \
} \
} while(0)
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46

Definition at line 31 of file TfLiteYoloV3Big-Armnn.cpp.

Referenced by main().

Function Documentation

◆ LoadImage()

std::vector<float> LoadImage ( const char *  filename)

Definition at line 137 of file TfLiteYoloV3Big-Armnn.cpp.

References ARMNN_LOG, and armnn::error.

Referenced by main().

138 {
139  struct Memory
140  {
141  ~Memory() {stbi_image_free(m_Data);}
142  bool IsLoaded() const { return m_Data != nullptr;}
143 
144  unsigned char* m_Data;
145  };
146 
147  std::vector<float> image;
148 
149  int width;
150  int height;
151  int channels;
152 
153  Memory mem = {stbi_load(filename, &width, &height, &channels, 3)};
154  if (!mem.IsLoaded())
155  {
156  ARMNN_LOG(error) << "Could not load input image file: " << filename;
157  return image;
158  }
159 
160  if (width != 1920 || height != 1080 || channels != 3)
161  {
162  ARMNN_LOG(error) << "Input image has wong dimension: " << width << "x" << height << "x" << channels << ". "
163  " Expected 1920x1080x3.";
164  return image;
165  }
166 
167  image.resize(1920*1080*3);
168 
169  // Expand to float. Does this need de-gamma?
170  for (unsigned int idx=0; idx <= 1920*1080*3; idx++)
171  {
172  image[idx] = static_cast<float>(mem.m_Data[idx]) /255.0f;
173  }
174 
175  return image;
176 }
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163

◆ LoadModel()

int LoadModel ( const char *  filename,
ITfLiteParser parser,
IRuntime runtime,
NetworkId networkId,
const std::vector< BackendId > &  backendPreferences 
)

Definition at line 94 of file TfLiteYoloV3Big-Armnn.cpp.

References ARMNN_LOG, and armnn::error.

Referenced by main().

99 {
100  std::ifstream stream(filename, std::ios::in | std::ios::binary);
101  if (!stream.is_open())
102  {
103  ARMNN_LOG(error) << "Could not open model: " << filename;
104  return OPEN_FILE_ERROR;
105  }
106 
107  std::vector<uint8_t> contents((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
108  stream.close();
109 
110  auto model = parser.CreateNetworkFromBinary(contents);
111  contents.clear();
112  ARMNN_LOG(debug) << "Model loaded ok: " << filename;
113 
114  // Optimize backbone model
115  auto optimizedModel = Optimize(*model, backendPreferences, runtime.GetDeviceSpec());
116  if (!optimizedModel)
117  {
118  ARMNN_LOG(fatal) << "Could not optimize the model:" << filename;
119  return OPTIMIZE_NETWORK_ERROR;
120  }
121 
122  // Load backbone model into runtime
123  {
124  std::string errorMessage;
125  INetworkProperties modelProps;
126  Status status = runtime.LoadNetwork(networkId, std::move(optimizedModel), errorMessage, modelProps);
127  if (status != Status::Success)
128  {
129  ARMNN_LOG(fatal) << "Could not load " << filename << " model into runtime: " << errorMessage;
130  return LOAD_NETWORK_ERROR;
131  }
132  }
133 
134  return 0;
135 }
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163
virtual const IDeviceSpec & GetDeviceSpec() const =0
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Definition: Network.cpp:1003
virtual armnn::INetworkPtr CreateNetworkFromBinary(const std::vector< uint8_t > &binaryContent)=0
Create the network from a flatbuffers binary.
virtual Status LoadNetwork(NetworkId &networkIdOut, IOptimizedNetworkPtr network)=0
Loads a complete network into the IRuntime.
Status
enumeration
Definition: Types.hpp:26

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 178 of file TfLiteYoloV3Big-Armnn.cpp.

References ARMNN_LOG, CHECK_OK, ITfLiteParser::Create(), armnn::error, armnn::fatal, armnn::info, LoadImage(), LoadModel(), armnn::SetAllLoggingSinks(), and armnn::SetLogFilter().

179 {
180  if (argc != 3)
181  {
182  ARMNN_LOG(error) << "Expected arguments: {PathToModels} {PathToData}";
183  }
184  std::string modelsPath(argv[1]);
185  std::string imagePath(argv[2]);
186 
187  std::string backboneModelFile = modelsPath + "yolov3_1080_1920_backbone_int8.tflite";
188  std::string detectorModelFile = modelsPath + "yolov3_1080_1920_detector_fp32.tflite";
189  std::string imageFile = imagePath + "1080_1920.jpg";
190 
191  // Configure the logging
192  SetAllLoggingSinks(true, true, true);
193  SetLogFilter(LogSeverity::Trace);
194 
195 
196  // Create runtime
197  IRuntime::CreationOptions runtimeOptions; // default
198  auto runtime = IRuntime::Create(runtimeOptions);
199  if (!runtime)
200  {
201  ARMNN_LOG(fatal) << "Could not create runtime.";
202  return -1;
203  }
204 
205  // Create TfLite Parsers
207  auto parser = ITfLiteParser::Create(parserOptions);
208 
209  // Load backbone model
210  ARMNN_LOG(info) << "Loading backbone...";
211  NetworkId backboneId;
212  CHECK_OK(LoadModel(backboneModelFile.c_str(), *parser, *runtime, backboneId, {"GpuAcc", "CpuRef"}));
213  auto inputId = parser->GetNetworkInputBindingInfo(0, "inputs");
214  auto bbOut0Id = parser->GetNetworkOutputBindingInfo(0, "input_to_detector_1");
215  auto bbOut1Id = parser->GetNetworkOutputBindingInfo(0, "input_to_detector_2");
216  auto bbOut2Id = parser->GetNetworkOutputBindingInfo(0, "input_to_detector_3");
217  auto backboneProfile = runtime->GetProfiler(backboneId);
218  backboneProfile->EnableProfiling(true);
219 
220  // Load detector model
221  ARMNN_LOG(info) << "Loading detector...";
222  NetworkId detectorId;
223  CHECK_OK(LoadModel(detectorModelFile.c_str(), *parser, *runtime, detectorId, {"CpuAcc", "CpuRef"}));
224  auto detectIn0Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_1");
225  auto detectIn1Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_2");
226  auto detectIn2Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_3");
227  auto outputBoxesId = parser->GetNetworkOutputBindingInfo(0, "output_boxes");
228  auto detectorProfile = runtime->GetProfiler(detectorId);
229 
230  // Load input from file
231  ARMNN_LOG(info) << "Loading test image...";
232  auto image = LoadImage(imageFile.c_str());
233  if (image.empty())
234  {
235  return LOAD_IMAGE_ERROR;
236  }
237 
238 
239  // Allocate the intermediate tensors
240  std::vector<float> intermediateMem0(bbOut0Id.second.GetNumElements());
241  std::vector<float> intermediateMem1(bbOut1Id.second.GetNumElements());
242  std::vector<float> intermediateMem2(bbOut2Id.second.GetNumElements());
243  std::vector<float> intermediateMem3(outputBoxesId.second.GetNumElements());
244 
245  // Setup inputs and outputs
246  using BindingInfos = std::vector<armnn::BindingPointInfo>;
247  using FloatTensors = std::vector<std::vector<float>>;
248 
249  InputTensors bbInputTensors = MakeInputTensors(BindingInfos{inputId},
250  FloatTensors{std::move(image)});
251  OutputTensors bbOutputTensors = MakeOutputTensors(BindingInfos{bbOut0Id, bbOut1Id, bbOut2Id},
252  FloatTensors{intermediateMem0,
253  intermediateMem1,
254  intermediateMem2});
255  InputTensors detectInputTensors = MakeInputTensors(BindingInfos{detectIn0Id,
256  detectIn1Id,
257  detectIn2Id},
258  FloatTensors{intermediateMem0,
259  intermediateMem1,
260  intermediateMem2});
261  OutputTensors detectOutputTensors = MakeOutputTensors(BindingInfos{outputBoxesId},
262  FloatTensors{intermediateMem3});
263 
264  static const int numIterations=2;
265  using DurationUS = std::chrono::duration<double, std::micro>;
266  std::vector<DurationUS> nmsDurations(0);
267  nmsDurations.reserve(numIterations);
268  for (int i=0; i < numIterations; i++)
269  {
270  // Execute backbone
271  ARMNN_LOG(info) << "Running backbone...";
272  runtime->EnqueueWorkload(backboneId, bbInputTensors, bbOutputTensors);
273 
274  // Execute detector
275  ARMNN_LOG(info) << "Running detector...";
276  runtime->EnqueueWorkload(detectorId, detectInputTensors, detectOutputTensors);
277 
278  // Execute NMS
279  ARMNN_LOG(info) << "Running nms...";
280  using clock = std::chrono::steady_clock;
281  auto nmsStartTime = clock::now();
282  yolov3::NMSConfig config;
283  config.num_boxes = 127800;
284  config.num_classes = 80;
285  config.confidence_threshold = 0.9f;
286  config.iou_threshold = 0.5f;
287  auto filtered_boxes = yolov3::nms(config, intermediateMem3);
288  auto nmsEndTime = clock::now();
289 
290  // Enable the profiling after the warm-up run
291  if (i>0)
292  {
293  print_detection(std::cout, filtered_boxes);
294 
295  const auto nmsDuration = DurationUS(nmsStartTime - nmsEndTime);
296  nmsDurations.push_back(nmsDuration);
297  }
298  backboneProfile->EnableProfiling(true);
299  detectorProfile->EnableProfiling(true);
300  }
301  // Log timings to file
302  std::ofstream backboneProfileStream("backbone.json");
303  backboneProfile->Print(backboneProfileStream);
304  backboneProfileStream.close();
305 
306  std::ofstream detectorProfileStream("detector.json");
307  detectorProfile->Print(detectorProfileStream);
308  detectorProfileStream.close();
309 
310  // Manually construct the json output
311  std::ofstream nmsProfileStream("nms.json");
312  nmsProfileStream << "{" << "\n";
313  nmsProfileStream << R"( "NmsTimings": {)" << "\n";
314  nmsProfileStream << R"( "raw": [)" << "\n";
315  bool isFirst = true;
316  for (auto duration : nmsDurations)
317  {
318  if (!isFirst)
319  {
320  nmsProfileStream << ",\n";
321  }
322 
323  nmsProfileStream << " " << duration.count();
324  isFirst = false;
325  }
326  nmsProfileStream << "\n";
327  nmsProfileStream << R"( "units": "us")" << "\n";
328  nmsProfileStream << " ]" << "\n";
329  nmsProfileStream << " }" << "\n";
330  nmsProfileStream << "}" << "\n";
331  nmsProfileStream.close();
332 
333  ARMNN_LOG(info) << "Run completed";
334  return 0;
335 }
void SetAllLoggingSinks(bool standardOut, bool debugOut, bool coloured)
Definition: Logging.cpp:146
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:225
int NetworkId
Definition: IRuntime.hpp:20
unsigned int num_boxes
Number of detected boxes.
Definition: NMS.hpp:15
armnn::OutputTensors MakeOutputTensors(const std::vector< armnn::BindingPointInfo > &outputBindings, const std::vector< TContainer > &outputDataContainers)
std::vector< float > LoadImage(const char *filename)
void SetLogFilter(LogSeverity level)
Definition: Logging.cpp:28
void print_detection(std::ostream &os, const std::vector< Detection > &detections)
Print identified yolo detections.
Definition: NMS.cpp:83
#define CHECK_OK(v)
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:226
float iou_threshold
Inclusion threshold for Intersection-Over-Union.
Definition: NMS.hpp:17
std::vector< Detection > nms(const NMSConfig &config, const std::vector< float > &detected_boxes)
Perform Non-Maxima Supression on a list of given detections.
Definition: NMS.cpp:100
Non Maxima Suprresion configuration meta-data.
Definition: NMS.hpp:13
float confidence_threshold
Inclusion confidence threshold for a box.
Definition: NMS.hpp:16
armnn::InputTensors MakeInputTensors(const std::vector< armnn::BindingPointInfo > &inputBindings, const std::vector< TContainer > &inputDataContainers)
int LoadModel(const char *filename, ITfLiteParser &parser, IRuntime &runtime, NetworkId &networkId, const std::vector< BackendId > &backendPreferences)
unsigned int num_classes
Number of classes in the detected boxes.
Definition: NMS.hpp:14

◆ MakeInputTensors()

armnn::InputTensors MakeInputTensors ( const std::vector< armnn::BindingPointInfo > &  inputBindings,
const std::vector< TContainer > &  inputDataContainers 
)
inline

Definition at line 47 of file TfLiteYoloV3Big-Armnn.cpp.

Referenced by InferenceModel< IParser, TDataType >::GetAllQuantizationParams(), and InferenceModel< IParser, TDataType >::Run().

49 {
50  armnn::InputTensors inputTensors;
51 
52  const size_t numInputs = inputBindings.size();
53  if (numInputs != inputDataContainers.size())
54  {
55  throw armnn::Exception("Mismatching vectors");
56  }
57 
58  for (size_t i = 0; i < numInputs; i++)
59  {
60  const armnn::BindingPointInfo& inputBinding = inputBindings[i];
61  const TContainer& inputData = inputDataContainers[i];
62 
63  armnn::ConstTensor inputTensor(inputBinding.second, inputData.data());
64  inputTensors.push_back(std::make_pair(inputBinding.first, inputTensor));
65  }
66 
67  return inputTensors;
68 }
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:225
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
boost::variant< std::vector< float >, std::vector< int >, std::vector< unsigned char > > TContainer
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
Definition: Tensor.hpp:146
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46

◆ MakeOutputTensors()

armnn::OutputTensors MakeOutputTensors ( const std::vector< armnn::BindingPointInfo > &  outputBindings,
const std::vector< TContainer > &  outputDataContainers 
)
inline

Definition at line 71 of file TfLiteYoloV3Big-Armnn.cpp.

Referenced by InferenceModel< IParser, TDataType >::GetAllQuantizationParams(), and InferenceModel< IParser, TDataType >::Run().

73 {
74  armnn::OutputTensors outputTensors;
75 
76  const size_t numOutputs = outputBindings.size();
77  if (numOutputs != outputDataContainers.size())
78  {
79  throw armnn::Exception("Mismatching vectors");
80  }
81 
82  for (size_t i = 0; i < numOutputs; i++)
83  {
84  const armnn::BindingPointInfo& outputBinding = outputBindings[i];
85  const TContainer& outputData = outputDataContainers[i];
86 
87  armnn::Tensor outputTensor(outputBinding.second, const_cast<float*>(outputData.data()));
88  outputTensors.push_back(std::make_pair(outputBinding.first, outputTensor));
89  }
90 
91  return outputTensors;
92 }
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:191
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:226
boost::variant< std::vector< float >, std::vector< int >, std::vector< unsigned char > > TContainer
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
Definition: Tensor.hpp:146
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46