Skip to content

Commit 77954e1

Browse files
committed
[QNN-EP] Add support for Softmax operator with opset < 13
1 parent 8ef6439 commit 77954e1

File tree

1 file changed

+31
-30
lines changed

1 file changed

+31
-30
lines changed

onnxruntime/core/providers/qnn/builder/opbuilder/softmax_op_builder.cc

+31-30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
#include <functional>
5+
#include <memory>
6+
#include <string>
7+
#include <utility>
8+
#include <vector>
9+
410
#include "core/providers/qnn/builder/opbuilder/base_op_builder.h"
511
#include "core/providers/qnn/builder/qnn_utils.h"
612
#include "core/providers/qnn/builder/qnn_model_wrapper.h"
@@ -45,8 +51,7 @@ std::vector<uint32_t> FlattenShapeFromAxis(std::vector<uint32_t>& input_shape, i
4551
output_shape.push_back(1); // Additional batch included
4652
}
4753
output_shape.push_back(
48-
std::accumulate(input_shape.begin() + axis, input_shape.end(), 1, std::multiplies<uint32_t>())
49-
);
54+
std::accumulate(input_shape.begin() + axis, input_shape.end(), 1, std::multiplies<uint32_t>()));
5055

5156
return output_shape;
5257
}
@@ -88,21 +93,21 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
8893
ORT_RETURN_IF(input_info.is_initializer, "QNN EP does not support (Log)Softmax with an initializer input, ",
8994
"which should be optimized away by the ORT optimizer");
9095

91-
/*
92-
For Onnx Softmax with opset < 13, its behavior is to flatten the input starting from the axis, and perform
93-
softmax operation along the axis dimension, then reshape back to the original input shape.
94-
QNN EP is able to support arbitrary axis attribute by wrapping reshapes around the operator.
95-
96-
Here provides an example:
97-
Given an input with shape=(3, 4, 5) and axis=1. Its behavior is to reshape the input to (3, 20), perform softmax,
98-
and then reshape back to (3, 4, 5).
99-
100-
When axis equals 0, the reshape output shape includes an additional batch of size 1 as the first dimension.
101-
Here provides an example:
102-
Given an input with shape=(3, 4, 5) and axis=0. Its behavior is to reshape the input to (1, 60), perform softmax,
103-
and then reshape back to (3, 4, 5).
104-
*/
10596
if (opset_version < 13) {
97+
/*
98+
For Onnx Softmax with opset < 13, its behavior is to flatten the input starting from the axis, and perform
99+
softmax operation along the axis dimension, then reshape back to the original input shape.
100+
QNN EP is able to support arbitrary axis attribute by wrapping reshapes around the operator.
101+
102+
Here provides an example:
103+
Given an input with shape=(3, 4, 5) and axis=1. Its behavior is to reshape the input to (3, 20), perform softmax,
104+
and then reshape back to (3, 4, 5).
105+
106+
When axis equals 0, the reshape output shape includes an additional batch of size 1 as the first dimension.
107+
Here provides an example:
108+
Given an input with shape=(3, 4, 5) and axis=0. Its behavior is to reshape the input to (1, 60), perform softmax,
109+
and then reshape back to (3, 4, 5).
110+
*/
106111
std::string reshape_output_name = input_name + "_ort_qnn_ep_reshape";
107112
std::vector<uint32_t> reshape_output_shape = FlattenShapeFromAxis(input_info.shape, axis);
108113

@@ -119,13 +124,12 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
119124
is_graph_input,
120125
false));
121126
input_names.push_back(reshape_output_name);
122-
}
123-
/*
124-
For Onnx Softmax with opset >= 13, the QNN HTP backend only supports the axis attribute that refers to the last
125-
input dimension.
126-
QNN EP is able to support arbitrary axis attribute by wrapping transposes around the operator.
127-
*/
128-
else if (is_npu_backend && axis != static_cast<int32_t>(input_rank) - 1) {
127+
} else if (is_npu_backend && axis != static_cast<int32_t>(input_rank) - 1) {
128+
/*
129+
For Onnx Softmax with opset >= 13, the QNN HTP backend only supports the axis attribute that refers to the last
130+
input dimension.
131+
QNN EP is able to support arbitrary axis attribute by wrapping transposes around the operator.
132+
*/
129133
std::string transpose_output_name = input_name + "_ort_qnn_ep_transpose";
130134
std::vector<uint32_t> transpose_perm = GetTransposePermToUseLastAxis(static_cast<uint32_t>(input_rank),
131135
static_cast<uint32_t>(axis));
@@ -149,9 +153,8 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
149153
is_graph_input,
150154
false));
151155
input_names.push_back(transpose_output_name);
152-
}
153-
// Process the input as normal.
154-
else {
156+
} else {
157+
// Process the input as normal.
155158
return ProcessInput(qnn_model_wrapper, inputs[0], logger, input_names);
156159
}
157160

@@ -213,8 +216,7 @@ Status SoftmaxOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_
213216
do_op_validation,
214217
false,
215218
is_graph_output));
216-
}
217-
else if (is_npu_backend && axis != static_cast<int32_t>(output_rank) - 1) {
219+
} else if (is_npu_backend && axis != static_cast<int32_t>(output_rank) - 1) {
218220
std::string transpose_input_name = orig_output_name + "_ort_qnn_ep_transpose";
219221

220222
std::vector<uint32_t> transpose_input_shape = output_info.shape;
@@ -255,8 +257,7 @@ Status SoftmaxOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_
255257
do_op_validation,
256258
false,
257259
is_graph_output));
258-
}
259-
else {
260+
} else {
260261
QnnParamWrapper axis_param(node_unit.Index(), node_unit.Name(), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar);
261262
std::vector<std::string> param_tensor_names;
262263
param_tensor_names.push_back(axis_param.GetParamTensorName());

0 commit comments

Comments
 (0)