diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/pad_op_builder.cc b/onnxruntime/core/providers/qnn/builder/opbuilder/pad_op_builder.cc index 2dfdfffe5fa54..fc8c5c357682c 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/pad_op_builder.cc +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/pad_op_builder.cc @@ -202,16 +202,8 @@ Status PadOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_wrap // Qnn format is begin_0, end_0, begin_1, end_1, ... ReArranagePads(pad_amount); - std::vector pad_amount_dim{static_cast(pad_amount.size() / 2), static_cast(2)}; - QnnParamWrapper multiples_param(node_unit.Index(), node_unit.Name(), QNN_OP_PAD_PARAM_PAD_AMOUNT, std::move(pad_amount_dim), - std::move(pad_amount)); - param_tensor_names.push_back(multiples_param.GetParamTensorName()); - qnn_model_wrapper.AddParamWrapper(std::move(multiples_param)); - - // Process optional input constant_value - if (node_unit.Inputs().size() > 2) { - ORT_RETURN_IF_ERROR(ProcessConstantValue(qnn_model_wrapper, param_tensor_names, node_unit, inputs[2])); - } // constant_value + std::vector input_shape; + ORT_RETURN_IF_NOT(qnn_model_wrapper.GetOnnxShape(inputs[0].node_arg, input_shape), "Cannot get shape of input 0."); NodeAttrHelper node_helper(node_unit); std::string mode = node_helper.Get("mode", "constant"); @@ -220,6 +212,10 @@ Status PadOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_wrap if ("constant" == mode) { mode_qnn_scalar.uint32Value = QNN_OP_PAD_SCHEME_CONSTANT; } else if ("reflect" == mode) { + for (size_t i = 0; i < input_shape.size(); i++) { + ORT_RETURN_IF(pad_amount[i * 2] > input_shape[i] - 1 || pad_amount[(i * 2) + 1] > input_shape[i] - 1, + "Pad amount should not be greater than shape(input[0])[i] - 1"); + } mode_qnn_scalar.uint32Value = QNN_OP_PAD_SCHEME_MIRROR_REFLECT; } else if ("edge" == mode) { mode_qnn_scalar.uint32Value = QNN_OP_PAD_SCHEME_EDGE; @@ -227,10 +223,21 @@ Status PadOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_wrap return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Pad mode only support constant."); } + std::vector pad_amount_dim{static_cast(pad_amount.size() / 2), static_cast(2)}; QnnParamWrapper mode_param(node_unit.Index(), node_unit.Name(), QNN_OP_PAD_PARAM_SCHEME, mode_qnn_scalar); param_tensor_names.push_back(mode_param.GetParamTensorName()); qnn_model_wrapper.AddParamWrapper(std::move(mode_param)); + QnnParamWrapper multiples_param(node_unit.Index(), node_unit.Name(), QNN_OP_PAD_PARAM_PAD_AMOUNT, + std::move(pad_amount_dim), std::move(pad_amount)); + param_tensor_names.push_back(multiples_param.GetParamTensorName()); + qnn_model_wrapper.AddParamWrapper(std::move(multiples_param)); + + // Process optional input constant_value + if (node_unit.Inputs().size() > 2) { + ORT_RETURN_IF_ERROR(ProcessConstantValue(qnn_model_wrapper, param_tensor_names, node_unit, inputs[2])); + } // constant_value + ORT_RETURN_IF_ERROR(ProcessOutputs(qnn_model_wrapper, node_unit, std::move(input_names), std::move(param_tensor_names), diff --git a/onnxruntime/test/providers/qnn/pad_op_test.cpp b/onnxruntime/test/providers/qnn/pad_op_test.cpp index e92f0ae770a88..792dbeadfa758 100644 --- a/onnxruntime/test/providers/qnn/pad_op_test.cpp +++ b/onnxruntime/test/providers/qnn/pad_op_test.cpp @@ -167,7 +167,7 @@ TEST_F(QnnCPUBackendTests, Pad2dPadsNotIni) { TEST_F(QnnCPUBackendTests, DISABLED_PadModeReflect) { bool has_constant_value = false; RunPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), - TestInputDef({4}, true, {0, 2, 0, 0}), + TestInputDef({4}, true, {0, 1, 0, 0}), TestInputDef({1}, true, {0.0f}), {utils::MakeAttribute("mode", "reflect")}, ExpectedEPNodeAssignment::All, @@ -266,13 +266,37 @@ TEST_F(QnnHTPBackendTests, PadHasConstantValueQuantized) { constant_value_quantized); } -// QNN graph execute error. Error code: 6031 -TEST_F(QnnHTPBackendTests, DISABLED_PadReflectMode) { +TEST_F(QnnHTPBackendTests, PadReflectMode) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), + TestInputDef({4}, true, {0, 1, 0, 0}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "reflect")}, + ExpectedEPNodeAssignment::All, + has_constant_value_input); +} + +// Pad amount should not be greater than shape(input[0])[i] - 1 +TEST_F(QnnHTPBackendTests, PadReflectModeOutOfRangePadAmount) { bool has_constant_value_input = false; RunQDQPadOpTest(TestInputDef({3, 2}, false, {1.0f, 1.2f, 2.3f, 3.4f, 4.5f, 5.6f}), TestInputDef({4}, true, {0, 2, 0, 0}), TestInputDef({1}, true, {0.0f}), {utils::MakeAttribute("mode", "reflect")}, + ExpectedEPNodeAssignment::None, + has_constant_value_input); +} + +TEST_F(QnnHTPBackendTests, Pad4dReflectMode) { + bool has_constant_value_input = false; + RunQDQPadOpTest(TestInputDef({1, 2, 2, 2}, false, + {1.0f, 2.0f, + 3.0f, 4.0f, + 5.0f, 6.0f, + 7.0f, 8.0f}), + TestInputDef({8}, true, {0, 1, 1, 1, 0, 1, 1, 1}), + TestInputDef({1}, true, {0.0f}), + {utils::MakeAttribute("mode", "reflect")}, ExpectedEPNodeAssignment::All, has_constant_value_input); }