blob: 2ac13468de2ff2b724771d7efde3797c26180aee [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:
Michalis Spyrou29a01c92019-08-22 11:44:04 +0100631 case DataType::QASYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100632 {
633 std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max());
634 fill(tensor, distribution_u8, seed_offset);
635 break;
636 }
637 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100638 case DataType::QSYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100639 {
640 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
641 fill(tensor, distribution_s8, seed_offset);
642 break;
643 }
644 case DataType::U16:
645 {
646 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
647 fill(tensor, distribution_u16, seed_offset);
648 break;
649 }
650 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100651 case DataType::QSYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100652 {
653 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
654 fill(tensor, distribution_s16, seed_offset);
655 break;
656 }
657 case DataType::U32:
658 {
659 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
660 fill(tensor, distribution_u32, seed_offset);
661 break;
662 }
663 case DataType::S32:
664 {
665 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
666 fill(tensor, distribution_s32, seed_offset);
667 break;
668 }
669 case DataType::U64:
670 {
671 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
672 fill(tensor, distribution_u64, seed_offset);
673 break;
674 }
675 case DataType::S64:
676 {
677 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
678 fill(tensor, distribution_s64, seed_offset);
679 break;
680 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100681 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100682 {
683 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
684 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
685 fill(tensor, distribution_f16, seed_offset);
686 break;
687 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100688 case DataType::F32:
689 {
690 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
691 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
692 fill(tensor, distribution_f32, seed_offset);
693 break;
694 }
695 case DataType::F64:
696 {
697 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
698 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
699 fill(tensor, distribution_f64, seed_offset);
700 break;
701 }
702 case DataType::SIZET:
703 {
704 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
705 fill(tensor, distribution_sizet, seed_offset);
706 break;
707 }
708 default:
709 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
710 }
711}
712
Georgios Pinitas587708b2018-12-31 15:43:52 +0000713template <typename T>
714void AssetsLibrary::fill_tensor_uniform_ranged(T &&tensor,
715 std::random_device::result_type seed_offset,
716 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const
717{
718 using namespace arm_compute::utils::random;
719
720 switch(tensor.data_type())
721 {
722 case DataType::U8:
723 case DataType::QASYMM8:
724 {
725 const auto converted_pairs = detail::convert_range_pair<uint8_t>(excluded_range_pairs);
726 RangedUniformDistribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(),
727 std::numeric_limits<uint8_t>::max(),
728 converted_pairs);
729 fill(tensor, distribution_u8, seed_offset);
730 break;
731 }
732 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100733 case DataType::QSYMM8:
Georgios Pinitas587708b2018-12-31 15:43:52 +0000734 {
735 const auto converted_pairs = detail::convert_range_pair<int8_t>(excluded_range_pairs);
736 RangedUniformDistribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(),
737 std::numeric_limits<int8_t>::max(),
738 converted_pairs);
739 fill(tensor, distribution_s8, seed_offset);
740 break;
741 }
742 case DataType::U16:
743 {
744 const auto converted_pairs = detail::convert_range_pair<uint16_t>(excluded_range_pairs);
745 RangedUniformDistribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(),
746 std::numeric_limits<uint16_t>::max(),
747 converted_pairs);
748 fill(tensor, distribution_u16, seed_offset);
749 break;
750 }
751 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100752 case DataType::QSYMM16:
Georgios Pinitas587708b2018-12-31 15:43:52 +0000753 {
754 const auto converted_pairs = detail::convert_range_pair<int16_t>(excluded_range_pairs);
755 RangedUniformDistribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(),
756 std::numeric_limits<int16_t>::max(),
757 converted_pairs);
758 fill(tensor, distribution_s16, seed_offset);
759 break;
760 }
761 case DataType::U32:
762 {
763 const auto converted_pairs = detail::convert_range_pair<uint32_t>(excluded_range_pairs);
764 RangedUniformDistribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(),
765 std::numeric_limits<uint32_t>::max(),
766 converted_pairs);
767 fill(tensor, distribution_u32, seed_offset);
768 break;
769 }
770 case DataType::S32:
771 {
772 const auto converted_pairs = detail::convert_range_pair<int32_t>(excluded_range_pairs);
773 RangedUniformDistribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(),
774 std::numeric_limits<int32_t>::max(),
775 converted_pairs);
776 fill(tensor, distribution_s32, seed_offset);
777 break;
778 }
779 case DataType::F16:
780 {
781 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
782 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
783 RangedUniformDistribution<float> distribution_f16(-100.f, 100.f, converted_pairs);
784 fill(tensor, distribution_f16, seed_offset);
785 break;
786 }
787 case DataType::F32:
788 {
789 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
790 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
791 RangedUniformDistribution<float> distribution_f32(-1000.f, 1000.f, converted_pairs);
792 fill(tensor, distribution_f32, seed_offset);
793 break;
794 }
795 default:
796 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
797 }
798}
799
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100800template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100801void 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 +0100802{
803 switch(tensor.data_type())
804 {
805 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000806 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100807 {
808 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
809 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
810 fill(tensor, distribution_u8, seed_offset);
811 break;
812 }
813 case DataType::S8:
Georgios Pinitas3d13af82019-06-04 13:04:16 +0100814 case DataType::QSYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100815 {
816 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
817 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
818 fill(tensor, distribution_s8, seed_offset);
819 break;
820 }
821 case DataType::U16:
822 {
823 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
824 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
825 fill(tensor, distribution_u16, seed_offset);
826 break;
827 }
828 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100829 case DataType::QSYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100830 {
831 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
832 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
833 fill(tensor, distribution_s16, seed_offset);
834 break;
835 }
836 case DataType::U32:
837 {
838 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
839 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
840 fill(tensor, distribution_u32, seed_offset);
841 break;
842 }
843 case DataType::S32:
844 {
845 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
846 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
847 fill(tensor, distribution_s32, seed_offset);
848 break;
849 }
850 case DataType::U64:
851 {
852 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
853 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
854 fill(tensor, distribution_u64, seed_offset);
855 break;
856 }
857 case DataType::S64:
858 {
859 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
860 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
861 fill(tensor, distribution_s64, seed_offset);
862 break;
863 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100864 case DataType::F16:
865 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100866 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100867 fill(tensor, distribution_f16, seed_offset);
868 break;
869 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100870 case DataType::F32:
871 {
872 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
873 std::uniform_real_distribution<float> distribution_f32(low, high);
874 fill(tensor, distribution_f32, seed_offset);
875 break;
876 }
877 case DataType::F64:
878 {
879 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
880 std::uniform_real_distribution<double> distribution_f64(low, high);
881 fill(tensor, distribution_f64, seed_offset);
882 break;
883 }
884 case DataType::SIZET:
885 {
886 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
887 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
888 fill(tensor, distribution_sizet, seed_offset);
889 break;
890 }
891 default:
892 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
893 }
894}
895
896template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100897void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100898{
899#ifdef _WIN32
900 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100901#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100902 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100903#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100904 const std::string path = _library_path + path_separator + name;
905
SiCong Li86b53332017-08-23 11:02:43 +0100906 std::vector<unsigned long> shape;
907
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100908 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100909 std::ifstream stream(path, std::ios::in | std::ios::binary);
Anthony Barbierf6705ec2017-09-28 12:01:10 +0100910 if(!stream.good())
911 {
912 throw framework::FileNotFound("Could not load npy file: " + path);
913 }
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000914 std::string header = npy::read_header(stream);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100915
SiCong Li86b53332017-08-23 11:02:43 +0100916 // Parse header
917 bool fortran_order = false;
918 std::string typestr;
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000919 npy::parse_header(header, typestr, fortran_order, shape);
SiCong Li86b53332017-08-23 11:02:43 +0100920
921 // Check if the typestring matches the given one
922 std::string expect_typestr = get_typestring(tensor.data_type());
923 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
924
925 // Validate tensor shape
926 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
927 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100928 {
SiCong Li86b53332017-08-23 11:02:43 +0100929 for(size_t i = 0; i < shape.size(); ++i)
930 {
931 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
932 }
933 }
934 else
935 {
936 for(size_t i = 0; i < shape.size(); ++i)
937 {
938 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
939 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100940 }
941
SiCong Li86b53332017-08-23 11:02:43 +0100942 // Read data
943 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100944 {
SiCong Li86b53332017-08-23 11:02:43 +0100945 // If tensor has no padding read directly from stream.
946 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
947 }
948 else
949 {
950 // If tensor has padding accessing tensor elements through execution window.
951 Window window;
952 window.use_tensor_dimensions(tensor.shape());
953
SiCong Li86b53332017-08-23 11:02:43 +0100954 execute_window_loop(window, [&](const Coordinates & id)
955 {
956 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
957 });
958 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100959}
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000960
961template <typename T, typename D>
962void AssetsLibrary::fill_tensor_value(T &&tensor, D value) const
963{
964 fill_tensor_uniform(tensor, 0, value, value);
965}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100966} // namespace test
967} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100968#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */