Migrate bnb4, io_datatype_converter, dynamic_to_fixed_shape, and static_llm passes to onnx_ir#2563
Migrate bnb4, io_datatype_converter, dynamic_to_fixed_shape, and static_llm passes to onnx_ir#2563justinchuby wants to merge 6 commits into
Conversation
…s to onnx_ir - OnnxBnb4Quantization: traverse/replace MatMul->MatMulBnb4 nodes via onnx_ir instead of the ORT MatMulBnb4Quantizer proto wrapper, keeping the native quantize_matmul_bnb4 kernel for FP4/NF4 packing. Preserves graph output names. - OnnxIODataTypeConverter: reimplement input/output Cast insertion and rewiring on onnx_ir. - DynamicToFixedShape: add IR-native fix_dim_params_ir/fix_input_shapes_ir helpers in common.py (native reimpl of ORT make_dim_param_fixed/make_input_shape_fixed/ remove_invalid_dim_values over ir.Graph incl. subgraphs); output shape inference still uses ORT SymbolicShapeInference. Proto helpers kept for static_llm. - Add OpType.MatMulBnb4 and OpType.Cast. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…aphs() The IR shape-fixing helpers are only used by DynamicToFixedShape, so move them out of common.py into the pass module. Replace the custom subgraph iterator with ir.Model.graphs() for traversal. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot Update olive/passes/onnx/static_llm.py to use onnx-ir completely. Remove any import/usage of OnnxModel from onnxruntime, and update / recreate the logic using onnx-ir / onnxscript rewriter instead |
There was a problem hiding this comment.
Pull request overview
This PR continues Olive’s ONNX pass migration from onnx.ModelProto-based graph edits to onnx_ir, aligning these passes with the newer IR-based weight-only quantization pattern already used elsewhere in the codebase.
Changes:
- Migrates
OnnxBnb4Quantizationto traverse/modify graphs viaonnx_irand replaceMatMulwithMatMulBnb4. - Reimplements
OnnxIODataTypeConverterinput/outputCastinsertion + rewiring usingonnx_ir. - Reimplements
DynamicToFixedShapedimension fixing overir.Model(including subgraph traversal), while keeping ORTSymbolicShapeInferencefor output shape inference.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/passes/onnx/test_bnb_quantization.py | Updates the test to use IR loading (load_ir_model) for MatMul discovery. |
| olive/passes/onnx/io_datatype_converter.py | Moves I/O Cast insertion and consumer/provider rewiring to onnx_ir. |
| olive/passes/onnx/dynamic_to_fixed_shape.py | Rebuilds dim-param and input-shape fixing logic on ir.Model, with ORT-based inference preserved. |
| olive/passes/onnx/bnb_quantization.py | Migrates BNB4 MatMul quantization to IR and performs node/value replacement in the IR graph. |
| olive/constants.py | Adds OpType.MatMulBnb4 and OpType.Cast to support the migrated passes. |
| ir_model.graph.sort() | ||
| for node in ir_model.graph.all_nodes(): | ||
| if node.op_type != str(OpType.MatMul): | ||
| continue | ||
|
|
||
| if node.name in nodes_to_exclude: | ||
| logger.debug("exclude to quantize %s as specified by nodes_to_exclude...", node.name) | ||
| continue | ||
|
|
||
| quantized_node = self._quantize_matmul(node, quant_type) | ||
| if quantized_node is node: | ||
| # nothing changed (non-const or non-2D weight) | ||
| continue | ||
|
|
||
| weight_graph = node.inputs[1].graph | ||
| for input_value in quantized_node.inputs: | ||
| if input_value is not None and input_value.const_value is not None: | ||
| weight_graph.register_initializer(input_value) | ||
|
|
| @staticmethod | ||
| def _bnb4_block_quant(fpweight: npt.ArrayLike, quant_type: int) -> tuple[np.ndarray, np.ndarray]: | ||
| """4b quantize fp32/fp16 weight using the native ORT bnb4 kernel.""" | ||
| from onnxruntime.capi._pybind_state import quantize_matmul_bnb4 | ||
|
|
Done.
Verified the shape-fixing parity and external-data sharing (both components load, pass |
| ) -> ONNXModelHandler: | ||
| onnx_model = model.load_model() | ||
| ir_model = model.load_ir_model() | ||
| ir.external_data.load_to_model(ir_model) |
There was a problem hiding this comment.
@copilot is ir.external_data.load_to_model needed? I don't think so?
There was a problem hiding this comment.
You're right — removed it. This pass only edits shape metadata, not tensor data, so lazily-loaded external tensors don't need to be materialized; ir.save reads them from the source file on save. Verified external data (and weight values) are preserved end-to-end and the test_dynamic_to_fixed_shape.py tests still pass.
|
@copilot error: |
| for output in ir_model.graph.outputs: | ||
| original_shape = original_shapes[output.name] | ||
| new_shape = _ir_io_shape(output) | ||
|
|
||
| for old_dim, new_dim in zip(original_shape, new_shape): |
| """4b quantize fp32/fp16 weight using the native ORT bnb4 kernel.""" | ||
| from onnxruntime.capi._pybind_state import quantize_matmul_bnb4 | ||
|
|
| onnx_model = model.load_model() | ||
| ir_model = model.load_ir_model() | ||
| ir.external_data.load_to_model(ir_model) | ||
| ir_model.graph.opset_imports[MSFT_DOMAIN] = 1 |
| weight_graph = node.inputs[1].graph | ||
| for input_value in quantized_node.inputs: | ||
| if input_value is not None and input_value.const_value is not None: | ||
| weight_graph.register_initializer(input_value) | ||
|
|
|
... Root cause: in Note: I have the fix committed locally, but the push is being rejected by a repository ruleset on |
Describe your changes
Continues the ongoing migration of ONNX passes from
onnx.ModelProtoAPIs toonnx_ir(following the pattern established by the weight-only quantizersrtn/hqq/kquant). Migrates four self-contained graph-transform passes:OnnxBnb4Quantization(bnb_quantization.py): Traverses the graph withonnx_irand replacesMatMulnodes withMatMulBnb4nodes viair.convenience.replace_nodes_and_values, instead of going through the ORTMatMulBnb4Quantizerproto wrapper. The nativequantize_matmul_bnb4kernel is retained for the FP4/NF4 bit-packing (that packing is defined by the kernel). Graph output names are preserved, consistent with the other weight-only quant passes.OnnxIODataTypeConverter(io_datatype_converter.py): Reimplements the input/outputCastinsertion and consumer rewiring ononnx_ir.DynamicToFixedShape(dynamic_to_fixed_shape.py): Reimplements ORT'smake_dim_param_fixed/make_input_shape_fixed/remove_invalid_dim_valuesnatively overir.Model(traversing subgraphs viair.Model.graphs()). Output shape inference uses theonnx-shape-inferencepackage (infer_symbolic_shapes), which runs directly on their.Modelwith no proto round-trip and refines shapes in place, replacing the earlier ORTSymbolicShapeInference(viair.to_proto).StaticLLM(static_llm.py): Now operates entirely onir.Model. Allonnx.ModelProto/onnx.load/onnx.saveusage is removed in favor ofir.load/ONNXModelHandler.load_ir_model()andir.save.fix_shaperuns on the IR model and reuses the IR-basedfix_dim_paramsfromdynamic_to_fixed_shape, removing the indirect dependency on onnxruntime'smake_dim_param_fixed/onnx_model_utils(output shape inference uses theonnx-shape-inferencepackage, as with the other migrated passes). The external-data sharing between the context and iterator component models is preserved by lazily loading the intermediate model so both fixed-shape outputs reference the sametransformer*.onnx.datafile.Also adds
OpType.MatMulBnb4andOpType.Casttoolive/constants.py, adds an IR-basedadd_version_metadata_to_ir_modelhelper tocommon.py, and removes the now-unused proto-basedfix_dim_params/fix_input_shapes/_fix_output_shapeshelpers fromcommon.py(they were the only remaining callers of the onnxruntimeonnx_model_utilsshape helpers, andstatic_llm.pyno longer depends on them). Addsonnx-shape-inference>=0.2.0torequirements.txt.Other remaining proto-based ONNX passes (e.g.
mixed_precision,mixed_precision_overrides,add_metadata, and external-tool wrappers likeaimet/inc/nvmo/transformer_optimization/optimum) are intentionally left as-is: they are thin wrappers over third-party proto APIs where an IR migration would only force an IR→proto→IR round-trip with no benefit.Checklist before requesting a review
lintrunner -aExisting pass tests (
test_bnb_quantization.py,test_io_datatype_converter.py,test_dynamic_to_fixed_shape.py) all pass (27 total). Verified end-to-end with ONNX Runtime inference, exact parity against the ORT reference for shape fixing (including subgraph recursion), andonnx.checkervalidity. Forstatic_llm.py, verified shape-fixing parity on a symbolic-dim model and that the context/iterator external-data sharing is preserved (both components load, passonnx.checker, and carryolive_versionmetadata). No new public config/behavior, so not user-facing.(Optional) Issue link