blob: 2f2665f38162a22ed0afa1a604771305be56186e [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Georgios Pinitas587708b2018-12-31 15:43:52 +00002 * Copyright (c) 2017-2019 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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 __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__
25#define __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__
26
Anthony Barbier6ff3b192017-09-04 18:44:23 +010027#include "arm_compute/core/Coordinates.h"
28#include "arm_compute/core/Error.h"
29#include "arm_compute/core/Helpers.h"
30#include "arm_compute/core/TensorInfo.h"
31#include "arm_compute/core/TensorShape.h"
32#include "arm_compute/core/Types.h"
33#include "arm_compute/core/Window.h"
Georgios Pinitas587708b2018-12-31 15:43:52 +000034#include "arm_compute/core/utils/misc/Random.h"
SiCong Li86b53332017-08-23 11:02:43 +010035#include "libnpy/npy.hpp"
Moritz Pflanzere49e2662017-07-21 15:55:28 +010036#include "tests/RawTensor.h"
37#include "tests/TensorCache.h"
38#include "tests/Utils.h"
Anthony Barbierf6705ec2017-09-28 12:01:10 +010039#include "tests/framework/Exceptions.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010040
41#include <algorithm>
42#include <cstddef>
43#include <fstream>
44#include <random>
45#include <string>
46#include <type_traits>
SiCong Li86b53332017-08-23 11:02:43 +010047#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010048
49namespace arm_compute
50{
51namespace test
52{
53/** Factory class to create and fill tensors.
54 *
55 * Allows to initialise tensors from loaded images or by specifying the shape
56 * explicitly. Furthermore, provides methods to fill tensors with the content of
57 * loaded images or with random values.
58 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010059class AssetsLibrary final
Anthony Barbier6ff3b192017-09-04 18:44:23 +010060{
61public:
Georgios Pinitas587708b2018-12-31 15:43:52 +000062 using RangePair = std::pair<float, float>;
63
64public:
John Richardson70f946b2017-10-02 16:52:16 +010065 /** Initialises the library with a @p path to the assets directory.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010066 * Furthermore, sets the seed for the random generator to @p seed.
67 *
John Richardson70f946b2017-10-02 16:52:16 +010068 * @param[in] path Path to load assets from.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010069 * @param[in] seed Seed used to initialise the random number generator.
70 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010071 AssetsLibrary(std::string path, std::random_device::result_type seed);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010072
Alex Gildayc357c472018-03-21 13:54:09 +000073 /** Path to assets directory used to initialise library.
74 *
75 * @return the path to the assets directory.
76 */
John Richardson70f946b2017-10-02 16:52:16 +010077 std::string path() const;
78
Alex Gildayc357c472018-03-21 13:54:09 +000079 /** Seed that is used to fill tensors with random values.
80 *
81 * @return the initial random seed.
82 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010083 std::random_device::result_type seed() const;
84
Giorgio Arenafda46182017-06-16 13:57:33 +010085 /** Provides a tensor shape for the specified image.
86 *
87 * @param[in] name Image file used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +000088 *
89 * @return the tensor shape for the specified image.
Giorgio Arenafda46182017-06-16 13:57:33 +010090 */
91 TensorShape get_image_shape(const std::string &name);
92
Alex Gildayc357c472018-03-21 13:54:09 +000093 /** Provides a constant raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010094 *
95 * @param[in] name Image file used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +000096 *
97 * @return a raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010098 */
99 const RawTensor &get(const std::string &name) const;
100
101 /** Provides a raw tensor for the specified image.
102 *
103 * @param[in] name Image file used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000104 *
105 * @return a raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100106 */
107 RawTensor get(const std::string &name);
108
109 /** Creates an uninitialised raw tensor with the given @p data_type and @p
110 * num_channels. The shape is derived from the specified image.
111 *
112 * @param[in] name Image file used to initialise the tensor.
113 * @param[in] data_type Data type used to initialise the tensor.
114 * @param[in] num_channels Number of channels used to initialise the tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000115 *
116 * @return a raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100117 */
118 RawTensor get(const std::string &name, DataType data_type, int num_channels = 1) const;
119
120 /** Provides a contant raw tensor for the specified image after it has been
121 * converted to @p format.
122 *
123 * @param[in] name Image file used to look up the raw tensor.
124 * @param[in] format Format used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000125 *
126 * @return a raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100127 */
128 const RawTensor &get(const std::string &name, Format format) const;
129
130 /** Provides a raw tensor for the specified image after it has been
131 * converted to @p format.
132 *
133 * @param[in] name Image file used to look up the raw tensor.
134 * @param[in] format Format used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000135 *
136 * @return a raw tensor for the specified image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100137 */
138 RawTensor get(const std::string &name, Format format);
139
140 /** Provides a contant raw tensor for the specified channel after it has
141 * been extracted form the given image.
142 *
143 * @param[in] name Image file used to look up the raw tensor.
144 * @param[in] channel Channel used to look up the raw tensor.
145 *
146 * @note The channel has to be unambiguous so that the format can be
147 * inferred automatically.
Alex Gildayc357c472018-03-21 13:54:09 +0000148 *
149 * @return a raw tensor for the specified image channel.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100150 */
151 const RawTensor &get(const std::string &name, Channel channel) const;
152
153 /** Provides a raw tensor for the specified channel after it has been
154 * extracted form the given image.
155 *
156 * @param[in] name Image file used to look up the raw tensor.
157 * @param[in] channel Channel used to look up the raw tensor.
158 *
159 * @note The channel has to be unambiguous so that the format can be
160 * inferred automatically.
Alex Gildayc357c472018-03-21 13:54:09 +0000161 *
162 * @return a raw tensor for the specified image channel.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100163 */
164 RawTensor get(const std::string &name, Channel channel);
165
166 /** Provides a constant raw tensor for the specified channel after it has
167 * been extracted form the given image formatted to @p format.
168 *
169 * @param[in] name Image file used to look up the raw tensor.
170 * @param[in] format Format used to look up the raw tensor.
171 * @param[in] channel Channel used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000172 *
173 * @return a raw tensor for the specified image channel.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100174 */
175 const RawTensor &get(const std::string &name, Format format, Channel channel) const;
176
177 /** Provides a raw tensor for the specified channel after it has been
178 * extracted form the given image formatted to @p format.
179 *
180 * @param[in] name Image file used to look up the raw tensor.
181 * @param[in] format Format used to look up the raw tensor.
182 * @param[in] channel Channel used to look up the raw tensor.
Alex Gildayc357c472018-03-21 13:54:09 +0000183 *
184 * @return a raw tensor for the specified image channel.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100185 */
186 RawTensor get(const std::string &name, Format format, Channel channel);
187
Giorgio Arenaa2611812017-07-21 10:08:48 +0100188 /** Puts garbage values all around the tensor for testing purposes
189 *
190 * @param[in, out] tensor To be filled tensor.
191 * @param[in] distribution Distribution used to fill the tensor's surroundings.
192 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
193 */
194 template <typename T, typename D>
195 void fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
196
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100197 /** Fills the specified @p tensor with random values drawn from @p
198 * distribution.
199 *
200 * @param[in, out] tensor To be filled tensor.
201 * @param[in] distribution Distribution used to fill the tensor.
202 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
203 *
204 * @note The @p distribution has to provide operator(Generator &) which
205 * will be used to draw samples.
206 */
207 template <typename T, typename D>
208 void fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
209
Pablo Telloe96e4f02018-12-21 16:47:23 +0000210 template <typename T, typename D>
211 void fill_boxes(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
212
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100213 /** Fills the specified @p raw tensor with random values drawn from @p
214 * distribution.
215 *
216 * @param[in, out] raw To be filled raw.
217 * @param[in] distribution Distribution used to fill the tensor.
218 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
219 *
220 * @note The @p distribution has to provide operator(Generator &) which
221 * will be used to draw samples.
222 */
223 template <typename D>
224 void fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const;
225
226 /** Fills the specified @p tensor with the content of the specified image
227 * converted to the given format.
228 *
229 * @param[in, out] tensor To be filled tensor.
230 * @param[in] name Image file used to fill the tensor.
231 * @param[in] format Format of the image used to fill the tensor.
232 *
233 * @warning No check is performed that the specified format actually
234 * matches the format of the tensor.
235 */
236 template <typename T>
237 void fill(T &&tensor, const std::string &name, Format format) const;
238
239 /** Fills the raw tensor with the content of the specified image
240 * converted to the given format.
241 *
242 * @param[in, out] raw To be filled raw tensor.
243 * @param[in] name Image file used to fill the tensor.
244 * @param[in] format Format of the image used to fill the tensor.
245 *
246 * @warning No check is performed that the specified format actually
247 * matches the format of the tensor.
248 */
249 void fill(RawTensor &raw, const std::string &name, Format format) const;
250
251 /** Fills the specified @p tensor with the content of the specified channel
252 * extracted from the given image.
253 *
254 * @param[in, out] tensor To be filled tensor.
255 * @param[in] name Image file used to fill the tensor.
256 * @param[in] channel Channel of the image used to fill the tensor.
257 *
258 * @note The channel has to be unambiguous so that the format can be
259 * inferred automatically.
260 *
261 * @warning No check is performed that the specified format actually
262 * matches the format of the tensor.
263 */
264 template <typename T>
265 void fill(T &&tensor, const std::string &name, Channel channel) const;
266
267 /** Fills the raw tensor with the content of the specified channel
268 * extracted from the given image.
269 *
270 * @param[in, out] raw To be filled raw tensor.
271 * @param[in] name Image file used to fill the tensor.
272 * @param[in] channel Channel of the image used to fill the tensor.
273 *
274 * @note The channel has to be unambiguous so that the format can be
275 * inferred automatically.
276 *
277 * @warning No check is performed that the specified format actually
278 * matches the format of the tensor.
279 */
280 void fill(RawTensor &raw, const std::string &name, Channel channel) const;
281
282 /** Fills the specified @p tensor with the content of the specified channel
283 * extracted from the given image after it has been converted to the given
284 * format.
285 *
286 * @param[in, out] tensor To be filled tensor.
287 * @param[in] name Image file used to fill the tensor.
288 * @param[in] format Format of the image used to fill the tensor.
289 * @param[in] channel Channel of the image used to fill the tensor.
290 *
291 * @warning No check is performed that the specified format actually
292 * matches the format of the tensor.
293 */
294 template <typename T>
295 void fill(T &&tensor, const std::string &name, Format format, Channel channel) const;
296
297 /** Fills the raw tensor with the content of the specified channel
298 * extracted from the given image after it has been converted to the given
299 * format.
300 *
301 * @param[in, out] raw To be filled raw tensor.
302 * @param[in] name Image file used to fill the tensor.
303 * @param[in] format Format of the image used to fill the tensor.
304 * @param[in] channel Channel of the image used to fill the tensor.
305 *
306 * @warning No check is performed that the specified format actually
307 * matches the format of the tensor.
308 */
309 void fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const;
310
Alex Gilday345ab182018-01-09 11:40:19 +0000311 /** Fills the specified @p tensor with the content of the raw tensor.
312 *
313 * @param[in, out] tensor To be filled tensor.
314 * @param[in] raw Raw tensor used to fill the tensor.
315 *
316 * @warning No check is performed that the specified format actually
317 * matches the format of the tensor.
318 */
319 template <typename T>
320 void fill(T &&tensor, RawTensor raw) const;
321
Georgios Pinitas587708b2018-12-31 15:43:52 +0000322 /** Fill a tensor with uniform distribution
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100323 *
324 * @param[in, out] tensor To be filled tensor.
325 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
326 */
327 template <typename T>
328 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const;
329
Georgios Pinitas587708b2018-12-31 15:43:52 +0000330 /** Fill a tensor with uniform distribution
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100331 *
332 * @param[in, out] tensor To be filled tensor.
333 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
334 * @param[in] low lowest value in the range (inclusive)
335 * @param[in] high highest value in the range (inclusive)
336 *
337 * @note @p low and @p high must be of the same type as the data type of @p tensor
338 */
339 template <typename T, typename D>
340 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const;
341
Georgios Pinitas587708b2018-12-31 15:43:52 +0000342 /** Fill a tensor with uniform distribution across the specified range
343 *
344 * @param[in, out] tensor To be filled tensor.
345 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
346 * @param[in] excluded_range_pairs Ranges to exclude from the generator
347 */
348 template <typename T>
349 void fill_tensor_uniform_ranged(T &&tensor,
350 std::random_device::result_type seed_offset,
351 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const;
352
SiCong Li86b53332017-08-23 11:02:43 +0100353 /** Fills the specified @p tensor with data loaded from .npy (numpy binary) in specified path.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100354 *
355 * @param[in, out] tensor To be filled tensor.
356 * @param[in] name Data file.
SiCong Li86b53332017-08-23 11:02:43 +0100357 *
358 * @note The numpy array stored in the binary .npy file must be row-major in the sense that it
359 * must store elements within a row consecutively in the memory, then rows within a 2D slice,
360 * then 2D slices within a 3D slice and so on. Note that it imposes no restrictions on what
361 * indexing convention is used in the numpy array. That is, the numpy array can be either fortran
362 * style or C style as long as it adheres to the rule above.
363 *
364 * More concretely, the orders of dimensions for each style are as follows:
365 * C-style (numpy default):
366 * array[HigherDims..., Z, Y, X]
367 * Fortran style:
368 * array[X, Y, Z, HigherDims...]
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100369 */
370 template <typename T>
371 void fill_layer_data(T &&tensor, std::string name) const;
372
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000373 /** Fill a tensor with a constant value
374 *
375 * @param[in, out] tensor To be filled tensor.
376 * @param[in] value Value to be assigned to all elements of the input tensor.
377 *
378 * @note @p value must be of the same type as the data type of @p tensor
379 */
380 template <typename T, typename D>
381 void fill_tensor_value(T &&tensor, D value) const;
382
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100383private:
384 // Function prototype to convert between image formats.
385 using Converter = void (*)(const RawTensor &src, RawTensor &dst);
386 // Function prototype to extract a channel from an image.
387 using Extractor = void (*)(const RawTensor &src, RawTensor &dst);
388 // Function prototype to load an image file.
389 using Loader = RawTensor (*)(const std::string &path);
390
391 const Converter &get_converter(Format src, Format dst) const;
392 const Converter &get_converter(DataType src, Format dst) const;
393 const Converter &get_converter(Format src, DataType dst) const;
394 const Converter &get_converter(DataType src, DataType dst) const;
395 const Extractor &get_extractor(Format format, Channel) const;
396 const Loader &get_loader(const std::string &extension) const;
397
398 /** Creates a raw tensor from the specified image.
399 *
400 * @param[in] name To be loaded image file.
401 *
402 * @note If use_single_image is true @p name is ignored and the user image
403 * is loaded instead.
404 */
405 RawTensor load_image(const std::string &name) const;
406
407 /** Provides a raw tensor for the specified image and format.
408 *
409 * @param[in] name Image file used to look up the raw tensor.
410 * @param[in] format Format used to look up the raw tensor.
411 *
412 * If the tensor has already been requested before the cached version will
413 * be returned. Otherwise the tensor will be added to the cache.
414 *
415 * @note If use_single_image is true @p name is ignored and the user image
416 * is loaded instead.
417 */
418 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format) const;
419
420 /** Provides a raw tensor for the specified image, format and channel.
421 *
422 * @param[in] name Image file used to look up the raw tensor.
423 * @param[in] format Format used to look up the raw tensor.
424 * @param[in] channel Channel used to look up the raw tensor.
425 *
426 * If the tensor has already been requested before the cached version will
427 * be returned. Otherwise the tensor will be added to the cache.
428 *
429 * @note If use_single_image is true @p name is ignored and the user image
430 * is loaded instead.
431 */
432 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const;
433
434 mutable TensorCache _cache{};
Georgios Pinitas421405b2018-10-26 19:05:32 +0100435 mutable arm_compute::Mutex _format_lock{};
436 mutable arm_compute::Mutex _channel_lock{};
Anthony Barbierac69aa12017-07-03 17:39:37 +0100437 const std::string _library_path;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100438 std::random_device::result_type _seed;
439};
440
Georgios Pinitas587708b2018-12-31 15:43:52 +0000441namespace detail
442{
443template <typename T>
444inline std::vector<std::pair<T, T>> convert_range_pair(const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs)
445{
446 std::vector<std::pair<T, T>> converted;
447 std::transform(excluded_range_pairs.begin(),
448 excluded_range_pairs.end(),
449 std::back_inserter(converted),
450 [](const AssetsLibrary::RangePair & p)
451 {
452 return std::pair<T, T>(static_cast<T>(p.first), static_cast<T>(p.second));
453 });
454 return converted;
455}
456} // namespace detail
457
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100458template <typename T, typename D>
Giorgio Arenaa2611812017-07-21 10:08:48 +0100459void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
460{
461 const PaddingSize padding_size = tensor.padding();
462
463 Window window;
464 window.set(0, Window::Dimension(-padding_size.left, tensor.shape()[0] + padding_size.right, 1));
Gian Marco5420b282017-11-29 10:41:38 +0000465 if(tensor.shape().num_dimensions() > 1)
466 {
467 window.set(1, Window::Dimension(-padding_size.top, tensor.shape()[1] + padding_size.bottom, 1));
468 }
Giorgio Arenaa2611812017-07-21 10:08:48 +0100469
470 std::mt19937 gen(_seed);
471
472 execute_window_loop(window, [&](const Coordinates & id)
473 {
474 TensorShape shape = tensor.shape();
475
476 // If outside of valid region
477 if(id.x() < 0 || id.x() >= static_cast<int>(shape.x()) || id.y() < 0 || id.y() >= static_cast<int>(shape.y()))
478 {
479 using ResultType = typename std::remove_reference<D>::type::result_type;
480 const ResultType value = distribution(gen);
481 void *const out_ptr = tensor(id);
482 store_value_with_data_type(out_ptr, value, tensor.data_type());
483 }
484 });
485}
486
487template <typename T, typename D>
Pablo Telloe96e4f02018-12-21 16:47:23 +0000488void AssetsLibrary::fill_boxes(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
489{
490 using ResultType = typename std::remove_reference<D>::type::result_type;
491 std::mt19937 gen(_seed + seed_offset);
492 TensorShape shape(tensor.shape());
493 const int num_boxes = tensor.num_elements() / 4;
494 // Iterate over all elements
495 std::uniform_real_distribution<> size_dist(0.f, 1.f);
496 for(int element_idx = 0; element_idx < num_boxes * 4; element_idx += 4)
497 {
498 const ResultType delta = size_dist(gen);
499 const ResultType epsilon = size_dist(gen);
500 const ResultType left = distribution(gen);
501 const ResultType top = distribution(gen);
502 const ResultType right = left + delta;
503 const ResultType bottom = top + epsilon;
504 const std::tuple<ResultType, ResultType, ResultType, ResultType> box(left, top, right, bottom);
505 Coordinates x1 = index2coord(shape, element_idx);
506 Coordinates y1 = index2coord(shape, element_idx + 1);
507 Coordinates x2 = index2coord(shape, element_idx + 2);
508 Coordinates y2 = index2coord(shape, element_idx + 3);
509 ResultType &target_value_x1 = reinterpret_cast<ResultType *>(tensor(x1))[0];
510 ResultType &target_value_y1 = reinterpret_cast<ResultType *>(tensor(y1))[0];
511 ResultType &target_value_x2 = reinterpret_cast<ResultType *>(tensor(x2))[0];
512 ResultType &target_value_y2 = reinterpret_cast<ResultType *>(tensor(y2))[0];
513 store_value_with_data_type(&target_value_x1, std::get<0>(box), tensor.data_type());
514 store_value_with_data_type(&target_value_y1, std::get<1>(box), tensor.data_type());
515 store_value_with_data_type(&target_value_x2, std::get<2>(box), tensor.data_type());
516 store_value_with_data_type(&target_value_y2, std::get<3>(box), tensor.data_type());
517 }
518 fill_borders_with_garbage(tensor, distribution, seed_offset);
519}
520
521template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100522void AssetsLibrary::fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100523{
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100524 using ResultType = typename std::remove_reference<D>::type::result_type;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100525
526 std::mt19937 gen(_seed + seed_offset);
527
Giorgio Arena563494c2018-04-30 17:29:41 +0100528 const bool is_nhwc = tensor.data_layout() == DataLayout::NHWC;
529 TensorShape shape(tensor.shape());
530
531 if(is_nhwc)
532 {
533 // Ensure that the equivalent tensors will be filled for both data layouts
534 permute(shape, PermutationVector(1U, 2U, 0U));
535 }
536
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100537 // Iterate over all elements
538 for(int element_idx = 0; element_idx < tensor.num_elements(); ++element_idx)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100539 {
Giorgio Arena563494c2018-04-30 17:29:41 +0100540 Coordinates id = index2coord(shape, element_idx);
541
542 if(is_nhwc)
543 {
544 // Write in the correct id for permuted shapes
545 permute(id, PermutationVector(2U, 0U, 1U));
546 }
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100547
548 // Iterate over all channels
549 for(int channel = 0; channel < tensor.num_channels(); ++channel)
550 {
551 const ResultType value = distribution(gen);
Kohei Takahashicedb78f2018-08-23 10:23:52 +0900552 ResultType &target_value = reinterpret_cast<ResultType *>(tensor(id))[channel];
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100553
554 store_value_with_data_type(&target_value, value, tensor.data_type());
555 }
556 }
Giorgio Arenaa2611812017-07-21 10:08:48 +0100557
558 fill_borders_with_garbage(tensor, distribution, seed_offset);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100559}
560
561template <typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100562void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100563{
564 std::mt19937 gen(_seed + seed_offset);
565
566 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
567 {
568 using ResultType = typename std::remove_reference<D>::type::result_type;
569 const ResultType value = distribution(gen);
Georgios Pinitas587708b2018-12-31 15:43:52 +0000570
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100571 store_value_with_data_type(raw.data() + offset, value, raw.data_type());
572 }
573}
574
575template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100576void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100577{
578 const RawTensor &raw = get(name, format);
579
580 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
581 {
582 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
583
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100584 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
585 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100586 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
587 }
588}
589
590template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100591void AssetsLibrary::fill(T &&tensor, const std::string &name, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100592{
593 fill(std::forward<T>(tensor), name, get_format_for_channel(channel), channel);
594}
595
596template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100597void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100598{
599 const RawTensor &raw = get(name, format, channel);
600
601 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
602 {
603 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
604
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100605 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
606 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100607 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
608 }
609}
610
611template <typename T>
Alex Gilday345ab182018-01-09 11:40:19 +0000612void AssetsLibrary::fill(T &&tensor, RawTensor raw) const
613{
614 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
615 {
616 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
617
618 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
619 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
620 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
621 }
622}
623
624template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100625void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100626{
627 switch(tensor.data_type())
628 {
629 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000630 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100631 {
632 std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max());
633 fill(tensor, distribution_u8, seed_offset);
634 break;
635 }
636 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100637 case DataType::QSYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100638 {
639 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
640 fill(tensor, distribution_s8, seed_offset);
641 break;
642 }
643 case DataType::U16:
644 {
645 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
646 fill(tensor, distribution_u16, seed_offset);
647 break;
648 }
649 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100650 case DataType::QSYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100651 {
652 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
653 fill(tensor, distribution_s16, seed_offset);
654 break;
655 }
656 case DataType::U32:
657 {
658 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
659 fill(tensor, distribution_u32, seed_offset);
660 break;
661 }
662 case DataType::S32:
663 {
664 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
665 fill(tensor, distribution_s32, seed_offset);
666 break;
667 }
668 case DataType::U64:
669 {
670 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
671 fill(tensor, distribution_u64, seed_offset);
672 break;
673 }
674 case DataType::S64:
675 {
676 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
677 fill(tensor, distribution_s64, seed_offset);
678 break;
679 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100680 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100681 {
682 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
683 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
684 fill(tensor, distribution_f16, seed_offset);
685 break;
686 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100687 case DataType::F32:
688 {
689 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
690 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
691 fill(tensor, distribution_f32, seed_offset);
692 break;
693 }
694 case DataType::F64:
695 {
696 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
697 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
698 fill(tensor, distribution_f64, seed_offset);
699 break;
700 }
701 case DataType::SIZET:
702 {
703 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
704 fill(tensor, distribution_sizet, seed_offset);
705 break;
706 }
707 default:
708 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
709 }
710}
711
Georgios Pinitas587708b2018-12-31 15:43:52 +0000712template <typename T>
713void AssetsLibrary::fill_tensor_uniform_ranged(T &&tensor,
714 std::random_device::result_type seed_offset,
715 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const
716{
717 using namespace arm_compute::utils::random;
718
719 switch(tensor.data_type())
720 {
721 case DataType::U8:
722 case DataType::QASYMM8:
723 {
724 const auto converted_pairs = detail::convert_range_pair<uint8_t>(excluded_range_pairs);
725 RangedUniformDistribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(),
726 std::numeric_limits<uint8_t>::max(),
727 converted_pairs);
728 fill(tensor, distribution_u8, seed_offset);
729 break;
730 }
731 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100732 case DataType::QSYMM8:
Georgios Pinitas587708b2018-12-31 15:43:52 +0000733 {
734 const auto converted_pairs = detail::convert_range_pair<int8_t>(excluded_range_pairs);
735 RangedUniformDistribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(),
736 std::numeric_limits<int8_t>::max(),
737 converted_pairs);
738 fill(tensor, distribution_s8, seed_offset);
739 break;
740 }
741 case DataType::U16:
742 {
743 const auto converted_pairs = detail::convert_range_pair<uint16_t>(excluded_range_pairs);
744 RangedUniformDistribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(),
745 std::numeric_limits<uint16_t>::max(),
746 converted_pairs);
747 fill(tensor, distribution_u16, seed_offset);
748 break;
749 }
750 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100751 case DataType::QSYMM16:
Georgios Pinitas587708b2018-12-31 15:43:52 +0000752 {
753 const auto converted_pairs = detail::convert_range_pair<int16_t>(excluded_range_pairs);
754 RangedUniformDistribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(),
755 std::numeric_limits<int16_t>::max(),
756 converted_pairs);
757 fill(tensor, distribution_s16, seed_offset);
758 break;
759 }
760 case DataType::U32:
761 {
762 const auto converted_pairs = detail::convert_range_pair<uint32_t>(excluded_range_pairs);
763 RangedUniformDistribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(),
764 std::numeric_limits<uint32_t>::max(),
765 converted_pairs);
766 fill(tensor, distribution_u32, seed_offset);
767 break;
768 }
769 case DataType::S32:
770 {
771 const auto converted_pairs = detail::convert_range_pair<int32_t>(excluded_range_pairs);
772 RangedUniformDistribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(),
773 std::numeric_limits<int32_t>::max(),
774 converted_pairs);
775 fill(tensor, distribution_s32, seed_offset);
776 break;
777 }
778 case DataType::F16:
779 {
780 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
781 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
782 RangedUniformDistribution<float> distribution_f16(-100.f, 100.f, converted_pairs);
783 fill(tensor, distribution_f16, seed_offset);
784 break;
785 }
786 case DataType::F32:
787 {
788 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
789 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
790 RangedUniformDistribution<float> distribution_f32(-1000.f, 1000.f, converted_pairs);
791 fill(tensor, distribution_f32, seed_offset);
792 break;
793 }
794 default:
795 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
796 }
797}
798
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100799template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100800void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100801{
802 switch(tensor.data_type())
803 {
804 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000805 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100806 {
807 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
808 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
809 fill(tensor, distribution_u8, seed_offset);
810 break;
811 }
812 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100813 case DataType::QSYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100814 {
815 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
816 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
817 fill(tensor, distribution_s8, seed_offset);
818 break;
819 }
820 case DataType::U16:
821 {
822 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
823 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
824 fill(tensor, distribution_u16, seed_offset);
825 break;
826 }
827 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100828 case DataType::QSYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100829 {
830 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
831 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
832 fill(tensor, distribution_s16, seed_offset);
833 break;
834 }
835 case DataType::U32:
836 {
837 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
838 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
839 fill(tensor, distribution_u32, seed_offset);
840 break;
841 }
842 case DataType::S32:
843 {
844 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
845 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
846 fill(tensor, distribution_s32, seed_offset);
847 break;
848 }
849 case DataType::U64:
850 {
851 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
852 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
853 fill(tensor, distribution_u64, seed_offset);
854 break;
855 }
856 case DataType::S64:
857 {
858 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
859 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
860 fill(tensor, distribution_s64, seed_offset);
861 break;
862 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100863 case DataType::F16:
864 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100865 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100866 fill(tensor, distribution_f16, seed_offset);
867 break;
868 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100869 case DataType::F32:
870 {
871 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
872 std::uniform_real_distribution<float> distribution_f32(low, high);
873 fill(tensor, distribution_f32, seed_offset);
874 break;
875 }
876 case DataType::F64:
877 {
878 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
879 std::uniform_real_distribution<double> distribution_f64(low, high);
880 fill(tensor, distribution_f64, seed_offset);
881 break;
882 }
883 case DataType::SIZET:
884 {
885 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
886 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
887 fill(tensor, distribution_sizet, seed_offset);
888 break;
889 }
890 default:
891 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
892 }
893}
894
895template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100896void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100897{
898#ifdef _WIN32
899 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100900#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100901 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100902#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100903 const std::string path = _library_path + path_separator + name;
904
SiCong Li86b53332017-08-23 11:02:43 +0100905 std::vector<unsigned long> shape;
906
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100907 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100908 std::ifstream stream(path, std::ios::in | std::ios::binary);
Anthony Barbierf6705ec2017-09-28 12:01:10 +0100909 if(!stream.good())
910 {
911 throw framework::FileNotFound("Could not load npy file: " + path);
912 }
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000913 std::string header = npy::read_header(stream);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100914
SiCong Li86b53332017-08-23 11:02:43 +0100915 // Parse header
916 bool fortran_order = false;
917 std::string typestr;
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000918 npy::parse_header(header, typestr, fortran_order, shape);
SiCong Li86b53332017-08-23 11:02:43 +0100919
920 // Check if the typestring matches the given one
921 std::string expect_typestr = get_typestring(tensor.data_type());
922 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
923
924 // Validate tensor shape
925 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
926 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100927 {
SiCong Li86b53332017-08-23 11:02:43 +0100928 for(size_t i = 0; i < shape.size(); ++i)
929 {
930 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
931 }
932 }
933 else
934 {
935 for(size_t i = 0; i < shape.size(); ++i)
936 {
937 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
938 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100939 }
940
SiCong Li86b53332017-08-23 11:02:43 +0100941 // Read data
942 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100943 {
SiCong Li86b53332017-08-23 11:02:43 +0100944 // If tensor has no padding read directly from stream.
945 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
946 }
947 else
948 {
949 // If tensor has padding accessing tensor elements through execution window.
950 Window window;
951 window.use_tensor_dimensions(tensor.shape());
952
SiCong Li86b53332017-08-23 11:02:43 +0100953 execute_window_loop(window, [&](const Coordinates & id)
954 {
955 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
956 });
957 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100958}
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000959
960template <typename T, typename D>
961void AssetsLibrary::fill_tensor_value(T &&tensor, D value) const
962{
963 fill_tensor_uniform(tensor, 0, value, value);
964}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100965} // namespace test
966} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100967#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */