blob: 6199a09012364c4a43e61c0bad4c4fe38976912a [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
2 * Copyright (c) 2017 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef __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"
SiCong Li86b53332017-08-23 11:02:43 +010034#include "libnpy/npy.hpp"
Moritz Pflanzere49e2662017-07-21 15:55:28 +010035#include "tests/RawTensor.h"
36#include "tests/TensorCache.h"
37#include "tests/Utils.h"
Anthony Barbierf6705ec2017-09-28 12:01:10 +010038#include "tests/framework/Exceptions.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010039
40#include <algorithm>
41#include <cstddef>
42#include <fstream>
43#include <random>
44#include <string>
45#include <type_traits>
SiCong Li86b53332017-08-23 11:02:43 +010046#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010047
48namespace arm_compute
49{
50namespace test
51{
52/** Factory class to create and fill tensors.
53 *
54 * Allows to initialise tensors from loaded images or by specifying the shape
55 * explicitly. Furthermore, provides methods to fill tensors with the content of
56 * loaded images or with random values.
57 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010058class AssetsLibrary final
Anthony Barbier6ff3b192017-09-04 18:44:23 +010059{
60public:
61 /** Initialises the library with a @p path to the image directory.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010062 * Furthermore, sets the seed for the random generator to @p seed.
63 *
64 * @param[in] path Path to load images from.
65 * @param[in] seed Seed used to initialise the random number generator.
66 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010067 AssetsLibrary(std::string path, std::random_device::result_type seed);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010068
69 /** Seed that is used to fill tensors with random values. */
70 std::random_device::result_type seed() const;
71
Giorgio Arenafda46182017-06-16 13:57:33 +010072 /** Provides a tensor shape for the specified image.
73 *
74 * @param[in] name Image file used to look up the raw tensor.
75 */
76 TensorShape get_image_shape(const std::string &name);
77
Anthony Barbier6ff3b192017-09-04 18:44:23 +010078 /** Provides a contant raw tensor for the specified image.
79 *
80 * @param[in] name Image file used to look up the raw tensor.
81 */
82 const RawTensor &get(const std::string &name) const;
83
84 /** Provides a raw tensor for the specified image.
85 *
86 * @param[in] name Image file used to look up the raw tensor.
87 */
88 RawTensor get(const std::string &name);
89
90 /** Creates an uninitialised raw tensor with the given @p data_type and @p
91 * num_channels. The shape is derived from the specified image.
92 *
93 * @param[in] name Image file used to initialise the tensor.
94 * @param[in] data_type Data type used to initialise the tensor.
95 * @param[in] num_channels Number of channels used to initialise the tensor.
96 */
97 RawTensor get(const std::string &name, DataType data_type, int num_channels = 1) const;
98
99 /** Provides a contant raw tensor for the specified image after it has been
100 * converted to @p format.
101 *
102 * @param[in] name Image file used to look up the raw tensor.
103 * @param[in] format Format used to look up the raw tensor.
104 */
105 const RawTensor &get(const std::string &name, Format format) const;
106
107 /** Provides a raw tensor for the specified image after it has been
108 * converted to @p format.
109 *
110 * @param[in] name Image file used to look up the raw tensor.
111 * @param[in] format Format used to look up the raw tensor.
112 */
113 RawTensor get(const std::string &name, Format format);
114
115 /** Provides a contant raw tensor for the specified channel after it has
116 * been extracted form the given image.
117 *
118 * @param[in] name Image file used to look up the raw tensor.
119 * @param[in] channel Channel used to look up the raw tensor.
120 *
121 * @note The channel has to be unambiguous so that the format can be
122 * inferred automatically.
123 */
124 const RawTensor &get(const std::string &name, Channel channel) const;
125
126 /** Provides a raw tensor for the specified channel after it has been
127 * extracted form the given image.
128 *
129 * @param[in] name Image file used to look up the raw tensor.
130 * @param[in] channel Channel used to look up the raw tensor.
131 *
132 * @note The channel has to be unambiguous so that the format can be
133 * inferred automatically.
134 */
135 RawTensor get(const std::string &name, Channel channel);
136
137 /** Provides a constant raw tensor for the specified channel after it has
138 * been extracted form the given image formatted to @p format.
139 *
140 * @param[in] name Image file used to look up the raw tensor.
141 * @param[in] format Format used to look up the raw tensor.
142 * @param[in] channel Channel used to look up the raw tensor.
143 */
144 const RawTensor &get(const std::string &name, Format format, Channel channel) const;
145
146 /** Provides a raw tensor for the specified channel after it has been
147 * extracted form the given image formatted to @p format.
148 *
149 * @param[in] name Image file used to look up the raw tensor.
150 * @param[in] format Format used to look up the raw tensor.
151 * @param[in] channel Channel used to look up the raw tensor.
152 */
153 RawTensor get(const std::string &name, Format format, Channel channel);
154
Giorgio Arenaa2611812017-07-21 10:08:48 +0100155 /** Puts garbage values all around the tensor for testing purposes
156 *
157 * @param[in, out] tensor To be filled tensor.
158 * @param[in] distribution Distribution used to fill the tensor's surroundings.
159 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
160 */
161 template <typename T, typename D>
162 void fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
163
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100164 /** Fills the specified @p tensor with random values drawn from @p
165 * distribution.
166 *
167 * @param[in, out] tensor To be filled tensor.
168 * @param[in] distribution Distribution used to fill the tensor.
169 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
170 *
171 * @note The @p distribution has to provide operator(Generator &) which
172 * will be used to draw samples.
173 */
174 template <typename T, typename D>
175 void fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
176
177 /** Fills the specified @p raw tensor with random values drawn from @p
178 * distribution.
179 *
180 * @param[in, out] raw To be filled raw.
181 * @param[in] distribution Distribution used to fill the tensor.
182 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
183 *
184 * @note The @p distribution has to provide operator(Generator &) which
185 * will be used to draw samples.
186 */
187 template <typename D>
188 void fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const;
189
190 /** Fills the specified @p tensor with the content of the specified image
191 * converted to the given format.
192 *
193 * @param[in, out] tensor To be filled tensor.
194 * @param[in] name Image file used to fill the tensor.
195 * @param[in] format Format of the image used to fill the tensor.
196 *
197 * @warning No check is performed that the specified format actually
198 * matches the format of the tensor.
199 */
200 template <typename T>
201 void fill(T &&tensor, const std::string &name, Format format) const;
202
203 /** Fills the raw tensor with the content of the specified image
204 * converted to the given format.
205 *
206 * @param[in, out] raw To be filled raw tensor.
207 * @param[in] name Image file used to fill the tensor.
208 * @param[in] format Format of the image used to fill the tensor.
209 *
210 * @warning No check is performed that the specified format actually
211 * matches the format of the tensor.
212 */
213 void fill(RawTensor &raw, const std::string &name, Format format) const;
214
215 /** Fills the specified @p tensor with the content of the specified channel
216 * extracted from the given image.
217 *
218 * @param[in, out] tensor To be filled tensor.
219 * @param[in] name Image file used to fill the tensor.
220 * @param[in] channel Channel of the image used to fill the tensor.
221 *
222 * @note The channel has to be unambiguous so that the format can be
223 * inferred automatically.
224 *
225 * @warning No check is performed that the specified format actually
226 * matches the format of the tensor.
227 */
228 template <typename T>
229 void fill(T &&tensor, const std::string &name, Channel channel) const;
230
231 /** Fills the raw tensor with the content of the specified channel
232 * extracted from the given image.
233 *
234 * @param[in, out] raw To be filled raw tensor.
235 * @param[in] name Image file used to fill the tensor.
236 * @param[in] channel Channel of the image used to fill the tensor.
237 *
238 * @note The channel has to be unambiguous so that the format can be
239 * inferred automatically.
240 *
241 * @warning No check is performed that the specified format actually
242 * matches the format of the tensor.
243 */
244 void fill(RawTensor &raw, const std::string &name, Channel channel) const;
245
246 /** Fills the specified @p tensor with the content of the specified channel
247 * extracted from the given image after it has been converted to the given
248 * format.
249 *
250 * @param[in, out] tensor To be filled tensor.
251 * @param[in] name Image file used to fill the tensor.
252 * @param[in] format Format of the image used to fill the tensor.
253 * @param[in] channel Channel of the image used to fill the tensor.
254 *
255 * @warning No check is performed that the specified format actually
256 * matches the format of the tensor.
257 */
258 template <typename T>
259 void fill(T &&tensor, const std::string &name, Format format, Channel channel) const;
260
261 /** Fills the raw tensor with the content of the specified channel
262 * extracted from the given image after it has been converted to the given
263 * format.
264 *
265 * @param[in, out] raw To be filled raw tensor.
266 * @param[in] name Image file used to fill the tensor.
267 * @param[in] format Format of the image used to fill the tensor.
268 * @param[in] channel Channel of the image used to fill the tensor.
269 *
270 * @warning No check is performed that the specified format actually
271 * matches the format of the tensor.
272 */
273 void fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const;
274
275 /** Fill a tensor with uniform distribution across the range of its type
276 *
277 * @param[in, out] tensor To be filled tensor.
278 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
279 */
280 template <typename T>
281 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const;
282
283 /** Fill a tensor with uniform distribution across the a specified range
284 *
285 * @param[in, out] tensor To be filled tensor.
286 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
287 * @param[in] low lowest value in the range (inclusive)
288 * @param[in] high highest value in the range (inclusive)
289 *
290 * @note @p low and @p high must be of the same type as the data type of @p tensor
291 */
292 template <typename T, typename D>
293 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const;
294
SiCong Li86b53332017-08-23 11:02:43 +0100295 /** Fills the specified @p tensor with data loaded from .npy (numpy binary) in specified path.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100296 *
297 * @param[in, out] tensor To be filled tensor.
298 * @param[in] name Data file.
SiCong Li86b53332017-08-23 11:02:43 +0100299 *
300 * @note The numpy array stored in the binary .npy file must be row-major in the sense that it
301 * must store elements within a row consecutively in the memory, then rows within a 2D slice,
302 * then 2D slices within a 3D slice and so on. Note that it imposes no restrictions on what
303 * indexing convention is used in the numpy array. That is, the numpy array can be either fortran
304 * style or C style as long as it adheres to the rule above.
305 *
306 * More concretely, the orders of dimensions for each style are as follows:
307 * C-style (numpy default):
308 * array[HigherDims..., Z, Y, X]
309 * Fortran style:
310 * array[X, Y, Z, HigherDims...]
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100311 */
312 template <typename T>
313 void fill_layer_data(T &&tensor, std::string name) const;
314
315private:
316 // Function prototype to convert between image formats.
317 using Converter = void (*)(const RawTensor &src, RawTensor &dst);
318 // Function prototype to extract a channel from an image.
319 using Extractor = void (*)(const RawTensor &src, RawTensor &dst);
320 // Function prototype to load an image file.
321 using Loader = RawTensor (*)(const std::string &path);
322
323 const Converter &get_converter(Format src, Format dst) const;
324 const Converter &get_converter(DataType src, Format dst) const;
325 const Converter &get_converter(Format src, DataType dst) const;
326 const Converter &get_converter(DataType src, DataType dst) const;
327 const Extractor &get_extractor(Format format, Channel) const;
328 const Loader &get_loader(const std::string &extension) const;
329
330 /** Creates a raw tensor from the specified image.
331 *
332 * @param[in] name To be loaded image file.
333 *
334 * @note If use_single_image is true @p name is ignored and the user image
335 * is loaded instead.
336 */
337 RawTensor load_image(const std::string &name) const;
338
339 /** Provides a raw tensor for the specified image and format.
340 *
341 * @param[in] name Image file used to look up the raw tensor.
342 * @param[in] format Format used to look up the raw tensor.
343 *
344 * If the tensor has already been requested before the cached version will
345 * be returned. Otherwise the tensor will be added to the cache.
346 *
347 * @note If use_single_image is true @p name is ignored and the user image
348 * is loaded instead.
349 */
350 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format) const;
351
352 /** Provides a raw tensor for the specified image, format and channel.
353 *
354 * @param[in] name Image file used to look up the raw tensor.
355 * @param[in] format Format used to look up the raw tensor.
356 * @param[in] channel Channel used to look up the raw tensor.
357 *
358 * If the tensor has already been requested before the cached version will
359 * be returned. Otherwise the tensor will be added to the cache.
360 *
361 * @note If use_single_image is true @p name is ignored and the user image
362 * is loaded instead.
363 */
364 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const;
365
366 mutable TensorCache _cache{};
367 mutable std::mutex _format_lock{};
368 mutable std::mutex _channel_lock{};
Anthony Barbierac69aa12017-07-03 17:39:37 +0100369 const std::string _library_path;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100370 std::random_device::result_type _seed;
371};
372
373template <typename T, typename D>
Giorgio Arenaa2611812017-07-21 10:08:48 +0100374void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
375{
376 const PaddingSize padding_size = tensor.padding();
377
378 Window window;
379 window.set(0, Window::Dimension(-padding_size.left, tensor.shape()[0] + padding_size.right, 1));
380 window.set(1, Window::Dimension(-padding_size.top, tensor.shape()[1] + padding_size.bottom, 1));
381
382 std::mt19937 gen(_seed);
383
384 execute_window_loop(window, [&](const Coordinates & id)
385 {
386 TensorShape shape = tensor.shape();
387
388 // If outside of valid region
389 if(id.x() < 0 || id.x() >= static_cast<int>(shape.x()) || id.y() < 0 || id.y() >= static_cast<int>(shape.y()))
390 {
391 using ResultType = typename std::remove_reference<D>::type::result_type;
392 const ResultType value = distribution(gen);
393 void *const out_ptr = tensor(id);
394 store_value_with_data_type(out_ptr, value, tensor.data_type());
395 }
396 });
397}
398
399template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100400void AssetsLibrary::fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100401{
402 Window window;
403 for(unsigned int d = 0; d < tensor.shape().num_dimensions(); ++d)
404 {
405 window.set(d, Window::Dimension(0, tensor.shape()[d], 1));
406 }
407
408 std::mt19937 gen(_seed + seed_offset);
409
410 //FIXME: Replace with normal loop
411 execute_window_loop(window, [&](const Coordinates & id)
412 {
413 using ResultType = typename std::remove_reference<D>::type::result_type;
414 const ResultType value = distribution(gen);
415 void *const out_ptr = tensor(id);
416 store_value_with_data_type(out_ptr, value, tensor.data_type());
417 });
Giorgio Arenaa2611812017-07-21 10:08:48 +0100418
419 fill_borders_with_garbage(tensor, distribution, seed_offset);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100420}
421
422template <typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100423void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100424{
425 std::mt19937 gen(_seed + seed_offset);
426
427 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
428 {
429 using ResultType = typename std::remove_reference<D>::type::result_type;
430 const ResultType value = distribution(gen);
431 store_value_with_data_type(raw.data() + offset, value, raw.data_type());
432 }
433}
434
435template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100436void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100437{
438 const RawTensor &raw = get(name, format);
439
440 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
441 {
442 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
443
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100444 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
445 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100446 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
447 }
448}
449
450template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100451void AssetsLibrary::fill(T &&tensor, const std::string &name, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100452{
453 fill(std::forward<T>(tensor), name, get_format_for_channel(channel), channel);
454}
455
456template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100457void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100458{
459 const RawTensor &raw = get(name, format, channel);
460
461 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
462 {
463 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
464
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100465 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
466 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100467 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
468 }
469}
470
471template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100472void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100473{
474 switch(tensor.data_type())
475 {
476 case DataType::U8:
477 {
478 std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max());
479 fill(tensor, distribution_u8, seed_offset);
480 break;
481 }
482 case DataType::S8:
483 case DataType::QS8:
484 {
485 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
486 fill(tensor, distribution_s8, seed_offset);
487 break;
488 }
489 case DataType::U16:
490 {
491 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
492 fill(tensor, distribution_u16, seed_offset);
493 break;
494 }
495 case DataType::S16:
Gian Marco Iodicebdb6b0b2017-06-30 12:21:00 +0100496 case DataType::QS16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100497 {
498 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
499 fill(tensor, distribution_s16, seed_offset);
500 break;
501 }
502 case DataType::U32:
503 {
504 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
505 fill(tensor, distribution_u32, seed_offset);
506 break;
507 }
508 case DataType::S32:
509 {
510 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
511 fill(tensor, distribution_s32, seed_offset);
512 break;
513 }
514 case DataType::U64:
515 {
516 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
517 fill(tensor, distribution_u64, seed_offset);
518 break;
519 }
520 case DataType::S64:
521 {
522 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
523 fill(tensor, distribution_s64, seed_offset);
524 break;
525 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100526 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100527 {
528 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
529 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
530 fill(tensor, distribution_f16, seed_offset);
531 break;
532 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100533 case DataType::F32:
534 {
535 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
536 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
537 fill(tensor, distribution_f32, seed_offset);
538 break;
539 }
540 case DataType::F64:
541 {
542 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
543 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
544 fill(tensor, distribution_f64, seed_offset);
545 break;
546 }
547 case DataType::SIZET:
548 {
549 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
550 fill(tensor, distribution_sizet, seed_offset);
551 break;
552 }
553 default:
554 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
555 }
556}
557
558template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100559void 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 +0100560{
561 switch(tensor.data_type())
562 {
563 case DataType::U8:
564 {
565 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
566 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
567 fill(tensor, distribution_u8, seed_offset);
568 break;
569 }
570 case DataType::S8:
571 case DataType::QS8:
572 {
573 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
574 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
575 fill(tensor, distribution_s8, seed_offset);
576 break;
577 }
578 case DataType::U16:
579 {
580 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
581 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
582 fill(tensor, distribution_u16, seed_offset);
583 break;
584 }
585 case DataType::S16:
Georgios Pinitas21efeb42017-07-04 12:47:17 +0100586 case DataType::QS16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100587 {
588 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
589 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
590 fill(tensor, distribution_s16, seed_offset);
591 break;
592 }
593 case DataType::U32:
594 {
595 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
596 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
597 fill(tensor, distribution_u32, seed_offset);
598 break;
599 }
600 case DataType::S32:
601 {
602 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
603 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
604 fill(tensor, distribution_s32, seed_offset);
605 break;
606 }
607 case DataType::U64:
608 {
609 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
610 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
611 fill(tensor, distribution_u64, seed_offset);
612 break;
613 }
614 case DataType::S64:
615 {
616 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
617 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
618 fill(tensor, distribution_s64, seed_offset);
619 break;
620 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100621 case DataType::F16:
622 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100623 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100624 fill(tensor, distribution_f16, seed_offset);
625 break;
626 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100627 case DataType::F32:
628 {
629 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
630 std::uniform_real_distribution<float> distribution_f32(low, high);
631 fill(tensor, distribution_f32, seed_offset);
632 break;
633 }
634 case DataType::F64:
635 {
636 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
637 std::uniform_real_distribution<double> distribution_f64(low, high);
638 fill(tensor, distribution_f64, seed_offset);
639 break;
640 }
641 case DataType::SIZET:
642 {
643 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
644 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
645 fill(tensor, distribution_sizet, seed_offset);
646 break;
647 }
648 default:
649 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
650 }
651}
652
653template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100654void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100655{
656#ifdef _WIN32
657 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100658#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100659 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100660#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100661 const std::string path = _library_path + path_separator + name;
662
SiCong Li86b53332017-08-23 11:02:43 +0100663 std::vector<unsigned long> shape;
664
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100665 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100666 std::ifstream stream(path, std::ios::in | std::ios::binary);
Anthony Barbierf6705ec2017-09-28 12:01:10 +0100667 if(!stream.good())
668 {
669 throw framework::FileNotFound("Could not load npy file: " + path);
670 }
SiCong Li86b53332017-08-23 11:02:43 +0100671 // Check magic bytes and version number
672 unsigned char v_major = 0;
673 unsigned char v_minor = 0;
674 npy::read_magic(stream, &v_major, &v_minor);
675
676 // Read header
677 std::string header;
678 if(v_major == 1 && v_minor == 0)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100679 {
SiCong Li86b53332017-08-23 11:02:43 +0100680 header = npy::read_header_1_0(stream);
681 }
682 else if(v_major == 2 && v_minor == 0)
683 {
684 header = npy::read_header_2_0(stream);
685 }
686 else
687 {
688 ARM_COMPUTE_ERROR("Unsupported file format version");
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100689 }
690
SiCong Li86b53332017-08-23 11:02:43 +0100691 // Parse header
692 bool fortran_order = false;
693 std::string typestr;
694 npy::ParseHeader(header, typestr, &fortran_order, shape);
695
696 // Check if the typestring matches the given one
697 std::string expect_typestr = get_typestring(tensor.data_type());
698 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
699
700 // Validate tensor shape
701 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
702 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100703 {
SiCong Li86b53332017-08-23 11:02:43 +0100704 for(size_t i = 0; i < shape.size(); ++i)
705 {
706 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
707 }
708 }
709 else
710 {
711 for(size_t i = 0; i < shape.size(); ++i)
712 {
713 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
714 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100715 }
716
SiCong Li86b53332017-08-23 11:02:43 +0100717 // Read data
718 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100719 {
SiCong Li86b53332017-08-23 11:02:43 +0100720 // If tensor has no padding read directly from stream.
721 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
722 }
723 else
724 {
725 // If tensor has padding accessing tensor elements through execution window.
726 Window window;
727 window.use_tensor_dimensions(tensor.shape());
728
729 //FIXME : Replace with normal loop
730 execute_window_loop(window, [&](const Coordinates & id)
731 {
732 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
733 });
734 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100735}
736} // namespace test
737} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100738#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */