Skip to content

Commit 0bc01a4

Browse files
authored
Merge pull request #217 from fastmachinelearning/fix/op_version-main-merge-yaman-changes
Op versioning for new registry system
2 parents f2602d1 + 1b58cf8 commit 0bc01a4

File tree

19 files changed

+590
-154
lines changed

19 files changed

+590
-154
lines changed

src/qonnx/core/execute_custom_node.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@
2727
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828

2929
import qonnx.custom_op.registry as registry
30-
from qonnx.util.basic import get_preferred_onnx_opset
3130

3231

33-
def execute_custom_node(node, context, graph, onnx_opset_version=get_preferred_onnx_opset()):
32+
def execute_custom_node(node, context, graph, onnx_opset_version):
3433
"""Call custom implementation to execute a single custom node.
3534
Input/output provided via context."""
3635
op_type = node.op_type

src/qonnx/core/onnx_exec.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,10 @@
3636
import qonnx.analysis.topology as ta
3737
import qonnx.core.execute_custom_node as ex_cu_node
3838
from qonnx.custom_op.registry import is_custom_op
39-
from qonnx.util.basic import (
40-
get_preferred_onnx_opset,
41-
get_sanitize_quant_tensors,
42-
qonnx_make_model,
43-
sanitize_quant_values,
44-
)
39+
from qonnx.util.basic import get_preferred_qonnx_opset, get_sanitize_quant_tensors, qonnx_make_model, sanitize_quant_values
4540

4641

