diff --git a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc index 49839811aa..e01fd8c78e 100644 --- a/onnxruntime/test/providers/cpu/nn/conv_op_test.cc +++ b/onnxruntime/test/providers/cpu/nn/conv_op_test.cc @@ -59,10 +59,17 @@ void TestConvOp(const ConvOpAndTestAttributes& attributes, std::unordered_set excluded_providers(attributes.excluded_providers); // Disable TensorRT because weight as input is not supported excluded_providers.insert(kTensorrtExecutionProvider); + + // QNN SDK 2.10.0 has a bug that breaks support for dynamic bias inputs. + excluded_providers.insert(kQnnExecutionProvider); + + // TODO: Enable QNN EP when bug with QNN SDK 2.10.0 is fixed: + /* // QNN have issue with dynamic weight, auto pad with SAME_UPPER, SAME_LOWER if (!weight_is_initializer || attributes.auto_pad == "SAME_UPPER" || attributes.auto_pad == "SAME_LOWER") { excluded_providers.insert(kQnnExecutionProvider); } + */ test.Run(expect_result, err_str, excluded_providers); } diff --git a/onnxruntime/test/providers/qnn/conv_htp_test.cc b/onnxruntime/test/providers/qnn/conv_htp_test.cc deleted file mode 100644 index 2412166d3c..0000000000 --- a/onnxruntime/test/providers/qnn/conv_htp_test.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#if !defined(ORT_MINIMAL_BUILD) - -#include -#include "core/graph/graph.h" - -#include "test/optimizer/qdq_test_utils.h" -#include "test/providers/qnn/qnn_test_utils.h" - -#include "gtest/gtest.h" - -namespace onnxruntime { -namespace test { -#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) - -// Check that QNN compiles DQ -> Conv -> Q as a single unit. -TEST_F(QnnHTPBackendTests, TestQDQConvU8U8S32) { - ProviderOptions provider_options; -#if defined(_WIN32) - provider_options["backend_path"] = "QnnHtp.dll"; -#else - provider_options["backend_path"] = "libQnnHtp.so"; -#endif - - RunQnnModelTest(BuildQDQConvTestCase({1, 1, 5, 5}, // Input shape - {1, 1, 3, 3}), // Weights shape - provider_options, - 18, // Opset - ExpectedEPNodeAssignment::All, // All nodes assigned to QNN EP. - 1, // Expect 1 fused node in graph. - "QDQConvU8U8S32"); -} -#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) - -} // namespace test -} // namespace onnxruntime - -#endif \ No newline at end of file diff --git a/onnxruntime/test/providers/qnn/conv_test.cc b/onnxruntime/test/providers/qnn/conv_test.cc new file mode 100644 index 0000000000..e3b41cbabf --- /dev/null +++ b/onnxruntime/test/providers/qnn/conv_test.cc @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#if !defined(ORT_MINIMAL_BUILD) + +#include +#include "core/graph/graph.h" + +#include "test/providers/qnn/qnn_test_utils.h" + +#include "gtest/gtest.h" + +namespace onnxruntime { +namespace test { + +// Creates a graph with a single Conv operator. Used for testing CPU backend. +static GetTestModelFn BuildConvTestCase(const std::vector& input_shape, + const std::vector& weights_shape, + bool is_bias_initializer) { + return [input_shape, weights_shape, is_bias_initializer](ModelTestBuilder& builder) { + auto* input = builder.MakeInput(input_shape, 0.0f, 10.0f); + auto* output = builder.MakeOutput(); + auto* weights = builder.MakeInitializer(weights_shape, 0.0f, 1.0f); + + onnxruntime::NodeArg* bias = nullptr; + + if (is_bias_initializer) { + bias = builder.MakeInitializer({weights_shape[0]}, -1.0f, 1.0f); + } else { + bias = builder.MakeInput({weights_shape[0]}, -1.0f, 1.0f); + } + + builder.AddNode("Conv", {input, weights, bias}, {output}); + }; +} + +// Runs a Conv model on the QNN CPU backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +static void RunCPUConvOpTest(const std::vector& input_shape, + const std::vector& weights_shape, + bool is_bias_initializer, + ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, + int opset = 13) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnCpu.dll"; +#else + provider_options["backend_path"] = "libQnnCpu.so"; +#endif + + constexpr int expected_nodes_in_partition = 1; + RunQnnModelTest(BuildConvTestCase(input_shape, weights_shape, is_bias_initializer), + provider_options, + opset, + expected_ep_assignment, + expected_nodes_in_partition, + test_description); +} + +// Creates a graph with a single Q/DQ Conv operator. Used for testing HTP backend. +template +GetTestModelFn BuildQDQConvTestCase(const std::vector& input_shape, + const std::vector& weights_shape, + bool is_bias_initializer = true) { + return [input_shape, weights_shape, is_bias_initializer](ModelTestBuilder& builder) { + auto* input_arg = builder.MakeInput(input_shape, -1.f, 1.f); + auto* output_arg = builder.MakeOutput(); + + using InputLimits = std::numeric_limits; + using WeightLimits = std::numeric_limits; + using OutputLimits = std::numeric_limits; + + InputType input_min_value = InputLimits::min(); + InputType input_max_value = InputLimits::max(); + + WeightType weight_min_value = WeightLimits::min(); + WeightType weight_max_value = WeightLimits::max(); + + auto* dq_w_output = builder.MakeIntermediate(); + auto* weight = builder.MakeInitializer(weights_shape, weight_min_value, weight_max_value); + builder.AddDequantizeLinearNode(weight, .03f, + (weight_min_value + weight_max_value) / 2 + 1, + dq_w_output); + + auto* dq_bias_output = builder.MakeIntermediate(); + onnxruntime::NodeArg* bias = nullptr; + + if (is_bias_initializer) { + bias = builder.MakeInitializer({weights_shape[0]}, static_cast(0), + static_cast(127)); + } else { + bias = builder.MakeInput({weights_shape[0]}, static_cast(0), + static_cast(127)); + } + + builder.AddDequantizeLinearNode(bias, .0012f, + 0, + dq_bias_output); + + auto* conv_output = builder.MakeIntermediate(); + auto* dq_output = AddQDQNodePair(builder, input_arg, .04f, + (input_min_value + input_max_value) / 2 + 1); + builder.AddNode("Conv", {dq_output, dq_w_output, dq_bias_output}, {conv_output}); + + auto* q_output = builder.MakeIntermediate(); + builder.AddQuantizeLinearNode(conv_output, .039f, + (OutputLimits::min() + OutputLimits::max()) / 2 + 1, + q_output); + + builder.AddDequantizeLinearNode(q_output, .039f, + (OutputLimits::min() + OutputLimits::max()) / 2 + 1, + output_arg); + }; +} + +// Runs a Conv model on the QNN HTP backend. Checks the graph node assignment, and that inference +// outputs for QNN EP and CPU EP match. +template +static void RunHTPConvOpTest(const std::vector& input_shape, + const std::vector& weights_shape, + bool is_bias_initializer, + ExpectedEPNodeAssignment expected_ep_assignment, const char* test_description, + int opset = 13) { + ProviderOptions provider_options; + +#if defined(_WIN32) + provider_options["backend_path"] = "QnnHtp.dll"; +#else + provider_options["backend_path"] = "libQnnHtp.so"; +#endif + + constexpr int expected_nodes_in_partition = 1; + RunQnnModelTest(BuildQDQConvTestCase(input_shape, weights_shape, + is_bias_initializer), + provider_options, + opset, + expected_ep_assignment, + expected_nodes_in_partition, + test_description); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an input. +// +// TODO: Enable this test when QNN CPU backend (QNN sdk 2.10.0) fixes bug that causes graph finalization to +// throw a segfault when the bias is a non-static input. +TEST_F(QnnCPUBackendTests, DISABLED_TestCPUConvf32_bias_input) { + RunCPUConvOpTest({1, 1, 3, 3}, {2, 1, 2, 2}, false, ExpectedEPNodeAssignment::All, "TestCPUConvf32_bias_input"); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an initializer. +TEST_F(QnnCPUBackendTests, TestCPUConvf32_bias_initializer) { + RunCPUConvOpTest({1, 1, 3, 3}, {2, 1, 2, 2}, true, ExpectedEPNodeAssignment::All, "TestCPUConvf32_bias_initializer"); +} + +#if defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an input. +TEST_F(QnnHTPBackendTests, TestQDQConvU8U8S32_bias_input) { + RunHTPConvOpTest({1, 1, 5, 5}, {1, 1, 3, 3}, false, ExpectedEPNodeAssignment::All, + "TestQDQConvU8U8S32_bias_input"); +} + +// Check that QNN compiles DQ -> Conv -> Q as a single unit. +// Tests bias as an initializer. +TEST_F(QnnHTPBackendTests, TestQDQConvU8U8S32_bias_initializer) { + RunHTPConvOpTest({1, 1, 5, 5}, {1, 1, 3, 3}, true, ExpectedEPNodeAssignment::All, + "TestQDQConvU8U8S32_bias_initializer"); +} +#endif // defined(__aarch64__) || defined(_M_ARM64) || defined(__linux__) + +} // namespace test +} // namespace onnxruntime + +#endif \ No newline at end of file diff --git a/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml index d57bfe1346..df0b9584d1 100644 --- a/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/android-arm64-v8a-QNN-crosscompile-ci-pipeline.yml @@ -3,7 +3,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.9.0.230327191003_53330 + default: qnn-v2.10.0.230425122932_54038 jobs: - job: Build_QNN_EP diff --git a/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml index 337346dfd5..802cc0ed50 100644 --- a/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/linux-qnn-ci-pipeline.yml @@ -3,7 +3,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.9.0.230327191003_53330 + default: qnn-v2.10.0.230425122932_54038 jobs: - job: Build_QNN_EP diff --git a/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml index 771174b32c..663ebcbbc9 100644 --- a/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-qnn-arm64-ci-pipeline.yml @@ -3,7 +3,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.9.0.230327191003_53330_win + default: qnn-v2.10.0.230425122932_54038_win jobs: - job: 'build' diff --git a/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml b/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml index 633a0a3361..e3db5158b2 100644 --- a/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml +++ b/tools/ci_build/github/azure-pipelines/win-qnn-ci-pipeline.yml @@ -3,7 +3,7 @@ parameters: - name: QnnSdk displayName: QNN SDK version type: string - default: qnn-v2.9.0.230327191003_53330_win + default: qnn-v2.10.0.230425122932_54038_win jobs: - job: 'build'