quark-onnx-quant-plan

SkillDev tools

Build a Quark ONNX PTQ quantization plan from `model_analysis.json` and user intent. Use when the user needs preset selection (XINT8 / A8W8 / A16W8 / BF16 / BFP16 / MX* / MXFP* …), calibration method choice (MinMax / Entropy / Percentile / Distribution / NonOverflow / MinMSE / LayerWisePercentile), algorithm selection (CLE / AdaRound / AdaQuant / BiasCorrection / AutoMixprecision), deployment-target gating (CPU / CUDA / ROCm / AMD NPU CNN / AMD NPU Transformer), op-type include/exclude lists, weights-only INT4 (MatMulNBits) decisions, dynamic vs static quantization, or a draft `quant_plan.json`. Trigger for "what preset should I use for my ONNX model", "choose XINT8 vs A8W8", "plan ONNX PTQ", "INT4 "BFP16 / MXFP4 for my model", "calibration method for Ryzen AI", "should I use AdaRound or AdaQuant", "SmoothQuant alpha", or when the user has a model analysis and needs to decide how to quantize an ONNX model.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the quark-onnx-quant-plan skill

What this skill tells your AI

The instructions your AI receives, as published by amd/quark in .claude/skills-impl/l1-atomic/onnx/quark-onnx-quant-plan/SKILL.md and read by ahel’s review.

Purpose

Convert an ONNX model_analysis.json plus the user's intent into a confirmed quant_plan.json. This skill makes the quantization decisions for the ONNX-to-ONNX flow — which preset, which calibration method, which algorithm, which op types to include/exclude, whether to enable an NPU target, whether to use external-data — without generating scripts or executing the quantization. The plan is the contract between the user's intent and the execution step.

Inputs

  • model_analysis.json from quark-onnx-model-intake (architecture, op histogram, opsets, external-data state, preset_candidates, risks)
  • env_context.json for accelerator-aware preset gating (CUDA major / ROCm major / NPU presence)
  • onnx_install_result.json (optional) — gates BFP/MX/Extended presets (require the custom-ops library to be compiled for the target EP)
  • User preferences: deployment target, accuracy goal, model-size goal, calibration data availability

Outputs: quant_plan.json

Records the chosen preset (or custom config), calibration method, algorithm list, layer/op overrides, NPU flag, external-data setting, and evaluation intent. Shares the schema with the Torch plan; ONNX-specific fields live under onnx_specific.

Schema: quant_plan.schema.json

{
  "model": {
    "model_type": "onnx",
    "architecture_guess": "cnn",
    "analysis_ref": "./model_analysis.json"
  },
  "backend": "onnx",
  "deployment_target": "npu_cnn",
  "preset": "XINT8",
  "calibration": {
    "method": "PowerOfTwo_MinMSE",
    "data_size": 200,
    "batch_size": 1,
    "use_external_data_format": false,
    "optimize_mem": false,
    "worker_num": 1
  },
  "algorithms": ["CLE"],
  "onnx_specific": {
    "enable_npu_cnn": true,
    "enable_npu_transformer": false,
    "include_cle": true,
    "include_fast_ft": false,
    "op_types_to_quantize": null,
    "nodes_to_quantize": null,
    "nodes_to_exclude": null,
    "subgraphs_to_exclude": [],
    "extra_options": {
      "OpTypesToExcludeOutputQuantization": []
    },
    "use_external_data_format": false,
    "execution_providers": ["CPUExecutionProvider"]
  },
  "evaluation_intent": "smoke",
  "requires_confirmation": false
}

Available Presets (from DefaultConfigMapping)

Quark ONNX ships 50+ named presets in quark/onnx/quantization/config/custom_config.py. Pick the smallest viable set for the user's architecture + deployment target; never list them all.

AMD NPU CNN — Ryzen AI / VAI (enable_npu_cnn=True, PoF2 scales, NHWC)

PresetDescriptionPicks
XINT8INT8 input + INT8 weight, optimized for NPUDefault for any CNN targeting NPU
XINT8_ADAROUNDXINT8 + AdaRound fast-finetuneWhen base XINT8 loses accuracy
XINT8_ADAQUANTXINT8 + AdaQuant fast-finetuneWhen AdaRound is not enough
VINT8INT8 optimized for VAIMLVAIML deployment

AMD NPU Transformer (enable_npu_transformer=True)

PresetDescriptionPicks
INT16_TRANSFORMER_DEFAULTINT16 activations + INT8 weights, fastOutlier-heavy activations
INT16_TRANSFORMER_ACCURATEINT16 + accuracy algorithmsLargest accuracy headroom

General CPU / CUDA / ROCm INT8 (deployment-agnostic)

