winml build¶
Run the entire winml-cli pipeline (export → optimize → quantize → compile) in one command.
When to use this¶
Use winml build when you want to go from a Hugging Face model ID (or an
existing .onnx file) to a deployment-ready artifact in a single invocation,
without manually chaining winml export, winml optimize, winml quantize,
and winml compile. A build config file — generated by winml config — controls every
stage of the pipeline.
Synopsis¶
Flags¶
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--config |
-c |
path | None |
WinMLBuildConfig JSON file, generated by winml config. If omitted, config is auto-generated from -m. |
--model |
-m |
string | None |
Hugging Face model ID or path to an existing .onnx file. |
--export-type |
choice | generic |
Output selector: generic builds the stock single/composite ONNX model; optimized builds the family's registered runtime-optimized recipe (today the onnxruntime-genai NPU bundle) for the resolved --ep/--device. optimized fails fast if the family has no recipe or the resolved target is not one the recipe supports. |
|
--output-dir |
-o |
path | None |
Directory for all build artifacts. Mutually exclusive with --use-cache. |
--use-cache/--no-use-cache |
flag | false |
Store artifacts in the winml-cli global cache (~/.cache/winml/). Mutually exclusive with --output-dir. |
|
--rebuild/--no-rebuild |
flag | false |
Overwrite existing artifacts and re-run the full pipeline. | |
--quant/--no-quant |
flag | true |
Run the quantization stage (use --no-quant to skip), overriding the config. |
|
--no-compile / --compile |
flag | None |
Override compilation. --compile forces enable (config must have a compile section). --no-compile forces skip. Default: inherit from config. |
|
--optimize/--no-optimize |
flag | true |
Run the optimization stage (use --no-optimize to skip). |
|
--ep |
string | None |
Target execution provider for the analyzer (e.g., qnn). Falls back to the compile config EP if not set. |
|
--device |
-d |
string | auto |
Target device for the analyzer (e.g., npu, gpu). Default: auto (auto-detect). |
--precision |
-p |
string | auto |
Target precision (e.g., fp16, int8, w8a16). With -c, applied only when --device or --precision is passed. |
--analyze/--no-analyze |
flag | true |
Run the analyzer loop during build (use --no-analyze to skip). |
|
--max-optim-iterations |
integer | None |
Maximum autoconf re-optimization rounds (3 enforced internally when not set). --no-analyze implicitly sets this to 0. |
|
--shape-config |
path | None |
JSON shape overrides used while auto-generating a Hugging Face export config, for example {"height": 480, "width": 480}. Only valid when --config is omitted. |
|
--input-specs |
path | None |
JSON input tensor specs to merge into the Hugging Face export config. Symbolic string dimensions infer dynamic axes. | |
--export-config |
path | None |
JSON ONNX export config overrides to merge into the Hugging Face export config. | |
--dynamic-axes |
path | None |
JSON dynamic axes mapping for Hugging Face ONNX export, for example {"input_ids": {"0": "batch", "1": "sequence"}}. |
|
--trust-remote-code/--no-trust-remote-code |
flag | false |
Allow executing custom code from model repositories. Use only with trusted sources. | |
--allow-unsupported-nodes/--no-allow-unsupported-nodes |
flag | false |
Allow unsupported nodes to remain in the graph instead of failing the build. | |
--help |
-h |
flag | Show this message and exit. |
How it works¶
winml build reads a WinMLBuildConfig JSON file (from winml config) that
encodes device, precision, export, quantization, and compilation settings.
When -m is a Hugging Face model ID, the full pipeline runs: export → optimize
→ quantize → compile. When -m points to an existing .onnx file, the export
stage is skipped and the pipeline starts at optimization. After compilation, an
optional analyzer loop (--max-optim-iterations) re-evaluates graph quality
and applies further passes; --no-analyze disables it for a deterministic
single-pass build. Individual stages can be suppressed with --no-quant,
--no-compile, and --no-optimize without touching the config file.
Reproducible CI/CD builds
The config file is a portable, self-contained pipeline specification. Check it into source control and invoke winml build -c config.json in CI to produce identical artifacts without manual flag management. Set "auto": false in the config to disable the autoconf discovery loop for fully deterministic output.
Genai bundles for decoder LLMs (NPU + QNN)¶
For a registered decoder-LLM family (currently Qwen3), --export-type
optimized switches winml build from the stock per-model ONNX output to a
complete onnxruntime-genai
bundle directory:
| File | Role | Precision |
|---|---|---|
ctx.onnx |
Transformer prefill graph | w8a16 (default) |
iter.onnx |
Transformer decode graph | w8a16 (default) |
embeddings.onnx |
Token embedding table (CPU) | fp32 |
lm_head.onnx |
Vocab projection (CPU) | w4a32 |
genai_config.json + tokenizer |
onnxruntime-genai runtime metadata | — |
# One command: HF decoder LLM → full onnxruntime-genai bundle
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --export-type optimized
--export-type optimized resolves --ep/--device the same way a generic
build does — an explicit value is honored, otherwise the host is probed — and
then builds the recipe for that resolved target. On an NPU host the command
above needs no flags; on a host without the accelerator the resolved target has
no recipe and the build fails fast (naming the ep/device) instead of
silently producing a generic model. Pin --ep qnn --device npu to build the
bundle anywhere (e.g. CI), since an explicit target skips host detection. An
unregistered family, a pre-exported .onnx input, or module mode also fail fast.
--output-dir is required (the bundle is a directory) and --use-cache is not
supported. Use --precision to override the transformer precision; the CPU
companions always use their bundle-standard precisions.
Backward-compatible shortcut
When --export-type is omitted, a registered family with an explicit
--ep qnn on an NPU target still routes to its optimized bundle. The NPU
target may be explicit (--device npu) or resolved from auto — whether
--device auto is typed or --device is left off entirely:
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --device npu --ep qnn
# or let device auto-detection pick the NPU (--device may be omitted):
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --ep qnn
--export-type generic always forces the stock composite build, even for a
registered family on the NPU.
See Qwen3 — Genai Bundle for the full walkthrough.
Examples¶
# Full pipeline: HF model → export → optimize → quantize → compile
winml build -c config.json -m microsoft/resnet-50 -o output/
winml build
Config: config.json
Model: microsoft/resnet-50
Output: output/
export done (28.3s)
optimize done (4.1s)
quantize done (6.8s)
compile done (14.2s)
Build complete in 53.4s
Final artifact: output/resnet50_ctx.onnx
# Start from a pre-exported ONNX file (skips export stage)
winml build -c config.json -m resnet50.onnx -o output/
# Export and optimize only — skip quantization and compilation for quick testing
winml build -c config.json -m bert-base-uncased -o output/ \
--no-quant --no-compile
# Force a clean rebuild, overwriting any cached artifacts
winml build -c config.json -m facebook/convnext-tiny-224 -o output/ --rebuild
# Use the global cache and cap optimizer iterations for faster turnaround
winml build -c config.json -m microsoft/resnet-50 \
--use-cache --max-optim-iterations 1
# Build with a dynamic batch axis during Hugging Face export
winml build -m microsoft/resnet-50 -o output/ \
--dynamic-axes dynamic_axes.json
Common pitfalls¶
- Either
--output-diror--use-cacheis required; they are mutually exclusive. Omitting both raises an error immediately. --use-cacheis not supported in module mode. When the config is a JSON array (module mode), only--output-diris accepted.- The config file must come from
winml config. The schema is strict; unknown keys are rejected. - Export-shape flags only affect Hugging Face export. They are rejected for pre-exported ONNX inputs because the export step has already happened.
- Existing artifacts are reused by default. Pass
--rebuildto force a fresh run after changing the config. - Genai bundles require
--output-dir, not--use-cache. An optimized decoder-LLM bundle (--export-type optimized, or the--device npu --ep qnnshortcut) writes a directory of components and rejects--use-cache.
See also¶
- winml export
- winml compile
- Config and build
- How it works
- Config Schema — full field-by-field config reference
- Output Layout — what each output file contains
- Supported Models — validated model architectures