From 633d30be83a7cc76cf7221d7004d768dc4381742 Mon Sep 17 00:00:00 2001 From: Michele Di Giorgio Date: Tue, 8 Oct 2019 17:17:18 +0100 Subject: COMPMID-2306: CLDepthwiseConvolution: support for QUANT8_PER_CHANNEL_SYMM - Reference This patch modifies the reference implementation and the fixtures of depthwise convolution layer to support QSYMM8_PER_CHANNEL quantization. Change-Id: I28adb5c110308b1024a213bec2d35a89180a46dc Signed-off-by: Michele Di Giorgio Reviewed-on: https://review.mlplatform.org/c/2063 Reviewed-by: Giorgio Arena Comments-Addressed: Arm Jenkins Reviewed-by: Giuseppe Rossini Tested-by: Arm Jenkins --- .../reference/DepthwiseConvolutionLayer.cpp | 82 ++++++++++++++++------ 1 file changed, 60 insertions(+), 22 deletions(-) (limited to 'tests/validation/reference/DepthwiseConvolutionLayer.cpp') diff --git a/tests/validation/reference/DepthwiseConvolutionLayer.cpp b/tests/validation/reference/DepthwiseConvolutionLayer.cpp index b1d2b923f7..7458f815b8 100644 --- a/tests/validation/reference/DepthwiseConvolutionLayer.cpp +++ b/tests/validation/reference/DepthwiseConvolutionLayer.cpp @@ -40,7 +40,9 @@ namespace validation { namespace reference { -/** Perform a depthwise convolution +namespace +{ +/** Perform a depthwise convolution for floating-point types * * - Three dimensions tensors * - Third dimention is number of channels @@ -48,9 +50,9 @@ namespace reference * - Padding, stride and output shape "match" * */ -template -SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, const PadStrideInfo &conv_info, - unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +template +SimpleTensor depthwise_convolution_fp(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, const PadStrideInfo &conv_info, + unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) { ARM_COMPUTE_UNUSED(out_quant_info); @@ -114,7 +116,7 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTe } } - dst[out_pos++] = saturate_cast(val + *static_cast(biases(Coordinates(out_z)))); + dst[out_pos++] = saturate_cast(val + *static_cast(biases(Coordinates(out_z)))); } } } @@ -124,26 +126,32 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTe return dst; } -template <> -SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, - const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +/** Perform a quantized depthwise convolution + * + * - Three dimensions tensors + * - Third dimention is number of channels + * - Depths of input tensor and filter are equals + * - Padding, stride and output shape "match" + * - QASYMM8 input, output + * - QASYMM8 or QSYMM8_PER_CHANNEL filter + * + */ +template +SimpleTensor depthwise_convolution_quantized(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) { // if no explicit quantization has been set you the same as src const QuantizationInfo &dst_qinfo = out_quant_info.uniform().empty() ? src.quantization_info() : out_quant_info; - SimpleTensor dst{ dst_shape, src.data_type(), 1, dst_qinfo }; + SimpleTensor dst{ dst_shape, src.data_type(), 1, dst_qinfo }; // Create reference const int input_offset = -src.quantization_info().uniform().offset; const float input_scale = src.quantization_info().uniform().scale; const int weights_offset = -weights.quantization_info().uniform().offset; - const float weights_scale = weights.quantization_info().uniform().scale; const int output_offset = dst_qinfo.uniform().offset; const float output_scale = dst_qinfo.uniform().scale; - int output_multiplier = 0; - int output_shift = 0; - const float multiplier = input_scale * weights_scale / output_scale; - arm_compute::quantization::calculate_quantized_multiplier_less_than_one(multiplier, &output_multiplier, &output_shift); + const std::vector weights_scale_vec = weights.quantization_info().scale(); // Compute reference const int filter_width = weights.shape().x(); @@ -173,11 +181,19 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, co const int maximum_x = input_width + pad_left + pad_right - static_cast(patch_width); const int maximum_y = input_height + pad_top + pad_bottom - static_cast(patch_height); + const bool is_quantized_per_channel = is_data_type_quantized_per_channel(weights.data_type()); + int out_pos = 0; for(int r = 0; r < num_batches; ++r) { for(int z = 0; z < input_depth; ++z) { + int output_multiplier = 0; + int output_shift = 0; + const float weights_scale = (is_quantized_per_channel) ? weights_scale_vec[z] : weights_scale_vec[0]; + const float multiplier = input_scale * weights_scale / output_scale; + arm_compute::quantization::calculate_quantized_multiplier_less_than_one(multiplier, &output_multiplier, &output_shift); + for(unsigned int m = 0; m < depth_multiplier; ++m) { const int out_z = z * depth_multiplier + m; @@ -197,8 +213,8 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, co { coords.set(0, i); coords.set(1, j); - const auto in_val = tensor_elem_at(src, coords, BorderMode::CONSTANT, -input_offset); - const uint8_t w_val = *(weights.data() + filter_offset); + const auto in_val = tensor_elem_at(src, coords, BorderMode::CONSTANT, -input_offset); + const TW w_val = *(weights.data() + filter_offset); val += (in_val + input_offset) * (w_val + weights_offset); ++filter_offset; } @@ -206,8 +222,7 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, co val += bias_val; val = asymm_rounding_divide_by_pow2(asymm_int_mult(val, output_multiplier), output_shift); val += output_offset; - val = std::max(val, 0); - val = std::min(val, 255); + val = utility::clamp(val, 0, 255); // Store the result dst[out_pos++] = val; @@ -219,12 +234,35 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, co return dst; } +} // namespace + +template <> +SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +{ + return depthwise_convolution_fp(src, weights, biases, dst_shape, conv_info, depth_multiplier, dilation, out_quant_info); +} -template SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, - const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info); +template <> +SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +{ + return depthwise_convolution_fp(src, weights, biases, dst_shape, conv_info, depth_multiplier, dilation, out_quant_info); +} -template SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, - const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info); +template <> +SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +{ + return depthwise_convolution_quantized(src, weights, biases, dst_shape, conv_info, depth_multiplier, dilation, out_quant_info); +} + +template <> +SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTensor &weights, const SimpleTensor &biases, const TensorShape &dst_shape, + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) +{ + return depthwise_convolution_quantized(src, weights, biases, dst_shape, conv_info, depth_multiplier, dilation, out_quant_info); +} } // namespace reference } // namespace validation } // namespace test -- cgit v1.2.1