Compute Library
 20.05
Utils.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2020 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
38 #include "support/MemorySupport.h"
39 #include "support/StringSupport.h"
40 
41 #ifdef ARM_COMPUTE_CL
45 #endif /* ARM_COMPUTE_CL */
46 #ifdef ARM_COMPUTE_GC
48 #endif /* ARM_COMPUTE_GC */
49 
50 #include <cstdlib>
51 #include <cstring>
52 #include <fstream>
53 #include <iostream>
54 #include <random>
55 #include <string>
56 #include <tuple>
57 #include <vector>
58 
59 namespace arm_compute
60 {
61 namespace utils
62 {
63 /** Supported image types */
64 enum class ImageType
65 {
66  UNKNOWN,
67  PPM,
68  JPEG
69 };
70 
71 /** Abstract Example class.
72  *
73  * All examples have to inherit from this class.
74  */
75 class Example
76 {
77 public:
78  /** Setup the example.
79  *
80  * @param[in] argc Argument count.
81  * @param[in] argv Argument values.
82  *
83  * @return True in case of no errors in setup else false
84  */
85  virtual bool do_setup(int argc, char **argv)
86  {
87  ARM_COMPUTE_UNUSED(argc, argv);
88  return true;
89  };
90  /** Run the example. */
91  virtual void do_run() {};
92  /** Teardown the example. */
93  virtual void do_teardown() {};
94 
95  /** Default destructor. */
96  virtual ~Example() = default;
97 };
98 
99 /** Run an example and handle the potential exceptions it throws
100  *
101  * @param[in] argc Number of command line arguments
102  * @param[in] argv Command line arguments
103  * @param[in] example Example to run
104  */
105 int run_example(int argc, char **argv, std::unique_ptr<Example> example);
106 
107 template <typename T>
108 int run_example(int argc, char **argv)
109 {
110  return run_example(argc, argv, support::cpp14::make_unique<T>());
111 }
112 
113 /** Draw a RGB rectangular window for the detected object
114  *
115  * @param[in, out] tensor Input tensor where the rectangle will be drawn on. Format supported: RGB888
116  * @param[in] rect Geometry of the rectangular window
117  * @param[in] r Red colour to use
118  * @param[in] g Green colour to use
119  * @param[in] b Blue colour to use
120  */
121 void draw_detection_rectangle(arm_compute::ITensor *tensor, const arm_compute::DetectionWindow &rect, uint8_t r, uint8_t g, uint8_t b);
122 
123 /** Gets image type given a file
124  *
125  * @param[in] filename File to identify its image type
126  *
127  * @return Image type
128  */
129 ImageType get_image_type_from_file(const std::string &filename);
130 
131 /** Parse the ppm header from an input file stream. At the end of the execution,
132  * the file position pointer will be located at the first pixel stored in the ppm file
133  *
134  * @param[in] fs Input file stream to parse
135  *
136  * @return The width, height and max value stored in the header of the PPM file
137  */
138 std::tuple<unsigned int, unsigned int, int> parse_ppm_header(std::ifstream &fs);
139 
140 /** Parse the npy header from an input file stream. At the end of the execution,
141  * the file position pointer will be located at the first pixel stored in the npy file //TODO
142  *
143  * @param[in] fs Input file stream to parse
144  *
145  * @return The width and height stored in the header of the NPY file
146  */
147 std::tuple<std::vector<unsigned long>, bool, std::string> parse_npy_header(std::ifstream &fs);
148 
149 /** Obtain numpy type string from DataType.
150  *
151  * @param[in] data_type Data type.
152  *
153  * @return numpy type string.
154  */
155 inline std::string get_typestring(DataType data_type)
156 {
157  // Check endianness
158  const unsigned int i = 1;
159  const char *c = reinterpret_cast<const char *>(&i);
160  std::string endianness;
161  if(*c == 1)
162  {
163  endianness = std::string("<");
164  }
165  else
166  {
167  endianness = std::string(">");
168  }
169  const std::string no_endianness("|");
170 
171  switch(data_type)
172  {
173  case DataType::U8:
174  case DataType::QASYMM8:
175  return no_endianness + "u" + support::cpp11::to_string(sizeof(uint8_t));
176  case DataType::S8:
177  case DataType::QSYMM8:
179  return no_endianness + "i" + support::cpp11::to_string(sizeof(int8_t));
180  case DataType::U16:
181  case DataType::QASYMM16:
182  return endianness + "u" + support::cpp11::to_string(sizeof(uint16_t));
183  case DataType::S16:
184  case DataType::QSYMM16:
185  return endianness + "i" + support::cpp11::to_string(sizeof(int16_t));
186  case DataType::U32:
187  return endianness + "u" + support::cpp11::to_string(sizeof(uint32_t));
188  case DataType::S32:
189  return endianness + "i" + support::cpp11::to_string(sizeof(int32_t));
190  case DataType::U64:
191  return endianness + "u" + support::cpp11::to_string(sizeof(uint64_t));
192  case DataType::S64:
193  return endianness + "i" + support::cpp11::to_string(sizeof(int64_t));
194  case DataType::F16:
195  return endianness + "f" + support::cpp11::to_string(sizeof(half));
196  case DataType::F32:
197  return endianness + "f" + support::cpp11::to_string(sizeof(float));
198  case DataType::F64:
199  return endianness + "f" + support::cpp11::to_string(sizeof(double));
200  case DataType::SIZET:
201  return endianness + "u" + support::cpp11::to_string(sizeof(size_t));
202  default:
203  ARM_COMPUTE_ERROR("Data type not supported");
204  }
205 }
206 
207 /** Maps a tensor if needed
208  *
209  * @param[in] tensor Tensor to be mapped
210  * @param[in] blocking Specified if map is blocking or not
211  */
212 template <typename T>
213 inline void map(T &tensor, bool blocking)
214 {
215  ARM_COMPUTE_UNUSED(tensor);
216  ARM_COMPUTE_UNUSED(blocking);
217 }
218 
219 /** Unmaps a tensor if needed
220  *
221  * @param tensor Tensor to be unmapped
222  */
223 template <typename T>
224 inline void unmap(T &tensor)
225 {
226  ARM_COMPUTE_UNUSED(tensor);
227 }
228 
229 #ifdef ARM_COMPUTE_CL
230 /** Maps a tensor if needed
231  *
232  * @param[in] tensor Tensor to be mapped
233  * @param[in] blocking Specified if map is blocking or not
234  */
235 inline void map(CLTensor &tensor, bool blocking)
236 {
237  tensor.map(blocking);
238 }
239 
240 /** Unmaps a tensor if needed
241  *
242  * @param tensor Tensor to be unmapped
243  */
244 inline void unmap(CLTensor &tensor)
245 {
246  tensor.unmap();
247 }
248 
249 /** Maps a distribution if needed
250  *
251  * @param[in] distribution Distribution to be mapped
252  * @param[in] blocking Specified if map is blocking or not
253  */
254 inline void map(CLDistribution1D &distribution, bool blocking)
255 {
256  distribution.map(blocking);
257 }
258 
259 /** Unmaps a distribution if needed
260  *
261  * @param distribution Distribution to be unmapped
262  */
263 inline void unmap(CLDistribution1D &distribution)
264 {
265  distribution.unmap();
266 }
267 #endif /* ARM_COMPUTE_CL */
268 
269 #ifdef ARM_COMPUTE_GC
270 /** Maps a tensor if needed
271  *
272  * @param[in] tensor Tensor to be mapped
273  * @param[in] blocking Specified if map is blocking or not
274  */
275 inline void map(GCTensor &tensor, bool blocking)
276 {
277  tensor.map(blocking);
278 }
279 
280 /** Unmaps a tensor if needed
281  *
282  * @param tensor Tensor to be unmapped
283  */
284 inline void unmap(GCTensor &tensor)
285 {
286  tensor.unmap();
287 }
288 #endif /* ARM_COMPUTE_GC */
289 
290 /** Specialized class to generate random non-zero FP16 values.
291  * uniform_real_distribution<half> generates values that get rounded off to zero, causing
292  * differences between ACL and reference implementation
293 */
295 {
296  half min{ 0.0f }, max{ 0.0f };
297  std::uniform_real_distribution<float> neg{ min, -0.3f };
298  std::uniform_real_distribution<float> pos{ 0.3f, max };
299  std::uniform_int_distribution<uint8_t> sign_picker{ 0, 1 };
300 
301 public:
302  using result_type = half;
303  /** Constructor
304  *
305  * @param[in] a Minimum value of the distribution
306  * @param[in] b Maximum value of the distribution
307  */
308  explicit uniform_real_distribution_fp16(half a = half(0.0), half b = half(1.0))
309  : min(a), max(b)
310  {
311  }
312 
313  /** () operator to generate next value
314  *
315  * @param[in] gen an uniform random bit generator object
316  */
317  half operator()(std::mt19937 &gen)
318  {
319  if(sign_picker(gen))
320  {
321  return (half)neg(gen);
322  }
323  return (half)pos(gen);
324  }
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  {
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>
377  void init_tensor(T &tensor, arm_compute::DataType dt)
378  {
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  {
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>
729 void fill_random_tensor(T &tensor, float lower_bound, float upper_bound)
730 {
731  std::random_device rd;
732  std::mt19937 gen(rd());
733 
734  Window window;
735  window.use_tensor_dimensions(tensor.info()->tensor_shape());
736 
737  map(tensor, true);
738 
739  Iterator it(&tensor, window);
740 
741  switch(tensor.info()->data_type())
742  {
744  {
745  std::uniform_real_distribution<float> dist(lower_bound, upper_bound);
746 
747  execute_window_loop(window, [&](const Coordinates &)
748  {
749  *reinterpret_cast<half *>(it.ptr()) = (half)dist(gen);
750  },
751  it);
752 
753  break;
754  }
756  {
757  std::uniform_real_distribution<float> dist(lower_bound, upper_bound);
758 
759  execute_window_loop(window, [&](const Coordinates &)
760  {
761  *reinterpret_cast<float *>(it.ptr()) = dist(gen);
762  },
763  it);
764 
765  break;
766  }
767  default:
768  {
769  ARM_COMPUTE_ERROR("Unsupported format");
770  }
771  }
772 
773  unmap(tensor);
774 }
775 
776 template <typename T>
777 void init_sgemm_output(T &dst, T &src0, T &src1, arm_compute::DataType dt)
778 {
779  dst.allocator()->init(TensorInfo(TensorShape(src1.info()->dimension(0), src0.info()->dimension(1), src0.info()->dimension(2)), 1, dt));
780 }
781 /** This function returns the amount of memory free reading from /proc/meminfo
782  *
783  * @return The free memory in kB
784  */
785 uint64_t get_mem_free_from_meminfo();
786 
787 /** Compare two tensors
788  *
789  * @param[in] tensor1 First tensor to be compared.
790  * @param[in] tensor2 Second tensor to be compared.
791  * @param[in] tolerance Tolerance used for the comparison.
792  *
793  * @return The number of mismatches
794  */
795 template <typename T>
796 int compare_tensor(ITensor &tensor1, ITensor &tensor2, T tolerance)
797 {
799  ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(&tensor1, &tensor2);
800 
801  int num_mismatches = 0;
802  Window window;
803  window.use_tensor_dimensions(tensor1.info()->tensor_shape());
804 
805  map(tensor1, true);
806  map(tensor2, true);
807 
808  Iterator itensor1(&tensor1, window);
809  Iterator itensor2(&tensor2, window);
810 
811  execute_window_loop(window, [&](const Coordinates &)
812  {
813  if(std::abs(*reinterpret_cast<T *>(itensor1.ptr()) - *reinterpret_cast<T *>(itensor2.ptr())) > tolerance)
814  {
815  ++num_mismatches;
816  }
817  },
818  itensor1, itensor2);
819 
820  unmap(itensor1);
821  unmap(itensor2);
822 
823  return num_mismatches;
824 }
825 } // namespace utils
826 } // namespace arm_compute
827 #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: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: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:366
#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:294
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:377
#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
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: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
#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 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:276
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:93
void permute(Dimensions< T > &dimensions, const PermutationVector &perm)
Permutes given Dimensions according to a permutation vector.
Definition: Helpers.h:605
void unmap(T &tensor)
Unmaps a tensor if needed.
Definition: Utils.h:224
void fill_random_tensor(T &tensor, float lower_bound, float upper_bound)
Definition: Utils.h:729
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:155
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:91
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: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
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:75
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: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
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:213
Detection window used for the object detection.
Definition: Types.h:557
int compare_tensor(ITensor &tensor1, ITensor &tensor2, T tolerance)
Compare two tensors.
Definition: Utils.h:796
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: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
half operator()(std::mt19937 &gen)
() operator to generate next value
Definition: Utils.h:317
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:308
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:353
unsigned 64-bit number
DataType
Available data types.
Definition: Types.h:77
void init_sgemm_output(T &dst, T &src0, T &src1, arm_compute::DataType dt)
Definition: Utils.h:777
DataLayout
[DataLayout enum definition]
Definition: Types.h:120
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:85
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