PresetDescriptionPicks
A8W8INT8 sym activations + INT8 sym weightsStandard CPU/GPU INT8
A8W8_ADAROUND / A8W8_ADAQUANT+ fast-finetuneAccuracy-tight A8W8
A16W8INT16 sym activations + INT8 sym weightsWide-activation needs
A16W8_ADAROUND / A16W8_ADAQUANT+ fast-finetuneAccuracy-tight A16W8
S8S8_AAWS / U8S8_AAWS / U8U8_AAWA / S16S8_ASWS / U16S8_AAWS (+ ADAROUND / ADAQUANT variants)Various sym/asym INT8/INT16 combosFine-tune sym/asym choice per ORT target
INT8_CNN_DEFAULT / INT8_CNN_ACCURATE / INT16_CNN_DEFAULT / INT16_CNN_ACCURATECNN-tuned INT8/INT16CPU/GPU CNN deployment

Float Fallbacks

PresetDescriptionPicks
FP16 / FP16_ADAQUANTFP16 W+AAccuracy-first when INT is too lossy
BF16 / BF16_ADAQUANTBFloat16 W+ASame, with BF16 range

Block Formats (require Quark custom-ops library compiled for the target EP)

PresetDescriptionPicks
BFP16 / BFP16_ADAQUANTBlock Floating Point 16-bitAMD accelerator deployments
MX4 / MX6 / MX9 (+ ADAQUANT)Micro-Exponents BFP variantsBit-budget exploration
MXFP4E2M1 / MXFP6E2M3 / MXFP6E3M2 / MXFP8E4M3 / MXFP8E5M2 / MXINT8 (+ ADAQUANT)OCP MX formatsModern AMD/NVIDIA accelerators

Mixed-Precision

PresetDescriptionPicks
BF16_BFP16 / BF16_MIXED_BFP16 / BF16_MIXED_BFP16_ADAQUANTBF16 + BFP16 hybridHigh-accuracy + AMD HW
BF16_MXINT8 / BF16_MIXED_MXINT8 / BF16_MIXED_MXINT8_ADAQUANTBF16 + MXInt8 hybridSame, OCP MX flavor
MX9_INT8MX9 + INT8 hybridBit-budget exploration
S16S16_MIXED_S8S8INT16 + INT8 mixedOutlier-aware INT mix

Available Calibration Methods

From quark/onnx/calibration/methods.py (+ ORT built-ins):

MethodWhen to pick
MinMaxDefault for most CNN / weights-only; cheap, deterministic
EntropyKL-divergence-based; helps when activations have long tails
PercentileClip outliers at a chosen percentile (default 99.999)
DistributionDistribution-matching; useful for FP8 p3/same
LayerWisePercentileAuto-picks per-tensor optimal percentile (MAE/MSE) — AMD-specific
PowerOfTwo_NonOverflow (a.k.a. NonOverflow)Required for AMD NPU XINT8 — picks the smallest PoF2 scale that doesn't overflow
PowerOfTwo_MinMSE (a.k.a. MinMSE)Required for AMD NPU XINT8 — picks the PoF2 scale that minimizes MSE; usually better than NonOverflow
Int16Method.MinMaxFor INT16 configs

NPU CNN / XINT8 targets must use a PowerOfTwo* method. Non-PoF2 scales are rejected at NPU runtime — flag this as a hard constraint in the plan.

Available Algorithms

From quark/onnx/quantization/config/algorithm.py and examples/onnx/accuracy_improvement/:

AlgorithmKindCompatible presetsDescription
CLE (Cross-Layer Equalization)PreINT8 CNN configsFolds BN, equalizes per-channel scales across consecutive Conv/Linear layers (Nagel et al., 2019)
BiasCorrectionPostINT8 CNNPost-hoc bias adjustment (Nagel et al., 2019)
AdaRoundPost (fast-finetune)XINT8 / A8W8 / A16W8 / block formatsAdaptive rounding optimization; needs cal data + LR + iterations; GPU-accelerated
AdaQuantPost (fast-finetune)Same as AdaRoundLayer-wise calibration tuning; usually after AdaRound is not enough
AutoMixprecisionPostBlock formats / mixed-precisionAuto-selects sensitivity-based per-layer dtype; can do dual BFP16+MX hybrid

Algorithms compose: e.g. CLE (pre) + AdaRound (post) is a common XINT8 recipe. Combinations beyond two algorithms are usually a red flag — flag them in risks.

Decision Guide

Help the user choose based on their priorities and the architecture from model_analysis.json.model.onnx_specific.architecture_guess:

User intentArchitectureRecommended starting plan
"Best accuracy, AMD GPU"anyBF16 or BF16_MIXED_BFP16
"INT8 CNN, CPU/GPU deployment"cnnINT8_CNN_DEFAULT or A8W8; add CLE if accuracy drops
"INT8 CNN → Ryzen AI NPU"cnnXINT8 + CLE, calibration = PowerOfTwo_MinMSE; usually NHWC pre-conversion via quark.onnx.tools.convert_nchw_to_nhwc
"Ryzen AI NPU, accuracy-tight CNN"cnnXINT8_ADAROUND (then XINT8_ADAQUANT if still short)
"Block format MXFP4 / BFP16 experimentation"anyBFP16 or MXFP4E2M1; require quark.onnx.operators.custom_ops to be compiled
"Hybrid mixed-precision for best size/accuracy"anyBF16_MIXED_BFP16 or S16S16_MIXED_S8S8 + AutoMixprecision

Deployment-Target Gating (HARD constraints)

TargetPreset must satisfyCalibration must beNotes
npu_cnn (Ryzen AI CNN)enable_npu_cnn=True, PoF2 symmetric INT8 per-tensor, NCHW→NHWC donePowerOfTwo_MinMSE or PowerOfTwo_NonOverflowReject A8W8 / BFP16 / MX* / FP16 if user requests npu_cnn
npu_transformer (Ryzen AI Transformer)enable_npu_transformer=True, INT8/INT16 QDQ on MatMul/GemmMinMax / Percentile typicallyReject CNN-only presets
cudaonnxruntime-gpu present, CUDAExecutionProvider availableAnyBlock-format presets require custom-ops
rocmonnxruntime_rocm (ROCm 6.x) or CPU ORT on ROCm 7.x (tools/ci/install_onnxruntime.sh)AnyCustom-ops library must compile for ROCm
cpuAnyAnyBlock-format presets work via CPU custom-ops; expect speed cost

If the deployment target conflicts with a requested preset, the plan must either (a) downgrade to a viable preset and explain, or (b) leave it unset with a high-severity risk in quant_plan.json.

Op-Type / Node Include/Exclude Levers

Three commonly-used knobs the plan should expose:

  • op_types_to_quantize — restrict QDQ insertion to a subset, e.g. ["Conv"] for CNN-only quantization.
  • nodes_to_quantize / nodes_to_exclude — surgical per-node control by graph node name. Node names change after pre-processing (NCHW→NHWC, BN folding, etc.), so resolve them after any pre-processing pass.
  • extra_options["OpTypesToExcludeOutputQuantization"] — keep certain op outputs in float while still quantizing their inputs/weights.

Extra Options Commonly Set in quant_plan.onnx_specific.extra_options

From real examples in examples/onnx/:

OptionTypical valueSource example
SimplifyModelTrue / Falsetoggle OnnxSlim pre-pass
QuantizeFP16TrueFP16-input models
OpTypesToExcludeOutputQuantization["Add", "Mul"] etc.keep selected op outputs in float
FastFinetune{"DataSize": 200, "BatchSize": 2, "NumIterations": 1000, "LearningRate": …, "OptimAlgorithm": "adaround"/"adaquant", "OptimDevice": "cuda:0"/"cpu", "InferDevice": "cuda:0"/"cpu", "EarlyStop": True}AdaRound / AdaQuant tutorials and Auto-Search tutorials

Decision Table (MUST show to user)

ALWAYS present this table and WAIT for confirmation before finalizing. Fill the "Value" column from the user's request, the model analysis, and the deployment-target gates above.

DecisionValueReason
backendonnxFixed for this skill
deployment_target(fill: cpu / cuda / rocm / npu_cnn / npu_transformer)(from env or user)
preset(fill: name from DefaultConfigMapping or "custom")(why)
calibration.method(fill: MinMax / Entropy / Percentile / Distribution / LayerWisePercentile / PowerOfTwo_MinMSE / PowerOfTwo_NonOverflow)(why)
calibration.data_size200 (default)(why)
calibration.batch_size14(why)
algorithms(fill: list e.g. ["CLE"], ["AdaRound"], ["AdaQuant"], ["BiasCorrection"])(why)
onnx_specific.enable_npu_cnn(fill: bool)Hard-tied to deployment_target == "npu_cnn"
onnx_specific.enable_npu_transformer(fill: bool)Hard-tied to deployment_target == "npu_transformer"
onnx_specific.include_cle(fill: bool)CNN INT8 default true
onnx_specific.op_types_to_quantizenull or ["MatMul"] etc.(why)
onnx_specific.use_external_data_formattrue if model > 2 GB (from model_analysis.json)Required for large models
onnx_specific.extra_options(fill: dict)(why — list each key)
evaluation_intentsmoke (default), mlperf, mAP(why)

After showing the table, ask: "Confirm this plan? Any changes?"

Do NOT proceed until the user confirms.

Per-Layer Overrides

For fine-grained control, individual layers can override the global config via QLayerConfig (see examples/onnx/yolo_quantization/quantize_yolo.py):

