GraphSurgeon reverse-engineers ONNX computational graphs from the command line or Python. It summarizes inputs and operators, maps depth and execution order, detects structural motifs in the DAG, cross-references adversarial ML literature, narrates data flow, and supports counterfactual edits with validation and diff.
The tool is ONNX-only. It does not require PyTorch or a CUDA toolkit.
| Command | Role |
|---|---|
inspect |
Model summary: I/O tensors, initializer count, operator mix |
topology |
Graph depth, early/middle/late layer buckets, execution order |
patterns |
Coarse structural blocks (conv stacks, attention, normalization chains) |
motifs |
Registry-backed structural motifs: which attack classes the graph topology makes architecturally plausible |
flow |
Plain-English execution narrative |
catalog |
Lookup gadgets, compound chains, literature techniques, and bundled paper notes |
operators |
ONNX operator reference keyed to security-relevant behavior |
edit |
Counterfactual graph surgery (remove-node) with structural, loadable, or runnable validation |
diff |
Compare two ONNX files after edits |
Motif hits describe attack landscape (what attack types the architecture enables), not confirmed exploitability. The tool does not assign risk scores or severity tiers.
cd graph-surgeon
python3 -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"| Package | Purpose |
|---|---|
onnx, numpy |
Core graph parsing, motifs, topology (always installed) |
onnxruntime |
edit validate --level loadable/runnable (via [dev]) |
pytest |
Test suite (via [dev]) |
Minimal install (no runtime validation or tests):
.venv/bin/python -m pip install -e .After pip install -e ., use the project venv (the graph-surgeon command is not on your system PATH unless you activate the venv):
source .venv/bin/activate # optional; then graph-surgeon works on PATH
# or always:
.venv/bin/graph-surgeon --help
.venv/bin/python -m graph_surgeon catalog --coveragegraph-surgeon inspect model.onnx
graph-surgeon topology model.onnx
graph-surgeon patterns model.onnx
graph-surgeon motifs model.onnx -o report.json
graph-surgeon flow model.onnx
graph-surgeon catalog --gadget GAP_FC_HEAD
graph-surgeon catalog --chain CHAIN-PATCH-ATTACK-SURFACE
graph-surgeon catalog --coverage
graph-surgeon operators --op Conv
graph-surgeon edit validate edited.onnx --level runnable
graph-surgeon edit remove-node model.onnx NODE_NAME -o edited.onnx
graph-surgeon diff baseline.onnx edited.onnxWhen a motif or chain is detected, use catalog --gadget or catalog --chain for registry metadata, detection logic, and paper write-ups. Display titles use registry IDs (for example GAP_FC_HEAD — Global Average Pool → FC Head).
Counterfactual edits (edit) currently expose one surgery subcommand: remove-node. Use inspect or topology to discover exact ONNX node names before editing.
GraphSurgeon ships per-paper analysis under graph_surgeon/taxonomy/data/ (notably attack_research_notes.md). That corpus is what powers rich catalog output: when you look up a gadget or chain, you get the linked AML literature, ONNX graph indicators, and attack-class mapping without fetching external docs.
Normal use does not require touching these files. To see completion status:
.venv/bin/graph-surgeon catalog --coverageGraphSurgeon is primarily a CLI tool, but the same analysis and surgery paths are available from Python. Package-level exports (from graph_surgeon import ...): GraphSurgeon, GraphTopology, GraphTopologyConfig, LayerPosition, NodeTopology, GraphValidationLevel, GraphValidationResult.
These mirror motifs, patterns, and flow:
from graph_surgeon.parsers.onnx_parser import analyze_onnx_graph, analyze_onnx_patterns, quick_scan
motif_report = analyze_onnx_graph("model.onnx", output_path="report.json")
print(len(motif_report.structural_findings), motif_report.model_flow_description)
pattern_report = analyze_onnx_patterns("model.onnx")
print(quick_scan("model.onnx"))JSON export from motifs uses the same sanitizer as CLI output (internal scoring fields stripped).
from graph_surgeon import GraphSurgeon, LayerPosition
surgeon = GraphSurgeon(verbose=False)
model = surgeon.load_model("model.onnx")
topo = surgeon.get_graph_topology(model.graph)
print(topo.total_nodes, topo.max_depth)
print(topo.by_position[LayerPosition.EARLY][:5])
print(topo.by_position[LayerPosition.LATE][:5])
print(surgeon.find_nodes_by_type(model.graph, "Conv"))These mirror catalog lookups:
from graph_surgeon.taxonomy.display import format_catalog_gadget, format_catalog_chain
from graph_surgeon.taxonomy.research_coverage import format_coverage_report
from graph_surgeon.taxonomy import motif_catalog
print(format_catalog_gadget("LINEAR_HEAD"))
print(format_catalog_chain("CHAIN-SKIP-HIGHWAY"))
print(format_coverage_report())
technique = motif_catalog.get_technique_by_id("AML-ADV-002")CLI parity: remove_node matches edit remove-node. All surgery methods mutate the loaded ModelProto in place and return a SurgeryResult (success, message, nodes_removed, edges_rewired, etc.).
from graph_surgeon import GraphSurgeon, GraphValidationLevel
surgeon = GraphSurgeon(verbose=False)
baseline = surgeon.load_model("model.onnx")
edited = surgeon.clone_model(baseline)
result = surgeon.remove_node(edited, "node_relu_23")
if not result.success:
raise RuntimeError(result.message)
surgeon.save_model(edited, "edited.onnx")
check = surgeon.validate(edited, level=GraphValidationLevel.STRUCTURAL)
print(check.valid, check.errors)
diff = surgeon.compare_graphs(baseline, edited)
print(diff["summary"], diff["nodes_removed"])GraphValidationLevel.LOADABLE and .RUNNABLE require onnxruntime (installed with pip install -e ".[dev]"). On a minimal install, validation falls back with warnings.
Additional graph surgery primitives (remove_subgraph, insert_node_before, insert_node_after, replace_node, modify_node_attribute, add_initializer, add_metadata) are Python-only today. See docs/PYTHON_API.md for the full GraphSurgeon reference.
Heuristic weight-distribution analysis (core deps only; no onnxruntime):
from graph_surgeon.behavior.weight_signature import analyze_onnx_weights
stats = analyze_onnx_weights("model.onnx")
print(stats.summary())| Doc | Contents |
|---|---|
| docs/PYTHON_API.md | Full GraphSurgeon method reference, validation levels, surgery result fields |
Netron is a graph viewer: nodes, tensors, and shapes on screen.
GraphSurgeon is an analysis and experimentation layer on top of the same ONNX files:
- Positional topology (stem vs middle vs head) and ordered execution, not just adjacency
- Automated motif and pattern detection with a typed registry and literature cross-reference
- A searchable catalog of gadgets, chains, techniques, and bundled paper notes
- Counterfactual edits (remove a node, rewire, validate, diff against baseline)
- JSON export for scripting and batch comparison across model variants
Use Netron to see the graph; use GraphSurgeon to interpret structure, relate it to published attack classes, and test what changes when you alter the DAG.
Unit tests (no external ONNX files):
.venv/bin/python -m pytest tests/ -vIntegration tests that require off-repo ONNX fixtures are gitignored and documented in tests/README.md.
MIT