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