blob: d09e22762d4ed10145fe9587e6da9b6157fd7e51 [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
210 /** Fills the specified @p raw tensor with random values drawn from @p
211 * distribution.
212 *
213 * @param[in, out] raw To be filled raw.
214 * @param[in] distribution Distribution used to fill the tensor.
215 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
216 *
217 * @note The @p distribution has to provide operator(Generator &) which
218 * will be used to draw samples.
219 */
220 template <typename D>
221 void fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const;
222
223 /** Fills the specified @p tensor with the content of the specified image
224 * converted to the given format.
225 *
226 * @param[in, out] tensor To be filled tensor.
227 * @param[in] name Image file used to fill the tensor.
228 * @param[in] format Format of the image used to fill the tensor.
229 *
230 * @warning No check is performed that the specified format actually
231 * matches the format of the tensor.
232 */
233 template <typename T>
234 void fill(T &&tensor, const std::string &name, Format format) const;
235
236 /** Fills the raw tensor with the content of the specified image
237 * converted to the given format.
238 *
239 * @param[in, out] raw To be filled raw tensor.
240 * @param[in] name Image file used to fill the tensor.
241 * @param[in] format Format of the image used to fill the tensor.
242 *
243 * @warning No check is performed that the specified format actually
244 * matches the format of the tensor.
245 */
246 void fill(RawTensor &raw, const std::string &name, Format format) const;
247
248 /** Fills the specified @p tensor with the content of the specified channel
249 * extracted from the given image.
250 *
251 * @param[in, out] tensor To be filled tensor.
252 * @param[in] name Image file used to fill the tensor.
253 * @param[in] channel Channel of the image used to fill the tensor.
254 *
255 * @note The channel has to be unambiguous so that the format can be
256 * inferred automatically.
257 *
258 * @warning No check is performed that the specified format actually
259 * matches the format of the tensor.
260 */
261 template <typename T>
262 void fill(T &&tensor, const std::string &name, Channel channel) const;
263
264 /** Fills the raw tensor with the content of the specified channel
265 * extracted from the given image.
266 *
267 * @param[in, out] raw To be filled raw tensor.
268 * @param[in] name Image file used to fill the tensor.
269 * @param[in] channel Channel of the image used to fill the tensor.
270 *
271 * @note The channel has to be unambiguous so that the format can be
272 * inferred automatically.
273 *
274 * @warning No check is performed that the specified format actually
275 * matches the format of the tensor.
276 */
277 void fill(RawTensor &raw, const std::string &name, Channel channel) const;
278
279 /** Fills the specified @p tensor with the content of the specified channel
280 * extracted from the given image after it has been converted to the given
281 * format.
282 *
283 * @param[in, out] tensor To be filled tensor.
284 * @param[in] name Image file used to fill the tensor.
285 * @param[in] format Format of the image used to fill the tensor.
286 * @param[in] channel Channel of the image used to fill the tensor.
287 *
288 * @warning No check is performed that the specified format actually
289 * matches the format of the tensor.
290 */
291 template <typename T>
292 void fill(T &&tensor, const std::string &name, Format format, Channel channel) const;
293
294 /** Fills the raw tensor with the content of the specified channel
295 * extracted from the given image after it has been converted to the given
296 * format.
297 *
298 * @param[in, out] raw To be filled raw tensor.
299 * @param[in] name Image file used to fill the tensor.
300 * @param[in] format Format of the image used to fill the tensor.
301 * @param[in] channel Channel of the image used to fill the tensor.
302 *
303 * @warning No check is performed that the specified format actually
304 * matches the format of the tensor.
305 */
306 void fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const;
307
Alex Gilday345ab182018-01-09 11:40:19 +0000308 /** Fills the specified @p tensor with the content of the raw tensor.
309 *
310 * @param[in, out] tensor To be filled tensor.
311 * @param[in] raw Raw tensor used to fill the tensor.
312 *
313 * @warning No check is performed that the specified format actually
314 * matches the format of the tensor.
315 */
316 template <typename T>
317 void fill(T &&tensor, RawTensor raw) const;
318
Georgios Pinitas587708b2018-12-31 15:43:52 +0000319 /** Fill a tensor with uniform distribution
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100320 *
321 * @param[in, out] tensor To be filled tensor.
322 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
323 */
324 template <typename T>
325 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const;
326
Georgios Pinitas587708b2018-12-31 15:43:52 +0000327 /** Fill a tensor with uniform distribution
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100328 *
329 * @param[in, out] tensor To be filled tensor.
330 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
331 * @param[in] low lowest value in the range (inclusive)
332 * @param[in] high highest value in the range (inclusive)
333 *
334 * @note @p low and @p high must be of the same type as the data type of @p tensor
335 */
336 template <typename T, typename D>
337 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const;
338
Georgios Pinitas587708b2018-12-31 15:43:52 +0000339 /** Fill a tensor with uniform distribution across the specified range
340 *
341 * @param[in, out] tensor To be filled tensor.
342 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
343 * @param[in] excluded_range_pairs Ranges to exclude from the generator
344 */
345 template <typename T>
346 void fill_tensor_uniform_ranged(T &&tensor,
347 std::random_device::result_type seed_offset,
348 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const;
349
SiCong Li86b53332017-08-23 11:02:43 +0100350 /** Fills the specified @p tensor with data loaded from .npy (numpy binary) in specified path.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100351 *
352 * @param[in, out] tensor To be filled tensor.
353 * @param[in] name Data file.
SiCong Li86b53332017-08-23 11:02:43 +0100354 *
355 * @note The numpy array stored in the binary .npy file must be row-major in the sense that it
356 * must store elements within a row consecutively in the memory, then rows within a 2D slice,
357 * then 2D slices within a 3D slice and so on. Note that it imposes no restrictions on what
358 * indexing convention is used in the numpy array. That is, the numpy array can be either fortran
359 * style or C style as long as it adheres to the rule above.
360 *
361 * More concretely, the orders of dimensions for each style are as follows:
362 * C-style (numpy default):
363 * array[HigherDims..., Z, Y, X]
364 * Fortran style:
365 * array[X, Y, Z, HigherDims...]
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100366 */
367 template <typename T>
368 void fill_layer_data(T &&tensor, std::string name) const;
369
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000370 /** Fill a tensor with a constant value
371 *
372 * @param[in, out] tensor To be filled tensor.
373 * @param[in] value Value to be assigned to all elements of the input tensor.
374 *
375 * @note @p value must be of the same type as the data type of @p tensor
376 */
377 template <typename T, typename D>
378 void fill_tensor_value(T &&tensor, D value) const;
379
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100380private:
381 // Function prototype to convert between image formats.
382 using Converter = void (*)(const RawTensor &src, RawTensor &dst);
383 // Function prototype to extract a channel from an image.
384 using Extractor = void (*)(const RawTensor &src, RawTensor &dst);
385 // Function prototype to load an image file.
386 using Loader = RawTensor (*)(const std::string &path);
387
388 const Converter &get_converter(Format src, Format dst) const;
389 const Converter &get_converter(DataType src, Format dst) const;
390 const Converter &get_converter(Format src, DataType dst) const;
391 const Converter &get_converter(DataType src, DataType dst) const;
392 const Extractor &get_extractor(Format format, Channel) const;
393 const Loader &get_loader(const std::string &extension) const;
394
395 /** Creates a raw tensor from the specified image.
396 *
397 * @param[in] name To be loaded image file.
398 *
399 * @note If use_single_image is true @p name is ignored and the user image
400 * is loaded instead.
401 */
402 RawTensor load_image(const std::string &name) const;
403
404 /** Provides a raw tensor for the specified image and format.
405 *
406 * @param[in] name Image file used to look up the raw tensor.
407 * @param[in] format Format used to look up the raw tensor.
408 *
409 * If the tensor has already been requested before the cached version will
410 * be returned. Otherwise the tensor will be added to the cache.
411 *
412 * @note If use_single_image is true @p name is ignored and the user image
413 * is loaded instead.
414 */
415 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format) const;
416
417 /** Provides a raw tensor for the specified image, format and channel.
418 *
419 * @param[in] name Image file used to look up the raw tensor.
420 * @param[in] format Format used to look up the raw tensor.
421 * @param[in] channel Channel used to look up the raw tensor.
422 *
423 * If the tensor has already been requested before the cached version will
424 * be returned. Otherwise the tensor will be added to the cache.
425 *
426 * @note If use_single_image is true @p name is ignored and the user image
427 * is loaded instead.
428 */
429 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const;
430
431 mutable TensorCache _cache{};
Georgios Pinitas421405b2018-10-26 19:05:32 +0100432 mutable arm_compute::Mutex _format_lock{};
433 mutable arm_compute::Mutex _channel_lock{};
Anthony Barbierac69aa12017-07-03 17:39:37 +0100434 const std::string _library_path;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100435 std::random_device::result_type _seed;
436};
437
Georgios Pinitas587708b2018-12-31 15:43:52 +0000438namespace detail
439{
440template <typename T>
441inline std::vector<std::pair<T, T>> convert_range_pair(const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs)
442{
443 std::vector<std::pair<T, T>> converted;
444 std::transform(excluded_range_pairs.begin(),
445 excluded_range_pairs.end(),
446 std::back_inserter(converted),
447 [](const AssetsLibrary::RangePair & p)
448 {
449 return std::pair<T, T>(static_cast<T>(p.first), static_cast<T>(p.second));
450 });
451 return converted;
452}
453} // namespace detail
454
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100455template <typename T, typename D>
Giorgio Arenaa2611812017-07-21 10:08:48 +0100456void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
457{
458 const PaddingSize padding_size = tensor.padding();
459
460 Window window;
461 window.set(0, Window::Dimension(-padding_size.left, tensor.shape()[0] + padding_size.right, 1));
Gian Marco5420b282017-11-29 10:41:38 +0000462 if(tensor.shape().num_dimensions() > 1)
463 {
464 window.set(1, Window::Dimension(-padding_size.top, tensor.shape()[1] + padding_size.bottom, 1));
465 }
Giorgio Arenaa2611812017-07-21 10:08:48 +0100466
467 std::mt19937 gen(_seed);
468
469 execute_window_loop(window, [&](const Coordinates & id)
470 {
471 TensorShape shape = tensor.shape();
472
473 // If outside of valid region
474 if(id.x() < 0 || id.x() >= static_cast<int>(shape.x()) || id.y() < 0 || id.y() >= static_cast<int>(shape.y()))
475 {
476 using ResultType = typename std::remove_reference<D>::type::result_type;
477 const ResultType value = distribution(gen);
478 void *const out_ptr = tensor(id);
479 store_value_with_data_type(out_ptr, value, tensor.data_type());
480 }
481 });
482}
483
484template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100485void AssetsLibrary::fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100486{
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100487 using ResultType = typename std::remove_reference<D>::type::result_type;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100488
489 std::mt19937 gen(_seed + seed_offset);
490
Giorgio Arena563494c2018-04-30 17:29:41 +0100491 const bool is_nhwc = tensor.data_layout() == DataLayout::NHWC;
492 TensorShape shape(tensor.shape());
493
494 if(is_nhwc)
495 {
496 // Ensure that the equivalent tensors will be filled for both data layouts
497 permute(shape, PermutationVector(1U, 2U, 0U));
498 }
499
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100500 // Iterate over all elements
501 for(int element_idx = 0; element_idx < tensor.num_elements(); ++element_idx)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100502 {
Giorgio Arena563494c2018-04-30 17:29:41 +0100503 Coordinates id = index2coord(shape, element_idx);
504
505 if(is_nhwc)
506 {
507 // Write in the correct id for permuted shapes
508 permute(id, PermutationVector(2U, 0U, 1U));
509 }
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100510
511 // Iterate over all channels
512 for(int channel = 0; channel < tensor.num_channels(); ++channel)
513 {
514 const ResultType value = distribution(gen);
Kohei Takahashicedb78f2018-08-23 10:23:52 +0900515 ResultType &target_value = reinterpret_cast<ResultType *>(tensor(id))[channel];
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100516
517 store_value_with_data_type(&target_value, value, tensor.data_type());
518 }
519 }
Giorgio Arenaa2611812017-07-21 10:08:48 +0100520
521 fill_borders_with_garbage(tensor, distribution, seed_offset);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100522}
523
524template <typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100525void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100526{
527 std::mt19937 gen(_seed + seed_offset);
528
529 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
530 {
531 using ResultType = typename std::remove_reference<D>::type::result_type;
532 const ResultType value = distribution(gen);
Georgios Pinitas587708b2018-12-31 15:43:52 +0000533
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100534 store_value_with_data_type(raw.data() + offset, value, raw.data_type());
535 }
536}
537
538template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100539void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100540{
541 const RawTensor &raw = get(name, format);
542
543 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
544 {
545 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
546
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100547 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
548 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100549 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
550 }
551}
552
553template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100554void AssetsLibrary::fill(T &&tensor, const std::string &name, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100555{
556 fill(std::forward<T>(tensor), name, get_format_for_channel(channel), channel);
557}
558
559template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100560void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100561{
562 const RawTensor &raw = get(name, format, channel);
563
564 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
565 {
566 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
567
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100568 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
569 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100570 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
571 }
572}
573
574template <typename T>
Alex Gilday345ab182018-01-09 11:40:19 +0000575void AssetsLibrary::fill(T &&tensor, RawTensor raw) const
576{
577 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
578 {
579 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
580
581 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
582 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
583 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
584 }
585}
586
587template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100588void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100589{
590 switch(tensor.data_type())
591 {
592 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000593 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100594 {
595 std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max());
596 fill(tensor, distribution_u8, seed_offset);
597 break;
598 }
599 case DataType::S8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100600 {
601 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
602 fill(tensor, distribution_s8, seed_offset);
603 break;
604 }
605 case DataType::U16:
606 {
607 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
608 fill(tensor, distribution_u16, seed_offset);
609 break;
610 }
611 case DataType::S16:
612 {
613 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
614 fill(tensor, distribution_s16, seed_offset);
615 break;
616 }
617 case DataType::U32:
618 {
619 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
620 fill(tensor, distribution_u32, seed_offset);
621 break;
622 }
623 case DataType::S32:
624 {
625 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
626 fill(tensor, distribution_s32, seed_offset);
627 break;
628 }
629 case DataType::U64:
630 {
631 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
632 fill(tensor, distribution_u64, seed_offset);
633 break;
634 }
635 case DataType::S64:
636 {
637 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
638 fill(tensor, distribution_s64, seed_offset);
639 break;
640 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100641 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100642 {
643 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
644 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
645 fill(tensor, distribution_f16, seed_offset);
646 break;
647 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100648 case DataType::F32:
649 {
650 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
651 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
652 fill(tensor, distribution_f32, seed_offset);
653 break;
654 }
655 case DataType::F64:
656 {
657 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
658 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
659 fill(tensor, distribution_f64, seed_offset);
660 break;
661 }
662 case DataType::SIZET:
663 {
664 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
665 fill(tensor, distribution_sizet, seed_offset);
666 break;
667 }
668 default:
669 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
670 }
671}
672
Georgios Pinitas587708b2018-12-31 15:43:52 +0000673template <typename T>
674void AssetsLibrary::fill_tensor_uniform_ranged(T &&tensor,
675 std::random_device::result_type seed_offset,
676 const std::vector<AssetsLibrary::RangePair> &excluded_range_pairs) const
677{
678 using namespace arm_compute::utils::random;
679
680 switch(tensor.data_type())
681 {
682 case DataType::U8:
683 case DataType::QASYMM8:
684 {
685 const auto converted_pairs = detail::convert_range_pair<uint8_t>(excluded_range_pairs);
686 RangedUniformDistribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(),
687 std::numeric_limits<uint8_t>::max(),
688 converted_pairs);
689 fill(tensor, distribution_u8, seed_offset);
690 break;
691 }
692 case DataType::S8:
693 {
694 const auto converted_pairs = detail::convert_range_pair<int8_t>(excluded_range_pairs);
695 RangedUniformDistribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(),
696 std::numeric_limits<int8_t>::max(),
697 converted_pairs);
698 fill(tensor, distribution_s8, seed_offset);
699 break;
700 }
701 case DataType::U16:
702 {
703 const auto converted_pairs = detail::convert_range_pair<uint16_t>(excluded_range_pairs);
704 RangedUniformDistribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(),
705 std::numeric_limits<uint16_t>::max(),
706 converted_pairs);
707 fill(tensor, distribution_u16, seed_offset);
708 break;
709 }
710 case DataType::S16:
711 {
712 const auto converted_pairs = detail::convert_range_pair<int16_t>(excluded_range_pairs);
713 RangedUniformDistribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(),
714 std::numeric_limits<int16_t>::max(),
715 converted_pairs);
716 fill(tensor, distribution_s16, seed_offset);
717 break;
718 }
719 case DataType::U32:
720 {
721 const auto converted_pairs = detail::convert_range_pair<uint32_t>(excluded_range_pairs);
722 RangedUniformDistribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(),
723 std::numeric_limits<uint32_t>::max(),
724 converted_pairs);
725 fill(tensor, distribution_u32, seed_offset);
726 break;
727 }
728 case DataType::S32:
729 {
730 const auto converted_pairs = detail::convert_range_pair<int32_t>(excluded_range_pairs);
731 RangedUniformDistribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(),
732 std::numeric_limits<int32_t>::max(),
733 converted_pairs);
734 fill(tensor, distribution_s32, seed_offset);
735 break;
736 }
737 case DataType::F16:
738 {
739 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
740 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
741 RangedUniformDistribution<float> distribution_f16(-100.f, 100.f, converted_pairs);
742 fill(tensor, distribution_f16, seed_offset);
743 break;
744 }
745 case DataType::F32:
746 {
747 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
748 const auto converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
749 RangedUniformDistribution<float> distribution_f32(-1000.f, 1000.f, converted_pairs);
750 fill(tensor, distribution_f32, seed_offset);
751 break;
752 }
753 default:
754 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
755 }
756}
757
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100758template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100759void 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 +0100760{
761 switch(tensor.data_type())
762 {
763 case DataType::U8:
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000764 case DataType::QASYMM8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100765 {
766 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
767 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
768 fill(tensor, distribution_u8, seed_offset);
769 break;
770 }
771 case DataType::S8:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100772 {
773 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
774 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
775 fill(tensor, distribution_s8, seed_offset);
776 break;
777 }
778 case DataType::U16:
779 {
780 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
781 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
782 fill(tensor, distribution_u16, seed_offset);
783 break;
784 }
785 case DataType::S16:
786 {
787 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
788 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
789 fill(tensor, distribution_s16, seed_offset);
790 break;
791 }
792 case DataType::U32:
793 {
794 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
795 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
796 fill(tensor, distribution_u32, seed_offset);
797 break;
798 }
799 case DataType::S32:
800 {
801 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
802 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
803 fill(tensor, distribution_s32, seed_offset);
804 break;
805 }
806 case DataType::U64:
807 {
808 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
809 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
810 fill(tensor, distribution_u64, seed_offset);
811 break;
812 }
813 case DataType::S64:
814 {
815 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
816 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
817 fill(tensor, distribution_s64, seed_offset);
818 break;
819 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100820 case DataType::F16:
821 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100822 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100823 fill(tensor, distribution_f16, seed_offset);
824 break;
825 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100826 case DataType::F32:
827 {
828 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
829 std::uniform_real_distribution<float> distribution_f32(low, high);
830 fill(tensor, distribution_f32, seed_offset);
831 break;
832 }
833 case DataType::F64:
834 {
835 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
836 std::uniform_real_distribution<double> distribution_f64(low, high);
837 fill(tensor, distribution_f64, seed_offset);
838 break;
839 }
840 case DataType::SIZET:
841 {
842 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
843 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
844 fill(tensor, distribution_sizet, seed_offset);
845 break;
846 }
847 default:
848 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
849 }
850}
851
852template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100853void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100854{
855#ifdef _WIN32
856 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100857#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100858 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100859#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100860 const std::string path = _library_path + path_separator + name;
861
SiCong Li86b53332017-08-23 11:02:43 +0100862 std::vector<unsigned long> shape;
863
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100864 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100865 std::ifstream stream(path, std::ios::in | std::ios::binary);
Anthony Barbierf6705ec2017-09-28 12:01:10 +0100866 if(!stream.good())
867 {
868 throw framework::FileNotFound("Could not load npy file: " + path);
869 }
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000870 std::string header = npy::read_header(stream);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100871
SiCong Li86b53332017-08-23 11:02:43 +0100872 // Parse header
873 bool fortran_order = false;
874 std::string typestr;
Anthony Barbier87f21cd2017-11-10 16:27:32 +0000875 npy::parse_header(header, typestr, fortran_order, shape);
SiCong Li86b53332017-08-23 11:02:43 +0100876
877 // Check if the typestring matches the given one
878 std::string expect_typestr = get_typestring(tensor.data_type());
879 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
880
881 // Validate tensor shape
882 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
883 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100884 {
SiCong Li86b53332017-08-23 11:02:43 +0100885 for(size_t i = 0; i < shape.size(); ++i)
886 {
887 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
888 }
889 }
890 else
891 {
892 for(size_t i = 0; i < shape.size(); ++i)
893 {
894 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
895 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100896 }
897
SiCong Li86b53332017-08-23 11:02:43 +0100898 // Read data
899 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100900 {
SiCong Li86b53332017-08-23 11:02:43 +0100901 // If tensor has no padding read directly from stream.
902 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
903 }
904 else
905 {
906 // If tensor has padding accessing tensor elements through execution window.
907 Window window;
908 window.use_tensor_dimensions(tensor.shape());
909
SiCong Li86b53332017-08-23 11:02:43 +0100910 execute_window_loop(window, [&](const Coordinates & id)
911 {
912 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
913 });
914 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100915}
Michele Di Giorgio4d336302018-03-02 09:43:54 +0000916
917template <typename T, typename D>
918void AssetsLibrary::fill_tensor_value(T &&tensor, D value) const
919{
920 fill_tensor_uniform(tensor, 0, value, value);
921}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100922} // namespace test
923} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100924#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */