blob: 366c1450ba1be2d972f32fdee38f0dbf436af6ab [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:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100637 {
638 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
639 fill(tensor, distribution_s8, seed_offset);
640 break;
641 }
642 case DataType::U16:
643 {
644 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
645 fill(tensor, distribution_u16, seed_offset);
646 break;
647 }
648 case DataType::S16:
649 {
650 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
651 fill(tensor, distribution_s16, seed_offset);
652 break;
653 }
654 case DataType::U32:
655 {
656 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
657 fill(tensor, distribution_u32, seed_offset);
658 break;
659 }
660 case DataType::S32:
661 {
662 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
663 fill(tensor, distribution_s32, seed_offset);
664 break;
665 }
666 case DataType::U64:
667 {
668 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
669 fill(tensor, distribution_u64, seed_offset);
670 break;
671 }
672 case DataType::S64:
673 {
674 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
675 fill(tensor, distribution_s64, seed_offset);
676 break;
677 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100678 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100679 {
680 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
681 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
682 fill(tensor, distribution_f16, seed_offset);
683 break;
684 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100685 case DataType::F32:
686 {
687 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
688 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
689 fill(tensor, distribution_f32, seed_offset);
690 break;
691 }
692 case DataType::F64:
693 {
694 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
695 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
696 fill(tensor, distribution_f64, seed_offset);
697 break;
698 }
699 case DataType::SIZET:
700 {
701 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
702 fill(tensor, distribution_sizet, seed_offset);
703 break;
704 }
705 default:
706 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
707 }
708}
709
Georgios Pinitas587708b2018-12-31 15:43:52 +0000710template <typename T>
711void AssetsLibrary::fill_tensor_uniform_ranged(T &&tensor,
712 std::random_device::result_type seed_offset,
713 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const
714{
715 using namespace arm_compute::utils::random;
716
717 switch(tensor.data_type())
718 {
719 case DataType::U8:
720 case DataType::QASYMM8:
721 {
722 const auto converted_pairs = detail::convert_range_pair<uint8_t>(excluded_range_pairs);
723 RangedUniformDistribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(),
724 std::numeric_limits<uint8_t>::max(),
725 converted_pairs);
726 fill(tensor, distribution_u8, seed_offset);
727 break;
728 }
729 case DataType::S8:
730 {
731 const auto converted_pairs = detail::convert_range_pair<int8_t>(excluded_range_pairs);
732 RangedUniformDistribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(),
733 std::numeric_limits<int8_t>::max(),
734 converted_pairs);
735 fill(tensor, distribution_s8, seed_offset);
736 break;
737 }
738 case DataType::U16:
739 {
740 const auto converted_pairs = detail::convert_range_pair<uint16_t>(excluded_range_pairs);
741 RangedUniformDistribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(),
742 std::numeric_limits<uint16_t>::max(),
743 converted_pairs);
744 fill(tensor, distribution_u16, seed_offset);
745 break;
746 }
747 case DataType::S16:
748 {
749 const auto converted_pairs = detail::convert_range_pair<int16_t>(excluded_range_pairs);
750 RangedUniformDistribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(),
751 std::numeric_limits<int16_t>::max(),
752 converted_pairs);
753 fill(tensor, distribution_s16, seed_offset);
754 break;
755 }
756 case DataType::U32:
757 {
758 const auto converted_pairs = detail::convert_range_pair<uint32_t>(excluded_range_pairs);
759 RangedUniformDistribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(),
760 std::numeric_limits<uint32_t>::max(),
761 converted_pairs);
762 fill(tensor, distribution_u32, seed_offset);
763 break;
764 }
765 case DataType::S32:
766 {
767 const auto converted_pairs = detail::convert_range_pair<int32_t>(excluded_range_pairs);
768 RangedUniformDistribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(),
769 std::numeric_limits<int32_t>::max(),
770 converted_pairs);
771 fill(tensor, distribution_s32, seed_offset);
772 break;
773 }
774 case DataType::F16:
775 {
776 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
777 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
778 RangedUniformDistribution<float> distribution_f16(-100.f, 100.f, converted_pairs);
779 fill(tensor, distribution_f16, seed_offset);
780 break;
781 }
782 case DataType::F32:
783 {
784 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
785 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
786 RangedUniformDistribution<float> distribution_f32(-1000.f, 1000.f, converted_pairs);
787 fill(tensor, distribution_f32, seed_offset);
788 break;
789 }
790 default:
791 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
792 }
793}
794
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100795template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100796void 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 +0100797{
798 switch(tensor.data_type())
799 {
800 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000801 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100802 {
803 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
804 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
805 fill(tensor, distribution_u8, seed_offset);
806 break;
807 }
808 case DataType::S8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100809 {
810 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
811 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
812 fill(tensor, distribution_s8, seed_offset);
813 break;
814 }
815 case DataType::U16:
816 {
817 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
818 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
819 fill(tensor, distribution_u16, seed_offset);
820 break;
821 }
822 case DataType::S16:
823 {
824 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
825 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
826 fill(tensor, distribution_s16, seed_offset);
827 break;
828 }
829 case DataType::U32:
830 {
831 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
832 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
833 fill(tensor, distribution_u32, seed_offset);
834 break;
835 }
836 case DataType::S32:
837 {
838 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
839 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
840 fill(tensor, distribution_s32, seed_offset);
841 break;
842 }
843 case DataType::U64:
844 {
845 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
846 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
847 fill(tensor, distribution_u64, seed_offset);
848 break;
849 }
850 case DataType::S64:
851 {
852 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
853 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
854 fill(tensor, distribution_s64, seed_offset);
855 break;
856 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100857 case DataType::F16:
858 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100859 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100860 fill(tensor, distribution_f16, seed_offset);
861 break;
862 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100863 case DataType::F32:
864 {
865 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
866 std::uniform_real_distribution<float> distribution_f32(low, high);
867 fill(tensor, distribution_f32, seed_offset);
868 break;
869 }
870 case DataType::F64:
871 {
872 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
873 std::uniform_real_distribution<double> distribution_f64(low, high);
874 fill(tensor, distribution_f64, seed_offset);
875 break;
876 }
877 case DataType::SIZET:
878 {
879 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
880 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
881 fill(tensor, distribution_sizet, seed_offset);
882 break;
883 }
884 default:
885 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
886 }
887}
888
889template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100890void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100891{
892#ifdef _WIN32
893 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100894#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100895 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100896#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100897 const std::string path = _library_path + path_separator + name;
898
SiCong Li86b53332017-08-23 11:02:43 +0100899 std::vector<unsigned long> shape;
900
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100901 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100902 std::ifstream stream(path, std::ios::in | std::ios::binary);
Anthony Barbierf6705ec2017-09-28 12:01:10 +0100903 if(!stream.good())
904 {
905 throw framework::FileNotFound("Could not load npy file: " + path);
906 }
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000907 std::string header = npy::read_header(stream);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100908
SiCong Li86b53332017-08-23 11:02:43 +0100909 // Parse header
910 bool fortran_order = false;
911 std::string typestr;
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000912 npy::parse_header(header, typestr, fortran_order, shape);
SiCong Li86b53332017-08-23 11:02:43 +0100913
914 // Check if the typestring matches the given one
915 std::string expect_typestr = get_typestring(tensor.data_type());
916 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
917
918 // Validate tensor shape
919 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
920 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100921 {
SiCong Li86b53332017-08-23 11:02:43 +0100922 for(size_t i = 0; i < shape.size(); ++i)
923 {
924 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
925 }
926 }
927 else
928 {
929 for(size_t i = 0; i < shape.size(); ++i)
930 {
931 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
932 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100933 }
934
SiCong Li86b53332017-08-23 11:02:43 +0100935 // Read data
936 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100937 {
SiCong Li86b53332017-08-23 11:02:43 +0100938 // If tensor has no padding read directly from stream.
939 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
940 }
941 else
942 {
943 // If tensor has padding accessing tensor elements through execution window.
944 Window window;
945 window.use_tensor_dimensions(tensor.shape());
946
SiCong Li86b53332017-08-23 11:02:43 +0100947 execute_window_loop(window, [&](const Coordinates & id)
948 {
949 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
950 });
951 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100952}
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000953
954template <typename T, typename D>
955void AssetsLibrary::fill_tensor_value(T &&tensor, D value) const
956{
957 fill_tensor_uniform(tensor, 0, value, value);
958}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100959} // namespace test
960} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100961#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */