Skip to content

If node adaptation fails when node outside subgraph is referenced. #145

@adityagoel4512

Description

The described error can be reproduced with the following example:

import spox.opset.ai.onnx.v19 as op19
import spox.opset.ai.onnx.v18 as op18
from spox import Tensor, Var, argument, build
import onnx
import numpy
import pytest

def test_if_adaptation_const():
    sq = op19.const(1.1453, dtype=numpy.float32)
    b = argument(Tensor(numpy.float32, ("N",)))
    cond = op18.equal(sq, b)
    out = op18.if_(cond,
        then_branch=lambda: [sq],
        else_branch=lambda: [sq])
    build({"b": b}, {"out": out[0]})

Spox (correctly) attempts to update the opset of the if node from 18 to 19, but in creating a singleton model fails to add the output of the const as an input of the singleton since this is not an "input" of the If node.

tests/test_adapt.py:131:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/spox/_public.py:117: in build
    return graph.to_onnx_model()
src/spox/_graph.py:412: in to_onnx_model
    self.to_onnx(concrete=concrete),
src/spox/_graph.py:343: in to_onnx
    node_protos = itertools.chain.from_iterable(self.get_adapted_nodes().values())
src/spox/_graph.py:281: in get_adapted_nodes
    best_effort = adapt_best_effort(
src/spox/_adapt.py:142: in adapt_best_effort
    adapted = adapt_node(
src/spox/_adapt.py:60: in adapt_node
    onnx.checker.check_model(source_model, full_check=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

model = ir_version: 9
graph {
  node {
    input: "Equal_0_C"
    output: "If_0_outputs_0"
    name: "If_0"
    op_type: "If"
..._type {
        elem_type: 1
        shape {
        }
      }
    }
  }
}
opset_import {
  domain: ""
  version: 16
}

full_check = True, skip_opset_compatibility_check = False

    def check_model(
        model: ModelProto | str | bytes | os.PathLike,
        full_check: bool = False,
        skip_opset_compatibility_check: bool = False,
    ) -> None:
        """Check the consistency of a model. An exception is raised if the test fails.

        Args:
            model: Model to check.
            full_check: If True, the function also checks for shapes that can be inferred.
            skip_opset_compatibility_check: If True, the function skips the check for
                opset compatibility.
        """
        # If model is a path instead of ModelProto
        if isinstance(model, (str, os.PathLike)):
            C.check_model_path(os.fspath(model), full_check, skip_opset_compatibility_check)
        else:
            protobuf_string = (
                model if isinstance(model, bytes) else model.SerializeToString()
            )
            # If the protobuf is larger than 2GB,
            # remind users should use the model path to check
            if sys.getsizeof(protobuf_string) > MAXIMUM_PROTOBUF:
                raise ValueError(
                    "This protobuf of onnx model is too large (>2GB). Call check_model with model path instead."
                )
>           C.check_model(protobuf_string, full_check, skip_opset_compatibility_check)
E           RuntimeError: Nodes in a graph must be topologically sorted, however input 'Constant_0_output' of node:
E           name: If_0_else_branch__Introduce_0_id0 OpType: Identity
E            is not output of any previous nodes.
E
E           ==> Context: Bad node spec for node. Name: If_0 OpType: If

../../micromamba/envs/spox/lib/python3.12/site-packages/onnx/checker.py:148: RuntimeError

Spox should either bail gracefully when it cannot adapt a node (this is a best effort thing anyway) or should support this behaviour.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions