@@ -30,9 +30,10 @@ static GetTestModelFn BuildF32ConvTestCase(const std::string& conv_op_type, cons
3030 const std::vector<int64_t >& dilations,
3131 std::optional<int64_t > group,
3232 const std::string& auto_pad = " NOTSET" ,
33- std::optional<OutputActivationInfo> output_activation = std::nullopt ) {
33+ std::optional<OutputActivationInfo> output_activation = std::nullopt ,
34+ std::optional<std::vector<int64_t >> output_shape = std::nullopt ) {
3435 return [conv_op_type, input_def, weights_def, bias_def, strides, pads,
35- dilations, group, auto_pad, output_activation](ModelTestBuilder& builder) {
36+ dilations, group, auto_pad, output_activation, output_shape ](ModelTestBuilder& builder) {
3637 std::vector<NodeArg*> conv_inputs = {
3738 MakeTestInput (builder, input_def),
3839 MakeTestInput (builder, weights_def)};
@@ -62,6 +63,10 @@ static GetTestModelFn BuildF32ConvTestCase(const std::string& conv_op_type, cons
6263 conv_node.AddAttribute (" dilations" , dilations);
6364 }
6465
66+ if (output_shape.has_value ()) {
67+ conv_node.AddAttribute (" output_shape" , output_shape.value ());
68+ }
69+
6570 if (output_activation.has_value ()) {
6671 NodeArg* output = builder.MakeOutput ();
6772 std::vector<NodeArg*> activation_inputs = {conv_output};
@@ -113,11 +118,12 @@ static GetTestQDQModelFn<ActivationQType> BuildQDQConvTestCase(
113118 std::optional<int64_t > group,
114119 const std::string& auto_pad = " NOTSET" ,
115120 bool use_contrib_qdq = false ,
116- std::optional<OutputActivationInfo> output_activation = std::nullopt ) {
121+ std::optional<OutputActivationInfo> output_activation = std::nullopt ,
122+ std::optional<std::vector<int64_t >> output_shape = std::nullopt ) {
117123 return [conv_op_type, input_def, weights_def, bias_def, strides, pads,
118124 dilations, group, auto_pad,
119- use_contrib_qdq, output_activation](ModelTestBuilder& builder,
120- std::vector<QuantParams<ActivationQType>>& output_qparams) {
125+ use_contrib_qdq, output_activation, output_shape ](ModelTestBuilder& builder,
126+ std::vector<QuantParams<ActivationQType>>& output_qparams) {
121127 std::vector<NodeArg*> conv_inputs;
122128
123129 // input -> Q/DQ ->
@@ -160,6 +166,9 @@ static GetTestQDQModelFn<ActivationQType> BuildQDQConvTestCase(
160166 if (!dilations.empty ()) {
161167 conv_node.AddAttribute (" dilations" , dilations);
162168 }
169+ if (output_shape.has_value ()) {
170+ conv_node.AddAttribute (" output_shape" , output_shape.value ());
171+ }
163172
164173 NodeArg* q_input = conv_output;
165174 if (output_activation.has_value ()) {
@@ -307,17 +316,18 @@ static void RunHTPConvOpTest(const std::string& conv_op_type, const TestInputDef
307316 bool use_contrib_qdq = false ,
308317 int opset = 13 ,
309318 QDQTolerance tolerance = QDQTolerance(),
310- std::optional<OutputActivationInfo> output_activation = std::nullopt) {
319+ std::optional<OutputActivationInfo> output_activation = std::nullopt,
320+ std::optional<std::vector<int64_t>> output_shape = std::nullopt) {
311321 ProviderOptions provider_options;
312322 provider_options[" backend_type" ] = " htp" ;
313323 provider_options[" offload_graph_io_quantization" ] = " 0" ;
314324
315325 TestQDQModelAccuracy (BuildF32ConvTestCase (conv_op_type, input_def, weights_def, bias_def, strides, pads, dilations,
316- group, auto_pad, output_activation),
326+ group, auto_pad, output_activation, output_shape ),
317327 BuildQDQConvTestCase<ActivationQType, WeightQType>(conv_op_type, input_def, weights_def,
318328 bias_def, strides, pads, dilations,
319329 group, auto_pad, use_contrib_qdq,
320- output_activation),
330+ output_activation, output_shape ),
321331 provider_options,
322332 opset,
323333 expected_ep_assignment,
@@ -2169,6 +2179,65 @@ TEST_F(QnnHTPBackendTests, ConvTransposeU8U8S32_AutoPadValid) {
21692179 13 );
21702180}
21712181
2182+ // Test ConvTranspose with output_shape attribute
2183+ // This test verifies that when 'output_shape' is provided, the QNN EP correctly
2184+ // calculates and applies padding for ConvTranspose, overriding any 'pads' attribute,
2185+ // and correctly distributes the padding according to 'auto_pad' rules.
2186+ TEST_F (QnnHTPBackendTests, ConvTransposeU8U8S32_OutputShape) {
2187+ std::vector<int64_t > output_shape = {6 , 6 };
2188+ RunHTPConvOpTest<uint8_t , uint8_t >(" ConvTranspose" ,
2189+ TestInputDef<float >({1 , 1 , 4 , 4 }, false , 0 .f , 10 .f ), // Dynamic input
2190+ TestInputDef<float >({1 , 1 , 2 , 2 }, true , -1 .f , 1 .f ), // Static weights
2191+ TestInputDef<float >({1 }, true , {1 .0f }), // Initializer bias
2192+ {2 , 2 }, // strides
2193+ {0 , 0 , 0 , 0 }, // pads
2194+ {1 , 1 }, // dilations
2195+ 1 , // group
2196+ " SAME_UPPER" , // auto_pad
2197+ ExpectedEPNodeAssignment::All,
2198+ false , // use_contrib_qdq
2199+ 13 , // opset
2200+ QDQTolerance (),
2201+ std::nullopt , // No output activation
2202+ output_shape); // Pass the output_shape attribute
2203+
2204+ std::vector<int64_t > output_shape_3d = {6 , 6 , 6 };
2205+ RunHTPConvOpTest<uint8_t , uint8_t >(" ConvTranspose" ,
2206+ TestInputDef<float >({1 , 1 , 4 , 4 , 4 }, false , 0 .f , 10 .f ), // Dynamic input
2207+ TestInputDef<float >({1 , 1 , 2 , 2 , 2 }, true , -1 .f , 1 .f ), // Static weights
2208+ TestInputDef<float >({1 }, true , {1 .0f }), // Initializer bias
2209+ {2 , 2 , 2 }, // strides
2210+ {0 , 0 , 0 , 0 , 0 , 0 }, // pads
2211+ {1 , 1 , 1 }, // dilations
2212+ 1 , // group
2213+ " SAME_UPPER" , // auto_pad
2214+ ExpectedEPNodeAssignment::All,
2215+ false , // use_contrib_qdq
2216+ 13 , // opset
2217+ QDQTolerance (),
2218+ std::nullopt , // No output activation
2219+ output_shape_3d); // Pass the output_shape attribute
2220+ }
2221+
2222+ TEST_F (QnnHTPBackendTests, ConvTranspose1DU8U8S32_OutputShape) {
2223+ std::vector<int64_t > output_shape = {6 };
2224+ RunHTPConvOpTest<uint8_t , uint8_t >(" ConvTranspose" ,
2225+ TestInputDef<float >({1 , 1 , 4 }, false , 0 .f , 10 .f ), // Dynamic input
2226+ TestInputDef<float >({1 , 1 , 2 }, true , -1 .f , 1 .f ), // Static weights
2227+ TestInputDef<float >({1 }, true , {1 .0f }), // Initializer bias
2228+ {2 }, // strides
2229+ {0 , 0 }, // pads
2230+ {1 }, // dilations
2231+ 1 , // group
2232+ " SAME_UPPER" , // auto_pad
2233+ ExpectedEPNodeAssignment::All,
2234+ false , // use_contrib_qdq
2235+ 13 , // opset
2236+ QDQTolerance (),
2237+ std::nullopt , // No output activation
2238+ output_shape); // Pass the output_shape attribute
2239+ }
2240+
21722241// Tests Conv1d auto_pad value "VALID" on HTP backend (compares to CPU EP).
21732242TEST_F (QnnHTPBackendTests, Conv1DU8U8S32_AutoPadValid) {
21742243 std::vector<float > input_data = {0 .f , 1 .f , 2 .f , 3 .f , 4 .f , 5 .f , 6 .f , 7 .f };
0 commit comments