47-
def execute_node(node, context, graph, return_full_exec_context=False, opset_version=get_preferred_onnx_opset()):
42+
def execute_node(node, context, graph, opset_version, return_full_exec_context=False):
4843
"""Executes a single node by using onnxruntime or with a custom function.
4944
5045
Input/output provided via context."""
@@ -158,7 +153,7 @@ def execute_onnx(model, input_dict, return_full_exec_context=False, start_node=N
158153
model_exec_mode = model.get_metadata_prop("exec_mode")
159154
if (model_exec_mode is None) or (model_exec_mode == ""):
160155
# extract opset version for node-by-node execution
161-
opset_version = model.model.opset_import[0].version
156+
opset_imports = model.get_opset_imports()
162157
# execute the model node by node
163158
# we can simply walk down the list since the ONNX spec guarantees that it is
164159
# topologically sorted
@@ -176,7 +171,11 @@ def execute_onnx(model, input_dict, return_full_exec_context=False, start_node=N
176171
if get_sanitize_quant_tensors() != 0:
177172
# round input values to match quantization annotation
178173
execution_context = sanitize_quant_values(model, node.input, execution_context)
179-
execute_node(node, execution_context, graph, return_full_exec_context, opset_version)
174+
if node.domain in opset_imports:
175+
opset_version = opset_imports[node.domain]
176+
else:
177+
opset_version = get_preferred_qonnx_opset()
178+
execute_node(node, execution_context, graph, opset_version, return_full_exec_context)
180179
if get_sanitize_quant_tensors() != 0:
181180
# round output values to quantization annotation
182181
execution_context = sanitize_quant_values(model, node.output, execution_context)

src/qonnx/custom_op/base.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,35 @@
3030
import onnx.numpy_helper as np_helper
3131
from abc import ABC, abstractmethod
3232

33-
from qonnx.util.basic import get_by_name, get_preferred_onnx_opset
33+
from qonnx.util.basic import get_by_name, get_preferred_qonnx_opset
3434

3535

3636
class CustomOp(ABC):
3737
"""CustomOp class all custom op nodes are based on. Contains different functions
3838
every custom node should have. Some as abstract methods, these have to be
39-
filled when writing a new custom op node."""
39+
filled when writing a new custom op node.
4040
41-
def __init__(self, onnx_node, onnx_opset_version=get_preferred_onnx_opset()):
41+
Opset Version Support:
42+
CustomOp classes use "since version" semantics matching ONNX operators.
43+
Version is determined by the class name using _vN suffix convention:
44+
45+
- No suffix (e.g., IntQuant): Version 1 (default)
46+
- _vN suffix (e.g., IntQuant_v2): Version N
47+
48+
The registry automatically selects the highest version <= requested opset.
49+
50+
Example:
51+
class IntQuant(CustomOp):
52+
pass # Version 1 (no suffix)
53+
54+
class IntQuant_v2(CustomOp):
55+
pass # Version 2, covers opset v2-v3 (if no v3 exists)
56+
57+
class IntQuant_v4(CustomOp):
58+
pass # Version 4, covers opset v4+
59+
"""
60+
61+
def __init__(self, onnx_node, onnx_opset_version=get_preferred_qonnx_opset()):
4262
super().__init__()
4363
self.onnx_node = onnx_node
4464
self.onnx_opset_version = onnx_opset_version
Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
# Importing registers CustomOps in qonnx.custom_op.channels_last domain
2-
from qonnx.custom_op.channels_last.batch_normalization import BatchNormalization
3-
from qonnx.custom_op.channels_last.conv import Conv
4-
from qonnx.custom_op.channels_last.max_pool import MaxPool
2+
from qonnx.custom_op.channels_last.batch_normalization import (
3+
BatchNormalization_v1,
4+
BatchNormalization_v9,
5+
BatchNormalization_v14,
6+
)
7+
from qonnx.custom_op.channels_last.conv import Conv_v1
8+
from qonnx.custom_op.channels_last.max_pool import MaxPool_v1, MaxPool_v10
59

6-
# Legacy dictionary for backward compatibility
7-
custom_op = {
8-
"Conv": Conv,
9-
"MaxPool": MaxPool,
10-
"BatchNormalization": BatchNormalization,
11-
}
10+
__all__ = [
11+
"Conv_v1",
12+
"MaxPool_v1",
13+
"MaxPool_v10",
14+
"BatchNormalization_v1",
15+
"BatchNormalization_v9",
16+
"BatchNormalization_v14",
17+
]

src/qonnx/custom_op/channels_last/batch_normalization.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from qonnx.custom_op.channels_last.base_wrapped_op import ChannelsLastWrappedOp
3333

3434

35-
class BatchNormalization(ChannelsLastWrappedOp):
35+
class BatchNormalization_v1(ChannelsLastWrappedOp):
3636
def get_nodeattr_types(self):
3737
"""Returns a dict of permitted attributes for node, where:
3838
ret_dict[attribute_name] = (dtype, require, default_value, <allowed_values>)
@@ -133,3 +133,13 @@ def verify_node(self):
133133
)
134134

135135
return info_messages
136+
137+
138+
class BatchNormalization_v9(BatchNormalization_v1):
139+
# no relevant changes for channels-last wrapper
140+
pass
141+
142+
143+
class BatchNormalization_v14(BatchNormalization_v9):
144+
# no relevant changes for channels-last wrapper
145+
pass

src/qonnx/custom_op/channels_last/conv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from qonnx.custom_op.general.im2col import compute_conv_output_dim
3434

3535

36-
class Conv(ChannelsLastWrappedOp):
36+
class Conv_v1(ChannelsLastWrappedOp):
3737
def get_nodeattr_types(self):
3838
"""Returns a dict of permitted attributes for node, where:
3939
ret_dict[attribute_name] = (dtype, require, default_value, <allowed_values>)

src/qonnx/custom_op/channels_last/max_pool.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from qonnx.custom_op.general.maxpoolnhwc import compute_pool_output_dim
3434

3535

36-
class MaxPool(ChannelsLastWrappedOp):
36+
class MaxPool_v1(ChannelsLastWrappedOp):
3737
def get_nodeattr_types(self):
3838
"""Returns a dict of permitted attributes for node, where:
3939
ret_dict[attribute_name] = (dtype, require, default_value, <allowed_values>)
@@ -171,3 +171,8 @@ def verify_node(self):
171171
)
172172

