fix: DML/GPU build crash — skip compile config for EPs with enable_ep_context=False#405
Merged
Conversation
…ists When compile runs with enable_ep_context=false (DML), no EPContext file is produced. The build pipeline unconditionally set current_path to the non-existent compiled_path, causing FileNotFoundError downstream. Now checks compiled_path.exists() before updating current_path, so the pipeline falls through to the previous stage's output (e.g. quantized.onnx). Fixes #396
xieofxie
approved these changes
Apr 28, 2026
Contributor
|
but I do think DML also supports compile, bug? |
Collaborator
Author
|
Good catch - DML does support compile, but in our current flow it is JIT-style (usually no persisted EPContext file). See: https://github.com/microsoft/WinML-ModelKit/blob/77d553b75846178e94e0e1dca0d5d0ec623cfc7e/src/winml/modelkit/compiler/configs.py#L177 So the bug fixed here is the path assumption: _run_compile_stage switched to compiled_path even when no file was produced. Now it only switches when the file actually exists. |
DML and CPU don't produce EPContext output, so running compile_onnx for them is pure overhead. Skip the stage early when enable_ep_context=False rather than running compile and silently falling back on missing output. Also replace the compiled_path.exists() silent fallback with an explicit RuntimeError for EPs that do expect EPContext output (e.g. QNN), so silent failures are no longer swallowed.
--no-compile/--compile flag pair replaces the previous --no-compile is_flag, with default=True (no-compile). Compilation is now opt-in: users pass --compile to enable it, or keep the default to skip.
WinMLCompileConfig.for_provider() now checks enable_ep_context on the factory result and returns None for EPs that don't produce EPContext (dml, cpu, cuda, nv_tensorrt_rtx, vitisai, migraphx). This fixes the DML build crash (#396) where compiled_path was set without checking the file exists, by preventing DML from entering the compile stage at all. Also changes --no-compile CLI default to True (compile disabled by default) and adds a RuntimeError when compile reports success but the output file is missing, replacing the previous silent fallback.
vortex-captain
approved these changes
Apr 29, 2026
tezheng
approved these changes
Apr 29, 2026
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.
Summary
Fixes #396
winml buildcrashes withFileNotFoundErrorwhen targeting GPU/DML because the compile stage produces no EPContext file, but the pipeline unconditionally advancescurrent_pathto the non-existentcompiled_path.Root Cause
Why DML hits this but CPU doesn't:
CPU is protected at config generation time:
_DEVICE_TO_PROVIDER["cpu"] = None→WinMLCompileConfig.for_provider(None)returnsNone→config.compile = None→ compile stage is skipped entirely by the first guard in_run_compile_stage.DML goes through a different path:
_DEVICE_TO_PROVIDER["gpu"] = "dml"→WinMLCompileConfig.for_dml()returns a config withenable_ep_context=False. This produced a non-None compile config, so the stage was entered. Butenable_ep_context=Falsemeans no EPContext file is ever written. The old code then unconditionally setcurrent_path = compiled_pathon a file that doesn't exist.Fix
Two changes:
1. Fix at config level —
WinMLCompileConfig.for_provider()returnsNonefor non-EPContext EPsRather than checking
enable_ep_contextinsidebuild.py, the fix teachesfor_provider()that EPs withenable_ep_context=Falsehave no offline compile step and should returnNone:This naturally covers DML, CPU, CUDA, NvTensorRTRTX, VitisAI, and MIGraphX without hardcoding EP names. The logic is derived from the
enable_ep_contextflag already set in each factory. Unknown/custom EPs (generic fallback) are not subject to this rule.2. Raise explicitly when EPContext-producing EP reports success but output is missing
Replaces the silent
compiled_path.exists()fallback with an explicitRuntimeError, so real failures (e.g. QNN) surface immediately:3.
--no-compiledefaults toTrueChanged from
is_flag=True, default=Falseto--no-compile/--compilepair withdefault=True, so compile is disabled by default in the CLI.