from quark.onnx import QConfig, QLayerConfig, XInt8Spec, CLEConfig

config = QConfig(
    global_config=QLayerConfig(activation=XInt8Spec(), weight=XInt8Spec()),
    algo_config=[CLEConfig()],
    EnableNPUCnn=True,
    exclude=[
        # YOLOX-style: keep a specific subgraph in float
        (["/_head/_modules_list.14/Transpose"], ["/_head/_modules_list.14/Concat_9"]),
    ],
)

Record any per-layer overrides under onnx_specific.subgraphs_to_exclude (list of (start_nodes, end_nodes) tuples) or onnx_specific.nodes_to_exclude (flat name list).

Rules

  • Keep scope to plan creation only. Do not generate scripts, do not run quantization, do not export. Those are separate skills.
  • Require a model analysis first. Without architecture, op histogram, opsets, and the already-QDQ flags, you cannot make informed preset / op-type recommendations. If model_analysis.json is missing, route back to quark-onnx-model-intake.
  • Honor hard deployment-target constraints. NPU CNN ⇒ XINT8 family + PowerOfTwo* calibration + NHWC. NPU Transformer ⇒ INT8_TRANSFORMER_* / INT16_TRANSFORMER_*. Reject conflicting preset requests with a clear explanation.
  • Custom-op preconditions for block formats. Any preset in {BFP16*, MX*, MXFP*, MXINT8*, BF16_*BFP*, BF16_*MXINT8*} requires the Quark custom-ops library to have compiled. If onnx_install_result.json shows the compile failed, suppress these presets from recommendations and emit a risk pointing back to quark-onnx-install.
  • External-data flag tracks model size. If model_analysis.json.model.estimated_size_gb > 2, set onnx_specific.use_external_data_format = true automatically. Otherwise default false.
  • Always present the decision table before finalizing. The user must explicitly confirm.
  • Record risks. If the user picks a risky combination (e.g. XINT8 without PoF2 calibration, MXFP4 on a model that hasn't been validated with AutoMixprecision), keep the user's choice but record the risk in the plan.
  • Do not duplicate fields between model_analysis.json and quant_plan.json. The plan references the analysis via analysis_ref.

Interaction Flow

  1. Check prerequisites: Is model_analysis.json available? If not, route to quark-onnx-model-intake first. Is onnx_install_result.json available? If a block-format preset is on the table, require it.
  2. Confirm deployment target: From session_context.json.constraints.deployment_target or ask. Apply the hard gates from the table above.
  3. Narrow presets: Start from model_analysis.json.quantization_targets.onnx_specific.preset_candidates, filter by deployment target and custom-op availability, present the top 1–3 with rationale.
  4. Pick calibration method: Default per target (MinMax for general; PowerOfTwo_MinMSE for NPU CNN; Percentile for outlier-heavy transformers; consider LayerWisePercentile when accuracy is critical). Decide data_size and batch_size.
  5. Pick algorithms: Default per architecture and preset (CLE for INT8 CNN; AdaRound→AdaQuant for accuracy-tight CNN; BiasCorrection as a cheap post-hoc fixup). At most two algorithms unless justified.
  6. Set extra options: From the table of common knobs, only set what's needed; document each.
  7. Present the decision table: Show defaults, explain the tradeoffs, let the user adjust.
  8. Confirm: Always required. Show the final plan summary before writing.
  9. Emit: Write quant_plan.json. Surface any new constraints back to quark-onnx-router so they land in session_context.json.

Recovery

  • If model_analysis.json shows has_qdq_already=true or has_quark_custom_ops=true — do not produce a plan. Route back to quark-onnx-model-intake with a recommendation to remove existing QDQ first (quark.onnx.tools.remove_qdq).
  • If the user picks a preset that conflicts with their deployment target — explain why it won't work (e.g. "A8W8 uses non-PoF2 scales which the AMD NPU CNN runtime rejects"), suggest the closest viable alternative (e.g. XINT8), and respect the user's choice if they insist — recording the risk.
  • If model_analysis.json shows architecture unknown — produce a draft plan with requires_confirmation: true, list the op histogram, and ask the user which of CNN / transformer / hybrid path to follow.
  • If calibration data is unavailable — explain that PTQ requires representative inputs for accurate scale estimation, and ask the user to supply a small calibration set (≥ a few dozen samples) before the plan can be finalized.
  • If a block-format preset is requested but custom-ops compile is unverified — hand off to quark-onnx-install to verify, then resume.
  • If the user picks an unusual combination (e.g. CLE + transformer, three or more algorithms) — explain why it's atypical and suggest the standard recipe, but respect the user's choice with a recorded risk.

Signals

GitHub stars
166
Forks
33
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
quark-onnx-quant-plan
Source
github.com/amd/quark