Custom Op

Submodules

Custom Op Nodes

Base Class

class qonnx.custom_op.base.CustomOp(onnx_node: NodeProto, onnx_opset_version: int = 1)

Bases: ABC

CustomOp class all custom op nodes are based on. Contains different functions every custom node should have. Some as abstract methods, these have to be filled when writing a new custom op node.

Opset Version Support:

CustomOp classes use “since version” semantics matching ONNX operators. Version is determined by the class name using _vN suffix convention:

  • No suffix (e.g., IntQuant): Version 1 (default)

  • _vN suffix (e.g., IntQuant_v2): Version N

The registry automatically selects the highest version <= requested opset.

Example:
class IntQuant(CustomOp):

pass # Version 1 (no suffix)

class IntQuant_v2(CustomOp):

pass # Version 2, covers opset v2-v3 (if no v3 exists)

class IntQuant_v4(CustomOp):

pass # Version 4, covers opset v4+

abstract execute_node(context: dict[str, ndarray[Any, dtype[_ScalarType_co]]], graph: GraphProto) None

Execute this CustomOp instance, given the execution context and ONNX graph.

get_nodeattr(name: str) int | float | str | bool | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float] | None

Get a node attribute by name. Data is stored inside the ONNX node’s AttributeProto container. Attribute must be part of get_nodeattr_types. Default value is returned if attribute is not set.

get_nodeattr_allowed_values(name: str) str | bool | int | float | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float] | set | None

Return set of allowed values for given attribute, None if not specified.

get_nodeattr_def(name: str) tuple[str, bool, int | float | str | bool | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float], set | None]

Return 4-tuple (dtype, required, default_val, allowed_values) for attribute with name. allowed_values will be None if not specified.

abstract get_nodeattr_types() Mapping[str, tuple[str, bool, int | float | str | bool | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float]] | tuple[str, bool, int | float | str | bool | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float], set | None]]

Returns a dict of permitted attributes for node, where: ret_dict[attribute_name] = (dtype, require, default_value, <allowed_values>) - dtype indicates which member of the ONNX AttributeProto will be utilized - require indicates whether this attribute is required - default_val indicates the default value that will be used if the attribute is not set - <allowed_values> (if specified) indicates that this attribute can only be set to one of the values in the set <allowed_values>. If not specified, all values permitted by dtype are allowed.

abstract infer_node_datatype(model: ModelWrapper) None

Set the DataType annotations corresponding to the outputs of this node.

make_const_shape_op(shape: Sequence[int] | ndarray[Any, dtype[_ScalarType_co]]) NodeProto

Return an ONNX node that generates the desired output shape for shape inference.

abstract make_shape_compatible_op(model: ModelWrapper) NodeProto

Returns a standard ONNX op which is compatible with this CustomOp for performing shape inference.

set_nodeattr(name: str, value: int | float | str | bool | ndarray[Any, dtype[_ScalarType_co]] | list[str | int | float] | None) None

Set a node attribute by name. Data is stored inside the ONNX node’s AttributeProto container. Attribute must be part of get_nodeattr_types.

abstract verify_node() None

Verifies that all attributes the node needs are there and that particular attributes are set correctly. Also checks if the number of inputs is equal to the expected number.

qonnx.custom_op.registry

qonnx.custom_op.registry.add_domain_alias(domain: str, module_path: str) None

Map a domain name to a different module path.

Args:

domain: The ONNX domain name (e.g., “finn.custom_op.fpgadataflow”) module_path: The Python module path to use instead (e.g., “finn_custom_ops.fpgadataflow”)

qonnx.custom_op.registry.add_op_to_domain(domain: str, op_class: Type[CustomOp]) None

Register a custom op directly to a domain at runtime.

The op_type and version are automatically derived from the class name. Useful for testing and experimentation. For production, define CustomOps in the appropriate module file.

Args:

domain: ONNX domain name (e.g., “qonnx.custom_op.general”) op_class: CustomOp subclass (version inferred from name)

Example:

add_op_to_domain(“qonnx.custom_op.general”, MyTestOp) # v1 add_op_to_domain(“qonnx.custom_op.general”, MyTestOp_v2) # v2

qonnx.custom_op.registry.getCustomOp(node: NodeProto, onnx_opset_version: int | None = None) CustomOp

Get a custom op instance for an ONNX node.

Uses “since version” semantics: selects highest version <= requested opset. Lazy loads only the requested op_type using __all__ for efficiency.

Args:

node: ONNX node with domain and op_type attributes onnx_opset_version: Opset version from model’s opset_import, or None for highest

Returns:

CustomOp instance for the node

Raises:

KeyError: If op_type not found in domain or no suitable version available

qonnx.custom_op.registry.get_ops_in_domain(domain: str) List[Tuple[str, Type[CustomOp]]]

Get all CustomOp classes available in a domain.

Note: Returns unique op_types. If multiple versions exist, returns the highest version. This function eagerly loads all ops in the domain.

Args:

domain: ONNX domain name (e.g., “qonnx.custom_op.general”)

Returns:

List of (op_type, op_class) tuples

Example:
ops = get_ops_in_domain("qonnx.custom_op.general")
for op_name, op_class in ops:
    print(f"{op_name}: {op_class}")
qonnx.custom_op.registry.get_supported_versions(domain: str, op_type: str) List[int]

Get list of supported opset versions for a custom op.

Returns all “since versions” where the operator was introduced or changed.

Args:

domain: ONNX domain name op_type: Operation type name

Returns:

Sorted list of opset versions

Raises:

KeyError: If op not found

qonnx.custom_op.registry.hasCustomOp(domain: str, op_type: str) bool

Deprecated: Use is_custom_op instead.

Check if a custom op exists.

Args:

domain: The ONNX domain name op_type: The operation type name

Returns:

True if the op exists, False otherwise

qonnx.custom_op.registry.is_custom_op(domain: str, op_type: str | None = None) bool

Check if a custom op exists or if a domain has any custom ops.

Args:

domain: The ONNX domain name op_type: Optional operation type name. If None, checks if domain has any ops.

Returns:

True if the specific op exists (when op_type given) or if any ops exist for the domain (when op_type=None), False otherwise

qonnx.custom_op.registry.resolve_domain(domain: str) str

Resolve a domain to its actual module path, handling aliases.

Args:

domain: The ONNX domain name

Returns:

Resolved module path