1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT License.
3
3
4
+ #include < functional>
5
+ #include < memory>
6
+ #include < string>
7
+ #include < utility>
8
+ #include < vector>
9
+
4
10
#include " core/providers/qnn/builder/opbuilder/base_op_builder.h"
5
11
#include " core/providers/qnn/builder/qnn_utils.h"
6
12
#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
45
51
output_shape.push_back (1 ); // Additional batch included
46
52
}
47
53
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 >()));
50
55
51
56
return output_shape;
52
57
}
@@ -88,21 +93,21 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
88
93
ORT_RETURN_IF (input_info.is_initializer , " QNN EP does not support (Log)Softmax with an initializer input, " ,
89
94
" which should be optimized away by the ORT optimizer" );
90
95
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
- */
105
96
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
+ */
106
111
std::string reshape_output_name = input_name + " _ort_qnn_ep_reshape" ;
107
112
std::vector<uint32_t > reshape_output_shape = FlattenShapeFromAxis (input_info.shape , axis);
108
113
@@ -119,13 +124,12 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
119
124
is_graph_input,
120
125
false ));
121
126
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
+ */
129
133
std::string transpose_output_name = input_name + " _ort_qnn_ep_transpose" ;
130
134
std::vector<uint32_t > transpose_perm = GetTransposePermToUseLastAxis (static_cast <uint32_t >(input_rank),
131
135
static_cast <uint32_t >(axis));
@@ -149,9 +153,8 @@ Status SoftmaxOpBuilder::ProcessInputs(QnnModelWrapper& qnn_model_wrapper,
149
153
is_graph_input,
150
154
false ));
151
155
input_names.push_back (transpose_output_name);
152
- }
153
- // Process the input as normal.
154
- else {
156
+ } else {
157
+ // Process the input as normal.
155
158
return ProcessInput (qnn_model_wrapper, inputs[0 ], logger, input_names);
156
159
}
157
160
@@ -213,8 +216,7 @@ Status SoftmaxOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_
213
216
do_op_validation,
214
217
false ,
215
218
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 ) {
218
220
std::string transpose_input_name = orig_output_name + " _ort_qnn_ep_transpose" ;
219
221
220
222
std::vector<uint32_t > transpose_input_shape = output_info.shape ;
@@ -255,8 +257,7 @@ Status SoftmaxOpBuilder::ProcessAttributesAndOutputs(QnnModelWrapper& qnn_model_
255
257
do_op_validation,
256
258
false ,
257
259
is_graph_output));
258
- }
259
- else {
260
+ } else {
260
261
QnnParamWrapper axis_param (node_unit.Index (), node_unit.Name (), QNN_OP_SOFTMAX_PARAM_AXIS, axis_qnn_scalar);
261
262
std::vector<std::string> param_tensor_names;
262
263
param_tensor_names.push_back (axis_param.GetParamTensorName ());
0 commit comments