173173
return info_messages
174+
175+
176+
class MaxPool_v10(MaxPool_v1):
177+
# no relevant changes for channels-last wrapper
178+
pass

src/qonnx/custom_op/general/__init__.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,22 @@
3535
from qonnx.custom_op.general.intquant import IntQuant
3636
from qonnx.custom_op.general.maxpoolnhwc import MaxPoolNHWC
3737
from qonnx.custom_op.general.multithreshold import MultiThreshold
38-
from qonnx.custom_op.general.quantavgpool2d import QuantAvgPool2d
3938
from qonnx.custom_op.general.quant import Quant
39+
from qonnx.custom_op.general.quantavgpool2d import QuantAvgPool2d
4040
from qonnx.custom_op.general.trunc import Trunc
4141
from qonnx.custom_op.general.xnorpopcount import XnorPopcountMatMul
4242

43-
# Legacy dictionary for backward compatibility
44-
custom_op = {
45-
"DebugMarker": DebugMarker,
46-
"QuantAvgPool2d": QuantAvgPool2d,
47-
"MaxPoolNHWC": MaxPoolNHWC,
48-
"GenericPartition": GenericPartition,
49-
"MultiThreshold": MultiThreshold,
50-
"XnorPopcountMatMul": XnorPopcountMatMul,
51-
"Im2Col": Im2Col,
52-
"IntQuant": IntQuant,
53-
"Quant": IntQuant, # Alias
54-
"Trunc": Trunc,
55-
"BipolarQuant": BipolarQuant,
56-
"FloatQuant": FloatQuant,
57-
}
43+
__all__ = [
44+
"BipolarQuant",
45+
"DebugMarker",
46+
"FloatQuant",
47+
"GenericPartition",
48+
"Im2Col",
49+
"IntQuant",
50+
"MaxPoolNHWC",
51+
"MultiThreshold",
52+
"Quant",
53+
"QuantAvgPool2d",
54+
"Trunc",
55+
"XnorPopcountMatMul",
56+
]

src/qonnx/custom_op/general/maxpoolnhwc.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,7 @@ def execute_node(self, context, graph):
9797
inp_vi = helper.make_tensor_value_info(inp_name, TensorProto.FLOAT, inp.shape)
9898
out_vi = helper.make_tensor_value_info(out_name, TensorProto.FLOAT, dummy_out.shape)
9999
tmp_graph = helper.make_graph(nodes=[node], name="tmp_graph", inputs=[inp_vi], outputs=[out_vi])
100-
opset_version = self.onnx_opset_version
101-
opset_imports = [helper.make_opsetid("", opset_version)]
102-
onnx_kwargs = {"opset_imports": opset_imports}
103-
tmp_model = qonnx_make_model(tmp_graph, producer_name="finn", **onnx_kwargs)
100+
tmp_model = qonnx_make_model(tmp_graph, producer_name="finn")
104101
tmp_model = ModelWrapper(tmp_model)
105102
new_ctx = {inp_name: inp}
106103
from qonnx.core.onnx_exec import execute_onnx

src/qonnx/custom_op/general/quantavgpool2d.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from qonnx.core.datatype import DataType
3434
from qonnx.custom_op.base import CustomOp
3535
from qonnx.custom_op.general.maxpoolnhwc import compute_pool_output_dim
36-
from qonnx.util.basic import qonnx_make_model
36+
from qonnx.util.basic import get_preferred_onnx_opset, qonnx_make_model
3737

3838

3939
class QuantAvgPool2d(CustomOp):
@@ -132,7 +132,7 @@ def execute_node(self, context, graph):
132132
outputs=[outp],
133133
)
134134

135-
opset_version = self.onnx_opset_version
135+
opset_version = get_preferred_onnx_opset()
136136
opset_imports = [helper.make_opsetid("", opset_version)]
137137
onnx_kwargs = {"opset_imports": opset_imports}
138138
model_avgpool = qonnx_make_model(graph_avgpool, **onnx_kwargs)

0 commit comments

Comments
 (0)