From 587708b05ca63fa88118daec82e2c39d63e60086 Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Mon, 31 Dec 2018 15:43:52 +0000 Subject: COMPMID-1796: Add support for ranged distribution. Change-Id: I6347a02219bf47e21a29b9b5d1a9e7e23de8a502 Reviewed-on: https://review.mlplatform.org/482 Reviewed-by: Michele Di Giorgio Tested-by: Arm Jenkins --- arm_compute/core/utils/misc/Random.h | 98 ++++++++++++++++ tests/AssetsLibrary.h | 124 ++++++++++++++++++++- .../fixtures/ElementwiseOperationsFixture.h | 4 +- 3 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 arm_compute/core/utils/misc/Random.h diff --git a/arm_compute/core/utils/misc/Random.h b/arm_compute/core/utils/misc/Random.h new file mode 100644 index 0000000000..4c40f5c2d7 --- /dev/null +++ b/arm_compute/core/utils/misc/Random.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_MISC_RANDOM_H__ +#define __ARM_COMPUTE_MISC_RANDOM_H__ + +#include "arm_compute/core/Error.h" + +#include +#include + +namespace arm_compute +{ +namespace utils +{ +namespace random +{ +/** Uniform distribution within a given number of sub-ranges + * + * @tparam T Distribution primitive type + */ +template +class RangedUniformDistribution +{ +public: + using DT = typename std::conditional::value, + std::uniform_int_distribution, + std::uniform_real_distribution>::type; + using result_type = T; + using range_pair = std::pair; + +public: + /** Constructor + * + * @param[in] low lowest value in the range (inclusive) + * @param[in] high highest value in the range (inclusive for uniform_int_distribution, exclusive for uniform_real_distribution) + * @param[in] exclude_ranges Ranges to exclude from the generator + */ + RangedUniformDistribution(result_type low, result_type high, const std::vector &exclude_ranges) + : _distributions(), _selector() + { + result_type clow = low; + for(const auto &erange : exclude_ranges) + { + result_type epsilon = std::is_integral::value ? 1 : static_cast(std::numeric_limits::epsilon()); + + ARM_COMPUTE_ERROR_ON(clow > erange.first || clow >= erange.second); + + _distributions.emplace_back(DT(clow, erange.first - epsilon)); + clow = erange.second + epsilon; + } + ARM_COMPUTE_ERROR_ON(clow > high); + _distributions.emplace_back(DT(clow, high)); + _selector = std::uniform_int_distribution(0, _distributions.size() - 1); + } + /** Generate random number + * + * @tparam URNG Random number generator object type + * + * @param[in] g A uniform random number generator object, used as the source of randomness. + * + * @return A new random number. + */ + template + result_type operator()(URNG &g) + { + unsigned int rand_select = _selector(g); + return _distributions[rand_select](g); + } + +private: + std::vector
_distributions; + std::uniform_int_distribution _selector; +}; +} // namespace random +} // namespace utils +} // namespace arm_compute +#endif /* __ARM_COMPUTE_MISC_RANDOM_H__ */ diff --git a/tests/AssetsLibrary.h b/tests/AssetsLibrary.h index 7af036d256..d09e22762d 100644 --- a/tests/AssetsLibrary.h +++ b/tests/AssetsLibrary.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -31,6 +31,7 @@ #include "arm_compute/core/TensorShape.h" #include "arm_compute/core/Types.h" #include "arm_compute/core/Window.h" +#include "arm_compute/core/utils/misc/Random.h" #include "libnpy/npy.hpp" #include "tests/RawTensor.h" #include "tests/TensorCache.h" @@ -57,6 +58,9 @@ namespace test */ class AssetsLibrary final { +public: + using RangePair = std::pair; + public: /** Initialises the library with a @p path to the assets directory. * Furthermore, sets the seed for the random generator to @p seed. @@ -312,7 +316,7 @@ public: template void fill(T &&tensor, RawTensor raw) const; - /** Fill a tensor with uniform distribution across the range of its type + /** Fill a tensor with uniform distribution * * @param[in, out] tensor To be filled tensor. * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. @@ -320,7 +324,7 @@ public: template void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const; - /** Fill a tensor with uniform distribution across the a specified range + /** Fill a tensor with uniform distribution * * @param[in, out] tensor To be filled tensor. * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. @@ -332,6 +336,17 @@ public: template void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const; + /** Fill a tensor with uniform distribution across the specified range + * + * @param[in, out] tensor To be filled tensor. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + * @param[in] excluded_range_pairs Ranges to exclude from the generator + */ + template + void fill_tensor_uniform_ranged(T &&tensor, + std::random_device::result_type seed_offset, + const std::vector &excluded_range_pairs) const; + /** Fills the specified @p tensor with data loaded from .npy (numpy binary) in specified path. * * @param[in, out] tensor To be filled tensor. @@ -420,6 +435,23 @@ private: std::random_device::result_type _seed; }; +namespace detail +{ +template +inline std::vector> convert_range_pair(const std::vector &excluded_range_pairs) +{ + std::vector> converted; + std::transform(excluded_range_pairs.begin(), + excluded_range_pairs.end(), + std::back_inserter(converted), + [](const AssetsLibrary::RangePair & p) + { + return std::pair(static_cast(p.first), static_cast(p.second)); + }); + return converted; +} +} // namespace detail + template void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const { @@ -498,6 +530,7 @@ void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::r { using ResultType = typename std::remove_reference::type::result_type; const ResultType value = distribution(gen); + store_value_with_data_type(raw.data() + offset, value, raw.data_type()); } } @@ -637,6 +670,91 @@ void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_t } } +template +void AssetsLibrary::fill_tensor_uniform_ranged(T &&tensor, + std::random_device::result_type seed_offset, + const std::vector &excluded_range_pairs) const +{ + using namespace arm_compute::utils::random; + + switch(tensor.data_type()) + { + case DataType::U8: + case DataType::QASYMM8: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_u8(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_u8, seed_offset); + break; + } + case DataType::S8: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_s8(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_s8, seed_offset); + break; + } + case DataType::U16: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_u16(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_u16, seed_offset); + break; + } + case DataType::S16: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_s16(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_s16, seed_offset); + break; + } + case DataType::U32: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_u32(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_u32, seed_offset); + break; + } + case DataType::S32: + { + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_s32(std::numeric_limits::lowest(), + std::numeric_limits::max(), + converted_pairs); + fill(tensor, distribution_s32, seed_offset); + break; + } + case DataType::F16: + { + // It doesn't make sense to check [-inf, inf], so hard code it to a big number + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_f16(-100.f, 100.f, converted_pairs); + fill(tensor, distribution_f16, seed_offset); + break; + } + case DataType::F32: + { + // It doesn't make sense to check [-inf, inf], so hard code it to a big number + const auto converted_pairs = detail::convert_range_pair(excluded_range_pairs); + RangedUniformDistribution distribution_f32(-1000.f, 1000.f, converted_pairs); + fill(tensor, distribution_f32, seed_offset); + break; + } + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } +} + template void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const { diff --git a/tests/validation/fixtures/ElementwiseOperationsFixture.h b/tests/validation/fixtures/ElementwiseOperationsFixture.h index 8190b2405a..8b88f6a8fb 100644 --- a/tests/validation/fixtures/ElementwiseOperationsFixture.h +++ b/tests/validation/fixtures/ElementwiseOperationsFixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -58,7 +58,7 @@ protected: template void fill(U &&tensor, int i) { - library->fill_tensor_uniform(tensor, i); + (_op == ArithmeticOperation::DIV) ? library->fill_tensor_uniform_ranged(tensor, i, { std::pair(-0.001f, 0.001f) }) : library->fill_tensor_uniform(tensor, i); } TensorType compute_target(const TensorShape &shape0, const TensorShape &shape1, DataType data_type0, DataType data_type1, DataType output_data_type, -- cgit v1.2.1