blob: bd1d8b47589615bb0c2d8f3a55fc33a63635ba1f [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 Barbier6ff3b192017-09-04 18:44:23 +010038
39#include <algorithm>
40#include <cstddef>
41#include <fstream>
42#include <random>
43#include <string>
44#include <type_traits>
SiCong Li86b53332017-08-23 11:02:43 +010045#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010046
47namespace arm_compute
48{
49namespace test
50{
51/** Factory class to create and fill tensors.
52 *
53 * Allows to initialise tensors from loaded images or by specifying the shape
54 * explicitly. Furthermore, provides methods to fill tensors with the content of
55 * loaded images or with random values.
56 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010057class AssetsLibrary final
Anthony Barbier6ff3b192017-09-04 18:44:23 +010058{
59public:
60 /** Initialises the library with a @p path to the image directory.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010061 * Furthermore, sets the seed for the random generator to @p seed.
62 *
63 * @param[in] path Path to load images from.
64 * @param[in] seed Seed used to initialise the random number generator.
65 */
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +010066 AssetsLibrary(std::string path, std::random_device::result_type seed);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010067
68 /** Seed that is used to fill tensors with random values. */
69 std::random_device::result_type seed() const;
70
Giorgio Arenafda46182017-06-16 13:57:33 +010071 /** Provides a tensor shape for the specified image.
72 *
73 * @param[in] name Image file used to look up the raw tensor.
74 */
75 TensorShape get_image_shape(const std::string &name);
76
Anthony Barbier6ff3b192017-09-04 18:44:23 +010077 /** Provides a contant raw tensor for the specified image.
78 *
79 * @param[in] name Image file used to look up the raw tensor.
80 */
81 const RawTensor &get(const std::string &name) const;
82
83 /** Provides a raw tensor for the specified image.
84 *
85 * @param[in] name Image file used to look up the raw tensor.
86 */
87 RawTensor get(const std::string &name);
88
89 /** Creates an uninitialised raw tensor with the given @p data_type and @p
90 * num_channels. The shape is derived from the specified image.
91 *
92 * @param[in] name Image file used to initialise the tensor.
93 * @param[in] data_type Data type used to initialise the tensor.
94 * @param[in] num_channels Number of channels used to initialise the tensor.
95 */
96 RawTensor get(const std::string &name, DataType data_type, int num_channels = 1) const;
97
98 /** Provides a contant raw tensor for the specified image after it has been
99 * converted to @p format.
100 *
101 * @param[in] name Image file used to look up the raw tensor.
102 * @param[in] format Format used to look up the raw tensor.
103 */
104 const RawTensor &get(const std::string &name, Format format) const;
105
106 /** Provides a raw tensor for the specified image after it has been
107 * converted to @p format.
108 *
109 * @param[in] name Image file used to look up the raw tensor.
110 * @param[in] format Format used to look up the raw tensor.
111 */
112 RawTensor get(const std::string &name, Format format);
113
114 /** Provides a contant raw tensor for the specified channel after it has
115 * been extracted form the given image.
116 *
117 * @param[in] name Image file used to look up the raw tensor.
118 * @param[in] channel Channel used to look up the raw tensor.
119 *
120 * @note The channel has to be unambiguous so that the format can be
121 * inferred automatically.
122 */
123 const RawTensor &get(const std::string &name, Channel channel) const;
124
125 /** Provides a raw tensor for the specified channel after it has been
126 * extracted form the given image.
127 *
128 * @param[in] name Image file used to look up the raw tensor.
129 * @param[in] channel Channel used to look up the raw tensor.
130 *
131 * @note The channel has to be unambiguous so that the format can be
132 * inferred automatically.
133 */
134 RawTensor get(const std::string &name, Channel channel);
135
136 /** Provides a constant raw tensor for the specified channel after it has
137 * been extracted form the given image formatted to @p format.
138 *
139 * @param[in] name Image file used to look up the raw tensor.
140 * @param[in] format Format used to look up the raw tensor.
141 * @param[in] channel Channel used to look up the raw tensor.
142 */
143 const RawTensor &get(const std::string &name, Format format, Channel channel) const;
144
145 /** Provides a raw tensor for the specified channel after it has been
146 * extracted form the given image formatted to @p format.
147 *
148 * @param[in] name Image file used to look up the raw tensor.
149 * @param[in] format Format used to look up the raw tensor.
150 * @param[in] channel Channel used to look up the raw tensor.
151 */
152 RawTensor get(const std::string &name, Format format, Channel channel);
153
Giorgio Arenaa2611812017-07-21 10:08:48 +0100154 /** Puts garbage values all around the tensor for testing purposes
155 *
156 * @param[in, out] tensor To be filled tensor.
157 * @param[in] distribution Distribution used to fill the tensor's surroundings.
158 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
159 */
160 template <typename T, typename D>
161 void fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
162
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100163 /** Fills the specified @p tensor with random values drawn from @p
164 * distribution.
165 *
166 * @param[in, out] tensor To be filled tensor.
167 * @param[in] distribution Distribution used to fill the tensor.
168 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
169 *
170 * @note The @p distribution has to provide operator(Generator &) which
171 * will be used to draw samples.
172 */
173 template <typename T, typename D>
174 void fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const;
175
176 /** Fills the specified @p raw tensor with random values drawn from @p
177 * distribution.
178 *
179 * @param[in, out] raw To be filled raw.
180 * @param[in] distribution Distribution used to fill the tensor.
181 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
182 *
183 * @note The @p distribution has to provide operator(Generator &) which
184 * will be used to draw samples.
185 */
186 template <typename D>
187 void fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const;
188
189 /** Fills the specified @p tensor with the content of the specified image
190 * converted to the given format.
191 *
192 * @param[in, out] tensor To be filled tensor.
193 * @param[in] name Image file used to fill the tensor.
194 * @param[in] format Format of the image used to fill the tensor.
195 *
196 * @warning No check is performed that the specified format actually
197 * matches the format of the tensor.
198 */
199 template <typename T>
200 void fill(T &&tensor, const std::string &name, Format format) const;
201
202 /** Fills the raw tensor with the content of the specified image
203 * converted to the given format.
204 *
205 * @param[in, out] raw To be filled raw tensor.
206 * @param[in] name Image file used to fill the tensor.
207 * @param[in] format Format of the image used to fill the tensor.
208 *
209 * @warning No check is performed that the specified format actually
210 * matches the format of the tensor.
211 */
212 void fill(RawTensor &raw, const std::string &name, Format format) const;
213
214 /** Fills the specified @p tensor with the content of the specified channel
215 * extracted from the given image.
216 *
217 * @param[in, out] tensor To be filled tensor.
218 * @param[in] name Image file used to fill the tensor.
219 * @param[in] channel Channel of the image used to fill the tensor.
220 *
221 * @note The channel has to be unambiguous so that the format can be
222 * inferred automatically.
223 *
224 * @warning No check is performed that the specified format actually
225 * matches the format of the tensor.
226 */
227 template <typename T>
228 void fill(T &&tensor, const std::string &name, Channel channel) const;
229
230 /** Fills the raw tensor with the content of the specified channel
231 * extracted from the given image.
232 *
233 * @param[in, out] raw To be filled raw tensor.
234 * @param[in] name Image file used to fill the tensor.
235 * @param[in] channel Channel of the image used to fill the tensor.
236 *
237 * @note The channel has to be unambiguous so that the format can be
238 * inferred automatically.
239 *
240 * @warning No check is performed that the specified format actually
241 * matches the format of the tensor.
242 */
243 void fill(RawTensor &raw, const std::string &name, Channel channel) const;
244
245 /** Fills the specified @p tensor with the content of the specified channel
246 * extracted from the given image after it has been converted to the given
247 * format.
248 *
249 * @param[in, out] tensor To be filled tensor.
250 * @param[in] name Image file used to fill the tensor.
251 * @param[in] format Format of the image used to fill the tensor.
252 * @param[in] channel Channel of the image used to fill the tensor.
253 *
254 * @warning No check is performed that the specified format actually
255 * matches the format of the tensor.
256 */
257 template <typename T>
258 void fill(T &&tensor, const std::string &name, Format format, Channel channel) const;
259
260 /** Fills the raw tensor with the content of the specified channel
261 * extracted from the given image after it has been converted to the given
262 * format.
263 *
264 * @param[in, out] raw To be filled raw tensor.
265 * @param[in] name Image file used to fill the tensor.
266 * @param[in] format Format of the image used to fill the tensor.
267 * @param[in] channel Channel of the image used to fill the tensor.
268 *
269 * @warning No check is performed that the specified format actually
270 * matches the format of the tensor.
271 */
272 void fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const;
273
274 /** Fill a tensor with uniform distribution across the range of its type
275 *
276 * @param[in, out] tensor To be filled tensor.
277 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
278 */
279 template <typename T>
280 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const;
281
282 /** Fill a tensor with uniform distribution across the a specified range
283 *
284 * @param[in, out] tensor To be filled tensor.
285 * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator.
286 * @param[in] low lowest value in the range (inclusive)
287 * @param[in] high highest value in the range (inclusive)
288 *
289 * @note @p low and @p high must be of the same type as the data type of @p tensor
290 */
291 template <typename T, typename D>
292 void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const;
293
SiCong Li86b53332017-08-23 11:02:43 +0100294 /** Fills the specified @p tensor with data loaded from .npy (numpy binary) in specified path.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100295 *
296 * @param[in, out] tensor To be filled tensor.
297 * @param[in] name Data file.
SiCong Li86b53332017-08-23 11:02:43 +0100298 *
299 * @note The numpy array stored in the binary .npy file must be row-major in the sense that it
300 * must store elements within a row consecutively in the memory, then rows within a 2D slice,
301 * then 2D slices within a 3D slice and so on. Note that it imposes no restrictions on what
302 * indexing convention is used in the numpy array. That is, the numpy array can be either fortran
303 * style or C style as long as it adheres to the rule above.
304 *
305 * More concretely, the orders of dimensions for each style are as follows:
306 * C-style (numpy default):
307 * array[HigherDims..., Z, Y, X]
308 * Fortran style:
309 * array[X, Y, Z, HigherDims...]
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100310 */
311 template <typename T>
312 void fill_layer_data(T &&tensor, std::string name) const;
313
314private:
315 // Function prototype to convert between image formats.
316 using Converter = void (*)(const RawTensor &src, RawTensor &dst);
317 // Function prototype to extract a channel from an image.
318 using Extractor = void (*)(const RawTensor &src, RawTensor &dst);
319 // Function prototype to load an image file.
320 using Loader = RawTensor (*)(const std::string &path);
321
322 const Converter &get_converter(Format src, Format dst) const;
323 const Converter &get_converter(DataType src, Format dst) const;
324 const Converter &get_converter(Format src, DataType dst) const;
325 const Converter &get_converter(DataType src, DataType dst) const;
326 const Extractor &get_extractor(Format format, Channel) const;
327 const Loader &get_loader(const std::string &extension) const;
328
329 /** Creates a raw tensor from the specified image.
330 *
331 * @param[in] name To be loaded image file.
332 *
333 * @note If use_single_image is true @p name is ignored and the user image
334 * is loaded instead.
335 */
336 RawTensor load_image(const std::string &name) const;
337
338 /** Provides a raw tensor for the specified image and format.
339 *
340 * @param[in] name Image file used to look up the raw tensor.
341 * @param[in] format Format used to look up the raw tensor.
342 *
343 * If the tensor has already been requested before the cached version will
344 * be returned. Otherwise the tensor will be added to the cache.
345 *
346 * @note If use_single_image is true @p name is ignored and the user image
347 * is loaded instead.
348 */
349 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format) const;
350
351 /** Provides a raw tensor for the specified image, format and channel.
352 *
353 * @param[in] name Image file used to look up the raw tensor.
354 * @param[in] format Format used to look up the raw tensor.
355 * @param[in] channel Channel used to look up the raw tensor.
356 *
357 * If the tensor has already been requested before the cached version will
358 * be returned. Otherwise the tensor will be added to the cache.
359 *
360 * @note If use_single_image is true @p name is ignored and the user image
361 * is loaded instead.
362 */
363 const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const;
364
365 mutable TensorCache _cache{};
366 mutable std::mutex _format_lock{};
367 mutable std::mutex _channel_lock{};
Anthony Barbierac69aa12017-07-03 17:39:37 +0100368 const std::string _library_path;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100369 std::random_device::result_type _seed;
370};
371
372template <typename T, typename D>
Giorgio Arenaa2611812017-07-21 10:08:48 +0100373void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
374{
375 const PaddingSize padding_size = tensor.padding();
376
377 Window window;
378 window.set(0, Window::Dimension(-padding_size.left, tensor.shape()[0] + padding_size.right, 1));
379 window.set(1, Window::Dimension(-padding_size.top, tensor.shape()[1] + padding_size.bottom, 1));
380
381 std::mt19937 gen(_seed);
382
383 execute_window_loop(window, [&](const Coordinates & id)
384 {
385 TensorShape shape = tensor.shape();
386
387 // If outside of valid region
388 if(id.x() < 0 || id.x() >= static_cast<int>(shape.x()) || id.y() < 0 || id.y() >= static_cast<int>(shape.y()))
389 {
390 using ResultType = typename std::remove_reference<D>::type::result_type;
391 const ResultType value = distribution(gen);
392 void *const out_ptr = tensor(id);
393 store_value_with_data_type(out_ptr, value, tensor.data_type());
394 }
395 });
396}
397
398template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100399void AssetsLibrary::fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100400{
401 Window window;
402 for(unsigned int d = 0; d < tensor.shape().num_dimensions(); ++d)
403 {
404 window.set(d, Window::Dimension(0, tensor.shape()[d], 1));
405 }
406
407 std::mt19937 gen(_seed + seed_offset);
408
409 //FIXME: Replace with normal loop
410 execute_window_loop(window, [&](const Coordinates & id)
411 {
412 using ResultType = typename std::remove_reference<D>::type::result_type;
413 const ResultType value = distribution(gen);
414 void *const out_ptr = tensor(id);
415 store_value_with_data_type(out_ptr, value, tensor.data_type());
416 });
Giorgio Arenaa2611812017-07-21 10:08:48 +0100417
418 fill_borders_with_garbage(tensor, distribution, seed_offset);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100419}
420
421template <typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100422void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100423{
424 std::mt19937 gen(_seed + seed_offset);
425
426 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
427 {
428 using ResultType = typename std::remove_reference<D>::type::result_type;
429 const ResultType value = distribution(gen);
430 store_value_with_data_type(raw.data() + offset, value, raw.data_type());
431 }
432}
433
434template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100435void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100436{
437 const RawTensor &raw = get(name, format);
438
439 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
440 {
441 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
442
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100443 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
444 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100445 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
446 }
447}
448
449template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100450void AssetsLibrary::fill(T &&tensor, const std::string &name, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100451{
452 fill(std::forward<T>(tensor), name, get_format_for_channel(channel), channel);
453}
454
455template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100456void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format, Channel channel) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100457{
458 const RawTensor &raw = get(name, format, channel);
459
460 for(size_t offset = 0; offset < raw.size(); offset += raw.element_size())
461 {
462 const Coordinates id = index2coord(raw.shape(), offset / raw.element_size());
463
Moritz Pflanzer82e70a12017-08-08 16:20:45 +0100464 const RawTensor::value_type *const raw_ptr = raw.data() + offset;
465 const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100466 std::copy_n(raw_ptr, raw.element_size(), out_ptr);
467 }
468}
469
470template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100471void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100472{
473 switch(tensor.data_type())
474 {
475 case DataType::U8:
476 {
477 std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max());
478 fill(tensor, distribution_u8, seed_offset);
479 break;
480 }
481 case DataType::S8:
482 case DataType::QS8:
483 {
484 std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max());
485 fill(tensor, distribution_s8, seed_offset);
486 break;
487 }
488 case DataType::U16:
489 {
490 std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max());
491 fill(tensor, distribution_u16, seed_offset);
492 break;
493 }
494 case DataType::S16:
Gian Marco Iodicebdb6b0b2017-06-30 12:21:00 +0100495 case DataType::QS16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100496 {
497 std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max());
498 fill(tensor, distribution_s16, seed_offset);
499 break;
500 }
501 case DataType::U32:
502 {
503 std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max());
504 fill(tensor, distribution_u32, seed_offset);
505 break;
506 }
507 case DataType::S32:
508 {
509 std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max());
510 fill(tensor, distribution_s32, seed_offset);
511 break;
512 }
513 case DataType::U64:
514 {
515 std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max());
516 fill(tensor, distribution_u64, seed_offset);
517 break;
518 }
519 case DataType::S64:
520 {
521 std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max());
522 fill(tensor, distribution_s64, seed_offset);
523 break;
524 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100525 case DataType::F16:
SiCong Li02dfb2c2017-07-27 17:59:20 +0100526 {
527 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
528 std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f);
529 fill(tensor, distribution_f16, seed_offset);
530 break;
531 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100532 case DataType::F32:
533 {
534 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
535 std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f);
536 fill(tensor, distribution_f32, seed_offset);
537 break;
538 }
539 case DataType::F64:
540 {
541 // It doesn't make sense to check [-inf, inf], so hard code it to a big number
542 std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f);
543 fill(tensor, distribution_f64, seed_offset);
544 break;
545 }
546 case DataType::SIZET:
547 {
548 std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max());
549 fill(tensor, distribution_sizet, seed_offset);
550 break;
551 }
552 default:
553 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
554 }
555}
556
557template <typename T, typename D>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100558void 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 +0100559{
560 switch(tensor.data_type())
561 {
562 case DataType::U8:
563 {
564 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value));
565 std::uniform_int_distribution<uint8_t> distribution_u8(low, high);
566 fill(tensor, distribution_u8, seed_offset);
567 break;
568 }
569 case DataType::S8:
570 case DataType::QS8:
571 {
572 ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value));
573 std::uniform_int_distribution<int8_t> distribution_s8(low, high);
574 fill(tensor, distribution_s8, seed_offset);
575 break;
576 }
577 case DataType::U16:
578 {
579 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value));
580 std::uniform_int_distribution<uint16_t> distribution_u16(low, high);
581 fill(tensor, distribution_u16, seed_offset);
582 break;
583 }
584 case DataType::S16:
Georgios Pinitas21efeb42017-07-04 12:47:17 +0100585 case DataType::QS16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100586 {
587 ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value));
588 std::uniform_int_distribution<int16_t> distribution_s16(low, high);
589 fill(tensor, distribution_s16, seed_offset);
590 break;
591 }
592 case DataType::U32:
593 {
594 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value));
595 std::uniform_int_distribution<uint32_t> distribution_u32(low, high);
596 fill(tensor, distribution_u32, seed_offset);
597 break;
598 }
599 case DataType::S32:
600 {
601 ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value));
602 std::uniform_int_distribution<int32_t> distribution_s32(low, high);
603 fill(tensor, distribution_s32, seed_offset);
604 break;
605 }
606 case DataType::U64:
607 {
608 ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value));
609 std::uniform_int_distribution<uint64_t> distribution_u64(low, high);
610 fill(tensor, distribution_u64, seed_offset);
611 break;
612 }
613 case DataType::S64:
614 {
615 ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value));
616 std::uniform_int_distribution<int64_t> distribution_s64(low, high);
617 fill(tensor, distribution_s64, seed_offset);
618 break;
619 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100620 case DataType::F16:
621 {
Moritz Pflanzere49e2662017-07-21 15:55:28 +0100622 std::uniform_real_distribution<float> distribution_f16(low, high);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100623 fill(tensor, distribution_f16, seed_offset);
624 break;
625 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100626 case DataType::F32:
627 {
628 ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value));
629 std::uniform_real_distribution<float> distribution_f32(low, high);
630 fill(tensor, distribution_f32, seed_offset);
631 break;
632 }
633 case DataType::F64:
634 {
635 ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value));
636 std::uniform_real_distribution<double> distribution_f64(low, high);
637 fill(tensor, distribution_f64, seed_offset);
638 break;
639 }
640 case DataType::SIZET:
641 {
642 ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value));
643 std::uniform_int_distribution<size_t> distribution_sizet(low, high);
644 fill(tensor, distribution_sizet, seed_offset);
645 break;
646 }
647 default:
648 ARM_COMPUTE_ERROR("NOT SUPPORTED!");
649 }
650}
651
652template <typename T>
Moritz Pflanzerfb5aabb2017-07-18 14:39:55 +0100653void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100654{
655#ifdef _WIN32
656 const std::string path_separator("\\");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100657#else /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100658 const std::string path_separator("/");
Anthony Barbierac69aa12017-07-03 17:39:37 +0100659#endif /* _WIN32 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100660 const std::string path = _library_path + path_separator + name;
661
SiCong Li86b53332017-08-23 11:02:43 +0100662 std::vector<unsigned long> shape;
663
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100664 // Open file
SiCong Li86b53332017-08-23 11:02:43 +0100665 std::ifstream stream(path, std::ios::in | std::ios::binary);
666 ARM_COMPUTE_ERROR_ON_MSG(!stream.good(), "Failed to load binary data");
667 // Check magic bytes and version number
668 unsigned char v_major = 0;
669 unsigned char v_minor = 0;
670 npy::read_magic(stream, &v_major, &v_minor);
671
672 // Read header
673 std::string header;
674 if(v_major == 1 && v_minor == 0)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100675 {
SiCong Li86b53332017-08-23 11:02:43 +0100676 header = npy::read_header_1_0(stream);
677 }
678 else if(v_major == 2 && v_minor == 0)
679 {
680 header = npy::read_header_2_0(stream);
681 }
682 else
683 {
684 ARM_COMPUTE_ERROR("Unsupported file format version");
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100685 }
686
SiCong Li86b53332017-08-23 11:02:43 +0100687 // Parse header
688 bool fortran_order = false;
689 std::string typestr;
690 npy::ParseHeader(header, typestr, &fortran_order, shape);
691
692 // Check if the typestring matches the given one
693 std::string expect_typestr = get_typestring(tensor.data_type());
694 ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
695
696 // Validate tensor shape
697 ARM_COMPUTE_ERROR_ON_MSG(shape.size() != tensor.shape().num_dimensions(), "Tensor ranks mismatch");
698 if(fortran_order)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100699 {
SiCong Li86b53332017-08-23 11:02:43 +0100700 for(size_t i = 0; i < shape.size(); ++i)
701 {
702 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[i], "Tensor dimensions mismatch");
703 }
704 }
705 else
706 {
707 for(size_t i = 0; i < shape.size(); ++i)
708 {
709 ARM_COMPUTE_ERROR_ON_MSG(tensor.shape()[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
710 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100711 }
712
SiCong Li86b53332017-08-23 11:02:43 +0100713 // Read data
714 if(tensor.padding().empty())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100715 {
SiCong Li86b53332017-08-23 11:02:43 +0100716 // If tensor has no padding read directly from stream.
717 stream.read(reinterpret_cast<char *>(tensor.data()), tensor.size());
718 }
719 else
720 {
721 // If tensor has padding accessing tensor elements through execution window.
722 Window window;
723 window.use_tensor_dimensions(tensor.shape());
724
725 //FIXME : Replace with normal loop
726 execute_window_loop(window, [&](const Coordinates & id)
727 {
728 stream.read(reinterpret_cast<char *>(tensor(id)), tensor.element_size());
729 });
730 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100731}
732} // namespace test
733} // namespace arm_compute
Anthony Barbierac69aa12017-07-03 17:39:37 +0100734#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */