Skip to content

Commit 7852669

Browse files
fix: apply optimize skip to hf.py and fix build -m model.onnx without -c
Address reviewer feedback: - build/hf.py: skip optimize_onnx for pre-quantized models (same fix as build/onnx.py, prevents QDQ-to-QLinear fusion that breaks EP compat) - commands/build.py: detect ONNX file input and route to generate_onnx_build_config via onnx_path param, fixing 'not a valid JSON file' error when running winml build -m model.onnx without -c - Update test_hf.py assertions to match new skip behavior
1 parent d7b1c38 commit 7852669

3 files changed

Lines changed: 22 additions & 21 deletions

File tree

src/winml/modelkit/build/hf.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,17 +255,10 @@ def _name(base: str) -> str:
255255
"Skipping optimize + quantize, running analyze-only."
256256
)
257257
stages_skipped.append("optimize")
258-
# Optimize+analyze only, no autoconf re-optimization
259-
current_path, _, analyze_iterations, analyze_unsupported_nodes, analyze_details = (
260-
run_optimize_analyze_loop(
261-
model_path=current_path,
262-
optimized_path=optimized_path,
263-
config=config,
264-
ep=ep,
265-
device=device,
266-
**onnx_kwargs,
267-
)
268-
)
258+
# Skip optimize entirely for pre-quantized models. ORT Level 2
259+
# optimization fuses QDQ patterns (e.g. DQ→Conv→Q → QLinearConv),
260+
# which breaks QNN/DML EP compatibility and causes CPU fallback.
261+
analyze_iterations, analyze_unsupported_nodes, analyze_details = 0, 0, {}
269262
else:
270263
logger.info("Optimizing ONNX model...")
271264
(

src/winml/modelkit/commands/build.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -588,11 +588,19 @@ def build(
588588
raise click.UsageError("-m/--model is required when -c is not provided.")
589589
from ..config import generate_build_config
590590

591-
config_or_configs = generate_build_config(
592-
model_id,
593-
trust_remote_code=trust_remote_code,
594-
device=device,
595-
)
591+
# Detect ONNX file input and route to generate_onnx_build_config
592+
if cli_utils.is_onnx_file_path(model_id):
593+
config_or_configs = generate_build_config(
594+
onnx_path=model_id,
595+
device=device,
596+
ep=ep,
597+
)
598+
else:
599+
config_or_configs = generate_build_config(
600+
model_id,
601+
trust_remote_code=trust_remote_code,
602+
device=device,
603+
)
596604
if not quant:
597605
config_or_configs.quant = None
598606
# Auto-generated configs: compile disabled by default unless

tests/unit/build/test_hf.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ def test_post_export_qdq_skips_optimize_and_quantize(
811811
assert "quantize" in result.stages_skipped
812812
assert "optimize" not in result.stages_completed
813813
assert "quantize" not in result.stages_completed
814-
mock_pipeline["optimize"].assert_called_once()
814+
mock_pipeline["optimize"].assert_not_called()
815815
mock_pipeline["quantize"].assert_not_called()
816816

817817
def test_post_export_qdq_still_exports(
@@ -847,7 +847,7 @@ def test_post_export_qdq_still_compiles(
847847
def test_post_export_qdq_runs_analyze_only(
848848
self, tmp_path: Path, sample_config, mock_pipeline
849849
) -> None:
850-
"""Pre-quantized path runs optimize but skips autoconf (no analyze)."""
850+
"""Pre-quantized path skips optimize entirely (no analyze either)."""
851851
mock_pipeline["is_quantized_onnx"].return_value = True
852852

853853
output_dir = tmp_path / "output"
@@ -856,9 +856,9 @@ def test_post_export_qdq_runs_analyze_only(
856856
output_dir=output_dir,
857857
pytorch_model=mock_pipeline["model"],
858858
)
859-
# max_optim_iterations=0 means no analyze loop runs
859+
# Pre-quantized models skip both optimize and analyze to preserve QDQ structure
860860
mock_pipeline["analyze"].assert_not_called()
861-
mock_pipeline["optimize"].assert_called_once()
861+
mock_pipeline["optimize"].assert_not_called()
862862

863863
def test_skip_optimize_kwarg(self, tmp_path: Path, sample_config, mock_pipeline) -> None:
864864
"""skip_optimize=True forces optimize+quantize skip."""
@@ -873,7 +873,7 @@ def test_skip_optimize_kwarg(self, tmp_path: Path, sample_config, mock_pipeline)
873873
)
874874
assert "optimize" in result.stages_skipped
875875
assert "quantize" in result.stages_skipped
876-
mock_pipeline["optimize"].assert_called_once()
876+
mock_pipeline["optimize"].assert_not_called()
877877
mock_pipeline["quantize"].assert_not_called()
878878

879879

0 commit comments

Comments
 (0)