From 0a878ae1bbb13002e50f8287721750d2e4b22680 Mon Sep 17 00:00:00 2001 From: Jaroslaw Rzepecki Date: Wed, 22 Nov 2017 17:16:39 +0000 Subject: COMPMID-556: Added a rounding policy to the quantize function Change-Id: I6272a36636c5d9baff6d35dee0a50dc847f65bfa Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/110266 Tested-by: BSG Visual Compute Jenkins server to access repositories on http://mpd-gerrit.cambridge.arm.com Reviewed-by: Anthony Barbier --- arm_compute/core/Types.h | 23 +++++++++-------- arm_compute/core/Utils.h | 9 +++++++ src/core/CL/kernels/CLActivationLayerKernel.cpp | 4 +-- src/core/Utils.cpp | 34 +++++++++++++++++++++++++ src/runtime/CL/functions/CLPoolingLayer.cpp | 2 +- tests/validation/Helpers.cpp | 2 +- tests/validation/UNIT/Utils.cpp | 14 ++++++++++ 7 files changed, 74 insertions(+), 14 deletions(-) diff --git a/arm_compute/core/Types.h b/arm_compute/core/Types.h index 36ec38ff68..c77f1d4157 100644 --- a/arm_compute/core/Types.h +++ b/arm_compute/core/Types.h @@ -102,6 +102,17 @@ constexpr float SCALE_PYRAMID_HALF = 0.5f; /* Constant value used to indicate a ORB scaled pyramid */ constexpr float SCALE_PYRAMID_ORB = 8.408964152537146130583778358414e-01; +/** Rounding method */ +enum class RoundingPolicy +{ + TO_ZERO, /**< Truncates the least significand values that are lost in operations. */ + TO_NEAREST_UP, /**< Rounds to nearest value; half rounds away from zero */ + TO_NEAREST_EVEN, /**< Rounds to nearest value; half rounds to nearest even */ +}; + +//forward declare round function +int round(float, RoundingPolicy); + /** Quantization settings (used for QASYMM8 data type) */ struct QuantizationInfo { @@ -129,10 +140,10 @@ struct QuantizationInfo int offset; /**< offset */ /** Quantizes a value using the scale/offset in this QuantizationInfo */ - uint8_t quantize(float value) const + uint8_t quantize(float value, RoundingPolicy rounding_policy) const { ARM_COMPUTE_ERROR_ON_MSG(scale == 0, "QuantizationInfo::quantize: scale == 0"); - int quantized = static_cast(value / scale + offset); + int quantized = arm_compute::round(value / scale, rounding_policy) + offset; quantized = std::max(0, std::min(quantized, 255)); return quantized; } @@ -296,14 +307,6 @@ enum class ThresholdType RANGE /**< Threshold with two values*/ }; -/** Rounding method */ -enum class RoundingPolicy -{ - TO_ZERO, /**< Truncates the least significand values that are lost in operations. */ - TO_NEAREST_UP, /**< Rounds to nearest value; half rounds up */ - TO_NEAREST_EVEN /**< Rounds to nearest value; half rounds to nearest even */ -}; - /** Termination criteria */ enum class Termination { diff --git a/arm_compute/core/Utils.h b/arm_compute/core/Utils.h index af9cf23548..9397d507f8 100644 --- a/arm_compute/core/Utils.h +++ b/arm_compute/core/Utils.h @@ -62,6 +62,15 @@ constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m) return (val + m - 1) / m; } +/** Return a rounded value of x. Rounding is done according to the rounding_policy. + * + * @param[in] x Float value to be rounded. + * @param[in] rounding_policy Policy determining how rounding is done. + * + * @return Rounded value of the argument x. + */ +int round(float x, RoundingPolicy rounding_policy); + /** Returns the arm_compute library build information * * Contains the version number and the build options used to build the library diff --git a/src/core/CL/kernels/CLActivationLayerKernel.cpp b/src/core/CL/kernels/CLActivationLayerKernel.cpp index 0f7003a38c..8172aafca9 100644 --- a/src/core/CL/kernels/CLActivationLayerKernel.cpp +++ b/src/core/CL/kernels/CLActivationLayerKernel.cpp @@ -131,8 +131,8 @@ void CLActivationLayerKernel::configure(ICLTensor *input, ICLTensor *output, Act } else { - a_const_int = input->info()->quantization_info().quantize(a_const); - b_const_int = input->info()->quantization_info().quantize(b_const); + a_const_int = input->info()->quantization_info().quantize(a_const, RoundingPolicy::TO_NEAREST_UP); + b_const_int = input->info()->quantization_info().quantize(b_const, RoundingPolicy::TO_NEAREST_UP); } } diff --git a/src/core/Utils.cpp b/src/core/Utils.cpp index af864f57f7..af50bbbaf7 100644 --- a/src/core/Utils.cpp +++ b/src/core/Utils.cpp @@ -21,10 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + #include "arm_compute/core/Utils.h" #include "arm_compute/core/FixedPoint.h" +#include "support/ToolchainSupport.h" + #include #include #include @@ -387,3 +390,34 @@ int arm_compute::max_consecutive_elements_display_width(std::ostream &s, DataTyp } return 0; } + +int arm_compute::round(float x, RoundingPolicy rounding_policy) +{ + using namespace std; + int rounded = 0; + switch(rounding_policy) + { + case RoundingPolicy::TO_ZERO: + { + rounded = static_cast(x); + break; + } + case RoundingPolicy::TO_NEAREST_UP: + { + rounded = static_cast(support::cpp11::round(x)); + break; + } + case RoundingPolicy::TO_NEAREST_EVEN: + { + ARM_COMPUTE_ERROR("TO_NEAREST_EVEN rounding policy is not supported."); + break; + } + default: + { + ARM_COMPUTE_ERROR("Unsupported rounding policy."); + break; + } + } + + return rounded; +} diff --git a/src/runtime/CL/functions/CLPoolingLayer.cpp b/src/runtime/CL/functions/CLPoolingLayer.cpp index ac360fbb3d..20564f6c9d 100644 --- a/src/runtime/CL/functions/CLPoolingLayer.cpp +++ b/src/runtime/CL/functions/CLPoolingLayer.cpp @@ -46,7 +46,7 @@ void CLPoolingLayer::configure(ICLTensor *input, ICLTensor *output, const Poolin uint32_t border_value = 0; if(is_data_type_quantized_asymmetric(input->info()->data_type()) && !pool_info.exclude_padding()) { - border_value = static_cast(input->info()->quantization_info().quantize(0)); + border_value = static_cast(input->info()->quantization_info().quantize(0.f, RoundingPolicy::TO_NEAREST_UP)); } _border_handler.configure(input, _kernel->border_size(), border_mode, PixelValue(border_value)); diff --git a/tests/validation/Helpers.cpp b/tests/validation/Helpers.cpp index 3ef5fc1cc5..313b059a8c 100644 --- a/tests/validation/Helpers.cpp +++ b/tests/validation/Helpers.cpp @@ -129,7 +129,7 @@ SimpleTensor convert_to_asymmetric(const SimpleTensor &src, cons SimpleTensor dst{ src.shape(), DataType::QASYMM8, 1, 0, quantization_info }; for(int i = 0; i < src.num_elements(); ++i) { - dst[i] = quantization_info.quantize(src[i]); + dst[i] = quantization_info.quantize(src[i], RoundingPolicy::TO_NEAREST_UP); } return dst; } diff --git a/tests/validation/UNIT/Utils.cpp b/tests/validation/UNIT/Utils.cpp index 96f9997d5b..b73edb1fb8 100644 --- a/tests/validation/UNIT/Utils.cpp +++ b/tests/validation/UNIT/Utils.cpp @@ -60,6 +60,20 @@ DATA_TEST_CASE(Index2Coord, framework::DatasetMode::ALL, zip(zip(framework::data ARM_COMPUTE_EXPECT(compare_dimensions(coordinate, ref_coordinate), framework::LogLevel::ERRORS); } +DATA_TEST_CASE(RoundFloatToZero, framework::DatasetMode::ALL, zip(framework::dataset::make("FloatIn", { 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }), + framework::dataset::make("FloatOut", { 1.f, 1.f, 1.f, 2.f, 2.f, -3.f, -3.f, -3.f, -4.f, -4.f })), + value, result) +{ + ARM_COMPUTE_EXPECT(round(value, RoundingPolicy::TO_ZERO) == result, framework::LogLevel::ERRORS); +} + +DATA_TEST_CASE(RoundFloatToNearestUp, framework::DatasetMode::ALL, zip(framework::dataset::make("FloatIn", { 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }), + framework::dataset::make("FloatOut", { 1.f, 1.f, 2.f, 3.f, 3.f, -3.f, -4.f, -4.f, -4.f, -5.f })), + value, result) +{ + ARM_COMPUTE_EXPECT(round(value, RoundingPolicy::TO_NEAREST_UP) == result, framework::LogLevel::ERRORS); +} + //FIXME: Negative tests only work in debug mode #if 0 DISABLED_DATA_TEST_CASE(Index2CoordFail, framework::DatasetMode::ALL, zip(framework::dataset::make("Shape", { TensorShape{}, TensorShape{ 2U }, TensorShape{ 2U } }), framework::dataset::make("Index", { 0, -1, 2 })), -- cgit v1.2.1