From 02c452fe1ec17c3941272a07b5cae1f32d614c56 Mon Sep 17 00:00:00 2001 From: Mohammed Suhail Munshi Date: Thu, 26 Oct 2023 00:14:36 +0100 Subject: Add Dynamic Quantization tests to Fully Connected Layer This patch calculates the output quantization info based on the inputs' quantization information. The previous approach was using the same quantization information for input, weights and output. This implementation does not cover the cases where we have fused activation function. Resolves: [COMPMID-6484] Signed-off-by: Mohammed Suhail Munshi Change-Id: Ib58143165191e82ae8547e661ac7c8d077bda200 Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/10539 Comments-Addressed: Arm Jenkins Reviewed-by: SiCong Li Tested-by: Arm Jenkins Benchmark: Arm Jenkins --- tests/validation/CL/FullyConnectedLayer.cpp | 232 +++++++++++------ tests/validation/Helpers.cpp | 10 +- tests/validation/Helpers.h | 5 +- tests/validation/NEON/FullyConnectedLayer.cpp | 284 ++++++++++++--------- .../fixtures/FullyConnectedLayerFixture.h | 205 ++++++++++++--- 5 files changed, 491 insertions(+), 245 deletions(-) (limited to 'tests') diff --git a/tests/validation/CL/FullyConnectedLayer.cpp b/tests/validation/CL/FullyConnectedLayer.cpp index 474a87dd1c..2f0c86499b 100644 --- a/tests/validation/CL/FullyConnectedLayer.cpp +++ b/tests/validation/CL/FullyConnectedLayer.cpp @@ -40,6 +40,7 @@ namespace test { namespace validation { +using framework::dataset::make; namespace { /** Tolerance for float operations */ @@ -51,15 +52,20 @@ constexpr float tolerance_num = 0.07f; /**< Tolerance n /** Tolerance for quantized asymmetric operations */ constexpr AbsoluteTolerance tolerance_qasymm8(1); -const auto FullyConnectedParameters = combine(framework::dataset::make("TransposeWeights", { false, true }), framework::dataset::make("ReshapeWeights", { false, true })); +const auto FullyConnectedParameters = combine(make("TransposeWeights", { false, true }), make("ReshapeWeights", { false, true })); -const auto QuantizationData = framework::dataset::make("QuantizationInfo", +const auto QuantizationData = make("QuantizationInfo", { QuantizationInfo(1.f / 255.f, 10), QuantizationInfo(1.1f, 10), }); -const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo", +const auto IgnoredQuantizationData = make("IgnoredQuantizationInfo", +{ + QuantizationInfo(), +}); + +const auto ActivationFunctionsDataset = make("ActivationInfo", { ActivationLayerInfo(), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU), @@ -68,11 +74,16 @@ const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::TANH) }); -const auto ActivationFunctionsQuantizedDataset = concat(concat(concat( - framework::dataset::make("ActivationInfo", ActivationLayerInfo()), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f))), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.75f, 0.25f))); +// This dataset case only runs with dynamic quantization +const auto NoActivationFunctionsQuantizedDataset = make("ActivationInfo", +{ + ActivationLayerInfo() +}); + +const auto ActivationFunctionsQuantizedDataset = concat(concat( + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f))), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 0.75f, 0.25f))); } // namespace TEST_SUITE(CL) @@ -81,33 +92,33 @@ TEST_SUITE(FullyConnectedLayer) // *INDENT-OFF* // clang-format off DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip( - framework::dataset::make("InputInfo", { TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Mismatching data types + make("InputInfo", { TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Mismatching data types TensorInfo(TensorShape(8U, 4U, 6U, 4U), 1, DataType::F32), TensorInfo(TensorShape(8U, 4U, 6U, 4U), 1, DataType::F32), TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Invalid weights dimensions TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Wrongly reshaped weights }), - framework::dataset::make("WeightsInfo",{ TensorInfo(TensorShape(315U, 271U), 1, DataType::F16), + make("WeightsInfo",{ TensorInfo(TensorShape(315U, 271U), 1, DataType::F16), TensorInfo(TensorShape(192U, 192U), 1, DataType::F32), TensorInfo(TensorShape(192U, 192U), 1, DataType::F32), TensorInfo(TensorShape(217U, 231U), 1, DataType::F32), TensorInfo(TensorShape(217U, 315U), 1, DataType::F32), })), - framework::dataset::make("BiasInfo",{ TensorInfo(TensorShape(271U), 1, DataType::F32), + make("BiasInfo",{ TensorInfo(TensorShape(271U), 1, DataType::F32), TensorInfo(TensorShape(192U), 1, DataType::F32), TensorInfo(TensorShape(192U), 1, DataType::F32), TensorInfo(TensorShape(271U), 1, DataType::F32), TensorInfo(TensorShape(271U), 1, DataType::F32), })), - framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), + make("OutputInfo",{ TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), TensorInfo(TensorShape(192U, 4U), 1, DataType::F32), TensorInfo(TensorShape(192U, 4U), 1, DataType::F32), TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), })), - framework::dataset::make("TransposeWeights",{ true, true, false, true, true })), - framework::dataset::make("ReshapedWeights",{ false, false, false, false, false})), - framework::dataset::make("Expected", { false, true, true, false, false })), + make("TransposeWeights",{ true, true, false, true, true })), + make("ReshapedWeights",{ false, false, false, false, false})), + make("Expected", { false, true, true, false, false })), input_info, weights_info, bias_info, output_info, transpose_weights, reshaped_weights, expected) { // Create Fully Connected layer info @@ -136,64 +147,64 @@ using CLFullyConnectedNoBiasFixture = FullyConnectedDynamicNoBiasFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F16)), +FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::F16), ActivationFunctionsDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_f16, tolerance_num); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(datasets::LargeFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F16)), +FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(datasets::LargeFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::F16), ActivationFunctionsDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_f16, tolerance_num); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::F16)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo())), - framework::dataset::make("WeightsReshaped", { false, true }))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::F16), + make("ActivationInfo", ActivationLayerInfo()), + make("WeightsReshaped", { false, true }))) { } TEST_SUITE_END() TEST_SUITE(FP32) -FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), +FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, + make("DataType", DataType::F32), ActivationFunctionsDataset)) { // Validate output validate(CLAccessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLFullyConnectedLayerMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLFullyConnectedLayerMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::F32), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) { // Validate output validate(CLAccessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::F32)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo())), - framework::dataset::make("WeightsReshaped", { false, true }))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::F32), + make("ActivationInfo", ActivationLayerInfo()), + make("WeightsReshaped", { false, true }))) { } -FIXTURE_DATA_TEST_CASE(RunDynamicNoBias, CLFullyConnectedNoBiasFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::F32)), - framework::dataset::make("ActivationInfo", { ActivationLayerInfo(), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) })), - framework::dataset::make("WeightsReshaped", { false }))) +FIXTURE_DATA_TEST_CASE(RunDynamicNoBias, CLFullyConnectedNoBiasFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::F32), + make("ActivationInfo", { ActivationLayerInfo(), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }), + make("WeightsReshaped", { false }))) { } -FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), +FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters, + make("DataType", DataType::F32), ActivationFunctionsDataset)) { // Validate output @@ -209,73 +220,130 @@ using CLFullyConnectedLayerQuantizedMixedDataLayoutFixture = FullyConnectedLayer TEST_SUITE(Quantized) TEST_SUITE(QASYMM8) -FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters), framework::dataset::make("DataType", DataType::QASYMM8)), QuantizationData), +FIXTURE_DATA_TEST_CASE(RunSmallWithActivation, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, + combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8), QuantizationData, ActivationFunctionsQuantizedDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8)), - QuantizationData), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayoutWithActivation, CLFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + QuantizationData, + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) { // Validate output validate(CLAccessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::NIGHTLY, - combine(combine(combine(combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters), framework::dataset::make("DataType", DataType::QASYMM8)), QuantizationData), +FIXTURE_DATA_TEST_CASE(RunLargeWithActivation, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::NIGHTLY, + combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8), QuantizationData, ActivationFunctionsQuantizedDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo())), - framework::dataset::make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) + +// Dynamic Quantization Tests +FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, + combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8), IgnoredQuantizationData, + NoActivationFunctionsQuantizedDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_qasymm8); +} +FIXTURE_DATA_TEST_CASE(RunLarge, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::NIGHTLY, + combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8), IgnoredQuantizationData, + NoActivationFunctionsQuantizedDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_qasymm8); +} +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8), + NoActivationFunctionsQuantizedDataset, + make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) { } + +FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + IgnoredQuantizationData, + NoActivationFunctionsQuantizedDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_qasymm8); +} + TEST_SUITE_END() /* QASYMM8 */ TEST_SUITE(QASYMM8_SIGNED) -FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters), framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), QuantizationData), +FIXTURE_DATA_TEST_CASE(RunSmallWithActivation, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, + combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8_SIGNED), QuantizationData, ActivationFunctionsQuantizedDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_qasymm8); } +FIXTURE_DATA_TEST_CASE(RunMixedDataLayoutWithActivation, CLFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + QuantizationData, + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_qasymm8); +} + +// Dynamic Quantization tests below +FIXTURE_DATA_TEST_CASE(RunSmall, CLFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, + combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, make("DataType", DataType::QASYMM8_SIGNED), IgnoredQuantizationData, + NoActivationFunctionsQuantizedDataset)) +{ + // Validate output + validate(CLAccessor(_target), _reference, tolerance_qasymm8); +} + FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, CLFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - QuantizationData), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + IgnoredQuantizationData, + NoActivationFunctionsQuantizedDataset)) { // Validate output validate(CLAccessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo())), - framework::dataset::make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) + +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, CLFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8_SIGNED), + make("ActivationInfo", ActivationLayerInfo()), + make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) { } -FIXTURE_DATA_TEST_CASE(RunDynamicNoBias, CLFullyConnectedNoBiasFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo())), - framework::dataset::make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) +FIXTURE_DATA_TEST_CASE(RunDynamicNoBias, CLFullyConnectedNoBiasFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8_SIGNED), + make("ActivationInfo", ActivationLayerInfo()), + make("WeightsReshaped", { false /* COMPMID-6000: Support FullyConnected with quantized dynamic weights already reshaped */ }))) { } TEST_SUITE_END() // QASYMM8_SIGNED diff --git a/tests/validation/Helpers.cpp b/tests/validation/Helpers.cpp index cb4d87601c..560460fd33 100644 --- a/tests/validation/Helpers.cpp +++ b/tests/validation/Helpers.cpp @@ -426,7 +426,7 @@ QuantizationHint suggest_matmul_dst_q_info_and_bias(const QuantizationInfo &lhs_ } QuantizationHint suggest_mac_dst_q_info_and_bias( - const QuantizationInfo &a_q_info, const QuantizationInfo &b_q_info, int32_t K, DataType data_type, float bias_fraction) + const QuantizationInfo &a_q_info, const QuantizationInfo &b_q_info, int32_t K, DataType data_type, float bias_fraction, int num_sd) { QuantizationInfo c_q_info; @@ -554,8 +554,8 @@ QuantizationHint suggest_mac_dst_q_info_and_bias( const float var_d = std_d * std_d; // Also calculate the suggested bias range - const int32_t min_bias = mean_d_int - 2 * std_d_int; - const int32_t max_bias = mean_d_int + 2 * std_d_int; + const int32_t min_bias = mean_d_int - (num_sd * std_d_int); + const int32_t max_bias = mean_d_int + (num_sd * std_d_int); // Output/C stats const float mean_out = K * mean_a * mean_b + mean_d; @@ -563,8 +563,8 @@ QuantizationHint suggest_mac_dst_q_info_and_bias( const float std_out = sqrt(var_out); // Output quantization setup - const float scale_out = 4 * std_out / 255; - const int32_t offset_out = static_cast(t_min - (mean_out - 2.f * std_out) / scale_out); + const float scale_out = (2 * num_sd) * std_out / 255; + const int32_t offset_out = static_cast(t_min - (mean_out - (num_sd * std_out)) / scale_out); c_q_info = QuantizationInfo(scale_out, offset_out); diff --git a/tests/validation/Helpers.h b/tests/validation/Helpers.h index 5a1e69afbd..647adcdb69 100644 --- a/tests/validation/Helpers.h +++ b/tests/validation/Helpers.h @@ -286,12 +286,13 @@ QuantizationHint suggest_matmul_dst_q_info_and_bias(const QuantizationInfo &lhs_ * @param[in] k number of accumulations taking place in the sum, i.e. c_k = sum_k(a_k * b_k) * @param[in] data_type data type, only QASYMM8, QASYMM8_SIGNED are supported * @param[in] bias_fraction the fraction of bias amplitude compared to integer accummulation. + * @param[in] num_sd (Optional) number of standard deviations we allow from the mean. Default value is 2. * * @return QuantizationHint object containing the suggested output quantization info and min/max bias range */ QuantizationHint suggest_mac_dst_q_info_and_bias(const QuantizationInfo &lhs_q_info, - const QuantizationInfo &rhs_q_info, int32_t k, DataType data_type, - float bias_fraction); + const QuantizationInfo &rhs_q_info, int32_t k, DataType data_type, float bias_fraction, + int num_sd = 2); } // namespace validation } // namespace test } // namespace arm_compute diff --git a/tests/validation/NEON/FullyConnectedLayer.cpp b/tests/validation/NEON/FullyConnectedLayer.cpp index 04889a9dba..31db8f0f80 100644 --- a/tests/validation/NEON/FullyConnectedLayer.cpp +++ b/tests/validation/NEON/FullyConnectedLayer.cpp @@ -42,6 +42,7 @@ namespace test { namespace validation { +using framework::dataset::make; namespace { /** Tolerance for float operations */ @@ -58,7 +59,7 @@ constexpr AbsoluteTolerance tolerance_qasymm8(1); constexpr AbsoluteTolerance tolerance_qasymm8_signed(1); /** CNN data types */ -const auto CNNDataTypes = framework::dataset::make("DataType", +const auto CNNDataTypes = make("DataType", { #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC DataType::F16, @@ -66,18 +67,25 @@ const auto CNNDataTypes = framework::dataset::make("DataType", DataType::F32, }); -const auto FullyConnectedParameters = combine(framework::dataset::make("TransposeWeights", { false, true }), framework::dataset::make("ReshapeWeights", { false, true })); +const auto FullyConnectedParameters = combine(make("TransposeWeights", { false, true }), make("ReshapeWeights", { false, true })); -const auto QuantizationData = framework::dataset::make("QuantizationInfo", +const auto QuantizationData = make("QuantizationInfo", { QuantizationInfo(1.f / 256.f, 10), QuantizationInfo(1.1f, 10), }); -const auto EmptyActivationFunctionDataset = framework::dataset::make("ActivationInfo", + +const auto IgnoredQuantizationData = make("IgnoredQuantizationInfo", +{ + QuantizationInfo(), +}); + +const auto NoActivationFunctionDataset = make("ActivationInfo", { ActivationLayerInfo(), }); -const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo", + +const auto ActivationFunctionsDataset = make("ActivationInfo", { ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f), @@ -85,7 +93,7 @@ const auto ActivationFunctionsDataset = framework::dataset::make("ActivationInfo ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::TANH), }); -const auto ActivationFunctionsQuantizedDataset = framework::dataset::make("ActivationInfo", +const auto ActivationFunctionsQuantizedDataset = make("ActivationInfo", { ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 0.5f), @@ -242,37 +250,37 @@ TEST_CASE(Quant8_Signed_Mult_gt_1, framework::DatasetMode::ALL) // *INDENT-OFF* // clang-format off DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip( - framework::dataset::make("InputInfo", { TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Mismatching data types + make("InputInfo", { TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Mismatching data types TensorInfo(TensorShape(8U, 4U, 6U, 4U), 1, DataType::F32), TensorInfo(TensorShape(8U, 4U, 6U, 4U), 1, DataType::F32), TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Invalid weights dimensions TensorInfo(TensorShape(9U, 5U, 7U, 3U), 1, DataType::F32), // Wrongly reshaped weights TensorInfo(TensorShape(8U, 4U, 6U, 4U), 1, DataType::F32), }), - framework::dataset::make("WeightsInfo",{ TensorInfo(TensorShape(315U, 271U), 1, DataType::F16), + make("WeightsInfo",{ TensorInfo(TensorShape(315U, 271U), 1, DataType::F16), TensorInfo(TensorShape(192U, 192U), 1, DataType::F32), TensorInfo(TensorShape(192U, 192U), 1, DataType::F32), TensorInfo(TensorShape(217U, 315U), 1, DataType::F32), TensorInfo(TensorShape(217U, 315U), 1, DataType::F32), TensorInfo(TensorShape(192U, 192U), 1, DataType::F32), })), - framework::dataset::make("BiasInfo",{ TensorInfo(TensorShape(271U), 1, DataType::F32), + make("BiasInfo",{ TensorInfo(TensorShape(271U), 1, DataType::F32), TensorInfo(TensorShape(192U), 1, DataType::F32), TensorInfo(TensorShape(192U), 1, DataType::F32), TensorInfo(TensorShape(271U), 1, DataType::F32), TensorInfo(TensorShape(271U), 1, DataType::F32), TensorInfo(TensorShape(192U), 1, DataType::F32), })), - framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), + make("OutputInfo",{ TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), TensorInfo(TensorShape(192U, 4U), 1, DataType::F32), TensorInfo(TensorShape(192U, 4U), 1, DataType::F32), TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), TensorInfo(TensorShape(271U, 3U), 1, DataType::F32), TensorInfo(TensorShape(192U, 4U), 1, DataType::F32), })), - framework::dataset::make("TransposeWeights",{ true, true, false, true, true, true })), - framework::dataset::make("ReshapedWeights",{ false, false, false, false, false , false})), - framework::dataset::make("Expected", { false, true, true, false, false, true })), + make("TransposeWeights",{ true, true, false, true, true, true })), + make("ReshapedWeights",{ false, false, false, false, false , false})), + make("Expected", { false, true, true, false, false, true })), input_info, weights_info, bias_info, output_info, transpose_weights, reshaped_weights, expected) { // Create Fully Connected layer info @@ -298,80 +306,79 @@ using NEFullyConnectedLayerDynamicBiasFixture = FullyConnectedWithDynamicBiasFix TEST_SUITE(Float) #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC TEST_SUITE(FP16) -FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F16)), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::F16), + NoActivationFunctionDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num_f16, abs_tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(combine( +FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::FullyConnectedLayerWithActivationDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F16)), + FullyConnectedParameters, + make("DataType", DataType::F16), ActivationFunctionsDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num_f16, abs_tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(datasets::LargeFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F16)), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(datasets::LargeFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::F16), + NoActivationFunctionDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f16, tolerance_num_f16, abs_tolerance_f16); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::F16)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))), - framework::dataset::make("WeightsReshaped", { false, true }))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::F16), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)), + make("WeightsReshaped", { false, true }))) { } TEST_SUITE_END() #endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */ TEST_SUITE(FP32) -FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), FullyConnectedParameters, + make("DataType", DataType::F32), + NoActivationFunctionDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::F32), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(combine( - combine(datasets::FullyConnectedLayerWithActivationDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), +FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::FullyConnectedLayerWithActivationDataset(), + FullyConnectedParameters, + make("DataType", DataType::F32), ActivationFunctionsDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters), - framework::dataset::make("DataType", DataType::F32)), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerFixture, framework::DatasetMode::NIGHTLY, combine(datasets::LargeFullyConnectedLayerDataset(), FullyConnectedParameters, + make("DataType", DataType::F32), + NoActivationFunctionDataset)) { // Validate output validate(Accessor(_target), _reference, rel_tolerance_f32, 0, abs_tolerance_f32); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::F32)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))), - framework::dataset::make("WeightsReshaped", { false, true }))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::F32), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)), + make("WeightsReshaped", { false, true }))) { } TEST_SUITE_END() @@ -384,103 +391,150 @@ using NEFullyConnectedLayerQuantizedMixedDataLayoutFixture = FullyConnectedLayer TEST_SUITE(Quantized) TEST_SUITE(QASYMM8) -FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine( - combine(datasets::SmallFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8)), - QuantizationData), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayoutWithActivation, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + QuantizationData, + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) { // Validate output validate(Accessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8)), - QuantizationData), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) -{ - // Validate output - validate(Accessor(_target), _reference, tolerance_qasymm8); -} -FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine( +FIXTURE_DATA_TEST_CASE(RunSmallWithActivation, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::FullyConnectedLayerWithActivationDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8)), - QuantizationData), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + QuantizationData, ActivationFunctionsQuantizedDataset)) { // Validate output validate(Accessor(_target), _reference, tolerance_qasymm8); } +FIXTURE_DATA_TEST_CASE(RunDynamicWeightsWithActivation, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)), + make("WeightsReshaped", { false }))) +{ +} +FIXTURE_DATA_TEST_CASE(RunDynamicBiasWithActivation, NEFullyConnectedLayerDynamicBiasFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +{ +} -FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::NIGHTLY, combine(combine(combine( - combine(datasets::LargeFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8)), - QuantizationData), - EmptyActivationFunctionDataset)) +// Dynamic Quantization Tests here +FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, + combine(datasets::SmallFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + IgnoredQuantizationData, + NoActivationFunctionDataset)) { // Validate output validate(Accessor(_target), _reference, tolerance_qasymm8); } - -FIXTURE_DATA_TEST_CASE(RunDynamicBias, NEFullyConnectedLayerDynamicBiasFixture, framework::DatasetMode::PRECOMMIT, combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +FIXTURE_DATA_TEST_CASE(RunLarge, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::NIGHTLY, combine( + datasets::LargeFullyConnectedLayerDataset(), + FullyConnectedParameters, + framework::dataset::make("DataType", DataType::QASYMM8), + QuantizationData, + NoActivationFunctionDataset)) { + // Validate output + validate(Accessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))), - framework::dataset::make("WeightsReshaped", { false }))) +FIXTURE_DATA_TEST_CASE(RunDynamicBias, NEFullyConnectedLayerDynamicBiasFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8), + NoActivationFunctionDataset)) { } -TEST_SUITE_END() -TEST_SUITE(QASYMM8_SIGNED) -FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine( - combine(datasets::SmallFullyConnectedLayerDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - QuantizationData), - EmptyActivationFunctionDataset)) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8), + IgnoredQuantizationData, + NoActivationFunctionDataset)) { // Validate output - validate(Accessor(_target), _reference, tolerance_qasymm8_signed); + validate(Accessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, - combine(combine(combine(combine(combine(combine(combine( - framework::dataset::make("Input", TensorShape(9U, 5U, 7U)), - framework::dataset::make("Weights", TensorShape(315U, 271U))), - framework::dataset::make("Biases", TensorShape(271U))), - framework::dataset::make("Output", TensorShape(271U))), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - QuantizationData), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8), + NoActivationFunctionDataset, + make("WeightsReshaped", { false }))) +{ +} +TEST_SUITE_END() // QASYMM8 +TEST_SUITE(QASYMM8_SIGNED) +FIXTURE_DATA_TEST_CASE(RunMixedDataLayoutWithActivation, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + QuantizationData, + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)))) { // Validate output validate(Accessor(_target), _reference, tolerance_qasymm8); } -FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine( +FIXTURE_DATA_TEST_CASE(RunWithActivation, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::FullyConnectedLayerWithActivationDataset(), - FullyConnectedParameters), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - QuantizationData), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + QuantizationData, ActivationFunctionsQuantizedDataset)) { // Validate output validate(Accessor(_target), _reference, tolerance_qasymm8_signed); } -FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(combine(combine(datasets::SmallFullyConnectedLayerDataset(), - framework::dataset::make("DataType", DataType::QASYMM8_SIGNED)), - framework::dataset::make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU))), - framework::dataset::make("WeightsReshaped", { false }))) +FIXTURE_DATA_TEST_CASE(RunDynamicWeightsWithActivation, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8_SIGNED), + make("ActivationInfo", ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)), + make("WeightsReshaped", { false }))) +{ +} + +// Dynamic Quantization tests +FIXTURE_DATA_TEST_CASE(RunSmall, NEFullyConnectedLayerQuantizedFixture, framework::DatasetMode::PRECOMMIT, combine( + datasets::SmallFullyConnectedLayerDataset(), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + IgnoredQuantizationData, + NoActivationFunctionDataset)) +{ + // Validate output + validate(Accessor(_target), _reference, tolerance_qasymm8_signed); +} +FIXTURE_DATA_TEST_CASE(RunMixedDataLayout, NEFullyConnectedLayerQuantizedMixedDataLayoutFixture, framework::DatasetMode::PRECOMMIT, + combine( + make("Input", TensorShape(9U, 5U, 7U)), + make("Weights", TensorShape(315U, 271U)), + make("Biases", TensorShape(271U)), + make("Output", TensorShape(271U)), + FullyConnectedParameters, + make("DataType", DataType::QASYMM8_SIGNED), + QuantizationData, + NoActivationFunctionDataset)) +{ + // Validate output + validate(Accessor(_target), _reference, tolerance_qasymm8); +} +FIXTURE_DATA_TEST_CASE(RunDynamicWeights, NEFullyConnectedLayerDynamicWeightsFixture, framework::DatasetMode::PRECOMMIT, combine(datasets::SmallFullyConnectedLayerDataset(), + make("DataType", DataType::QASYMM8_SIGNED), + NoActivationFunctionDataset, + make("WeightsReshaped", { false }))) { } TEST_SUITE_END() // QASYMM8_SIGNED diff --git a/tests/validation/fixtures/FullyConnectedLayerFixture.h b/tests/validation/fixtures/FullyConnectedLayerFixture.h index 7cfe6e49b9..05f20ac12b 100644 --- a/tests/validation/fixtures/FullyConnectedLayerFixture.h +++ b/tests/validation/fixtures/FullyConnectedLayerFixture.h @@ -55,6 +55,40 @@ public: using TBias = typename std::conditional < (std::is_same::value || std::is_same::value), int32_t, T >::type; public: + void setup_quantization(TensorShape weights_shape, TensorShape output_shape, QuantizationInfo &input_q_info, QuantizationInfo &weights_q_info, DataType data_type) + { + _hash = weights_shape[0] + weights_shape[1] + output_shape[0] + output_shape[1]; + const int32_t t_max = static_cast(std::numeric_limits::max()); + const int32_t t_min = static_cast(std::numeric_limits::min()); + + std::mt19937 generator(library->seed() + _hash); + std::uniform_real_distribution distribution_float(-5.0f, 3.0f); + std::uniform_int_distribution distribution_t(t_min, t_max); + + const float scale_lhs = pow(2, distribution_float(generator)); // [2^-5, 2^3] + const float scale_rhs = pow(2, distribution_float(generator)); // [2^-5, 2^3] + const int32_t offset_lhs = distribution_t(generator); + const int32_t offset_rhs = distribution_t(generator); + + input_q_info = QuantizationInfo(scale_lhs, offset_lhs); + weights_q_info = QuantizationInfo(scale_rhs, offset_rhs); + + + const int k = weights_shape.x(); + QuantizationHint q_hint = suggest_mac_dst_q_info_and_bias(input_q_info, weights_q_info, k, data_type, 0.1f /* bias_fraction */, 4 /* number of standard deviations*/); + + _dst_q_info = q_hint.q_info; + _min_bias = q_hint.bias_min; + _max_bias = q_hint.bias_max; + + // Do not change here as these limits are the natural limits of the associated data types and + // are embedded in the computation of the dst quantization info. + _min_u8 = 0; + _max_u8 = 255; + _min_s8 = -128; + _max_s8 = 127; + } + void setup(TensorShape input_shape, TensorShape weights_shape, TensorShape bias_shape, TensorShape output_shape, bool transpose_weights, bool reshape_weights, DataType data_type, QuantizationInfo quantization_info, ActivationLayerInfo activation_info, bool mixed_layout = false) { @@ -64,7 +98,20 @@ public: _mixed_layout = mixed_layout; _data_type = data_type; _bias_data_type = is_data_type_quantized_asymmetric(data_type) ? DataType::S32 : data_type; - _quantization_info = quantization_info; + + // Note : Quantization Info parameter from setup function is only used when quant datatype and activation function is not enabled or is identity. + if(is_data_type_quantized(data_type) && (!activation_info.enabled() || activation_info.activation() == ActivationFunction::IDENTITY)) + { + // Initialises quantization info with appropriate scale and offset for given input shapes. + setup_quantization(weights_shape, output_shape,_input_q_info, _weight_q_info, data_type); + } + else + { + _input_q_info = quantization_info; + _weight_q_info = quantization_info; + _dst_q_info = quantization_info; + } + _activation_info = activation_info; _target = compute_target(input_shape, weights_shape, bias_shape, output_shape, transpose_weights, reshape_weights); @@ -92,17 +139,17 @@ protected: { if(_data_type == DataType::QASYMM8) { - std::uniform_int_distribution distribution(0, 30); + std::uniform_int_distribution distribution(_min_u8, _max_u8); library->fill(tensor, distribution, i); } else if(_data_type == DataType::QASYMM8_SIGNED) { - std::uniform_int_distribution distribution(-15, 15); + std::uniform_int_distribution distribution(_min_s8, _max_s8); library->fill(tensor, distribution, i); } else if(_data_type == DataType::S32) { - std::uniform_int_distribution distribution(-50, 50); + std::uniform_int_distribution distribution(_min_bias, _max_bias); library->fill(tensor, distribution, i); } else if(_data_type == DataType::F16) @@ -144,10 +191,10 @@ protected: } // Create tensors - TensorType src = create_tensor(input_shape, _data_type, 1, _quantization_info); - TensorType weights = create_tensor(reshaped_weights_shape, _data_type, 1, _quantization_info); - TensorType bias = create_tensor(bias_shape, _bias_data_type, 1, _quantization_info); - TensorType dst = create_tensor(output_shape, _data_type, 1, _quantization_info); + TensorType src = create_tensor(input_shape, _data_type, 1, _input_q_info); + TensorType weights = create_tensor(reshaped_weights_shape, _data_type, 1, _weight_q_info); + TensorType bias = create_tensor(bias_shape, _bias_data_type, 1); + TensorType dst = create_tensor(output_shape, _data_type, 1, _dst_q_info); // Create Fully Connected layer info FullyConnectedLayerInfo fc_info; @@ -178,8 +225,8 @@ protected: ARM_COMPUTE_ASSERT(!dst.info()->is_resizable()); // Fill tensors - fill(AccessorType(src), 0); - fill(AccessorType(bias), 2); + fill(AccessorType(src), 0 + _hash); + fill(AccessorType(bias), 2 + _hash); if(!reshape_weights || !transpose_weights) { @@ -187,7 +234,7 @@ protected: RawTensor tmp(tmp_shape, _data_type, 1); // Fill with original shape - fill(tmp, 1); + fill(tmp, 1 + _hash); // Transpose elementwise tmp = transpose(tmp); @@ -204,7 +251,7 @@ protected: } else { - fill(AccessorType(weights), 1); + fill(AccessorType(weights), 1 + _hash); } if(_mixed_layout) @@ -223,16 +270,16 @@ protected: SimpleTensor compute_reference(const TensorShape &input_shape, const TensorShape &weights_shape, const TensorShape &bias_shape, const TensorShape &output_shape) { // Create reference - SimpleTensor src{ input_shape, _data_type, 1, _quantization_info }; - SimpleTensor weights{ weights_shape, _data_type, 1, _quantization_info }; - SimpleTensor bias{ bias_shape, _bias_data_type, 1, _quantization_info }; + SimpleTensor src{ input_shape, _data_type, 1, _input_q_info }; + SimpleTensor weights{ weights_shape, _data_type, 1, _weight_q_info }; + SimpleTensor bias{ bias_shape, _bias_data_type, 1, QuantizationInfo() }; // Fill reference - fill(src, 0); - fill(weights, 1); - fill(bias, 2); + fill(src, 0 + _hash); + fill(weights, 1 + _hash); + fill(bias, 2 + _hash); - return reference::activation_layer(reference::fully_connected_layer(src, weights, bias, output_shape, _quantization_info), _activation_info, _quantization_info); + return reference::activation_layer(reference::fully_connected_layer(src, weights, bias, output_shape, _dst_q_info), _activation_info, _dst_q_info); } TensorType _target{}; @@ -240,8 +287,22 @@ protected: DataType _data_type{}; DataType _bias_data_type{}; bool _mixed_layout{ false }; - QuantizationInfo _quantization_info{}; + QuantizationInfo _input_q_info{}; + QuantizationInfo _weight_q_info{}; + QuantizationInfo _dst_q_info{}; ActivationLayerInfo _activation_info{}; + + // Random initialization limits + // Default values are previously handcrafted limits + // that sould be used when we don't use dynamic quantization + int32_t _min_bias{-50}; + int32_t _max_bias{50}; + + int32_t _min_u8{0}; + int32_t _max_u8{30}; + int32_t _min_s8{-15}; + int32_t _max_s8{15}; + int _hash{0}; }; template @@ -289,12 +350,17 @@ private: } else if(_data_type == DataType::QASYMM8) { - std::uniform_int_distribution distribution(0, 30); + std::uniform_int_distribution distribution(_min_u8, _max_u8); + library->fill(tensor, distribution, i); + } + else if(_data_type == DataType::QASYMM8_SIGNED) + { + std::uniform_int_distribution distribution(_min_s8, _max_s8); library->fill(tensor, distribution, i); } else if(_data_type == DataType::S32) { - std::uniform_int_distribution distribution(-50, 50); + std::uniform_int_distribution distribution(_min_bias, _max_bias); library->fill(tensor, distribution, i); } else @@ -352,6 +418,40 @@ private: validate(AccessorType(target), ref, tolerance_qasymm8_signed); } + void setup_quantization(TensorShape weights_shape, TensorShape output_shape, QuantizationInfo &input_q_info, QuantizationInfo &weights_q_info, DataType data_type) + { + _hash = weights_shape[0] + weights_shape[1] + output_shape[0] + output_shape[1]; + + const int32_t t_max = static_cast(std::numeric_limits::max()); + const int32_t t_min = static_cast(std::numeric_limits::min()); + + std::mt19937 generator(library->seed() + _hash); + std::uniform_real_distribution distribution_float(-5.0f, 3.0f); + std::uniform_int_distribution distribution_t(t_min, t_max); + + const float scale_lhs = pow(2, distribution_float(generator)); // [2^-5, 2^3] + const float scale_rhs = pow(2, distribution_float(generator)); // [2^-5, 2^3] + const int32_t offset_lhs = distribution_t(generator); + const int32_t offset_rhs = distribution_t(generator); + + input_q_info = QuantizationInfo(scale_lhs, offset_lhs); + weights_q_info = QuantizationInfo(scale_rhs, offset_rhs); + + const int k = weights_shape.x(); + QuantizationHint q_hint = suggest_mac_dst_q_info_and_bias(input_q_info, weights_q_info, k, data_type, 0.1f /* bias_fraction */, 4 /* number of standard deviations*/); + + _dst_q_info = q_hint.q_info; + _min_bias = q_hint.bias_min; + _max_bias = q_hint.bias_max; + + // Do not change here as these limits are the natural limits of the associated data types and + // are embedded in the computation of the dst quantization info. + _min_u8 = 0; + _max_u8 = 255; + _min_s8 = -128; + _max_s8 = 127; + } + public: using TDecay = typename std::decay::type; using TBias = typename std::conditional < (std::is_same::value || std::is_same::value), int32_t, T >::type; @@ -364,15 +464,22 @@ public: const bool is_quantized = is_data_type_quantized(data_type); const DataType bias_data_type = (is_quantized) ? DataType::S32 : data_type; - const QuantizationInfo src_qinfo = is_quantized ? QuantizationInfo(0.1f, 10) : QuantizationInfo(); - const QuantizationInfo weights_qinfo = is_quantized ? QuantizationInfo(0.3f, 20) : QuantizationInfo(); - const QuantizationInfo dst_qinfo = is_quantized ? QuantizationInfo(0.2f, 5) : QuantizationInfo(); + if (is_quantized && (!activation_info.enabled() || activation_info.activation() == ActivationFunction::IDENTITY)) + { + setup_quantization(weights_shape, dst_shape, _src_q_info, _weights_q_info, data_type); + } + else + { + _src_q_info = QuantizationInfo(0.1f, 10); + _dst_q_info = QuantizationInfo(0.3f, 20); + _weights_q_info = QuantizationInfo(0.2f, 5); + } // Configure TensorInfo Objects - const TensorInfo src_info(src_shape, 1, data_type, src_qinfo); - const TensorInfo dst_info(dst_shape, 1, data_type, dst_qinfo); + const TensorInfo src_info(src_shape, 1, data_type, _src_q_info); + const TensorInfo dst_info(dst_shape, 1, data_type, _dst_q_info); TensorInfo bias_info(bias_shape, 1, bias_data_type); - TensorInfo wei_info(weights_shape, 1, data_type, weights_qinfo); + TensorInfo wei_info(weights_shape, 1, data_type, _weights_q_info); if(!constant_weights && weights_reshaped) { @@ -412,20 +519,20 @@ public: int randomizer_offset = 0; // Create reference tensors - SimpleTensor src{ src_shape, data_type, 1, src_qinfo }; - SimpleTensor weights{ weights_shape, data_type, 1, weights_qinfo }; + SimpleTensor src{ src_shape, data_type, 1, _src_q_info }; + SimpleTensor weights{ weights_shape, data_type, 1, _weights_q_info }; SimpleTensor bias{ bias_shape, bias_data_type }; // Fill weights and/or bias if they remain constant if(constant_weights) { - fill(AccessorType(_weights), 1); - fill(weights, 1); + fill(AccessorType(_weights), 1 + _hash); + fill(weights, 1 + _hash); } if(constant_bias && !remove_bias) { - fill(AccessorType(_bias), 2); - fill(bias, 2); + fill(AccessorType(_bias), 2 + _hash); + fill(bias, 2 + _hash); } // To remove bias, fill with 0 if(remove_bias && is_quantized) @@ -446,16 +553,16 @@ public: { if(weights_reshaped) { - fill_transposed_weights(_weights, weights_shape, randomizer_offset + 1); + fill_transposed_weights(_weights, weights_shape, randomizer_offset + 1 + _hash); } else { - fill(AccessorType(_weights), randomizer_offset + 1); + fill(AccessorType(_weights), randomizer_offset + 1 +_hash); } } if(!constant_bias && !remove_bias) { - fill(AccessorType(_bias), randomizer_offset + 2); + fill(AccessorType(_bias), randomizer_offset + 2 + _hash); } fc.run(); @@ -467,14 +574,14 @@ public: fill(src, randomizer_offset); if(!constant_weights) { - fill(weights, randomizer_offset + 1); + fill(weights, randomizer_offset + 1 + _hash); } if(!constant_bias && !remove_bias) { - fill(bias, randomizer_offset + 2); + fill(bias, randomizer_offset + 2 + _hash); } - auto dst = reference::activation_layer(reference::fully_connected_layer(src, weights, bias, dst_shape, dst_qinfo), activation_info, dst_qinfo); + auto dst = reference::activation_layer(reference::fully_connected_layer(src, weights, bias, dst_shape, _dst_q_info), activation_info, _dst_q_info); // Validate validate_with_tolerance(_dst, dst); @@ -487,6 +594,22 @@ public: private: TensorType _src{}, _weights{}, _bias{}, _dst{}; DataType _data_type{ DataType::UNKNOWN }; + + QuantizationInfo _src_q_info{}; + QuantizationInfo _weights_q_info{}; + QuantizationInfo _dst_q_info{}; + + // Random initialization limits + // Default values are previously handcrafted limits + // that sould be used when we don't use dynamic quantization + int32_t _min_bias{-50}; + int32_t _max_bias{50}; + + int32_t _min_u8{0}; + int32_t _max_u8{30}; + int32_t _min_s8{-15}; + int32_t _max_s8{15}; + int _hash{0}; }; template @@ -521,7 +644,7 @@ public: DataType data_type, ActivationLayerInfo activation_info) { FullyConnectedWithDynamicTensorsFixture::setup(src_shape, weights_shape, bias_shape, - dst_shape, data_type, activation_info, true, false, false, false /* weights_reshaped (not used) */); + dst_shape, data_type, activation_info, true, false, false, false); } }; } // namespace validation -- cgit v1.2.1