Debugging transformations¶

ONNX IR provides readable object displays, ONNX text conversion, mutation journaling, and construction tapes for inspecting model transformations.

Use ONNX text format¶

Convert a model to the standard ONNX textual syntax when comparing structure with other ONNX tools:

text = ir.to_onnx_text(model)
print(text)

round_tripped = ir.from_onnx_text(text)

Pass exclude_initializers=True to to_onnx_text when large constant values would obscure the graph structure. Text conversion serializes through ONNX and is best used for diagnostics or interchange rather than inside performance-sensitive transformation loops.

Record mutations with a journal¶

The alpha onnx_ir.journaling API records supported IR operations, including stack traces and object references:

from onnx_ir.journaling import Journal

with Journal() as journal:
    transform(model)

journal.display()

Inspect journal.entries to filter by operation or class, call entry.display() for full details, or attach a hook for real-time logging:

journal = Journal()
journal.add_hook(lambda entry: print(entry.operation, entry.class_name))

Keep the journal scope focused around the suspicious transformation. Recording a large pipeline creates substantial diagnostic output and stack-trace data.

Inspect graph relationships¶

Use object relationships rather than names when diagnosing connectivity:

print(value.producer())
print(list(value.uses()))
print(list(value.consumers()))
print(node.predecessors())
print(node.successors())
print(node.graph)

For nested graphs, use RecursiveGraphIterator and analysis.analyze_implicit_usage to reveal control-flow bodies and outer-scope captures.

Isolate a failing region¶

onnx_ir.convenience.extract() can clone a bounded region into a smaller graph for inspection or reproduction:

region = ir.convenience.extract(
    model.graph,
    inputs=["x", "weight"],
    outputs=["y"],
)
region.display()

Extraction reports undeclared frontier dependencies instead of silently creating an incomplete graph.

Validate between pipeline stages¶

When a long pass pipeline fails, insert focused checks to locate the first invalid stage:

import onnx_ir.passes.common as common_passes

checker = common_passes.CheckerPass()

for pass_ in passes:
    result = pass_(model)
    model = result.model
    checker(model)

This per-stage checking is a diagnostic technique, not a recommended production pipeline: it serializes and checks the whole model after each pass.

Topological sorting, name fixing, shape inference, and ONNX checking test different properties. Apply the checks relevant to the invariant each stage promises.

Use Tape to reproduce construction bugs¶

onnx_ir.tape.Tape records nodes and initializers while constructing a graph. It is useful for reducing a failing model to a short sequence of operations that can be copied into a regression test.

See Constructing models for a complete example.