Describe the bug
When performing Post-Training Quantization (PTQ) via modelopt.onnx.quantization.quantize(), static calibration fails when the input ONNX graph contains non-standard custom domains or third-party operators (e.g., custom_domain::CustomOp), even when those custom operators are explicitly excluded from quantization via op_types_to_exclude / nodes_to_exclude.
Impact: Blocker for networks containing custom C++/CUDA operations when executing single-stage PTQ workflows under ONNX Runtime execution providers (such as CUDAExecutionProvider).
Technical Root Causes Identified:
-
Validation Gate Failure (trt_utils.py):
load_onnx_model invokes get_custom_layers(), which initializes a native trt.OnnxParser. If a node belongs to a custom namespace/domain outside the empty default "" or trt.plugins, the native parser throws an unhandled API error (INVALID_NODE: creator && "Plugin not found..."). Furthermore, set_trt_plugin_domain unconditionally overrides user-defined domains to "trt.plugins".
-
Session Isolation in Calibrator (ort_patching.py):
When bypassing initial parser validation, calibration fails during static graph execution. In _create_inference_session_with_ep_config, ModelOpt instantiates an ort.InferenceSession for the temporary augmented_model.onnx graph without providing a mechanism to register external custom operator binaries (e.g., calling sess_options.register_custom_ops_library(plugin_path)). This causes ONNX Runtime to halt execution with:
[ONNXRuntimeError] : 1 : FAIL : Load model failed: Fatal error: custom_domain:CustomOp(-1) is not a registered function/op
Steps/Code to reproduce bug
import modelopt.onnx.quantization as moq
# Model containing a custom operator (e.g., domain: "custom_domain", op_type: "CustomOp")
onnx_model_path = "model_with_custom_op.onnx"
# Configure PTQ engine settings
# Assume user has a custom ORT operator shared library (.so) for execution
quant_cfg = {
"quantize_mode": "int8",
"calibration_method": "max",
"calibration_eps": ["cuda:0", "cpu"],
"op_types_to_exclude": ["CustomOp"],
"nodes_to_exclude": ["/path/to/custom_node"],
}
# Execution halts during initial TRT parsing or internal augmented session instantiation
moq.quantize(
onnx_path=onnx_model_path,
quantize_mode="int8",
calibration_data_reader=data_reader,
engine_settings=quant_cfg,
)
Expected behavior
ModelOpt should provide an official mechanism (e.g., via engine_settings or extra_options) to pass external custom operator shared libraries (.so / .dll) into both the initial graph inspection pass and all internal ort.InferenceSession instances (such as the augmented model calibrator in ort_patching.py), allowing custom operators to execute seamlessly on CUDA without requiring manual source patching.
Who can help
N/A
System information
- Container used (if applicable): Custom Docker Development Container
- OS: Linux 6.14.0-37-generic (Ubuntu x86_64)
- CPU architecture: x86_64
- GPU name: NVIDIA RTX 2000 Ada Generation
- GPU memory size: 15.58 GB
- Number of GPUs: 1
- Library versions:
- Python: 3.12.12
- ModelOpt version or commit hash: 0.42.0
- CUDA: 12.4
- PyTorch: 2.5.0+cu124
- Transformers: N/A
- TensorRT-LLM: N/A
- ONNXRuntime: 1.23.0
- TensorRT: 10.3.0
- Any other details that may help: Hard-patching
ort_patching.py to invoke sess_options.register_custom_ops_library("/path/to/plugin.so") directly inside _create_inference_session_with_ep_config resolved the issue completely and allowed 100% of quantizable nodes (191 nodes) to calibrate and export successfully.
Describe the bug
When performing Post-Training Quantization (PTQ) via
modelopt.onnx.quantization.quantize(), static calibration fails when the input ONNX graph contains non-standard custom domains or third-party operators (e.g.,custom_domain::CustomOp), even when those custom operators are explicitly excluded from quantization viaop_types_to_exclude/nodes_to_exclude.Impact: Blocker for networks containing custom C++/CUDA operations when executing single-stage PTQ workflows under ONNX Runtime execution providers (such as
CUDAExecutionProvider).Technical Root Causes Identified:
Validation Gate Failure (
trt_utils.py):load_onnx_modelinvokesget_custom_layers(), which initializes a nativetrt.OnnxParser. If a node belongs to a custom namespace/domain outside the empty default""ortrt.plugins, the native parser throws an unhandled API error (INVALID_NODE: creator && "Plugin not found..."). Furthermore,set_trt_plugin_domainunconditionally overrides user-defined domains to"trt.plugins".Session Isolation in Calibrator (
ort_patching.py):When bypassing initial parser validation, calibration fails during static graph execution. In
_create_inference_session_with_ep_config, ModelOpt instantiates anort.InferenceSessionfor the temporaryaugmented_model.onnxgraph without providing a mechanism to register external custom operator binaries (e.g., callingsess_options.register_custom_ops_library(plugin_path)). This causes ONNX Runtime to halt execution with:[ONNXRuntimeError] : 1 : FAIL : Load model failed: Fatal error: custom_domain:CustomOp(-1) is not a registered function/opSteps/Code to reproduce bug
Expected behavior
ModelOpt should provide an official mechanism (e.g., via
engine_settingsorextra_options) to pass external custom operator shared libraries (.so/.dll) into both the initial graph inspection pass and all internalort.InferenceSessioninstances (such as the augmented model calibrator inort_patching.py), allowing custom operators to execute seamlessly on CUDA without requiring manual source patching.Who can help
N/A
System information
ort_patching.pyto invokesess_options.register_custom_ops_library("/path/to/plugin.so")directly inside_create_inference_session_with_ep_configresolved the issue completely and allowed 100% of quantizable nodes (191 nodes) to calibrate and export successfully.