Add dynamo export support and make it the default exporter#1156
Open
DingmaomaoBJTU wants to merge 15 commits into
Open
Add dynamo export support and make it the default exporter#1156DingmaomaoBJTU wants to merge 15 commits into
DingmaomaoBJTU wants to merge 15 commits into
Conversation
Flip `winml export` to torch's dynamo-based ONNX exporter by default (--dynamo/--no-dynamo, default True). Add DynamoMetadataTagger that reads torch's native pkg.torch.onnx.class_hierarchy / name_scopes node metadata into the existing winml.hierarchy.* tag contract, so module-hierarchy tags survive without a separate TorchScript trace. - config + CLI default flipped to dynamo=True; stale "not supported" warning removed - DynamoMetadataTagger drop-in tagger (same interface as ONNXNodeTagger) - HTP exporter skips the redundant TorchScript trace under dynamo and sets verbose=False to avoid a UnicodeEncodeError on Windows consoles - TorchScript-path-specific tests pin dynamo=False; docs updated
xieofxie
reviewed
Jul 21, 2026
xieofxie
reviewed
Jul 21, 2026
xieofxie
reviewed
Jul 21, 2026
- test_dynamo_metadata_tagger: consolidate onnx imports to a single 'from onnx import ...' (CodeQL: module imported with both import and import-from) - docs/help: 'QNN-safe' reworded to name the real differentiator (opset/op decomposition, not shapes, since both exporters default to static shapes); add a static-shape export example
The dynamo exporter does not default to a higher final opset; winml passes the same opset (17) to both paths. torch's dynamo op library only implements ops at a minimum opset of 18, so it builds at 18 and then down-converts to the requested opset. Reword the export docs and concept doc to describe that lowering-and-conversion pass accurately instead of claiming a "newer opset" default.
torch's dynamo exporter targets a minimum opset of 18 and does not always lower to a smaller requested version (e.g. ResNet's ReduceMean keeps an opset-18-only attribute), so the export metadata previously misreported the requested opset (17) while the real graph was opset 18. - exporter: read the produced model's default-domain opset from the exported file and record that in the export monitor/metadata; warn when it differs from the requested opset. No post-export conversion is performed -- the requested opset is passed straight to the exporter and we report what it actually produced. - docs: correct the dynamo vs TorchScript opset wording (dynamo exports at opset 18, TorchScript at the configured opset 17) with the ResNet head decomposition example. - tests: add unit coverage for _read_default_opset.
When the dynamo exporter cannot down-convert a model to the requested opset, onnxscript's version_converter logs a WARNING with a full call stack (e.g. ResNet's ReduceMean during an 18->17 attempt). winml already surfaces a concise opset warning for that case, so the raw traceback is redundant noise in normal output. Add onnxscript.version_converter to the noisy-library logger floor so it is pinned at ERROR by default and only follows the CLI level once the user passes -v/-vv, matching how optimum's chatter is handled.
Resolves the CodeQL double-import alert on exporter.py: _read_default_opset now reads the proto through winml's own load_onnx helper (load_weights=False, validate=False) instead of a bare `import onnx`, matching the runtime onnx-loading style already used elsewhere in the file. Also floors torch's one-line "Setting ONNX exporter to use operator set version 18 ..." notice (logger torch.onnx._internal.exporter._compat) at ERROR by default, alongside the onnxscript version-converter traceback. winml already surfaces a concise opset warning, so both are redundant in normal output and only follow the CLI level at -v/-vv.
xieofxie
reviewed
Jul 22, 2026
xieofxie
reviewed
Jul 22, 2026
Two dynamo-path fidelity fixes from review: - DynamoMetadataTagger now folds each module's local scope name into its tag segment (Class.local) for every level, not just numeric indices, so same-class named siblings (an attention block's query/key/value Linears) stay independently addressable instead of collapsing to a single /.../Linear tag. Indexed children keep the existing Class.N form. - Add DynamoMetadataTagger.build_module_hierarchy to reconstruct the flat module hierarchy from node metadata. The exporter now recovers it after loading the exported ONNX and issues the deferred HIERARCHY monitor update, so the report/console/metadata module tree and the hierarchy_modules stat are populated for dynamo exports (previously 0). Output names for the dynamo path are sourced from the ONNX graph outputs instead of the empty traced outputs. Adds same-class-sibling tag tests and build_module_hierarchy unit tests.
xieofxie
reviewed
Jul 22, 2026
xieofxie
reviewed
Jul 22, 2026
xieofxie
reviewed
Jul 22, 2026
xieofxie
reviewed
Jul 22, 2026
Round-2 review follow-ups on the reconstructed dynamo module hierarchy. The tagger-level fixes from the previous commit were correct, but the shared tree writers could still drop or collapse modules: - metadata_writer: same-class named siblings (an attention block's query/key/value Linears) collapsed to one tree entry because children were keyed by bare class name. Key indexed children as Class.N (unchanged), disambiguate colliding same-class named siblings as Class.local, and keep the bare Class key for the unique case. Two-pass collision detection makes the keys order-independent, with a final full-remainder fallback for safety. - hierarchy_utils.find_immediate_children: rewrite traversal around a nearest-present-ancestor helper so a sparse hierarchy (an indexed child whose ModuleList container never emitted its own scope, e.g. blocks.0 with no blocks) attaches to its nearest real ancestor instead of being orphaned. metadata_writer now reuses this shared traversal, fixing the same root-scope limitation in the JSON report. - exporter: normalize the TorchScript output_names branch so output_names is always list[str] (infer_output_names returns list[str] | None), fixing the mypy union at the merge point. - docs: the dynamo path does not always export at opset 18. It targets a minimum opset of 18 and attempts to down-convert to a lower requested opset, which may succeed or fail; winml reports the opset actually produced. Update export.md and load-and-export.md accordingly. Add tests/unit/export/test_dynamo_hierarchy_report.py exercising the real MetadataWriter tree: all same-class siblings serialize and the sparse-root subtree is present; plus find_immediate_children sparse/dense nesting.
xieofxie
reviewed
Jul 22, 2026
xieofxie
reviewed
Jul 22, 2026
The dynamo export path reconstructs the module hierarchy from ONNX node metadata after export, but the reporting pipeline still described it as a TorchScript forward trace: the console/report claimed "Tracing module execution", the export summary said "Traced modules", and the metadata's execution_steps was set to the reconstructed-module count (a fabricated step total). Docs and the CLI docstring likewise presented forward-hook tracing as the default behaviour. Thread an explicit hierarchy source through the reporting pipeline so writers use source-appropriate wording and never report a trace that did not run: - step_data: add HIERARCHY_SOURCE_TRACE / HIERARCHY_SOURCE_ONNX_METADATA; HierarchyData.execution_steps is now int | None (None = no trace) and carries a source field. - exporter: tag the TorchScript HIERARCHY update as trace and the dynamo one as onnx_metadata, dropping the fabricated execution_steps count. - console/markdown writers: dynamo shows "Reconstructing/Recovered" with no execution-step line; the export summary label switches between "Recovered modules" and "Traced modules" by source. - metadata: record source + the real producer (DynamoMetadataTagger vs TracingHierarchyBuilder) and emit execution_steps=0 for dynamo instead of the module count; document the new source field in the schema. - docs + CLI docstring: distinguish the default dynamo metadata recovery from the --no-dynamo forward-hook trace. Add source-wording tests (console, markdown, and metadata) for both paths.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
winml exportpreviously rejected--dynamoeven though PyTorch's dynamo ONNX exporter is the actively developed path. This PR makes dynamo a supported default while preserving the module hierarchy metadata used by inspection, reporting, benchmarking, and optimization tooling.What changed
WinMLExportConfigandwinml exportnow default todynamo=True.--no-dynamoremains available for the legacy TorchScript exporter, and generated submodule configs preserve an explicit parent exporter choice.DynamoMetadataTaggerreads genericpkg.torch.onnx.name_scopesandpkg.torch.onnx.class_hierarchymetadata. It handles sparse scopes and same-class siblings without architecture-, operator-, or tensor-specific logic.onnx_metadatarecovery fromtrace, use discovery-order wording for dynamo, and source output names from the exported ONNX graph.dynamo=false, and--no-dynamopreserves the existing TorchScript path.Validation