diff --git a/onnxruntime/core/providers/qnn/builder/opbuilder/slice_op_builder.cc b/onnxruntime/core/providers/qnn/builder/opbuilder/slice_op_builder.cc index 71e3150ae7..ea8054a7a1 100644 --- a/onnxruntime/core/providers/qnn/builder/opbuilder/slice_op_builder.cc +++ b/onnxruntime/core/providers/qnn/builder/opbuilder/slice_op_builder.cc @@ -13,9 +13,6 @@ namespace onnxruntime { namespace qnn { -const int SLICE_MIN_INPUT = 3; -const int SLICE_MAX_INPUT = 5; - class SliceOpBuilder : public BaseOpBuilder { public: SliceOpBuilder() : BaseOpBuilder("SliceOpBuilder") {} @@ -38,6 +35,10 @@ class SliceOpBuilder : public BaseOpBuilder { private: Status ExplictOpCheck(QnnModelWrapper& qnn_model_wrapper, const NodeUnit& node_unit) const; + void GetDataFromAttribute(const NodeUnit& node_unit, + TensorShapeVector& raw_starts, + TensorShapeVector& raw_ends, + TensorShapeVector& raw_axes) const; typedef struct { int32_t begin, end, stride; } Range; @@ -46,19 +47,36 @@ class SliceOpBuilder : public BaseOpBuilder { Status SliceOpBuilder::ExplictOpCheck(QnnModelWrapper& qnn_model_wrapper, const NodeUnit& node_unit) const { size_t input_count = node_unit.Inputs().size(); - ORT_RETURN_IF_NOT(input_count >= SLICE_MIN_INPUT && input_count <= SLICE_MAX_INPUT, - "For ONNX Slice operation the expected number of inputs is between 3 and 5."); - // Skip the first input. All other input need to be initializer - for (size_t i = 1; i < node_unit.Inputs().size(); i++) { - const auto& next_input = node_unit.Inputs()[i].node_arg.Name(); - if (!qnn_model_wrapper.IsInitializerInput(next_input)) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "QNN desn't support dynamic slice."); + // Op set 9 only has 1 input with starts, ends, axes attribute + // Op set > 9, starts, ends, axes are from node input + if (input_count > 1) { + // Skip the first input. All other input need to be initializer + for (size_t i = 1; i < input_count; i++) { + const auto& next_input = node_unit.Inputs()[i].node_arg.Name(); + if (!qnn_model_wrapper.IsInitializerInput(next_input)) { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "QNN desn't support dynamic slice."); + } } } return Status::OK(); } +void SliceOpBuilder::GetDataFromAttribute(const NodeUnit& node_unit, + TensorShapeVector& raw_starts, + TensorShapeVector& raw_ends, + TensorShapeVector& raw_axes) const { + NodeAttrHelper node_helper(node_unit); + auto starts = node_helper.Get("starts", std::vector{0}); + raw_starts.assign(starts.begin(), starts.end()); + auto ends = node_helper.Get("ends", std::vector{0}); + raw_ends.assign(ends.begin(), ends.end()); + if (node_helper.HasAttr("axes")) { + auto axes = node_helper.Get("axes", std::vector{0}); + raw_axes.assign(axes.begin(), axes.end()); + } +} + // Note: For ONNX Slice operation the expected number of inputs is between 3 and 5 Status SliceOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper, const NodeUnit& node_unit, @@ -79,7 +97,13 @@ Status SliceOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper, std::vector input0_shape; auto inputs = node_unit.Inputs(); - for (size_t input_i = 0; input_i < inputs.size(); ++input_i) { + auto input_count = inputs.size(); + // Opset 9, only 1 input, starts, ends, axes are in attribute + if (1 == input_count) { + GetDataFromAttribute(node_unit, raw_starts, raw_ends, raw_axes); + } + + for (size_t input_i = 0; input_i < input_count; ++input_i) { auto& input_name = inputs[input_i].node_arg.Name(); if (input_name.empty()) { // Ignore unspecified/unused optional input @@ -144,7 +168,6 @@ Status SliceOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper, continue; } } - ORT_ENFORCE(input_i == 0, "QNN ReluMinMax operator expects only one input. other inputs, starts, ends, axes and steps are expected to be parameters, ie. initializer inputs in ONNX model"); input0_shape = input_shape; input_names.push_back(input_name);