Edit

winml build

Run the entire Windows ML 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

winml build [options]

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 CPU/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.
--submodel string all components Build a named component of a composite model instead of every component.
--use-cache/--no-use-cache flag false Store artifacts in the Windows ML 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. During optimization, the optional analyzer feedback loop (--max-optim-iterations) recommends further transformations before later quantization and compilation stages. --no-analyze disables that loop, not the need to validate the result. Individual stages can be suppressed with --no-quant, --no-compile, and --no-optimize without touching the config file.

When generating a configuration without -c, compilation is off unless you pass --compile. With an existing configuration, --compile requires a non-null compile section; generate it with winml config --compile first. An auto precision choice is target-dependent, so specify --precision fp32 --no-quant for a floating-point baseline.

Use --rebuild when intentionally rebuilding existing artifacts. The output location contains a final artifact and intermediates from the stages that actually ran; a skipped stage doesn't produce a new artifact. Run perf and eval separately to measure performance and quality rather than treating a successful build as deployment validation.

Tip

Reproducible CI/CD builds

Check the config into source control to record the pipeline settings. Also pin tool versions, model and dataset revisions, calibration inputs, and the target runtime environment when comparing builds. Set "auto": false to disable automatic configuration discovery. A configuration file alone doesn't guarantee identical artifacts across machines or versions.

Genai bundles for decoder LLMs (CPU/NPU)

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. The Qwen3 recipe supports CPU, QNN/NPU, VitisAI/NPU, and OpenVINO/NPU. Other targets fail fast (naming the ep/device) instead of silently producing a generic model. Pin the provider when needed:

# Qualcomm Snapdragon NPU
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --export-type optimized --ep qnn --device npu

# AMD Ryzen AI NPU
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --export-type optimized --ep vitisai --device npu

# CPU, without an NPU provider
winml build -m Qwen/Qwen3-0.6B -o out/qwen3-bundle --export-type optimized --ep cpu --device cpu

An explicit target skips host detection, which is useful for reproducible CI. 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. Precision choices are recipe-specific: the Qwen3 recipe requires w8a16 for its transformer and rejects incompatible overrides. CPU companions retain their recipe-defined precisions.

Note

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/

The build reports each enabled stage and its final artifact path. Skipped stages don't produce new intermediates. See Output layout for files to retain.

# 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-dir or --use-cache is required; they are mutually exclusive. Omitting both raises an error immediately.
  • --use-cache is not supported in module mode. When the config is a JSON array (module mode), only --output-dir is 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 --rebuild to 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 qnn shortcut) writes a directory of components and rejects --use-cache.

See also