From 4c5469b192665c94118a8a558787cb9cec2d0765 Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Tue, 21 May 2019 13:32:43 +0100 Subject: COMPMID-2225: Add interface support for new quantized data types. Add support for: -QSYMM8, 8-bit quantized symmetric -QSYMM8_PER_CHANNEL, 8-bit quantized symmetric with per channel quantization Change-Id: I00c4ff98e44af37419470af61419ee95d0de2463 Signed-off-by: Georgios Pinitas Reviewed-on: https://review.mlplatform.org/c/1236 Tested-by: Arm Jenkins Reviewed-by: Gian Marco Iodice Comments-Addressed: Arm Jenkins --- tests/validation/CL/UNIT/TensorAllocator.cpp | 42 ++++++++++++++ tests/validation/Helpers.cpp | 16 +++--- tests/validation/UNIT/TensorInfo.cpp | 64 +++++++++++++++++++++- .../fixtures/NormalizePlanarYUVLayerFixture.h | 4 +- tests/validation/fixtures/RangeFixture.h | 6 +- tests/validation/reference/ConcatenateLayer.cpp | 9 ++- tests/validation/reference/Convolution3d.h | 22 +++++--- tests/validation/reference/DeconvolutionLayer.cpp | 2 +- .../validation/reference/DepthConcatenateLayer.cpp | 20 ++++--- .../reference/DepthwiseConvolutionLayer.cpp | 27 ++++----- .../reference/DepthwiseConvolutionLayer.h | 2 +- tests/validation/reference/DequantizationLayer.cpp | 6 +- tests/validation/reference/FullyConnectedLayer.cpp | 16 ++++-- tests/validation/reference/Im2Col.cpp | 6 +- tests/validation/reference/QuantizationLayer.cpp | 11 ++-- tests/validation/reference/QuantizationLayer.h | 2 +- tests/validation/reference/Scale.cpp | 6 +- 17 files changed, 192 insertions(+), 69 deletions(-) (limited to 'tests/validation') diff --git a/tests/validation/CL/UNIT/TensorAllocator.cpp b/tests/validation/CL/UNIT/TensorAllocator.cpp index e5b37d8387..4b8e105240 100644 --- a/tests/validation/CL/UNIT/TensorAllocator.cpp +++ b/tests/validation/CL/UNIT/TensorAllocator.cpp @@ -66,6 +66,7 @@ TEST_SUITE(CL) TEST_SUITE(UNIT) TEST_SUITE(TensorAllocator) +/** Validates import memory interface when importing cl buffer objects */ TEST_CASE(ImportMemoryBuffer, framework::DatasetMode::ALL) { // Init tensor info @@ -106,6 +107,7 @@ TEST_CASE(ImportMemoryBuffer, framework::DatasetMode::ALL) ARM_COMPUTE_EXPECT(t4.cl_buffer().get() != buf.get(), framework::LogLevel::ERRORS); } +/** Validates import memory interface when importing malloced memory */ TEST_CASE(ImportMemoryMalloc, framework::DatasetMode::ALL) { // Check if import extension is supported @@ -168,6 +170,7 @@ TEST_CASE(ImportMemoryMalloc, framework::DatasetMode::ALL) } #if !defined(BARE_METAL) +/** Validates import memory interface when importing memory mapped objects */ TEST_CASE(ImportMemoryMappedFile, framework::DatasetMode::ALL) { // Check if import extension is supported @@ -235,6 +238,45 @@ TEST_CASE(ImportMemoryMappedFile, framework::DatasetMode::ALL) } #endif // !defined(BARE_METAL) +/** Validates symmetric per channel quantization */ +TEST_CASE(Symm8PerChannelQuantizationInfo, framework::DatasetMode::ALL) +{ + // Create tensor + CLTensor tensor; + const std::vector scale = { 0.25f, 1.4f, 3.2f, 2.3f, 4.7f }; + const TensorInfo info(TensorShape(32U, 16U), 1, DataType::QSYMM8_PER_CHANNEL, QuantizationInfo(scale)); + tensor.allocator()->init(info); + + // Check quantization information + ARM_COMPUTE_EXPECT(!tensor.info()->quantization_info().empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!tensor.info()->quantization_info().scale.empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(tensor.info()->quantization_info().scale.size() == scale.size(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(tensor.info()->quantization_info().offset.empty(), framework::LogLevel::ERRORS); + + CLQuantization quantization = tensor.quantization(); + ARM_COMPUTE_ASSERT(quantization.scale != nullptr); + ARM_COMPUTE_ASSERT(quantization.offset != nullptr); + + // Check OpenCL quantization arrays before allocating + ARM_COMPUTE_EXPECT(quantization.scale->max_num_values() == 0, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(quantization.offset->max_num_values() == 0, framework::LogLevel::ERRORS); + + // Check OpenCL quantization arrays after allocating + tensor.allocator()->allocate(); + ARM_COMPUTE_EXPECT(quantization.scale->max_num_values() == scale.size(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(quantization.offset->max_num_values() == 0, framework::LogLevel::ERRORS); + + // Validate that the scale values are the same + auto cl_scale_buffer = quantization.scale->cl_buffer(); + void *mapped_ptr = CLScheduler::get().queue().enqueueMapBuffer(cl_scale_buffer, CL_TRUE, CL_MAP_READ, 0, scale.size()); + auto cl_scale_ptr = static_cast(mapped_ptr); + for(unsigned int i = 0; i < scale.size(); ++i) + { + ARM_COMPUTE_EXPECT(cl_scale_ptr[i] == scale[i], framework::LogLevel::ERRORS); + } + CLScheduler::get().queue().enqueueUnmapMemObject(cl_scale_buffer, mapped_ptr); +} + TEST_SUITE_END() // TensorAllocator TEST_SUITE_END() // UNIT TEST_SUITE_END() // CL diff --git a/tests/validation/Helpers.cpp b/tests/validation/Helpers.cpp index 71a674b515..31d6bfae07 100644 --- a/tests/validation/Helpers.cpp +++ b/tests/validation/Helpers.cpp @@ -110,22 +110,24 @@ CannyEdgeParameters canny_edge_parameters() SimpleTensor convert_from_asymmetric(const SimpleTensor &src) { - const QuantizationInfo &quantization_info = src.quantization_info(); - SimpleTensor dst{ src.shape(), DataType::F32, 1, QuantizationInfo(), src.data_layout() }; + const UniformQuantizationInfo &quantization_info = src.quantization_info().uniform(); + SimpleTensor dst{ src.shape(), DataType::F32, 1, QuantizationInfo(), src.data_layout() }; for(int i = 0; i < src.num_elements(); ++i) { - dst[i] = quantization_info.dequantize(src[i]); + dst[i] = dequantize_qasymm8(src[i], quantization_info); } return dst; } SimpleTensor convert_to_asymmetric(const SimpleTensor &src, const QuantizationInfo &quantization_info) { - SimpleTensor dst{ src.shape(), DataType::QASYMM8, 1, quantization_info }; + SimpleTensor dst{ src.shape(), DataType::QASYMM8, 1, quantization_info }; + const UniformQuantizationInfo &qinfo = quantization_info.uniform(); + for(int i = 0; i < src.num_elements(); ++i) { - dst[i] = quantization_info.quantize(src[i], RoundingPolicy::TO_NEAREST_UP); + dst[i] = quantize_qasymm8(src[i], qinfo); } return dst; } @@ -267,8 +269,8 @@ std::pair get_quantized_bounds(const QuantizationInfo &quant_info, flo { ARM_COMPUTE_ERROR_ON_MSG(min > max, "min must be lower equal than max"); - const int min_bound = quant_info.quantize(min, RoundingPolicy::TO_NEAREST_UP); - const int max_bound = quant_info.quantize(max, RoundingPolicy::TO_NEAREST_UP); + const int min_bound = quantize_qasymm8(min, quant_info.uniform()); + const int max_bound = quantize_qasymm8(max, quant_info.uniform()); return std::pair { min_bound, max_bound }; } diff --git a/tests/validation/UNIT/TensorInfo.cpp b/tests/validation/UNIT/TensorInfo.cpp index b78f656932..96d07da2b4 100644 --- a/tests/validation/UNIT/TensorInfo.cpp +++ b/tests/validation/UNIT/TensorInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -122,6 +122,68 @@ TEST_CASE(TensorInfoBuild, framework::DatasetMode::ALL) ARM_COMPUTE_EXPECT(info.tensor_shape() == TensorShape(13U, 15U), framework::LogLevel::ERRORS); } +/** Validates empty quantization info */ +TEST_CASE(NoQuantizationInfo, framework::DatasetMode::ALL) +{ + // Create tensor info + const TensorInfo info(TensorShape(32U, 16U), 1, DataType::F32); + + // Check quantization information + ARM_COMPUTE_EXPECT(info.quantization_info().empty(), framework::LogLevel::ERRORS); +} + +/** Validates symmetric quantization info */ +TEST_CASE(SymmQuantizationInfo, framework::DatasetMode::ALL) +{ + // Create tensor info + const float scale = 0.25f; + const TensorInfo info(TensorShape(32U, 16U), 1, DataType::QSYMM8, QuantizationInfo(scale)); + + // Check quantization information + ARM_COMPUTE_EXPECT(!info.quantization_info().empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!info.quantization_info().scale.empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().scale.size() == 1, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().offset.empty(), framework::LogLevel::ERRORS); + + UniformQuantizationInfo qinfo = info.quantization_info().uniform(); + ARM_COMPUTE_EXPECT(qinfo.scale == scale, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(qinfo.offset == 0.f, framework::LogLevel::ERRORS); +} + +/** Validates asymmetric quantization info */ +TEST_CASE(AsymmQuantizationInfo, framework::DatasetMode::ALL) +{ + // Create tensor info + const float scale = 0.25f; + const int32_t offset = 126; + const TensorInfo info(TensorShape(32U, 16U), 1, DataType::QSYMM8, QuantizationInfo(scale, offset)); + + // Check quantization information + ARM_COMPUTE_EXPECT(!info.quantization_info().empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!info.quantization_info().scale.empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().scale.size() == 1, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!info.quantization_info().offset.empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().offset.size() == 1, framework::LogLevel::ERRORS); + + UniformQuantizationInfo qinfo = info.quantization_info().uniform(); + ARM_COMPUTE_EXPECT(qinfo.scale == scale, framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(qinfo.offset == offset, framework::LogLevel::ERRORS); +} + +/** Validates symmetric per channel quantization info */ +TEST_CASE(SymmPerChannelQuantizationInfo, framework::DatasetMode::ALL) +{ + // Create tensor info + const std::vector scale = { 0.25f, 1.4f, 3.2f, 2.3f, 4.7f }; + const TensorInfo info(TensorShape(32U, 16U), 1, DataType::QSYMM8_PER_CHANNEL, QuantizationInfo(scale)); + + // Check quantization information + ARM_COMPUTE_EXPECT(!info.quantization_info().empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!info.quantization_info().scale.empty(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().scale.size() == scale.size(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(info.quantization_info().offset.empty(), framework::LogLevel::ERRORS); +} + TEST_SUITE_END() // TensorInfoValidation TEST_SUITE_END() } // namespace validation diff --git a/tests/validation/fixtures/NormalizePlanarYUVLayerFixture.h b/tests/validation/fixtures/NormalizePlanarYUVLayerFixture.h index 93e4e64830..b46bd3c407 100644 --- a/tests/validation/fixtures/NormalizePlanarYUVLayerFixture.h +++ b/tests/validation/fixtures/NormalizePlanarYUVLayerFixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -71,7 +71,7 @@ protected: const QuantizationInfo quant_info = src_tensor.quantization_info(); std::pair bounds = get_quantized_bounds(quant_info, -1.f, 1.0f); std::uniform_int_distribution<> distribution(bounds.first, bounds.second); - std::uniform_int_distribution<> distribution_std(quant_info.quantize(0.1f, RoundingPolicy::TO_NEAREST_UP), bounds.second); + std::uniform_int_distribution<> distribution_std(quantize_qasymm8(0.1f, quant_info.uniform()), bounds.second); library->fill(src_tensor, distribution, 0); library->fill(mean_tensor, distribution, 1); library->fill(std_tensor, distribution_std, 2); diff --git a/tests/validation/fixtures/RangeFixture.h b/tests/validation/fixtures/RangeFixture.h index c192eee14f..4862069694 100644 --- a/tests/validation/fixtures/RangeFixture.h +++ b/tests/validation/fixtures/RangeFixture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -95,7 +95,9 @@ protected: end += std::max(half(1.0f), static_cast(distribution(gen))) * step; return utility::clamp(end); case DataType::QASYMM8: - return utility::clamp(end + (float)distribution(gen) * step, qinfo_out.dequantize(0), qinfo_out.dequantize(std::numeric_limits::max())); + return utility::clamp(end + (float)distribution(gen) * step, + dequantize_qasymm8(0, qinfo_out.uniform()), + dequantize_qasymm8(std::numeric_limits::max(), qinfo_out.uniform())); default: return 0; } diff --git a/tests/validation/reference/ConcatenateLayer.cpp b/tests/validation/reference/ConcatenateLayer.cpp index af818a576c..6c90d74a0f 100644 --- a/tests/validation/reference/ConcatenateLayer.cpp +++ b/tests/validation/reference/ConcatenateLayer.cpp @@ -72,10 +72,13 @@ SimpleTensor widthconcatenate_layer(const std::vector> &srcs, const int offset = u * height * depth + d * height + r; if(src.data_type() == DataType::QASYMM8 && src.quantization_info() != dst.quantization_info()) { - std::transform(src_ptr, src_ptr + width, dst_ptr + width_offset + offset * width_out, [src, dst](T t) + const UniformQuantizationInfo iq_info = src.quantization_info().uniform(); + const UniformQuantizationInfo oq_info = dst.quantization_info().uniform(); + + std::transform(src_ptr, src_ptr + width, dst_ptr + width_offset + offset * width_out, [&](T t) { - const float dequantized_input = src.quantization_info().dequantize(t); - return dst.quantization_info().quantize(dequantized_input, RoundingPolicy::TO_NEAREST_UP); + const float dequantized_input = dequantize_qasymm8(t, iq_info); + return quantize_qasymm8(dequantized_input, oq_info); }); src_ptr += width; } diff --git a/tests/validation/reference/Convolution3d.h b/tests/validation/reference/Convolution3d.h index 2e5fefd99a..30be25f504 100644 --- a/tests/validation/reference/Convolution3d.h +++ b/tests/validation/reference/Convolution3d.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -9,14 +9,14 @@ * 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: - *asymm_int_mult + * * 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, asymm_int_multDAMAGES OR OTHER + * 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. @@ -101,12 +101,16 @@ inline void convolution3d(const SimpleTensor &in, const SimpleTensor &weig const TB *b_ptr = bias.data() + b_offset; T *out_ptr = out.data() + o_offset; - const int input_offset = -in.quantization_info().offset; - const float input_scale = in.quantization_info().scale; - const int weights_offset = -weights.quantization_info().offset; - const float weights_scale = weights.quantization_info().scale; - const int output_offset = out.quantization_info().offset; - const float output_scale = out.quantization_info().scale; + const UniformQuantizationInfo iq_info = in.quantization_info().uniform(); + const UniformQuantizationInfo wq_info = weights.quantization_info().uniform(); + const UniformQuantizationInfo oq_info = out.quantization_info().uniform(); + + const int input_offset = -iq_info.offset; + const float input_scale = iq_info.scale; + const int weights_offset = -wq_info.offset; + const float weights_scale = wq_info.scale; + const int output_offset = oq_info.offset; + const float output_scale = oq_info.scale; int output_multiplier = 0; int output_shift = 0; diff --git a/tests/validation/reference/DeconvolutionLayer.cpp b/tests/validation/reference/DeconvolutionLayer.cpp index 916792479f..af59830722 100644 --- a/tests/validation/reference/DeconvolutionLayer.cpp +++ b/tests/validation/reference/DeconvolutionLayer.cpp @@ -68,7 +68,7 @@ SimpleTensor deconvolution_layer(const SimpleTensor &src, const SimpleTens if(src.data_type() == DataType::QASYMM8) { - const uint8_t quantized_zero = src.quantization_info().offset; + const uint8_t quantized_zero = src.quantization_info().uniform().offset; std::fill_n(scaled.data(), scaled.num_elements(), quantized_zero); } else diff --git a/tests/validation/reference/DepthConcatenateLayer.cpp b/tests/validation/reference/DepthConcatenateLayer.cpp index 22271a0d10..d6e6e78187 100644 --- a/tests/validation/reference/DepthConcatenateLayer.cpp +++ b/tests/validation/reference/DepthConcatenateLayer.cpp @@ -55,6 +55,7 @@ SimpleTensor depthconcatenate_layer(const std::vector> &srcs, { return tensor.quantization_info() != dst.quantization_info(); }; + if(srcs[0].data_type() == DataType::QASYMM8 && std::any_of(srcs.cbegin(), srcs.cend(), have_different_quantization_info)) { for(int b = 0; b < batches; ++b) @@ -64,11 +65,14 @@ SimpleTensor depthconcatenate_layer(const std::vector> &srcs, int slice = 0; for(const auto &src : srcs) { - auto ptr_slice = static_cast(dst(Coordinates(0, 0, slice, b))); - const auto num_elems_in_slice((dst.num_elements() / depth_out) * src.shape().z()); - std::transform(ptr_slice, ptr_slice + num_elems_in_slice, ptr_slice, [src, dst](T) + auto ptr_slice = static_cast(dst(Coordinates(0, 0, slice, b))); + const auto num_elems_in_slice((dst.num_elements() / depth_out) * src.shape().z()); + const UniformQuantizationInfo iq_info = src.quantization_info().uniform(); + const UniformQuantizationInfo oq_info = dst.quantization_info().uniform(); + + std::transform(ptr_slice, ptr_slice + num_elems_in_slice, ptr_slice, [&](T) { - return dst.quantization_info().quantize(src.quantization_info().dequantize(0), RoundingPolicy::TO_NEAREST_UP); + return quantize_qasymm8(dequantize_qasymm8(0, iq_info), oq_info); }); slice += src.shape().z(); } @@ -102,10 +106,12 @@ SimpleTensor depthconcatenate_layer(const std::vector> &srcs, { if(src.data_type() == DataType::QASYMM8 && src.quantization_info() != dst.quantization_info()) { - std::transform(src_ptr, src_ptr + width, dst.data() + offset_to_first_element + d * out_stride_z + r * width_out, [src, dst](T t) + const UniformQuantizationInfo iq_info = src.quantization_info().uniform(); + const UniformQuantizationInfo oq_info = dst.quantization_info().uniform(); + std::transform(src_ptr, src_ptr + width, dst.data() + offset_to_first_element + d * out_stride_z + r * width_out, [&](T t) { - const float dequantized_input = src.quantization_info().dequantize(t); - return dst.quantization_info().quantize(dequantized_input, RoundingPolicy::TO_NEAREST_UP); + const float dequantized_input = dequantize_qasymm8(t, iq_info); + return quantize_qasymm8(dequantized_input, oq_info); }); src_ptr += width; } diff --git a/tests/validation/reference/DepthwiseConvolutionLayer.cpp b/tests/validation/reference/DepthwiseConvolutionLayer.cpp index 90ecffbbca..2192d681b6 100644 --- a/tests/validation/reference/DepthwiseConvolutionLayer.cpp +++ b/tests/validation/reference/DepthwiseConvolutionLayer.cpp @@ -50,7 +50,7 @@ namespace reference */ 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, QuantizationInfo out_quant_info) + unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info) { ARM_COMPUTE_UNUSED(out_quant_info); @@ -126,22 +126,19 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, const SimpleTe 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, QuantizationInfo out_quant_info) + 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 - if(out_quant_info == QuantizationInfo(0.0f, 0)) - { - out_quant_info = src.quantization_info(); - } - SimpleTensor dst{ dst_shape, src.data_type(), 1, out_quant_info }; + 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 }; // Create reference - const int input_offset = -src.quantization_info().offset; - const float input_scale = src.quantization_info().scale; - const int weights_offset = -weights.quantization_info().offset; - const float weights_scale = weights.quantization_info().scale; - const int output_offset = dst.quantization_info().offset; - const float output_scale = dst.quantization_info().scale; + 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.quantization_info().uniform().offset; + const float output_scale = dst.quantization_info().uniform().scale; int output_multiplier; int output_shift; @@ -224,10 +221,10 @@ SimpleTensor depthwise_convolution(const SimpleTensor &src, co } 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, QuantizationInfo out_quant_info); + 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, QuantizationInfo out_quant_info); + const PadStrideInfo &conv_info, unsigned int depth_multiplier, const Size2D &dilation, const QuantizationInfo &out_quant_info); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/DepthwiseConvolutionLayer.h b/tests/validation/reference/DepthwiseConvolutionLayer.h index ac70de02ca..ee323fa8df 100644 --- a/tests/validation/reference/DepthwiseConvolutionLayer.h +++ b/tests/validation/reference/DepthwiseConvolutionLayer.h @@ -37,7 +37,7 @@ namespace reference { 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 = Size2D(1U, 1U), QuantizationInfo out_quant_info = QuantizationInfo(0.0f, 0)); + unsigned int depth_multiplier, const Size2D &dilation = Size2D(1U, 1U), const QuantizationInfo &out_quant_info = QuantizationInfo(0.0f, 0)); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/DequantizationLayer.cpp b/tests/validation/reference/DequantizationLayer.cpp index df50c14ec7..286a609d79 100644 --- a/tests/validation/reference/DequantizationLayer.cpp +++ b/tests/validation/reference/DequantizationLayer.cpp @@ -34,14 +34,14 @@ namespace reference template SimpleTensor dequantization_layer(const SimpleTensor &src) { - const DataType dst_data_type = std::is_same::value ? DataType::F32 : DataType::F16; - const QuantizationInfo &quantization_info = src.quantization_info(); + const DataType dst_data_type = std::is_same::value ? DataType::F32 : DataType::F16; + const UniformQuantizationInfo &quantization_info = src.quantization_info().uniform(); SimpleTensor dst{ src.shape(), dst_data_type }; for(int i = 0; i < src.num_elements(); ++i) { - dst[i] = static_cast(quantization_info.dequantize(src[i])); + dst[i] = static_cast(dequantize_qasymm8(src[i], quantization_info)); } return dst; diff --git a/tests/validation/reference/FullyConnectedLayer.cpp b/tests/validation/reference/FullyConnectedLayer.cpp index 07ddf6d308..cd84b9cfd1 100644 --- a/tests/validation/reference/FullyConnectedLayer.cpp +++ b/tests/validation/reference/FullyConnectedLayer.cpp @@ -67,12 +67,16 @@ void vector_matrix_multiply(const SimpleTensor &src, const SimpleTensor &w const TB *bias_ptr = bias.data(); T *dst_ptr = dst.data() + offset_dst; - const int input_offset = -src.quantization_info().offset; - const float input_scale = src.quantization_info().scale; - const int weights_offset = -weights.quantization_info().offset; - const float weights_scale = weights.quantization_info().scale; - const int output_offset = dst.quantization_info().offset; - const float output_scale = dst.quantization_info().scale; + const UniformQuantizationInfo iq_info = src.quantization_info().uniform(); + const UniformQuantizationInfo wq_info = weights.quantization_info().uniform(); + const UniformQuantizationInfo oq_info = dst.quantization_info().uniform(); + + const int input_offset = -iq_info.offset; + const float input_scale = iq_info.scale; + const int weights_offset = -wq_info.offset; + const float weights_scale = wq_info.scale; + const int output_offset = oq_info.offset; + const float output_scale = oq_info.scale; int output_multiplier = 0; int output_shift = 0; diff --git a/tests/validation/reference/Im2Col.cpp b/tests/validation/reference/Im2Col.cpp index 076b2aba07..4d63696e67 100644 --- a/tests/validation/reference/Im2Col.cpp +++ b/tests/validation/reference/Im2Col.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -50,7 +50,7 @@ void im2col_nchw(const SimpleTensor &src, SimpleTensor &dst, const Size2D const int src_channels = src.shape().z(); const int batches = src.shape().total_size_upper(3); const int dst_height = dst.shape().y(); - const int pad_val = is_data_type_quantized_asymmetric(src.data_type()) ? src.quantization_info().offset : 0; + const int pad_val = is_data_type_quantized_asymmetric(src.data_type()) ? src.quantization_info().uniform().offset : 0; int dst_idx = 0; // Compute width and height of the convolved tensors @@ -105,7 +105,7 @@ void im2col_nhwc(const SimpleTensor &src, SimpleTensor &dst, const Size2D const int batches = src.shape().total_size_upper(3); const int dst_width = has_bias ? dst.shape().x() - 1 : dst.shape().x(); const int dst_height = dst.shape().y(); - const int pad_val = is_data_type_quantized_asymmetric(src.data_type()) ? src.quantization_info().offset : 0; + const int pad_val = is_data_type_quantized_asymmetric(src.data_type()) ? src.quantization_info().uniform().offset : 0; // Compute width and height of the convolved tensors std::pair convolved_dims = scaled_dimensions(src_width, src_height, kernel_dims.width, kernel_dims.height, conv_info); diff --git a/tests/validation/reference/QuantizationLayer.cpp b/tests/validation/reference/QuantizationLayer.cpp index 2f3348178c..182585abf9 100644 --- a/tests/validation/reference/QuantizationLayer.cpp +++ b/tests/validation/reference/QuantizationLayer.cpp @@ -34,24 +34,25 @@ namespace validation namespace reference { template -SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo quantization_info) +SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo &quantization_info) { // Create reference SimpleTensor dst{ src.shape(), DataType::QASYMM8, 1, quantization_info }; + const UniformQuantizationInfo qinfo = quantization_info.uniform(); for(int i = 0; i < src.num_elements(); ++i) { #ifdef __aarch64__ - dst[i] = quantization_info.quantize((src[i]), RoundingPolicy::TO_NEAREST_EVEN); + dst[i] = quantize_qasymm8((src[i]), qinfo, RoundingPolicy::TO_NEAREST_EVEN); #else // __aarch64__ - dst[i] = quantization_info.quantize((src[i]), RoundingPolicy::TO_ZERO); + dst[i] = quantize_qasymm8((src[i]), qinfo, RoundingPolicy::TO_ZERO); #endif // __aarch64__ } return dst; } -template SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo quantization_info); -template SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo quantization_info); +template SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo &quantization_info); +template SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo &quantization_info); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/QuantizationLayer.h b/tests/validation/reference/QuantizationLayer.h index 2d136908af..462396f131 100644 --- a/tests/validation/reference/QuantizationLayer.h +++ b/tests/validation/reference/QuantizationLayer.h @@ -36,7 +36,7 @@ namespace validation namespace reference { template -SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo quantization_info); +SimpleTensor quantization_layer(const SimpleTensor &src, const QuantizationInfo &quantization_info); } // namespace reference } // namespace validation } // namespace test diff --git a/tests/validation/reference/Scale.cpp b/tests/validation/reference/Scale.cpp index 2f7bf2deb3..84f4fb83c1 100644 --- a/tests/validation/reference/Scale.cpp +++ b/tests/validation/reference/Scale.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -180,10 +180,10 @@ SimpleTensor scale(const SimpleTensor &src, float scale_x, flo SamplingPolicy sampling_policy, bool ceil_policy_scale) { SimpleTensor dst; - if(src.quantization_info().scale != 0.f) + if(src.quantization_info().uniform().scale != 0.f) { SimpleTensor src_tmp = convert_from_asymmetric(src); - float constant_border_value_f = scvt_f32_qasymm8(constant_border_value, src.quantization_info().scale, src.quantization_info().offset); + float constant_border_value_f = dequantize_qasymm8(constant_border_value, src.quantization_info()); SimpleTensor dst_tmp = scale_core(src_tmp, scale_x, scale_y, policy, border_mode, constant_border_value_f, sampling_policy, ceil_policy_scale); dst = convert_to_asymmetric(dst_tmp, src.quantization_info()); } -- cgit v1.2.1