From 3d13af8a39f408318328a95d5329bc17fd923438 Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Tue, 4 Jun 2019 13:04:16 +0100 Subject: COMPMID-2235: Extend type support for CL/NEON DequantizationLayer. Adds support for: - QSYMM8 Change-Id: Ia0b839fc844ce0f968dad1b69a001f9a660dbcd5 Signed-off-by: Georgios Pinitas Reviewed-on: https://review.mlplatform.org/c/1378 Comments-Addressed: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Manuel Bottini Reviewed-by: Michalis Spyrou --- .../core/CL/kernels/CLDequantizationLayerKernel.h | 4 +- arm_compute/core/NEON/NEAsymm.h | 46 ++++++++++++++ .../NEON/kernels/NEDequantizationLayerKernel.h | 4 +- arm_compute/core/QuantizationInfo.h | 71 +++++++++++++++++----- 4 files changed, 107 insertions(+), 18 deletions(-) (limited to 'arm_compute/core') diff --git a/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h b/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h index 3dfb19b306..6d37f6a1a5 100644 --- a/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h +++ b/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h @@ -48,13 +48,13 @@ public: ~CLDequantizationLayerKernel() = default; /** Set the input, output, min and max. * - * @param[in] input Source tensor. Data types supported: QASYMM8. + * @param[in] input Source tensor. Data types supported: QASYMM8/QSYMM8. * @param[out] output Destination tensor. Data types supported: F16/F32. */ void configure(const ICLTensor *input, ICLTensor *output); /** Static function to check if given info will lead to a valid configuration of @ref CLDequantizationLayerKernel * - * @param[in] input Input tensor info. Data types supported: QASYMM8. + * @param[in] input Input tensor info. Data types supported: QASYMM8/QSYMM8. * @param[in] output Output tensor info. Data types supported: F16/F32. * * @return a status diff --git a/arm_compute/core/NEON/NEAsymm.h b/arm_compute/core/NEON/NEAsymm.h index 2347c468ab..4c8f797360 100644 --- a/arm_compute/core/NEON/NEAsymm.h +++ b/arm_compute/core/NEON/NEAsymm.h @@ -223,6 +223,52 @@ inline float32x4x4_t vdequantize(const uint8x16_t &qv, const UniformQuantization return vdequantized_input; } +/** Dequantize following an asymmetric quantization scheme a neon vector holding 16 quantized values. + * + * @param[in] qv Input values to be dequantized. + * @param[in] scale Quantization scaling factor. + * @param[in] offset Zero quantization offset. + * + * @return Dequantized values in a neon vector + */ +inline float32x4x4_t vdequantize(const uint8x16_t &qv, float scale, int32_t offset) +{ + const int32x4_t voffset = vdupq_n_s32(offset); + const float32x4_t vscale = vdupq_n_f32(scale); + const float32x4x4_t vdequantized_input = + { + { + vmulq_f32(vcvtq_f32_s32(vsubq_s32(vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(vmovl_u8(vget_low_u8(qv))))), voffset)), vscale), + vmulq_f32(vcvtq_f32_s32(vsubq_s32(vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(vmovl_u8(vget_low_u8(qv))))), voffset)), vscale), + vmulq_f32(vcvtq_f32_s32(vsubq_s32(vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(vmovl_u8(vget_high_u8(qv))))), voffset)), vscale), + vmulq_f32(vcvtq_f32_s32(vsubq_s32(vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(vmovl_u8(vget_high_u8(qv))))), voffset)), vscale), + } + }; + return vdequantized_input; +} + +/** Dequantize following a symmetric quantization scheme a neon vector holding 16 quantized values. + * + * @param[in] qv Input values to be dequantized. + * @param[in] scale Quantization scaling factor. + * + * @return Dequantized values in a neon vector + */ +inline float32x4x4_t vdequantize(const int8x16_t &qv, float scale) +{ + const float32x4_t vscale = vdupq_n_f32(scale); + const float32x4x4_t vdequantized_input = + { + { + vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(vmovl_s8(vget_low_s8(qv))))), vscale), + vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(vmovl_s8(vget_low_s8(qv))))), vscale), + vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(vmovl_s8(vget_high_s8(qv))))), vscale), + vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(vmovl_s8(vget_high_s8(qv))))), vscale), + } + }; + return vdequantized_input; +} + /** Quantize a neon vector holding 8 floating point values. * * @param[in] qv Input values to be quantized. diff --git a/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h b/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h index 7d215f5f7b..3320ba6889 100644 --- a/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h +++ b/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h @@ -52,13 +52,13 @@ public: ~NEDequantizationLayerKernel() = default; /** Set input, output tensors. * - * @param[in] input Source tensor. Data type supported: QASYMM8. + * @param[in] input Source tensor. Data type supported: QASYMM8/QSYMM8. * @param[out] output Destination tensor with the same dimensions of input. Data type supported: F16/F32. */ void configure(const ITensor *input, ITensor *output); /** Static function to check if given info will lead to a valid configuration of @ref NEDequantizationLayerKernel * - * @param[in] input Input tensor info. Data types supported: QASYMM8. + * @param[in] input Input tensor info. Data types supported: QASYMM8/QSYMM8. * @param[in] output Output tensor info. Data types supported: F16/F32. * * @return a status diff --git a/arm_compute/core/QuantizationInfo.h b/arm_compute/core/QuantizationInfo.h index 06c9b61154..dcfdd6ba16 100644 --- a/arm_compute/core/QuantizationInfo.h +++ b/arm_compute/core/QuantizationInfo.h @@ -63,12 +63,13 @@ struct UniformQuantizationInfo }; /** Quantization information */ -struct QuantizationInfo +class QuantizationInfo { +public: /** Default constructor */ QuantizationInfo() noexcept - : scale(), - offset() + : _scale(), + _offset() { } /** Construct quantization info. @@ -78,7 +79,7 @@ struct QuantizationInfo * @param[in] scale Scale. */ QuantizationInfo(float scale) - : scale(1, scale), offset() + : _scale(1, scale), _offset() { } /** Construct quantization info. @@ -89,7 +90,7 @@ struct QuantizationInfo * @param[in] offset Offset. */ QuantizationInfo(float scale, int offset) - : scale(1, scale), offset(1, offset) + : _scale(1, scale), _offset(1, offset) { } /** Construct quantization info. @@ -99,16 +100,32 @@ struct QuantizationInfo * @param[in] scale Scale. */ QuantizationInfo(std::vector scale) - : scale(scale), offset() + : _scale(scale), _offset() { } + /** Scale vector accessor + * + * @return A reference to quantization scale metadata + */ + const std::vector &scale() const + { + return _scale; + } + /** Offset vector accessor + * + * @return A reference to quantization offset metadata + */ + const std::vector &offset() const + { + return _offset; + } /** Indicates whether this QuantizationInfo has valid settings or not * * @return True if the this has invalid settings. */ bool empty() const { - return scale.empty() && offset.empty(); + return _scale.empty() && _offset.empty(); } /** Return per layer quantization info * @@ -117,14 +134,15 @@ struct QuantizationInfo UniformQuantizationInfo uniform() const { UniformQuantizationInfo uqinfo; - uqinfo.scale = scale.empty() ? 0 : scale[0]; - uqinfo.offset = offset.empty() ? 0 : offset[0]; + uqinfo.scale = _scale.empty() ? 0 : _scale[0]; + uqinfo.offset = _offset.empty() ? 0 : _offset[0]; return uqinfo; } - std::vector scale; /**< Vector containing scaling factors */ - std::vector offset; /**< Vector containing zero offsets */ +private: + std::vector _scale; /**< Vector containing scaling factors */ + std::vector _offset; /**< Vector containing zero offsets */ }; /** Check whether two quantization info are equal. @@ -136,7 +154,7 @@ struct QuantizationInfo */ inline bool operator==(const QuantizationInfo &lhs, const QuantizationInfo &rhs) { - return (lhs.scale == rhs.scale) && (lhs.offset == rhs.offset); + return (lhs.scale() == rhs.scale()) && (lhs.offset() == rhs.offset()); } /** Check whether two quantization info are not equal. @@ -245,6 +263,19 @@ inline float dequantize_qasymm8(uint8_t value, const QuantizationInfo &qinfo) return (static_cast(value) - uqinfo.offset) * uqinfo.scale; } +/** Dequantize a value given an asymmetric quantization scheme + * + * @param[in] value Value to dequantize + * @param[in] scale Scale to use for dequantization + * @param[in] offset Zero-offset to use for dequantization + * + * @return Dequantized value + */ +inline float dequantize(uint8_t value, float scale, int32_t offset) +{ + return (static_cast(value) - offset) * scale; +} + /** Dequantize a value given a symmetric quantization scheme * * @param[in] value Value to dequantize @@ -252,9 +283,21 @@ inline float dequantize_qasymm8(uint8_t value, const QuantizationInfo &qinfo) * * @return Dequantized value */ -inline float dequantize_qsymm8(int8_t value, const QuantizationInfo &qinfo) +inline float dequantize_qsymm8(int8_t value, const UniformQuantizationInfo &qinfo) +{ + return value * qinfo.scale; +} + +/** Dequantize a value given a symmetric quantization scheme + * + * @param[in] value Value to dequantize + * @param[in] scale Scale to use for dequantization + * + * @return Dequantized value + */ +inline float dequantize(int8_t value, float scale) { - return value * qinfo.uniform().scale; + return value * scale; } /** Quantize a value given a 16-bit symmetric quantization scheme -- cgit v1.2.1