From 3e4c5e64877c6d9814e4ebce5dcbb1fe71588ec5 Mon Sep 17 00:00:00 2001 From: Adrian Lizarraga Date: Mon, 20 Jan 2025 21:35:47 -0800 Subject: [PATCH] [QNN EP] workaround for QNN validation bug for Tanh with uint16 quantized output (#23432) ### Description - Skip QNN validation for Tanh with uint16 quantized output (workaround for QNN validation bug). - Re-enables unit test for Tanh with uint16 quantized output. The [QNN documentation](https://docs.qualcomm.com/bundle/publicresource/topics/80-63442-50/HtpOpDefSupplement.html#tanh) states that the output scale and offset for `ufixed_point_16` should be (1/32768) and -32768, respectively. However, the QNN validator incorrectly rejects these values. So, we skip validation for this configuration of Tanh. Building an actual QNN graph with the correct scale/offset still works. ### Motivation and Context This QNN validation bug appeared in QNN SDK 2.28.0 and is still present in QNN SDK 2.30.0. A previous PR disabled the corresponding unit test: https://github.com/microsoft/onnxruntime/pull/22724/files#diff-57f590c6c548b073ba8cd8af6cf198799906f7059ea46b31cd33972ea9b01983R232 --- .../qnn/builder/opbuilder/simple_op_builder.cc | 16 ++++++++++++++++ onnxruntime/core/providers/qnn/qnn_allocator.cc | 2 +- .../test/providers/qnn/simple_op_htp_test.cc | 8 +++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc b/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc index 9902617b71..cf87266754 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/simple_op_builder.cc @@ -262,6 +262,22 @@ Status SimpleOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_w if (node_unit.Domain() != kMSInternalNHWCDomain && (op_type == "DepthToSpace" || op_type == "SpaceToDepth" || op_type == "GridSample")) { return Status::OK(); } + +#if QNN_API_VERSION_MAJOR >= 2 && QNN_API_VERSION_MINOR >= 21 && QNN_API_VERSION_MINOR <= 23 + // Skip QNN validation for Tanh with uint16 (quantized) output. + // This gets around a Tanh QNN validation bug in QNN SDK 2.28.0 - 2.30.0. + // The QNN documentation states that the output scale and offset for ufixed_point_16 should be + // (1/32768) and -32768, respectively. However, the QNN validator incorrectly rejects these values. + if (op_type == "Tanh") { + TensorInfo output_info = {}; + ORT_RETURN_IF_ERROR(qnn_model_wrapper.GetTensorInfo(node_unit.Outputs()[0], output_info)); + if (output_info.qnn_data_type == QNN_DATATYPE_UFIXED_POINT_16) { + LOGS(logger, INFO) << "Skipping QNN validation for Tanh node '" + << node_unit.Name() << "' with quantized unit16 output."; + return Status::OK(); + } + } +#endif } std::vector param_tensor_names; diff --git a/onnxruntime/core/providers/qnn/qnn_allocator.cc b/onnxruntime/core/providers/qnn/qnn_allocator.cc index e0a8cac599..68dac68275 100644 --- a/onnxruntime/core/providers/qnn/qnn_allocator.cc +++ b/onnxruntime/core/providers/qnn/qnn_allocator.cc @@ -60,7 +60,7 @@ size_t DivRoundUp(size_t a, size_t b) { // TODO is there already a helper funct } bool IsAligned(const void* address, size_t alignment) { - assert((alignment & alignment - 1) == 0); // alignment must be a power of two + assert((alignment & (alignment - 1)) == 0); // alignment must be a power of two return (reinterpret_cast(address) & (alignment - 1)) == 0; } diff --git a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc index 78889b52ba..83a02a61b1 100644 --- a/onnxruntime/test/providers/qnn/simple_op_htp_test.cc +++ b/onnxruntime/test/providers/qnn/simple_op_htp_test.cc @@ -230,7 +230,7 @@ TEST_F(QnnHTPBackendTests, UnaryOp_Tanh) { } // disabled for QNN 2.28.0.241029 backendValidateOpConfig failed -// still fails on QNN 2.28.2. +// still fails on QNN 2.28.2 and QNN 2.30.0 // QnnDsp [4294967295] has incorrect Value -32768, expected equal to 0. // QnnDsp validateNativeOps node_token_6:qti.aisw:Tanh htp op validator failed 3110 // QnnDsp registered validator failed => 3110 @@ -238,9 +238,11 @@ TEST_F(QnnHTPBackendTests, UnaryOp_Tanh) { // QnnDsp Wake up free backend (id: 1)'s thread(s) // QnnDsp Failed to validate op node_token_6 with error 0xc26 // Tests accuracy of 16-bit QDQ Tanh. -TEST_F(QnnHTPBackendTests, DISABLED_UnaryOp_Tanh_U16) { +// +// We now skip QNN validation as a workaround for QNN SDK 2.28.0 to 2.30.0 +TEST_F(QnnHTPBackendTests, UnaryOp_Tanh_U16) { RunQDQOpTest("Tanh", - {TestInputDef({1, 2, 3}, false, GetFloatDataInRange(-10.0f, 10.0f, 6))}, + {TestInputDef({1, 2, 64}, false, GetFloatDataInRange(-10.0f, 10.0f, 128))}, {}, 13, ExpectedEPNodeAssignment::All,