yobx.xshape#
modules
BasicShapeBuilder#
- class yobx.xshape.BasicShapeBuilder(verbose: int = 0, opset: int | None = None)[source]#
Implements a basic class doing shape inference in an ONNX model.
A couple of environment variables can be set to help debugging any issue.
ONNXSTOPSHAPE=<name>: raises an exception whennamereceives a shape.ONNXSTOPTYPE=<name>: raises an exception whennamereceives a type.ONNXDYNDIM=<name>: raises an exception when dimensionnameis usedONNXCST=1: shows which constant is requestedONNXSHAPECOMPUTE=1: raises an exception when a shape is missingONNXSTOPVALUESHAPE=<name>: more information in function dealing with shapes
- estimate_node_flops(node: NodeProto) int | str | None[source]#
Estimates the number of floating-point operations for node using the shapes already inferred by
run_model().Uses
estimate_node_flops()internally, providing this builder’sget_shape()andget_constant()implementations as the shape_fn and literal_fn callbacks.- Parameters:
node – ONNX node to estimate
- Returns:
estimated FLOPs count, or
Nonewhen shapes are unknown or the op_type is not supported
- evaluate_cost_with_true_inputs(feeds: Dict[str, ndarray], cost: List[Tuple[str, int | str | None, Tuple]], exc: bool = False) List[Tuple[str, int | None, Tuple]][source]#
Evaluates symbolic FLOPs expressions in cost using actual tensor shapes from feeds.
When
run_model()is called withInferenceMode.COSTon a model that has symbolic (dynamic) input shapes, the returned FLOPs values may be symbolic expressions (strings such as"(DIM1)*(DIM2)*(3)"). This method substitutes the true dimension values extracted from feeds to produce concrete integer FLOPs.- Parameters:
feeds – mapping
{name: array}of actual input tensorscost – list of
(op_type, flops, input_shapes)tuples as returned byrun_model(..., inference=InferenceMode.COST)exc – if
True, re-raise any evaluation error; otherwise the FLOPs entry is set toNonefor that node
- Returns:
list of
(op_type, evaluated_flops, input_shapes)tuples
- get_constant(name: str, exc: bool = True, computed_value: bool = False, as_shape: bool = False, multiple_outputs: bool = False) ndarray | NodeProto[source]#
The method returns the constant name. It is a tensor (numpy array) or a NodeProto which must be evaluated. If computed_value is True, the NodeProto is evaluated with the ReferenceEvaluator.
- Parameters:
name – constant name
exc – raise an exception if anything is impossible to do
computed_value – compute the value if not a constant
as_shape – returns a tuple for a shape
multiple_outputs – allow multiple outputs
- Returns:
value
- get_debug_msg(limit: int = 1000) str[source]#
Returns a string providing as much information as possible to help the developer understand why a conversion failed.
- Parameters:
limit – limit the string if the model is big
- Returns:
many pieces of information about the on going conversion
- get_local_function(name: str, domain: str = '', builder: bool = False) FunctionProto | BasicShapeBuilder[source]#
Returns a local function.
- get_opset(name: str) int[source]#
Returns the opset version for domain name.
- Parameters:
name – domain name
- Returns:
domain version or 0 if not specified
- get_shape(name: str) Tuple[int | torch.SymInt | torch.SymFloat | TracingInt | float | str, ...][source]#
Returns the shape of a result.
- has_local_function(name: str, domain: str = '', builder: bool = False) bool[source]#
Checks if a local function exists.
- has_shape(name: str, full=False) bool[source]#
Tells if a result has a shape. If full is True, it returns True if the shape exists and if it is a static shape with all dimensions > 0.
- register_dynamic_objects_from_dim(dim: str)[source]#
Registers all the dynamic objects required in a dimension.
- run_model(model: ModelProto | GraphProto, functions: Dict[Tuple[str, str], FunctionProto] | None = None, exc: bool = False, inference: InferenceMode | str = InferenceMode.SHAPE)[source]#
Runs inference over a model or a graph.
- Parameters:
model – an ONNX model or graph
functions – a dictionary of functions available to the model
exc – if True, raises an exception when inference fails
inference –
InferenceModevalue (or its string name, case-insensitive).InferenceMode.SHAPE(default) runs the full shape and type inference using symbolic expressions;InferenceMode.TYPEruns a lighter type-only inference viatype_inference.infer_typesthat only propagates element types without computing shapes
- run_node(node: NodeProto, exc: bool = False, cost: bool = True)[source]#
Uses shapes availables in the ShapeBuilder to infer the output shapes and types.
- run_value_info(info: ValueInfoProto, is_input: bool)[source]#
Fills ShapeBuilder with information coming from an input or output.
- set_constant(name: str, value: TensorProto | NodeProto) None[source]#
Stores a constant (a
onnx.TensorProtoor aonnx.NodeProto).
- set_device(name: str, device: int | torch.dtype, exc: bool = True)[source]#
Sets the shape for a result. It is exists, it checks the new shape is equal to the existing one.
- Parameters:
name – name
device – an integer or a torch device then converted into an integer
exc – raises an exception
- set_opset(name: str, version: int)[source]#
Sets the opset version for domain name.
- Parameters:
name – domain name
version – domain version
- set_rank(name: str, value: int) bool[source]#
Sets the rank for a result.
- Parameters:
name – result name
value – rank
- Returns:
True if there is no rank conflict
- set_shape(name: str, shape: Tuple[int | torch.SymInt | torch.SymFloat | TracingInt | float | str, ...], exc: bool = False, **_kwargs)[source]#
Sets the shape for a result. It is exists, it checks the new shape is equal to the existing one.
- Parameters:
name – result name
shape – shape
exc – raise an exception if inconsistency
- set_type(name: str, dtype: int, exc: bool = True) bool[source]#
Sets the shape for a result. It is exists, it checks the new shape is equal to the existing one.
- Parameters:
name – name
dtype – element type (an integer, ONNX), 0 (unknown is a possible value)
exc – raises an exception
- Returns:
returns True if there is no type conflict
- set_value_shape(name: str, value: Any, equal_to: Tuple[str, str] | None = None)[source]#
Sets the value for a shape result.
- Parameters:
name – name
value – it cannot be empty
equal_to – if specified, the value is also equal to this value
A value can be a string (for an unknown shape, a tuple for a shape, an integer for a single scalar.
ShapeBuilder#
- class yobx.xshape.ShapeBuilder[source]#
API for a class computing shapes in an ONNX model.
The main implementation is
BasicShapeBuilder. It walks through all the nodes of an ONNX model and infers output shapes and types based on the input shapes, using symbolic expressions when the exact integer values are not known.Symbolic expressions — When a dimension cannot be determined as a plain integer (e.g. because it depends on a dynamic input dimension), it is stored as a Python-arithmetic string expression built from the input dimension names. For instance, concatenating tensors of shapes
("batch", "seq1")and("batch", "seq2")along axis 1 yields output shape("batch", "seq1+seq2"). The supported operators inside a symbolic expression are+,-,*,//,%and^(where^meansmax). Expressions are automatically simplified bysimplify_expressionbefore being stored, sod + f - fbecomesdand2*seq//2becomesseq. Once concrete values are available they can be resolved withevaluate_shape()orevaluate_expression.<<<
import onnx import onnx.helper as oh from yobx.xshape import BasicShapeBuilder TFLOAT = onnx.TensorProto.FLOAT # Build a small model: Z = Concat(X, Y, axis=1) model = oh.make_model( oh.make_graph( [oh.make_node("Concat", ["X", "Y"], ["Z"], axis=1)], "graph", [ oh.make_tensor_value_info("X", TFLOAT, ["batch", "seq1"]), oh.make_tensor_value_info("Y", TFLOAT, ["batch", "seq2"]), ], [oh.make_tensor_value_info("Z", TFLOAT, [None, None])], ), opset_imports=[oh.make_opsetid("", 18)], ir_version=10, ) builder = BasicShapeBuilder() builder.run_model(model) print("input names :", builder.input_names) print("output names:", builder.output_names) print("shape of Z :", builder.get_shape("Z")) print("type of Z :", builder.get_type("Z"))
>>>
input names : ['X', 'Y'] output names: ['Z'] shape of Z : ('batch', 'seq1+seq2') type of Z : 1
Constraint mechanism — When a broadcasting operation aligns a symbolic dimension (e.g.
"d_model") with a concrete integer (e.g.64), the concrete value is used immediately as the output dimension and the equality"d_model" = 64is stored as a constraint. This avoids the need to backtrack through earlier nodes when the concrete value is later discovered. Constraints are inspected withget_registered_constraints()and are used internally for dimension renaming and equality checks. See ShapeBuilder for details.- add_to_constraints(dim_name: str, value: str | int | Set[str | int])[source]#
Adds a constraint associating a symbolic dimension name with a value or set of values.
- Parameters:
dim_name – symbolic dimension name (e.g.
"batch")value – the value, name, or set of values/names to associate with that dimension
- compare_with_true_inputs(inputs: Dict[str, ndarray] | List[ndarray], outputs: Dict[str, ndarray] | List[ndarray], exc: bool = True, do_shape: bool = True, do_type: bool = True) Dict[str, Tuple[Tuple[str, int, int], ...]][source]#
Compares the shape of the outputs with what the output shapes would return.
- Parameters:
inputs – inputs
outputs – outputs
exc – raises an exception when a discrepancy is met
do_type – compares types
do_shape – compares shapes
- Returns:
list of expression, expected value, computed value
- evaluate_dimension_equality_with_constraints(d1: str, *args) bool[source]#
Tells if two dimensions are equal.
- get_attribute(node: NodeProto, att_name: str, exc: bool = True) AttributeProto | None[source]#
Returns an attribute for a node.
- get_attribute_with_default(node: NodeProto, name: str, default_value: Any) Any[source]#
Returns an attribute or its default value if missing.
- Parameters:
node – node
name – attribute name
default_value – default value
- Returns:
value
- get_attributes_with_default(node: NodeProto, **default_values) Dict[str, Any][source]#
Returns int or float attributes. If missing, the default value is returned if it is not None.
- Parameters:
node – node
default_values – default values
- get_debug_msg(limit: int = 1000) str[source]#
Returns a string providing as much information as possible to help the developer understand why a conversion failed.
- Parameters:
limit – limit the string if the model is big
- Returns:
many pieces of information about the on going conversion
- get_device(name: str) int[source]#
Returns the device of result name.
- Parameters:
name – result name
- Returns:
rank as an integer
- get_opset(name: str) int[source]#
Returns the opset version for domain name.
- Parameters:
name – domain name
- Returns:
domain version or 0 if not defined
- get_rank(name: str) int[source]#
Returns the rank (number of dimensions) of result name.
- Parameters:
name – result name
- Returns:
rank as an integer
- get_registered_constraints() Dict[str, Set[str | int]][source]#
Returns the constraints registered so far.
- Returns:
mapping from dimension name to the set of values/names it is constrained to be equal to
- get_shape(name: str) Tuple[int | torch.SymInt | torch.SymFloat | TracingInt | float | str, ...][source]#
Returns the shape of result name as a tuple. Each dimension is either an integer or a string (symbolic dimension).
- Parameters:
name – result name
- Returns:
shape as a tuple of integers and/or strings
- get_shape_renamed(name: str) Tuple[int | torch.SymInt | torch.SymFloat | TracingInt | float | str, ...][source]#
Returns the shape of result name using user-visible dimension names.
After
_improves_dynamic_dimension_naming()has been called, symbolic dimension names that were given by the user (e.g."batch","seq_length") are substituted for the internal names (e.g."s0","s1"). When no renaming has been computed yet this falls back toget_shape().- Parameters:
name – result name
- Returns:
shape tuple with user dimension names where available
- get_type(name: str) int[source]#
Returns the element type of result name as an ONNX integer (e.g.
onnx.TensorProto.FLOAT == 1).- Parameters:
name – result name
- Returns:
element type as an integer
- pretty_node(node: NodeProto | None, limit: int = 80, short: bool = True, shape: bool = False) str[source]#
Pretty rendering for a node.
- Parameters:
node – node to render
limit – to show type and shapes after the limit
short – do not display shape information on the left
shape – show shape information below
- Returns:
string
- register_constraint_dimension(dim_name: str, value: Any)[source]#
Registers a constraint associating a symbolic dimension name with a value. This allows to deal backward constraints after a single pass if the model.
- Parameters:
dim_name – symbolic dimension name (e.g.
"batch")value – the value or set of values to associate with that dimension
- set_device(name: str, rank: int)[source]#
Sets the rank (number of dimensions) for result name.
- Parameters:
name – result name
rank – rank as an integer
- set_opset(name: str, itype: int)[source]#
Sets the opset version for domain name.
- Parameters:
name – domain name
version – domain version
- set_rank(name: str, rank: int)[source]#
Sets the rank (number of dimensions) for result name.
- Parameters:
name – result name
rank – rank as an integer
- set_shape(name: str, shape: Tuple[int | torch.SymInt | torch.SymFloat | TracingInt | float | str, ...])[source]#
Sets the shape for result name.
- Parameters:
name – result name
shape – tuple of integers and/or strings (symbolic dimensions)
- set_type(name: str, itype: int)[source]#
Sets the element type for result name.
- Parameters:
name – result name
itype – element type as an ONNX integer (e.g.
onnx.TensorProto.FLOAT == 1)
- update_shapes(model: ModelProto)[source]#
Updates model shapes with the value stored inside this graph.
estimate_node_flops#
- yobx.xshape.estimate_node_flops(node: NodeProto, shape_fn: Callable[[str], Tuple[int | str, ...] | None], literal_fn: Callable[[str], Tuple[int | str, ...] | None]) int | str | None[source]#
Estimates the number of floating-point operations for a single ONNX node.
Returns
Nonewhen the shapes are not fully known (dynamic shapes) or theop_typeis not covered.- Parameters:
node – ONNX node
shape_fn – callable mapping tensor name → shape tuple (from shape inference)
literal_fn – callable mapping tensor name → int-value tuple for 1-D integer constant tensors (shape specification tensors); used as a fallback when shape_fn cannot resolve a shape
- Returns:
estimated number of FLOPs, or
None
list_op_cost_formulas#
- yobx.xshape.list_op_cost_formulas() Dict[str, str][source]#
Returns a mapping from each supported ONNX
op_typeto the symbolic FLOPs expression produced byestimate_node_flops()on a representative test case from the ONNX backend test suite.For every single-node model found in the ONNX backend test data directory the static input dimensions are replaced by symbolic variables (
DIM<n>) usingreplace_static_dimensions_by_strings().BasicShapeBuilderis then run withinference=InferenceMode.COSTto obtain the symbolic FLOPs expression.Only the first passing test case per
op_typeis kept. Operators with no matching backend test case, or whose cost cannot be inferred symbolically, are omitted.- Returns:
{op_type: symbolic_flops_expression}sorted alphabetically.