From 48519add3f84979320b82212989cb0d2a07fe8fd Mon Sep 17 00:00:00 2001 From: Maxwell Collins Date: Sun, 18 Jan 2026 22:29:05 -0800 Subject: [PATCH 1/4] Baseline test on dropping QDQ around MaxPool --- .../test/optimizer/qdq_transformer_test.cc | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/onnxruntime/test/optimizer/qdq_transformer_test.cc b/onnxruntime/test/optimizer/qdq_transformer_test.cc index 7fe68a38d23a0..3eba56c96865f 100644 --- a/onnxruntime/test/optimizer/qdq_transformer_test.cc +++ b/onnxruntime/test/optimizer/qdq_transformer_test.cc @@ -989,6 +989,53 @@ TEST(QDQTransformerTests, ReshapeDropQDQ) { RunReshapeDropQDQTestCase({1, 3, 2, 2}, {1, 12}, false, 21); // Use int16 ONNX QDQ ops } +// Runs a test case that checks if Q/DQ nodes are dropped from DQ -> MaxPool -> Q. +template +static void RunMaxPoolDropQDQTestCase(bool use_contrib_qdq = false, + int opset = 12) { + auto build_test_case = [use_contrib_qdq](ModelTestBuilder& builder) { + constexpr QuantType qmin = std::numeric_limits::min(); + constexpr QuantType qmax = std::numeric_limits::max(); + + const std::vector input_shape = {1, 17, 17, 3}; + auto* input_arg = builder.MakeInput(input_shape, qmin, qmax); + auto* output_arg = builder.MakeOutput(); + QuantType zero_point = 1 + (qmax + qmin) / 2; + + // add DequantizeLinear + auto* input_arg_dq = builder.MakeIntermediate(); + builder.AddDequantizeLinearNode(input_arg, .003f, zero_point, input_arg_dq, use_contrib_qdq); + + // add MaxPool + auto* maxpool_output = builder.MakeIntermediate(); + Node& maxpool_node = builder.AddNode("MaxPool", {input_arg_dq}, {maxpool_output}); + maxpool_node.AddAttribute("auto_pad", "VALID"); + maxpool_node.AddAttribute("kernel_shape", std::vector({2, 2})); + + // add QuantizeLinear + builder.AddQuantizeLinearNode(maxpool_output, .003f, zero_point, output_arg, use_contrib_qdq); + }; + + auto check_graph = [use_contrib_qdq](InferenceSessionWrapper& session) { + auto op_to_count = CountOpsInGraph(session.GetGraph()); + const QDQOpKeys qdq_keys = GetQDQOpKeys(use_contrib_qdq); + EXPECT_EQ(op_to_count["MaxPool"], 1); + EXPECT_EQ(op_to_count[qdq_keys.quantize_linear], 0); + EXPECT_EQ(op_to_count[qdq_keys.dequantize_linear], 0); + }; + + TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2, opset); +} + +// Checks that Q/DQ nodes are dropped from DQ -> MaxPool -> Q. Uses 8-bit Q/DQ ops. +TEST(QDQTransformerTests, MaxPoolDropQDQ) { + // Opset 12 + RunMaxPoolDropQDQTestCase(); + RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops + RunMaxPoolDropQDQTestCase(); + RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops +} + // Runs a test case that checks if Q/DQ nodes are *not* dropped from DQ -> MaxPool -> Q if the quantization scale is // negative. template From ba887a8506a99e6ba5a5ce62e81b3e04eb865ef1 Mon Sep 17 00:00:00 2001 From: Maxwell Collins Date: Sun, 18 Jan 2026 22:58:25 -0800 Subject: [PATCH 2/4] Test dropping QDQ around MaxPool at opset 22 --- onnxruntime/test/optimizer/qdq_transformer_test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/onnxruntime/test/optimizer/qdq_transformer_test.cc b/onnxruntime/test/optimizer/qdq_transformer_test.cc index 3eba56c96865f..067b6662ad68a 100644 --- a/onnxruntime/test/optimizer/qdq_transformer_test.cc +++ b/onnxruntime/test/optimizer/qdq_transformer_test.cc @@ -1034,6 +1034,10 @@ TEST(QDQTransformerTests, MaxPoolDropQDQ) { RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops RunMaxPoolDropQDQTestCase(); RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops + + // Opset 22 + RunMaxPoolDropQDQTestCase(false, 22); + RunMaxPoolDropQDQTestCase(false, 22); } // Runs a test case that checks if Q/DQ nodes are *not* dropped from DQ -> MaxPool -> Q if the quantization scale is From a2114ec03408f4fa5d63950e0b04bba2e8f203ed Mon Sep 17 00:00:00 2001 From: Maxwell Collins Date: Sun, 18 Jan 2026 23:28:48 -0800 Subject: [PATCH 3/4] Select MaxPool opset 22 in DropQDQNodesRules --- .../selectors_actions/qdq_selector_action_transformer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc index d454df3393f2b..2cc8531dc3d79 100644 --- a/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc +++ b/onnxruntime/core/optimizer/qdq_transformer/selectors_actions/qdq_selector_action_transformer.cc @@ -85,7 +85,7 @@ void DropQDQNodesRules(SelectorActionRegistry& qdq_selector_action_registry) { std::unique_ptr selector_no_16bit_and_positive_scale = std::make_unique(false, true, false, providers); qdq_selector_action_registry.RegisterSelectorAndAction(drop_action_no_int16_and_positive_scale_name, - {{"MaxPool", {12}}, + {{"MaxPool", {12, 22}}, {"ReduceMax", {}}, {"ReduceMin", {}}}, std::move(selector_no_16bit_and_positive_scale), From 5a1ed913ec2586d4205a919c7d9e918ccbe6929b Mon Sep 17 00:00:00 2001 From: Maxwell Collins Date: Sun, 18 Jan 2026 23:30:34 -0800 Subject: [PATCH 4/4] Autoformatter changes (from lintrunner) --- onnxruntime/test/optimizer/qdq_transformer_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/onnxruntime/test/optimizer/qdq_transformer_test.cc b/onnxruntime/test/optimizer/qdq_transformer_test.cc index 067b6662ad68a..6acbf0a3d9c0a 100644 --- a/onnxruntime/test/optimizer/qdq_transformer_test.cc +++ b/onnxruntime/test/optimizer/qdq_transformer_test.cc @@ -1031,9 +1031,9 @@ static void RunMaxPoolDropQDQTestCase(bool use_contrib_qdq = false, TEST(QDQTransformerTests, MaxPoolDropQDQ) { // Opset 12 RunMaxPoolDropQDQTestCase(); - RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops + RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops RunMaxPoolDropQDQTestCase(); - RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops + RunMaxPoolDropQDQTestCase(true); // Use com.microsoft QDQ ops // Opset 22 RunMaxPoolDropQDQTestCase(false, 22);