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