ArmNN
 20.08
ImageTensorGenerator.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 #include "../InferenceTestImage.hpp"
8 #include <armnn/Logging.hpp>
9 #include <armnn/TypesUtils.hpp>
10 #include <Filesystem.hpp>
11 
12 #include <boost/program_options.hpp>
13 #include <boost/variant.hpp>
14 
15 #include <algorithm>
16 #include <fstream>
17 #include <iostream>
18 #include <string>
19 
20 namespace
21 {
22 
23 // parses the command line to extract
24 // * the input image file -i the input image file path (must exist)
25 // * the layout -l the data layout output generated with (optional - default value is NHWC)
26 // * the output file -o the output raw tensor file path (must not already exist)
27 class CommandLineProcessor
28 {
29 public:
30  bool ValidateInputFile(const std::string& inputFileName)
31  {
32  if (inputFileName.empty())
33  {
34  std::cerr << "No input file name specified" << std::endl;
35  return false;
36  }
37 
38  if (!fs::exists(inputFileName))
39  {
40  std::cerr << "Input file [" << inputFileName << "] does not exist" << std::endl;
41  return false;
42  }
43 
44  if (fs::is_directory(inputFileName))
45  {
46  std::cerr << "Input file [" << inputFileName << "] is a directory" << std::endl;
47  return false;
48  }
49 
50  return true;
51  }
52 
53  bool ValidateLayout(const std::string& layout)
54  {
55  if (layout.empty())
56  {
57  std::cerr << "No layout specified" << std::endl;
58  return false;
59  }
60 
61  std::vector<std::string> supportedLayouts = { "NHWC", "NCHW" };
62 
63  auto iterator = std::find(supportedLayouts.begin(), supportedLayouts.end(), layout);
64  if (iterator == supportedLayouts.end())
65  {
66  std::cerr << "Layout [" << layout << "] is not supported" << std::endl;
67  return false;
68  }
69 
70  return true;
71  }
72 
73  bool ValidateOutputFile(std::string& outputFileName)
74  {
75  if (outputFileName.empty())
76  {
77  std::cerr << "No output file name specified" << std::endl;
78  return false;
79  }
80 
81  if (fs::exists(outputFileName))
82  {
83  std::cerr << "Output file [" << outputFileName << "] already exists" << std::endl;
84  return false;
85  }
86 
87  if (fs::is_directory(outputFileName))
88  {
89  std::cerr << "Output file [" << outputFileName << "] is a directory" << std::endl;
90  return false;
91  }
92 
93  fs::path outputPath(outputFileName);
94  if (!fs::exists(outputPath.parent_path()))
95  {
96  std::cerr << "Output directory [" << outputPath.parent_path().c_str() << "] does not exist" << std::endl;
97  return false;
98  }
99 
100  return true;
101  }
102 
103  bool ProcessCommandLine(int argc, char* argv[])
104  {
105  namespace po = boost::program_options;
106 
107  po::options_description desc("Options");
108  try
109  {
110  desc.add_options()
111  ("help,h", "Display help messages")
112  ("infile,i", po::value<std::string>(&m_InputFileName)->required(),
113  "Input image file to generate tensor from")
114  ("model-format,f", po::value<std::string>(&m_ModelFormat)->required(),
115  "Format of the intended model file that uses the images."
116  "Different formats have different image normalization styles."
117  "Accepted values (caffe, tensorflow, tflite)")
118  ("outfile,o", po::value<std::string>(&m_OutputFileName)->required(),
119  "Output raw tensor file path")
120  ("output-type,z", po::value<std::string>(&m_OutputType)->default_value("float"),
121  "The data type of the output tensors."
122  "If unset, defaults to \"float\" for all defined inputs. "
123  "Accepted values (float, int or qasymm8)")
124  ("new-width", po::value<std::string>(&m_NewWidth)->default_value("0"),
125  "Resize image to new width. Keep original width if unspecified")
126  ("new-height", po::value<std::string>(&m_NewHeight)->default_value("0"),
127  "Resize image to new height. Keep original height if unspecified")
128  ("layout,l", po::value<std::string>(&m_Layout)->default_value("NHWC"),
129  "Output data layout, \"NHWC\" or \"NCHW\", default value NHWC");
130  }
131  catch (const std::exception& e)
132  {
133  std::cerr << "Fatal internal error: [" << e.what() << "]" << std::endl;
134  return false;
135  }
136 
137  po::variables_map vm;
138 
139  try
140  {
141  po::store(po::parse_command_line(argc, argv, desc), vm);
142 
143  if (vm.count("help"))
144  {
145  std::cout << desc << std::endl;
146  return false;
147  }
148 
149  po::notify(vm);
150  }
151  catch (const po::error& e)
152  {
153  std::cerr << e.what() << std::endl << std::endl;
154  std::cerr << desc << std::endl;
155  return false;
156  }
157 
158  if (!ValidateInputFile(m_InputFileName))
159  {
160  return false;
161  }
162 
163  if (!ValidateLayout(m_Layout))
164  {
165  return false;
166  }
167 
168  if (!ValidateOutputFile(m_OutputFileName))
169  {
170  return false;
171  }
172 
173  return true;
174  }
175 
176  std::string GetInputFileName() {return m_InputFileName;}
177  armnn::DataLayout GetLayout()
178  {
179  if (m_Layout == "NHWC")
180  {
182  }
183  else if (m_Layout == "NCHW")
184  {
186  }
187  else
188  {
189  throw armnn::Exception("Unsupported data layout: " + m_Layout);
190  }
191  }
192  std::string GetOutputFileName() {return m_OutputFileName;}
193  unsigned int GetNewWidth() {return static_cast<unsigned int>(std::stoi(m_NewWidth));}
194  unsigned int GetNewHeight() {return static_cast<unsigned int>(std::stoi(m_NewHeight));}
195  SupportedFrontend GetModelFormat()
196  {
197  if (m_ModelFormat == "caffe")
198  {
200  }
201  else if (m_ModelFormat == "tensorflow")
202  {
204  }
205  else if (m_ModelFormat == "tflite")
206  {
208  }
209  else
210  {
211  throw armnn::Exception("Unsupported model format" + m_ModelFormat);
212  }
213  }
214  armnn::DataType GetOutputType()
215  {
216  if (m_OutputType == "float")
217  {
219  }
220  else if (m_OutputType == "int")
221  {
223  }
224  else if (m_OutputType == "qasymm8")
225  {
227  }
228  else
229  {
230  throw armnn::Exception("Unsupported input type" + m_OutputType);
231  }
232  }
233 
234 private:
235  std::string m_InputFileName;
236  std::string m_Layout;
237  std::string m_OutputFileName;
238  std::string m_NewWidth;
239  std::string m_NewHeight;
240  std::string m_ModelFormat;
241  std::string m_OutputType;
242 };
243 
244 } // namespace anonymous
245 
246 int main(int argc, char* argv[])
247 {
248  CommandLineProcessor cmdline;
249  if (!cmdline.ProcessCommandLine(argc, argv))
250  {
251  return -1;
252  }
253  const std::string imagePath(cmdline.GetInputFileName());
254  const std::string outputPath(cmdline.GetOutputFileName());
255  const SupportedFrontend& modelFormat(cmdline.GetModelFormat());
256  const armnn::DataType outputType(cmdline.GetOutputType());
257  const unsigned int newWidth = cmdline.GetNewWidth();
258  const unsigned int newHeight = cmdline.GetNewHeight();
259  const unsigned int batchSize = 1;
260  const armnn::DataLayout outputLayout(cmdline.GetLayout());
261 
262  using TContainer = boost::variant<std::vector<float>, std::vector<int>, std::vector<uint8_t>>;
263  std::vector<TContainer> imageDataContainers;
264  const NormalizationParameters& normParams = GetNormalizationParameters(modelFormat, outputType);
265  try
266  {
267  switch (outputType)
268  {
270  imageDataContainers.push_back(PrepareImageTensor<int>(
271  imagePath, newWidth, newHeight, normParams, batchSize, outputLayout));
272  break;
274  imageDataContainers.push_back(PrepareImageTensor<uint8_t>(
275  imagePath, newWidth, newHeight, normParams, batchSize, outputLayout));
276  break;
278  default:
279  imageDataContainers.push_back(PrepareImageTensor<float>(
280  imagePath, newWidth, newHeight, normParams, batchSize, outputLayout));
281  break;
282  }
283  }
284  catch (const InferenceTestImageException& e)
285  {
286  ARMNN_LOG(fatal) << "Failed to load image file " << imagePath << " with error: " << e.what();
287  return -1;
288  }
289 
290  std::ofstream imageTensorFile;
291  imageTensorFile.open(outputPath, std::ofstream::out);
292  if (imageTensorFile.is_open())
293  {
294  boost::apply_visitor([&imageTensorFile](auto&& imageData) { WriteImageTensorImpl(imageData, imageTensorFile); },
295  imageDataContainers[0]);
296  if (!imageTensorFile)
297  {
298  ARMNN_LOG(fatal) << "Failed to write to output file" << outputPath;
299  imageTensorFile.close();
300  return -1;
301  }
302  imageTensorFile.close();
303  }
304  else
305  {
306  ARMNN_LOG(fatal) << "Failed to open output file" << outputPath;
307  return -1;
308  }
309 
310  return 0;
311 }
DataLayout
Definition: Types.hpp:49
NormalizationParameters GetNormalizationParameters(const SupportedFrontend &modelFormat, const armnn::DataType &outputType)
Get normalization parameters.
virtual const char * what() const noexcept override
Definition: Exceptions.cpp:32
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163
void WriteImageTensorImpl(const std::vector< ElemType > &imageData, std::ofstream &imageTensorFile)
Write image tensor to ofstream.
std::vector< uint8_t > PrepareImageTensor< uint8_t >(const std::string &imagePath, unsigned int newWidth, unsigned int newHeight, const NormalizationParameters &normParams, unsigned int batchSize, const armnn::DataLayout &outputLayout)
boost::variant< std::vector< float >, std::vector< int >, std::vector< unsigned char > > TContainer
DataType
Definition: Types.hpp:32
std::vector< int > PrepareImageTensor< int >(const std::string &imagePath, unsigned int newWidth, unsigned int newHeight, const NormalizationParameters &normParams, unsigned int batchSize, const armnn::DataLayout &outputLayout)
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
int main(int argc, char *argv[])
std::vector< float > PrepareImageTensor< float >(const std::string &imagePath, unsigned int newWidth, unsigned int newHeight, const NormalizationParameters &normParams, unsigned int batchSize, const armnn::DataLayout &outputLayout)