Compute Library
 20.02.1
Utils.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2019 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #ifndef __UTILS_UTILS_H__
25 #define __UTILS_UTILS_H__
26 
29 #include "arm_compute/core/Types.h"
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wunused-parameter"
35 #pragma GCC diagnostic ignored "-Wstrict-overflow"
36 #include "libnpy/npy.hpp"
37 #pragma GCC diagnostic pop
39 
40 #ifdef ARM_COMPUTE_CL
44 #endif /* ARM_COMPUTE_CL */
45 #ifdef ARM_COMPUTE_GC
47 #endif /* ARM_COMPUTE_GC */
48 
49 #include <cstdlib>
50 #include <cstring>
51 #include <fstream>
52 #include <iostream>
53 #include <random>
54 #include <string>
55 #include <tuple>
56 #include <vector>
57 
58 namespace arm_compute
59 {
60 namespace utils
61 {
62 /** Supported image types */
63 enum class ImageType
64 {
65  UNKNOWN,
66  PPM,
67  JPEG
68 };
69 
70 /** Abstract Example class.
71  *
72  * All examples have to inherit from this class.
73  */
74 class Example
75 {
76 public:
77  /** Setup the example.
78  *
79  * @param[in] argc Argument count.
80  * @param[in] argv Argument values.
81  *
82  * @return True in case of no errors in setup else false
83  */
84  virtual bool do_setup(int argc, char **argv)
85  {
86  ARM_COMPUTE_UNUSED(argc, argv);
87  return true;
88  };
89  /** Run the example. */
90  virtual void do_run() {};
91  /** Teardown the example. */
92  virtual void do_teardown() {};
93 
94  /** Default destructor. */
95  virtual ~Example() = default;
96 };
97 
98 /** Run an example and handle the potential exceptions it throws
99  *
100  * @param[in] argc Number of command line arguments
101  * @param[in] argv Command line arguments
102  * @param[in] example Example to run
103  */
104 int run_example(int argc, char **argv, std::unique_ptr<Example> example);
105 
106 template <typename T>
107 int run_example(int argc, char **argv)
108 {
109  return run_example(argc, argv, support::cpp14::make_unique<T>());
110 }
111 
112 /** Draw a RGB rectangular window for the detected object
113  *
114  * @param[in, out] tensor Input tensor where the rectangle will be drawn on. Format supported: RGB888
115  * @param[in] rect Geometry of the rectangular window
116  * @param[in] r Red colour to use
117  * @param[in] g Green colour to use
118  * @param[in] b Blue colour to use
119  */
120 void draw_detection_rectangle(arm_compute::ITensor *tensor, const arm_compute::DetectionWindow &rect, uint8_t r, uint8_t g, uint8_t b);
121 
122 /** Gets image type given a file
123  *
124  * @param[in] filename File to identify its image type
125  *
126  * @return Image type
127  */
128 ImageType get_image_type_from_file(const std::string &filename);
129 
130 /** Parse the ppm header from an input file stream. At the end of the execution,
131  * the file position pointer will be located at the first pixel stored in the ppm file
132  *
133  * @param[in] fs Input file stream to parse
134  *
135  * @return The width, height and max value stored in the header of the PPM file
136  */
137 std::tuple<unsigned int, unsigned int, int> parse_ppm_header(std::ifstream &fs);
138 
139 /** Parse the npy header from an input file stream. At the end of the execution,
140  * the file position pointer will be located at the first pixel stored in the npy file //TODO
141  *
142  * @param[in] fs Input file stream to parse
143  *
144  * @return The width and height stored in the header of the NPY file
145  */
146 std::tuple<std::vector<unsigned long>, bool, std::string> parse_npy_header(std::ifstream &fs);
147 
148 /** Obtain numpy type string from DataType.
149  *
150  * @param[in] data_type Data type.
151  *
152  * @return numpy type string.
153  */
154 inline std::string get_typestring(DataType data_type)
155 {
156  // Check endianness
157  const unsigned int i = 1;
158  const char *c = reinterpret_cast<const char *>(&i);
159  std::string endianness;
160  if(*c == 1)
161  {
162  endianness = std::string("<");
163  }
164  else
165  {
166  endianness = std::string(">");
167  }
168  const std::string no_endianness("|");
169 
170  switch(data_type)
171  {
172  case DataType::U8:
173  case DataType::QASYMM8:
174  return no_endianness + "u" + support::cpp11::to_string(sizeof(uint8_t));
175  case DataType::S8:
176  case DataType::QSYMM8:
178  return no_endianness + "i" + support::cpp11::to_string(sizeof(int8_t));
179  case DataType::U16:
180  case DataType::QASYMM16:
181  return endianness + "u" + support::cpp11::to_string(sizeof(uint16_t));
182  case DataType::S16:
183  case DataType::QSYMM16:
184  return endianness + "i" + support::cpp11::to_string(sizeof(int16_t));
185  case DataType::U32:
186  return endianness + "u" + support::cpp11::to_string(sizeof(uint32_t));
187  case DataType::S32:
188  return endianness + "i" + support::cpp11::to_string(sizeof(int32_t));
189  case DataType::U64:
190  return endianness + "u" + support::cpp11::to_string(sizeof(uint64_t));
191  case DataType::S64:
192  return endianness + "i" + support::cpp11::to_string(sizeof(int64_t));
193  case DataType::F16:
194  return endianness + "f" + support::cpp11::to_string(sizeof(half));
195  case DataType::F32:
196  return endianness + "f" + support::cpp11::to_string(sizeof(float));
197  case DataType::F64:
198  return endianness + "f" + support::cpp11::to_string(sizeof(double));
199  case DataType::SIZET:
200  return endianness + "u" + support::cpp11::to_string(sizeof(size_t));
201  default:
202  ARM_COMPUTE_ERROR("Data type not supported");
203  }
204 }
205 
206 /** Maps a tensor if needed
207  *
208  * @param[in] tensor Tensor to be mapped
209  * @param[in] blocking Specified if map is blocking or not
210  */
211 template <typename T>
212 inline void map(T &tensor, bool blocking)
213 {
214  ARM_COMPUTE_UNUSED(tensor);
215  ARM_COMPUTE_UNUSED(blocking);
216 }
217 
218 /** Unmaps a tensor if needed
219  *
220  * @param tensor Tensor to be unmapped
221  */
222 template <typename T>
223 inline void unmap(T &tensor)
224 {
225  ARM_COMPUTE_UNUSED(tensor);
226 }
227 
228 #ifdef ARM_COMPUTE_CL
229 /** Maps a tensor if needed
230  *
231  * @param[in] tensor Tensor to be mapped
232  * @param[in] blocking Specified if map is blocking or not
233  */
234 inline void map(CLTensor &tensor, bool blocking)
235 {
236  tensor.map(blocking);
237 }
238 
239 /** Unmaps a tensor if needed
240  *
241  * @param tensor Tensor to be unmapped
242  */
243 inline void unmap(CLTensor &tensor)
244 {
245  tensor.unmap();
246 }
247 
248 /** Maps a distribution if needed
249  *
250  * @param[in] distribution Distribution to be mapped
251  * @param[in] blocking Specified if map is blocking or not
252  */
253 inline void map(CLDistribution1D &distribution, bool blocking)
254 {
255  distribution.map(blocking);
256 }
257 
258 /** Unmaps a distribution if needed
259  *
260  * @param distribution Distribution to be unmapped
261  */
262 inline void unmap(CLDistribution1D &distribution)
263 {
264  distribution.unmap();
265 }
266 #endif /* ARM_COMPUTE_CL */
267 
268 #ifdef ARM_COMPUTE_GC
269 /** Maps a tensor if needed
270  *
271  * @param[in] tensor Tensor to be mapped
272  * @param[in] blocking Specified if map is blocking or not
273  */
274 inline void map(GCTensor &tensor, bool blocking)
275 {
276  tensor.map(blocking);
277 }
278 
279 /** Unmaps a tensor if needed
280  *
281  * @param tensor Tensor to be unmapped
282  */
283 inline void unmap(GCTensor &tensor)
284 {
285  tensor.unmap();
286 }
287 #endif /* ARM_COMPUTE_GC */
288 
289 /** Specialized class to generate random non-zero FP16 values.
290  * uniform_real_distribution<half> generates values that get rounded off to zero, causing
291  * differences between ACL and reference implementation
292 */
294 {
295  half min{ 0.0f }, max{ 0.0f };
296  std::uniform_real_distribution<float> neg{ min, -0.3f };
297  std::uniform_real_distribution<float> pos{ 0.3f, max };
298  std::uniform_int_distribution<uint8_t> sign_picker{ 0, 1 };
299 
300 public:
301  using result_type = half;
302  /** Constructor
303  *
304  * @param[in] a Minimum value of the distribution
305  * @param[in] b Maximum value of the distribution
306  */
307  explicit uniform_real_distribution_fp16(half a = half(0.0), half b = half(1.0))
308  : min(a), max(b)
309  {
310  }
311 
312  /** () operator to generate next value
313  *
314  * @param[in] gen an uniform random bit generator object
315  */
316  half operator()(std::mt19937 &gen)
317  {
318  if(sign_picker(gen))
319  {
320  return (half)neg(gen);
321  }
322  return (half)pos(gen);
323  }
324 };
325 
326 /** Numpy data loader */
328 {
329 public:
330  /** Default constructor */
332  : _fs(), _shape(), _fortran_order(false), _typestring(), _file_layout(DataLayout::NCHW)
333  {
334  }
335 
336  /** Open a NPY file and reads its metadata
337  *
338  * @param[in] npy_filename File to open
339  * @param[in] file_layout (Optional) Layout in which the weights are stored in the file.
340  */
341  void open(const std::string &npy_filename, DataLayout file_layout = DataLayout::NCHW)
342  {
344  try
345  {
346  _fs.open(npy_filename, std::ios::in | std::ios::binary);
347  ARM_COMPUTE_EXIT_ON_MSG_VAR(!_fs.good(), "Failed to load binary data from %s", npy_filename.c_str());
348  _fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
349  _file_layout = file_layout;
350 
351  std::tie(_shape, _fortran_order, _typestring) = parse_npy_header(_fs);
352  }
353  catch(const std::ifstream::failure &e)
354  {
355  ARM_COMPUTE_ERROR_VAR("Accessing %s: %s", npy_filename.c_str(), e.what());
356  }
357  }
358  /** Return true if a NPY file is currently open */
359  bool is_open()
360  {
361  return _fs.is_open();
362  }
363 
364  /** Return true if a NPY file is in fortran order */
365  bool is_fortran()
366  {
367  return _fortran_order;
368  }
369 
370  /** Initialise the tensor's metadata with the dimensions of the NPY file currently open
371  *
372  * @param[out] tensor Tensor to initialise
373  * @param[in] dt Data type to use for the tensor
374  */
375  template <typename T>
376  void init_tensor(T &tensor, arm_compute::DataType dt)
377  {
380 
381  // Use the size of the input NPY tensor
383  shape.set_num_dimensions(_shape.size());
384  for(size_t i = 0; i < _shape.size(); ++i)
385  {
386  size_t src = i;
387  if(_fortran_order)
388  {
389  src = _shape.size() - 1 - i;
390  }
391  shape.set(i, _shape.at(src));
392  }
393 
394  arm_compute::TensorInfo tensor_info(shape, 1, dt);
395  tensor.allocator()->init(tensor_info);
396  }
397 
398  /** Fill a tensor with the content of the currently open NPY file.
399  *
400  * @note If the tensor is a CLTensor, the function maps and unmaps the tensor
401  *
402  * @param[in,out] tensor Tensor to fill (Must be allocated, and of matching dimensions with the opened NPY).
403  */
404  template <typename T>
405  void fill_tensor(T &tensor)
406  {
409  try
410  {
411  // Map buffer if creating a CLTensor
412  map(tensor, true);
413 
414  // Check if the file is large enough to fill the tensor
415  const size_t current_position = _fs.tellg();
416  _fs.seekg(0, std::ios_base::end);
417  const size_t end_position = _fs.tellg();
418  _fs.seekg(current_position, std::ios_base::beg);
419 
420  ARM_COMPUTE_ERROR_ON_MSG((end_position - current_position) < tensor.info()->tensor_shape().total_size() * tensor.info()->element_size(),
421  "Not enough data in file");
422  ARM_COMPUTE_UNUSED(end_position);
423 
424  // Check if the typestring matches the given one
425  std::string expect_typestr = get_typestring(tensor.info()->data_type());
426  ARM_COMPUTE_ERROR_ON_MSG(_typestring != expect_typestr, "Typestrings mismatch");
427 
428  bool are_layouts_different = (_file_layout != tensor.info()->data_layout());
429  // Correct dimensions (Needs to match TensorShape dimension corrections)
430  if(_shape.size() != tensor.info()->tensor_shape().num_dimensions())
431  {
432  for(int i = static_cast<int>(_shape.size()) - 1; i > 0; --i)
433  {
434  if(_shape[i] == 1)
435  {
436  _shape.pop_back();
437  }
438  else
439  {
440  break;
441  }
442  }
443  }
444 
445  TensorShape permuted_shape = tensor.info()->tensor_shape();
447  if(are_layouts_different && tensor.info()->tensor_shape().num_dimensions() > 2)
448  {
449  perm = (tensor.info()->data_layout() == arm_compute::DataLayout::NHWC) ? arm_compute::PermutationVector(2U, 0U, 1U) : arm_compute::PermutationVector(1U, 2U, 0U);
451 
452  arm_compute::permute(permuted_shape, perm_vec);
453  }
454 
455  // Validate tensor shape
456  ARM_COMPUTE_ERROR_ON_MSG(_shape.size() != tensor.info()->tensor_shape().num_dimensions(), "Tensor ranks mismatch");
457  for(size_t i = 0; i < _shape.size(); ++i)
458  {
459  ARM_COMPUTE_ERROR_ON_MSG(permuted_shape[i] != _shape[i], "Tensor dimensions mismatch");
460  }
461 
462  switch(tensor.info()->data_type())
463  {
468  {
469  // Read data
470  if(!are_layouts_different && !_fortran_order && tensor.info()->padding().empty())
471  {
472  // If tensor has no padding read directly from stream.
473  _fs.read(reinterpret_cast<char *>(tensor.buffer()), tensor.info()->total_size());
474  }
475  else
476  {
477  // If tensor has padding or is in fortran order accessing tensor elements through execution window.
478  Window window;
479  const unsigned int num_dims = _shape.size();
480  if(_fortran_order)
481  {
482  for(unsigned int dim = 0; dim < num_dims; dim++)
483  {
484  permuted_shape.set(dim, _shape[num_dims - dim - 1]);
485  perm.set(dim, num_dims - dim - 1);
486  }
487  if(are_layouts_different)
488  {
489  // Permute only if num_dimensions greater than 2
490  if(num_dims > 2)
491  {
492  if(_file_layout == DataLayout::NHWC) // i.e destination is NCHW --> permute(1,2,0)
493  {
495  }
496  else
497  {
499  }
500  }
501  }
502  }
503  window.use_tensor_dimensions(permuted_shape);
504 
505  execute_window_loop(window, [&](const Coordinates & id)
506  {
507  Coordinates dst(id);
508  arm_compute::permute(dst, perm);
509  _fs.read(reinterpret_cast<char *>(tensor.ptr_to_element(dst)), tensor.info()->element_size());
510  });
511  }
512 
513  break;
514  }
515  default:
516  ARM_COMPUTE_ERROR("Unsupported data type");
517  }
518 
519  // Unmap buffer if creating a CLTensor
520  unmap(tensor);
521  }
522  catch(const std::ifstream::failure &e)
523  {
524  ARM_COMPUTE_ERROR_VAR("Loading NPY file: %s", e.what());
525  }
526  }
527 
528 private:
529  std::ifstream _fs;
530  std::vector<unsigned long> _shape;
531  bool _fortran_order;
532  std::string _typestring;
533  DataLayout _file_layout;
534 };
535 
536 /** Template helper function to save a tensor image to a PPM file.
537  *
538  * @note Only U8 and RGB888 formats supported.
539  * @note Only works with 2D tensors.
540  * @note If the input tensor is a CLTensor, the function maps and unmaps the image
541  *
542  * @param[in] tensor The tensor to save as PPM file
543  * @param[in] ppm_filename Filename of the file to create.
544  */
545 template <typename T>
546 void save_to_ppm(T &tensor, const std::string &ppm_filename)
547 {
549  ARM_COMPUTE_ERROR_ON(tensor.info()->num_dimensions() > 2);
550 
551  std::ofstream fs;
552 
553  try
554  {
555  fs.exceptions(std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
556  fs.open(ppm_filename, std::ios::out | std::ios::binary);
557 
558  const unsigned int width = tensor.info()->tensor_shape()[0];
559  const unsigned int height = tensor.info()->tensor_shape()[1];
560 
561  fs << "P6\n"
562  << width << " " << height << " 255\n";
563 
564  // Map buffer if creating a CLTensor/GCTensor
565  map(tensor, true);
566 
567  switch(tensor.info()->format())
568  {
570  {
571  arm_compute::Window window;
574 
575  arm_compute::Iterator in(&tensor, window);
576 
578  {
579  const unsigned char value = *in.ptr();
580 
581  fs << value << value << value;
582  },
583  in);
584 
585  break;
586  }
588  {
589  arm_compute::Window window;
592 
593  arm_compute::Iterator in(&tensor, window);
594 
596  {
597  fs.write(reinterpret_cast<std::fstream::char_type *>(in.ptr()), width * tensor.info()->element_size());
598  },
599  in);
600 
601  break;
602  }
603  default:
604  ARM_COMPUTE_ERROR("Unsupported format");
605  }
606 
607  // Unmap buffer if creating a CLTensor/GCTensor
608  unmap(tensor);
609  }
610  catch(const std::ofstream::failure &e)
611  {
612  ARM_COMPUTE_ERROR_VAR("Writing %s: (%s)", ppm_filename.c_str(), e.what());
613  }
614 }
615 
616 /** Template helper function to save a tensor image to a NPY file.
617  *
618  * @note Only F32 data type supported.
619  * @note If the input tensor is a CLTensor, the function maps and unmaps the image
620  *
621  * @param[in] tensor The tensor to save as NPY file
622  * @param[in] npy_filename Filename of the file to create.
623  * @param[in] fortran_order If true, save matrix in fortran order.
624  */
625 template <typename T, typename U = float>
626 void save_to_npy(T &tensor, const std::string &npy_filename, bool fortran_order)
627 {
629 
630  std::ofstream fs;
631  try
632  {
633  fs.exceptions(std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
634  fs.open(npy_filename, std::ios::out | std::ios::binary);
635 
636  std::vector<npy::ndarray_len_t> shape(tensor.info()->num_dimensions());
637 
638  for(unsigned int i = 0, j = tensor.info()->num_dimensions() - 1; i < tensor.info()->num_dimensions(); ++i, --j)
639  {
640  shape[i] = tensor.info()->tensor_shape()[!fortran_order ? j : i];
641  }
642 
643  // Map buffer if creating a CLTensor
644  map(tensor, true);
645 
646  using typestring_type = typename std::conditional<std::is_floating_point<U>::value, float, qasymm8_t>::type;
647 
648  std::vector<typestring_type> tmp; /* Used only to get the typestring */
649  npy::Typestring typestring_o{ tmp };
650  std::string typestring = typestring_o.str();
651 
652  std::ofstream stream(npy_filename, std::ofstream::binary);
653  npy::write_header(stream, typestring, fortran_order, shape);
654 
655  arm_compute::Window window;
656  window.use_tensor_dimensions(tensor.info()->tensor_shape());
657 
658  arm_compute::Iterator in(&tensor, window);
659 
661  {
662  stream.write(reinterpret_cast<const char *>(in.ptr()), sizeof(typestring_type));
663  },
664  in);
665 
666  // Unmap buffer if creating a CLTensor
667  unmap(tensor);
668  }
669  catch(const std::ofstream::failure &e)
670  {
671  ARM_COMPUTE_ERROR_VAR("Writing %s: (%s)", npy_filename.c_str(), e.what());
672  }
673 }
674 
675 /** Load the tensor with pre-trained data from a binary file
676  *
677  * @param[in] tensor The tensor to be filled. Data type supported: F32.
678  * @param[in] filename Filename of the binary file to load from.
679  */
680 template <typename T>
681 void load_trained_data(T &tensor, const std::string &filename)
682 {
684 
685  std::ifstream fs;
686 
687  try
688  {
689  fs.exceptions(std::ofstream::failbit | std::ofstream::badbit | std::ofstream::eofbit);
690  // Open file
691  fs.open(filename, std::ios::in | std::ios::binary);
692 
693  if(!fs.good())
694  {
695  throw std::runtime_error("Could not load binary data: " + filename);
696  }
697 
698  // Map buffer if creating a CLTensor/GCTensor
699  map(tensor, true);
700 
701  Window window;
702 
704 
705  for(unsigned int d = 1; d < tensor.info()->num_dimensions(); ++d)
706  {
707  window.set(d, Window::Dimension(0, tensor.info()->tensor_shape()[d], 1));
708  }
709 
710  arm_compute::Iterator in(&tensor, window);
711 
712  execute_window_loop(window, [&](const Coordinates &)
713  {
714  fs.read(reinterpret_cast<std::fstream::char_type *>(in.ptr()), tensor.info()->tensor_shape()[0] * tensor.info()->element_size());
715  },
716  in);
717 
718  // Unmap buffer if creating a CLTensor/GCTensor
719  unmap(tensor);
720  }
721  catch(const std::ofstream::failure &e)
722  {
723  ARM_COMPUTE_ERROR_VAR("Writing %s: (%s)", filename.c_str(), e.what());
724  }
725 }
726 
727 template <typename T>
728 void fill_random_tensor(T &tensor, float lower_bound, float upper_bound)
729 {
730  std::random_device rd;
731  std::mt19937 gen(rd());
732 
733  Window window;
734  window.use_tensor_dimensions(tensor.info()->tensor_shape());
735 
736  map(tensor, true);
737 
738  Iterator it(&tensor, window);
739 
740  switch(tensor.info()->data_type())
741  {
743  {
744  std::uniform_real_distribution<float> dist(lower_bound, upper_bound);
745 
746  execute_window_loop(window, [&](const Coordinates &)
747  {
748  *reinterpret_cast<half *>(it.ptr()) = (half)dist(gen);
749  },
750  it);
751 
752  break;
753  }
755  {
756  std::uniform_real_distribution<float> dist(lower_bound, upper_bound);
757 
758  execute_window_loop(window, [&](const Coordinates &)
759  {
760  *reinterpret_cast<float *>(it.ptr()) = dist(gen);
761  },
762  it);
763 
764  break;
765  }
766  default:
767  {
768  ARM_COMPUTE_ERROR("Unsupported format");
769  }
770  }
771 
772  unmap(tensor);
773 }
774 
775 template <typename T>
776 void init_sgemm_output(T &dst, T &src0, T &src1, arm_compute::DataType dt)
777 {
778  dst.allocator()->init(TensorInfo(TensorShape(src1.info()->dimension(0), src0.info()->dimension(1), src0.info()->dimension(2)), 1, dt));
779 }
780 /** This function returns the amount of memory free reading from /proc/meminfo
781  *
782  * @return The free memory in kB
783  */
784 uint64_t get_mem_free_from_meminfo();
785 
786 /** Compare two tensors
787  *
788  * @param[in] tensor1 First tensor to be compared.
789  * @param[in] tensor2 Second tensor to be compared.
790  * @param[in] tolerance Tolerance used for the comparison.
791  *
792  * @return The number of mismatches
793  */
794 template <typename T>
795 int compare_tensor(ITensor &tensor1, ITensor &tensor2, T tolerance)
796 {
798  ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(&tensor1, &tensor2);
799 
800  int num_mismatches = 0;
801  Window window;
802  window.use_tensor_dimensions(tensor1.info()->tensor_shape());
803 
804  map(tensor1, true);
805  map(tensor2, true);
806 
807  Iterator itensor1(&tensor1, window);
808  Iterator itensor2(&tensor2, window);
809 
810  execute_window_loop(window, [&](const Coordinates &)
811  {
812  if(std::abs(*reinterpret_cast<T *>(itensor1.ptr()) - *reinterpret_cast<T *>(itensor2.ptr())) > tolerance)
813  {
814  ++num_mismatches;
815  }
816  },
817  itensor1, itensor2);
818 
819  unmap(itensor1);
820  unmap(itensor2);
821 
822  return num_mismatches;
823 }
824 
825 /** This function saves opencl kernels library to a file
826  *
827  * @param[in] filename Name of the file to be used to save the library
828  */
829 void save_program_cache_to_file(const std::string &filename = "cache.bin");
830 
831 /** This function loads prebuilt opencl kernels from a file
832  *
833  * @param[in] filename Name of the file to be used to load the kernels
834  */
835 void restore_program_cache_from_file(const std::string &filename = "cache.bin");
836 } // namespace utils
837 } // namespace arm_compute
838 #endif /* __UTILS_UTILS_H__*/
void save_to_ppm(T &tensor, const std::string &ppm_filename)
Template helper function to save a tensor image to a PPM file.
Definition: Utils.h:546
int run_example(int argc, char **argv, std::unique_ptr< Example > example)
Run an example and handle the potential exceptions it throws.
Definition: RunExample.cpp:96
uint64_t get_mem_free_from_meminfo()
This function returns the amount of memory free reading from /proc/meminfo.
Definition: Utils.cpp:248
Shape of a tensor.
Definition: TensorShape.h:39
quantized, symmetric fixed-point 16-bit number
bool is_fortran()
Return true if a NPY file is in fortran order.
Definition: Utils.h:365
#define ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(...)
Definition: Validate.h:543
SimpleTensor< float > b
Definition: DFT.cpp:157
Specialized class to generate random non-zero FP16 values.
Definition: Utils.h:293
void init_tensor(T &tensor, arm_compute::DataType dt)
Initialise the tensor's metadata with the dimensions of the NPY file currently open.
Definition: Utils.h:376
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
1 channel, 1 U8 per channel
#define ARM_COMPUTE_EXIT_ON_MSG_VAR(cond, msg,...)
If the condition is true, the given message is printed and program exits.
Definition: Error.h:395
void restore_program_cache_from_file(const std::string &filename)
This function loads prebuilt opencl kernels from a file.
Definition: Utils.cpp:282
std::string to_string(T &&value)
Convert integer and float values to string.
#define ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(t,...)
Definition: Validate.h:643
void fill_tensor(T &tensor)
Fill a tensor with the content of the currently open NPY file.
Definition: Utils.h:405
half_float::half half
16-bit floating point type
Definition: Types.h:45
1 channel, 1 F32 per channel
Strides PermutationVector
Permutation vector.
Definition: Types.h:48
#define ARM_COMPUTE_ERROR_VAR(msg,...)
Print the given message then throw an std::runtime_error.
Definition: Error.h:346
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
CLTensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: CLTensor.cpp:61
Describe one of the image's dimensions with a start, end and step.
Definition: Window.h:75
quantized, asymmetric fixed-point 16-bit number
1 channel, 1 U16 per channel
void save_program_cache_to_file(const std::string &filename)
This function saves opencl kernels library to a file.
Definition: Utils.cpp:328
void set(size_t dimension, T value)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:74
Interface for NEON tensor.
Definition: ITensor.h:36
void use_tensor_dimensions(const TensorShape &shape, size_t first_dimension=Window::DimX)
Use the tensor's dimensions to fill the window dimensions.
Definition: Window.inl:264
void init(const TensorInfo &input, size_t alignment=0)
Initialize a tensor based on the passed TensorInfo.
Copyright (c) 2017-2020 ARM Limited.
#define ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(...)
Definition: Validate.h:441
1 channel, 1 F16 per channel
void map(bool blocking=true)
Enqueue a map operation of the allocated buffer.
Definition: CLTensor.cpp:66
virtual void do_teardown()
Teardown the example.
Definition: Utils.h:92
void permute(Dimensions< T > &dimensions, const PermutationVector &perm)
Permutes given Dimensions according to a permutation vector.
Definition: Helpers.h:570
void unmap(T &tensor)
Unmaps a tensor if needed.
Definition: Utils.h:223
void fill_random_tensor(T &tensor, float lower_bound, float upper_bound)
Definition: Utils.h:728
1 channel, 1 S32 per channel
signed 64-bit number
3 channels, 1 U8 per channel
std::string get_typestring(DataType data_type)
Obtain numpy type string from DataType.
Definition: Utils.h:154
static constexpr size_t DimX
Alias for dimension 0 also known as X dimension.
Definition: Window.h:43
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
void save_to_npy(T &tensor, const std::string &npy_filename, bool fortran_order)
Template helper function to save a tensor image to a NPY file.
Definition: Utils.h:626
virtual void do_run()
Run the example.
Definition: Utils.h:90
1 channel, 1 U32 per channel
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
Numpy data loader.
Definition: Utils.h:327
quantized, asymmetric fixed-point 8-bit number unsigned
#define ARM_COMPUTE_ERROR_ON_MSG(cond, msg)
Definition: Error.h:456
NPYLoader()
Default constructor.
Definition: Utils.h:331
Coordinates of an item.
Definition: Coordinates.h:37
std::tuple< std::vector< unsigned long >, bool, std::string > parse_npy_header(std::ifstream &fs)
Parse the npy header from an input file stream.
Definition: Utils.cpp:227
Abstract Example class.
Definition: Utils.h:74
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor's metadata.
constexpr uint8_t * ptr() const
Return a pointer to the current pixel.
Definition: Helpers.inl:185
void set(size_t dimension, const Dimension &dim)
Set the values of a given dimension.
Definition: Window.inl:49
std::uniform_real_distribution< float > distribution(-5.f, 5.f)
bool is_open()
Return true if a NPY file is currently open.
Definition: Utils.h:359
1 channel, 1 S16 per channel
quantized, symmetric fixed-point 8-bit number
Num samples, channels, height, width.
#define ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:790
Strides of an item in bytes.
Definition: Strides.h:37
quantized, symmetric per channel fixed-point 8-bit number
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
virtual ~Example()=default
Default destructor.
void map(T &tensor, bool blocking)
Maps a tensor if needed.
Definition: Utils.h:212
Detection window used for the object detection.
Definition: Types.h:554
int compare_tensor(ITensor &tensor1, ITensor &tensor2, T tolerance)
Compare two tensors.
Definition: Utils.h:795
uint8_t qasymm8_t
8 bit quantized asymmetric scalar value
Num samples, height, width, channels.
void draw_detection_rectangle(ITensor *tensor, const DetectionWindow &rect, uint8_t r, uint8_t g, uint8_t b)
Draw a RGB rectangular window for the detected object.
Definition: Utils.cpp:124
ImageType
Supported image types.
Definition: Utils.h:63
void open(const std::string &npy_filename, DataLayout file_layout=DataLayout::NCHW)
Open a NPY file and reads its metadata.
Definition: Utils.h:341
half operator()(std::mt19937 &gen)
() operator to generate next value
Definition: Utils.h:316
std::tuple< unsigned int, unsigned int, int > parse_ppm_header(std::ifstream &fs)
Parse the ppm header from an input file stream.
Definition: Utils.cpp:196
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:78
Store the tensor's metadata.
Definition: TensorInfo.h:45
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:123
ImageType get_image_type_from_file(const std::string &filename)
Gets image type given a file.
Definition: Utils.cpp:161
uniform_real_distribution_fp16(half a=half(0.0), half b=half(1.0))
Constructor.
Definition: Utils.h:307
void load_trained_data(T &tensor, const std::string &filename)
Load the tensor with pre-trained data from a binary file.
Definition: Utils.h:681
64-bit floating-point number
Iterator updated by execute_window_loop for each window element.
Definition: Helpers.h:318
unsigned 64-bit number
DataType
Available data types.
Definition: Types.h:75
void init_sgemm_output(T &dst, T &src0, T &src1, arm_compute::DataType dt)
Definition: Utils.h:776
DataLayout
[DataLayout enum definition]
Definition: Types.h:117
signed 8-bit number
Describe a multidimensional execution window.
Definition: Window.h:39
virtual bool do_setup(int argc, char **argv)
Setup the example.
Definition: Utils.h:84
cast configure & src
Definition: Cast.cpp:169
#define ARM_COMPUTE_ERROR_ON_DATA_TYPE_NOT_IN(t,...)
Definition: Validate.h:692
Basic implementation of the OpenCL tensor interface.
Definition: CLTensor.h:41