From 6b6341fe778b8819a0088f65c75c6c14a547ee2f Mon Sep 17 00:00:00 2001 From: hualxie Date: Wed, 22 Apr 2026 11:01:47 +0800 Subject: [PATCH] updated for SqueezeNet --- .../op_input_gen/binary_input_generator.py | 4 ++-- .../op_input_gen/conv_input_generator.py | 7 +++++- .../op_input_gen/flatten_input_generator.py | 1 + .../global_pooling_input_generator.py | 1 + tests/unit/analyze/core/test_qdq.py | 23 ++++++++++++++----- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/winml/modelkit/pattern/op_input_gen/binary_input_generator.py b/src/winml/modelkit/pattern/op_input_gen/binary_input_generator.py index 752ad1008..c39efaa81 100644 --- a/src/winml/modelkit/pattern/op_input_gen/binary_input_generator.py +++ b/src/winml/modelkit/pattern/op_input_gen/binary_input_generator.py @@ -371,10 +371,10 @@ def get_qdq_config(self): """Return QDQ configuration for binary operator inputs.""" return { self.op_input_names[0]: QDQParameterConfig( - support_activation=True, support_weight=True + support_activation=True, support_weight=True, support_non_qdq=True ), self.op_input_names[1]: QDQParameterConfig( - support_activation=True, support_weight=True + support_activation=True, support_weight=True, support_non_qdq=True ), } diff --git a/src/winml/modelkit/pattern/op_input_gen/conv_input_generator.py b/src/winml/modelkit/pattern/op_input_gen/conv_input_generator.py index f57ad8246..d9c54c854 100644 --- a/src/winml/modelkit/pattern/op_input_gen/conv_input_generator.py +++ b/src/winml/modelkit/pattern/op_input_gen/conv_input_generator.py @@ -262,10 +262,15 @@ def get_infinite_property_names(self) -> list[str]: def get_qdq_config(self): """Return QDQ configuration for Conv operator inputs.""" # B/Y can be non-QDQ from P1 models + # TODO: INT8 bias is a workaround — P1 models observed with INT8-quantized + # bias; revisit once EP-level INT8 bias support is confirmed/rejected. return { "X": QDQParameterConfig(support_activation=True), "W": QDQParameterConfig(support_weight=True), - "B": QDQParameterConfig(support_non_qdq=True, qdq_types=[SupportedONNXType.INT32]), + "B": QDQParameterConfig( + support_non_qdq=True, + qdq_types=[SupportedONNXType.INT32, SupportedONNXType.INT8], + ), "Y": QDQParameterConfig(support_non_qdq=True, support_activation=True), } diff --git a/src/winml/modelkit/pattern/op_input_gen/flatten_input_generator.py b/src/winml/modelkit/pattern/op_input_gen/flatten_input_generator.py index be4315b71..1c1527328 100644 --- a/src/winml/modelkit/pattern/op_input_gen/flatten_input_generator.py +++ b/src/winml/modelkit/pattern/op_input_gen/flatten_input_generator.py @@ -104,4 +104,5 @@ def get_qdq_config(self): """Return QDQ configuration for Flatten operator inputs.""" return { "input": QDQParameterConfig(support_activation=True), + "output": QDQParameterConfig(support_activation=True, support_non_qdq=True), } diff --git a/src/winml/modelkit/pattern/op_input_gen/global_pooling_input_generator.py b/src/winml/modelkit/pattern/op_input_gen/global_pooling_input_generator.py index 6b7bcec04..99f87ab00 100644 --- a/src/winml/modelkit/pattern/op_input_gen/global_pooling_input_generator.py +++ b/src/winml/modelkit/pattern/op_input_gen/global_pooling_input_generator.py @@ -118,6 +118,7 @@ def get_qdq_config(self): """Return QDQ configuration for GlobalAveragePool operator inputs.""" return { "X": QDQParameterConfig(support_activation=True), + "Y": QDQParameterConfig(support_activation=True, support_non_qdq=True), } diff --git a/tests/unit/analyze/core/test_qdq.py b/tests/unit/analyze/core/test_qdq.py index 61758ab40..a1ba96bc2 100644 --- a/tests/unit/analyze/core/test_qdq.py +++ b/tests/unit/analyze/core/test_qdq.py @@ -1053,8 +1053,15 @@ class TestIterQDQCombinations: @pytest.mark.parametrize( "op_name,expected_count", [ - # All binary use this and it is enough - ("Add", binary_input_shapes * (16 * 2 - 4)), # 1204 + # All binary use this and it is enough. + # A and B each support activation + weight + non_qdq; output always Q-wrapped. + # Per shape by (A, B) should_qdq combo: + # (Q, Q) = 16*2 - 4 = 28 (4 types * 4 types * 2 is_constant - 4 scalar adj) + # (Q, raw) = 20 + # (raw, Q) = 20 + # (raw, raw)= 12 + # Total per shape: 28 + 20 + 20 + 12 = 80. + ("Add", binary_input_shapes * 80), # 3440 ( "AveragePool", 1152, @@ -1074,8 +1081,12 @@ class TestIterQDQCombinations: ("Concat", 240), # 15 base shapes/axes * 4 variadic counts * 4 activation types ( "Conv", - 1536 * 4, - ), # shape 3 * attrs 4 * 2 * kernel shape 2 * opt B 2 * 16 * B/Y non qdq 4 + 1536 * 5, + ), # 7680. 1536 = shape 3 * auto_pad 4 * group 2 * kernel_opt 2 + # * 16 (X act 4 * W weight 4) * 2 (Y QDQ-wrapped or not). + # Five bias states each contribute 1536: + # (no bias) + (bias INT32) + (bias INT8, P1 workaround) + # + (bias non-QDQ, B constant) + (bias non-QDQ, B non-constant). ( "ConvTranspose", 3328, @@ -1088,7 +1099,7 @@ class TestIterQDQCombinations: # All comparison use this ("Equal", binary_input_shapes * 16), # 688 ("Expand", 328), # case 41 * QDQ 4 * is_constant shape 2 - ("Flatten", 28 * 4), # 112 + ("Flatten", 28 * 4 * 2), # 224: 28 shapes * 4 types * 2 (output Q-wrapped or not) ( "Gather", 1184, @@ -1103,7 +1114,7 @@ class TestIterQDQCombinations: "Gemm", 36 * 16 * (4 + 3 * 2), ), # attributes (2 * 2 * 3 * 3) * QDQ * C (qdq + non-qdq * opt) - ("GlobalAveragePool", 3 * 4), # 12 + ("GlobalAveragePool", 3 * 4 * 2), # 24: 3 shapes * 4 types * 2 (Y Q-wrapped or not) ("InstanceNormalization", 3 * 16), # 48 ("LayerNormalization", 5 * 2 * 2 * 16), # 320 ("LpNormalization", 3 * 2 * 4 * 4), # 96: 3 shapes (>=3D) x 2 p x 4 axis x 4 act types