finn-plus-tests 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- finn_plus_tests-1.3.0/PKG-INFO +25 -0
- finn_plus_tests-1.3.0/__init__.py +0 -0
- finn_plus_tests-1.3.0/analysis/test_unsupported_layers.py +301 -0
- finn_plus_tests-1.3.0/brevitas/king_charles.jpg +0 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_avg_pool_export.py +114 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_cnv.py +82 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_debug.py +98 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_deconv.py +82 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_fc.py +87 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_mobilenet.py +130 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_non_scaled_quanthardtanh_export.py +87 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_qconv2d.py +108 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_qlinear.py +83 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_relu_act_export.py +105 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_scaled_qhardtanh_export.py +123 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_selu_act_export.py +73 -0
- finn_plus_tests-1.3.0/brevitas/test_brevitas_validate_mobilenet.py +214 -0
- finn_plus_tests-1.3.0/conftest.py +91 -0
- finn_plus_tests-1.3.0/end2end/test_end2end_bnn_pynq.py +834 -0
- finn_plus_tests-1.3.0/end2end/test_end2end_cybsec_mlp.py +193 -0
- finn_plus_tests-1.3.0/end2end/test_end2end_mobilenet_v1.py +523 -0
- finn_plus_tests-1.3.0/end2end/test_ext_weights.py +104 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/build.py +70 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/dataflow_build_config.json +28 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/expected_output.npy +0 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/folding_config.json +29 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/input.npy +0 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/model.onnx +0 -0
- finn_plus_tests-1.3.0/example_data/build_dataflow/specialize_layers_config.json +21 -0
- finn_plus_tests-1.3.0/example_data/cifar10/cifar10-test-data-class3.npz +0 -0
- finn_plus_tests-1.3.0/example_data/cybsec-mlp/state_dict.pth +0 -0
- finn_plus_tests-1.3.0/example_data/cybsec-mlp/validate-unsw-nb15.py +105 -0
- finn_plus_tests-1.3.0/example_data/test_ext_weights/specialize_layers_config.json +30 -0
- finn_plus_tests-1.3.0/example_data/test_ext_weights/tfc-w2a2-extw.json +38 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_code_gen_trafo.py +98 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_compilation_trafo.py +95 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_1d_conv_layer.py +196 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_channelwise_layer.py +143 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_conv_fc_transition.py +226 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_conv_layer.py +173 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_layers_cnv.py +153 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_layers_fc.py +208 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_layers_synthetic.py +238 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_convert_to_hw_pool_batch.py +244 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_depthwise_convolution.py +242 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fifosizing.py +180 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_addstreams.py +148 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_attention.py +537 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_attention_heads.py +411 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_channelwise_ops.py +174 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_checksum.py +230 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_concat.py +176 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_convinputgenerator.py +227 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_convinputgenerator_rtl_dynamic.py +616 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_deconv.py +206 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_downsampler.py +162 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_duplicatestreams.py +159 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_dwc.py +174 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_elementwise_binary.py +329 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_eltwise.py +143 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_fifo.py +111 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_fmpadding.py +160 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_globalaccpool.py +146 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_ipstitch.py +329 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_labelselect.py +138 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_lookup.py +192 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_mvau.py +961 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_replicate_stream.py +222 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_res_estimate.py +145 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_split.py +154 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_thresholding.py +387 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_thresholding_runtime.py +356 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_upsampler.py +217 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_fpgadataflow_vvau.py +474 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_minimize_bit_width.py +304 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_runtime_weights.py +141 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_set_folding.py +136 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_split_large_fifos.py +123 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_squeeze.py +392 -0
- finn_plus_tests-1.3.0/fpgadataflow/test_unsqueeze.py +397 -0
- finn_plus_tests-1.3.0/infrastructure/custom_steps.py +2 -0
- finn_plus_tests-1.3.0/infrastructure/test_custom_step_resolution.py +32 -0
- finn_plus_tests-1.3.0/notebooks/test_jupyter_notebooks.py +108 -0
- finn_plus_tests-1.3.0/pyproject.toml +47 -0
- finn_plus_tests-1.3.0/test_enforce_import_order.py +43 -0
- finn_plus_tests-1.3.0/testing_util/__init__.py +34 -0
- finn_plus_tests-1.3.0/testing_util/imagenet.py +1146 -0
- finn_plus_tests-1.3.0/testing_util/pytorch.py +65 -0
- finn_plus_tests-1.3.0/testing_util/test.py +172 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_absorb_mul_into_topk.py +108 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_absorb_opposite_transposes.py +81 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_absorb_transp_into_flatten.py +100 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_collapse_repeated_op.py +132 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_factor_out_mul_sign_magnitude.py +61 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_maxpool_nhwc.py +97 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_add_past_mul.py +150 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_chw_add_past_conv.py +107 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_flatten_past_affine.py +108 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_flatten_past_topk.py +94 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_identical_op_past_join_add.py +151 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_identical_op_past_join_add_broadcast.py +255 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_identical_op_past_join_concat.py +184 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_identical_op_past_split.py +140 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_maxpool_past_multithreshold.py +125 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_mul_past_dw_conv.py +118 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_mul_past_maxpool.py +116 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_past_fork.py +133 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_scalar_past_conv.py +196 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_scalar_past_convtranspose.py +106 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_scalar_past_matmul.py +190 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_move_transpose_past_scalar_mul.py +113 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_round_thresholds.py +270 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_scale_resize_nhwc.py +376 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_sign_to_thres.py +66 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_streamline_cnv.py +103 -0
- finn_plus_tests-1.3.0/transformation/streamline/test_streamline_fc.py +98 -0
- finn_plus_tests-1.3.0/transformation/test_batchnorm_to_affine_bnn_pynq.py +96 -0
- finn_plus_tests-1.3.0/transformation/test_infer_data_layouts_cnv.py +124 -0
- finn_plus_tests-1.3.0/transformation/test_infer_datatypes_lfc.py +68 -0
- finn_plus_tests-1.3.0/transformation/test_qonnx_to_finn.py +145 -0
- finn_plus_tests-1.3.0/util/test_build_dataflow.py +81 -0
- finn_plus_tests-1.3.0/util/test_create.py +67 -0
- finn_plus_tests-1.3.0/util/test_data_packing.py +182 -0
- finn_plus_tests-1.3.0/util/test_hls_vector.py +117 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: finn-plus-tests
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Test suite for finn-plus
|
|
5
|
+
Maintainer: Felix Jentzsch
|
|
6
|
+
Maintainer-email: felix.jentzsch@upb.de
|
|
7
|
+
Requires-Python: >=3.10,<3.12
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Requires-Dist: pytest (>=8.4.1,<8.5.0)
|
|
12
|
+
Requires-Dist: pytest-cov (>=6.2.1,<6.3.0)
|
|
13
|
+
Requires-Dist: pytest-dependency (>=0.6.0,<0.7.0)
|
|
14
|
+
Requires-Dist: pytest-forked (>=1.6.0,<1.7.0)
|
|
15
|
+
Requires-Dist: pytest-html (>=4.1.1,<4.2.0)
|
|
16
|
+
Requires-Dist: pytest-html-merger (>=0.1.0,<0.2.0)
|
|
17
|
+
Requires-Dist: pytest-metadata (>=3.1.1,<3.2.0)
|
|
18
|
+
Requires-Dist: pytest-parallel (>=0.1.1,<0.2.0)
|
|
19
|
+
Requires-Dist: pytest-rerunfailures (>=15.1,<15.2)
|
|
20
|
+
Requires-Dist: pytest-xdist[setproctitle] (>=3.6.1,<3.7.0)
|
|
21
|
+
Requires-Dist: torch (>=2.7.1,<2.8.0)
|
|
22
|
+
Requires-Dist: torchvision (>=0.22.1,<0.23.0)
|
|
23
|
+
Requires-Dist: wget (>=3.2,<3.3)
|
|
24
|
+
Project-URL: EKI Project, https://www.eki-project.tech/
|
|
25
|
+
Project-URL: GitHub, https://github.com/eki-project/finn-plus
|
|
File without changes
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import random
|
|
4
|
+
import string
|
|
5
|
+
from onnx import TensorProto, helper
|
|
6
|
+
from qonnx.core.modelwrapper import ModelWrapper
|
|
7
|
+
from qonnx.util.basic import qonnx_make_model
|
|
8
|
+
|
|
9
|
+
from finn.analysis.fpgadataflow.unsupported_layers import unsupported_layers
|
|
10
|
+
from finn.builder.build_dataflow_steps import step_create_dataflow_partition
|
|
11
|
+
from finn.util.exception import FINNUserError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_random_name():
|
|
15
|
+
return "".join(random.choices(string.ascii_lowercase, k=10))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_tensor():
|
|
19
|
+
return helper.make_tensor_value_info(get_random_name(), TensorProto.FLOAT, None)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_node(inputs, outputs, fpga=False, name=None):
|
|
23
|
+
if fpga:
|
|
24
|
+
domain = "finn.custom_op.fpgadataflow"
|
|
25
|
+
else:
|
|
26
|
+
domain = "somethingelse"
|
|
27
|
+
|
|
28
|
+
return helper.make_node(
|
|
29
|
+
"CustomOp", [i.name for i in inputs], [o.name for o in outputs], domain=domain, name=name
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.analysis
|
|
34
|
+
def test_unsupported_layers_expected_fail():
|
|
35
|
+
inp1 = create_tensor()
|
|
36
|
+
inp2 = create_tensor()
|
|
37
|
+
|
|
38
|
+
n1n3 = create_tensor()
|
|
39
|
+
n2n3 = create_tensor()
|
|
40
|
+
|
|
41
|
+
n1 = create_node([inp1], [n1n3], fpga=False)
|
|
42
|
+
n2 = create_node([inp2], [n2n3], fpga=False)
|
|
43
|
+
|
|
44
|
+
n3n5 = create_tensor()
|
|
45
|
+
n3n4 = create_tensor()
|
|
46
|
+
|
|
47
|
+
n3 = create_node([n1n3, n2n3], [n3n4, n3n5], fpga=True)
|
|
48
|
+
|
|
49
|
+
n5n6 = create_tensor()
|
|
50
|
+
n4n6 = create_tensor()
|
|
51
|
+
|
|
52
|
+
n5 = create_node([n3n5], [n5n6], fpga=False)
|
|
53
|
+
n4 = create_node([n3n4], [n4n6], fpga=True)
|
|
54
|
+
|
|
55
|
+
n6n7 = create_tensor()
|
|
56
|
+
|
|
57
|
+
n6 = create_node([n5n6, n4n6], [n6n7], fpga=True)
|
|
58
|
+
|
|
59
|
+
out = create_tensor()
|
|
60
|
+
|
|
61
|
+
n7 = create_node([n6n7], [out], fpga=True)
|
|
62
|
+
|
|
63
|
+
mul_graph = helper.make_graph(
|
|
64
|
+
nodes=[n1, n2, n3, n4, n5, n6, n7],
|
|
65
|
+
name="g1",
|
|
66
|
+
inputs=[inp1, inp2],
|
|
67
|
+
outputs=[out],
|
|
68
|
+
value_info=[n1n3, n2n3, n3n4, n3n5, n5n6, n4n6, n6n7],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
model = qonnx_make_model(mul_graph)
|
|
72
|
+
model = ModelWrapper(model)
|
|
73
|
+
|
|
74
|
+
ret = unsupported_layers(model)
|
|
75
|
+
assert ret[0] is False, "Model should not be supported, but was not detected as such"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.analysis
|
|
79
|
+
def test_unsupported_layers():
|
|
80
|
+
inp1 = create_tensor()
|
|
81
|
+
inp2 = create_tensor()
|
|
82
|
+
|
|
83
|
+
n1n3 = create_tensor()
|
|
84
|
+
n2n3 = create_tensor()
|
|
85
|
+
|
|
86
|
+
n1 = create_node([inp1], [n1n3], fpga=False)
|
|
87
|
+
n2 = create_node([inp2], [n2n3], fpga=False)
|
|
88
|
+
|
|
89
|
+
n3n5 = create_tensor()
|
|
90
|
+
n3n4 = create_tensor()
|
|
91
|
+
|
|
92
|
+
n3 = create_node([n1n3, n2n3], [n3n4, n3n5], fpga=True)
|
|
93
|
+
|
|
94
|
+
n5n6 = create_tensor()
|
|
95
|
+
n4n6 = create_tensor()
|
|
96
|
+
|
|
97
|
+
n5 = create_node([n3n5], [n5n6], fpga=True)
|
|
98
|
+
n4 = create_node([n3n4], [n4n6], fpga=True)
|
|
99
|
+
|
|
100
|
+
n6n7 = create_tensor()
|
|
101
|
+
|
|
102
|
+
n6 = create_node([n5n6, n4n6], [n6n7], fpga=True)
|
|
103
|
+
|
|
104
|
+
out = create_tensor()
|
|
105
|
+
|
|
106
|
+
n7 = create_node([n6n7], [out], fpga=True)
|
|
107
|
+
|
|
108
|
+
mul_graph = helper.make_graph(
|
|
109
|
+
nodes=[n1, n2, n3, n4, n5, n6, n7],
|
|
110
|
+
name="g1",
|
|
111
|
+
inputs=[inp1, inp2],
|
|
112
|
+
outputs=[out],
|
|
113
|
+
value_info=[n1n3, n2n3, n3n4, n3n5, n5n6, n4n6, n6n7],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
model = qonnx_make_model(mul_graph)
|
|
117
|
+
model = ModelWrapper(model)
|
|
118
|
+
|
|
119
|
+
ret = unsupported_layers(model)
|
|
120
|
+
assert ret[0] is True, "Model should be supported, but was not detected as such"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@pytest.mark.analysis
|
|
124
|
+
def test_unsupported_layers_loop():
|
|
125
|
+
inp1 = create_tensor()
|
|
126
|
+
inp2 = create_tensor()
|
|
127
|
+
|
|
128
|
+
n1n3 = create_tensor()
|
|
129
|
+
n2n3 = create_tensor()
|
|
130
|
+
|
|
131
|
+
n1 = create_node([inp1], [n1n3], fpga=False)
|
|
132
|
+
n2 = create_node([inp2], [n2n3], fpga=False)
|
|
133
|
+
|
|
134
|
+
n3n5 = create_tensor()
|
|
135
|
+
n3n4 = create_tensor()
|
|
136
|
+
|
|
137
|
+
n3 = create_node([n1n3, n2n3], [n3n4, n3n5], fpga=True)
|
|
138
|
+
|
|
139
|
+
n5n6 = create_tensor()
|
|
140
|
+
n4n6 = create_tensor()
|
|
141
|
+
|
|
142
|
+
n6n5 = create_tensor()
|
|
143
|
+
|
|
144
|
+
n5 = create_node([n3n5, n6n5], [n5n6], fpga=True)
|
|
145
|
+
n4 = create_node([n3n4], [n4n6], fpga=True)
|
|
146
|
+
|
|
147
|
+
n6n7 = create_tensor()
|
|
148
|
+
|
|
149
|
+
n6 = create_node([n5n6, n4n6], [n6n7, n6n5], fpga=True)
|
|
150
|
+
|
|
151
|
+
out = create_tensor()
|
|
152
|
+
|
|
153
|
+
n7 = create_node([n6n7], [out], fpga=True)
|
|
154
|
+
|
|
155
|
+
mul_graph = helper.make_graph(
|
|
156
|
+
nodes=[n1, n2, n3, n4, n5, n6, n7],
|
|
157
|
+
name="g1",
|
|
158
|
+
inputs=[inp1, inp2],
|
|
159
|
+
outputs=[out],
|
|
160
|
+
value_info=[n1n3, n2n3, n3n4, n3n5, n5n6, n4n6, n6n7],
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
model = qonnx_make_model(mul_graph)
|
|
164
|
+
model = ModelWrapper(model)
|
|
165
|
+
|
|
166
|
+
ret = unsupported_layers(model)
|
|
167
|
+
assert ret[0] is True, "Model should be supported, but was not detected as such"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@pytest.mark.analysis
|
|
171
|
+
def test_large_model():
|
|
172
|
+
inp1 = create_tensor()
|
|
173
|
+
inp2 = create_tensor()
|
|
174
|
+
|
|
175
|
+
n1n3 = create_tensor()
|
|
176
|
+
n2n4 = create_tensor()
|
|
177
|
+
|
|
178
|
+
n1 = create_node([inp1], [n1n3], fpga=False)
|
|
179
|
+
n2 = create_node([inp2], [n2n4], fpga=False)
|
|
180
|
+
|
|
181
|
+
n3n5 = create_tensor()
|
|
182
|
+
n4n5 = create_tensor()
|
|
183
|
+
n4n6 = create_tensor()
|
|
184
|
+
|
|
185
|
+
n3 = create_node([n1n3], [n3n5], fpga=True)
|
|
186
|
+
n4 = create_node([n2n4], [n4n5, n4n6], fpga=False)
|
|
187
|
+
|
|
188
|
+
out1 = create_tensor()
|
|
189
|
+
|
|
190
|
+
n6 = create_node([n4n6], [out1], fpga=False)
|
|
191
|
+
|
|
192
|
+
n5n7 = create_tensor()
|
|
193
|
+
n5n8 = create_tensor()
|
|
194
|
+
|
|
195
|
+
n5 = create_node([n3n5, n4n5], [n5n7, n5n8], fpga=True)
|
|
196
|
+
|
|
197
|
+
out2 = create_tensor()
|
|
198
|
+
|
|
199
|
+
n7 = create_node([n5n7], [out2], fpga=True)
|
|
200
|
+
|
|
201
|
+
n8n9 = create_tensor()
|
|
202
|
+
|
|
203
|
+
n8 = create_node([n5n8], [n8n9], fpga=True)
|
|
204
|
+
|
|
205
|
+
n9n10 = create_tensor()
|
|
206
|
+
|
|
207
|
+
n9 = create_node([n8n9], [n9n10], fpga=True, name="n9")
|
|
208
|
+
|
|
209
|
+
n10n11 = create_tensor()
|
|
210
|
+
n10n12 = create_tensor()
|
|
211
|
+
|
|
212
|
+
n10 = create_node([n9n10], [n10n11, n10n12], fpga=False, name="n10")
|
|
213
|
+
|
|
214
|
+
out3 = create_tensor()
|
|
215
|
+
|
|
216
|
+
n11 = create_node([n10n11], [out3], fpga=False, name="n11")
|
|
217
|
+
|
|
218
|
+
out4 = create_tensor()
|
|
219
|
+
|
|
220
|
+
n12 = create_node([n10n12], [out4], fpga=True, name="n12")
|
|
221
|
+
|
|
222
|
+
mul_graph = helper.make_graph(
|
|
223
|
+
nodes=[n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12],
|
|
224
|
+
name="g2",
|
|
225
|
+
inputs=[inp1, inp2],
|
|
226
|
+
outputs=[out1, out2, out3, out4],
|
|
227
|
+
value_info=[n1n3, n2n4, n3n5, n4n5, n4n6, n5n7, n5n8, n8n9, n9n10, n10n11, n10n12],
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
model = qonnx_make_model(mul_graph)
|
|
231
|
+
model = ModelWrapper(model)
|
|
232
|
+
|
|
233
|
+
ret = unsupported_layers(model)
|
|
234
|
+
assert ret[0] is False, "Model should not be supported, but was not detected as such"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
@pytest.mark.analysis
|
|
238
|
+
def test_large_model_step():
|
|
239
|
+
inp1 = create_tensor()
|
|
240
|
+
inp2 = create_tensor()
|
|
241
|
+
|
|
242
|
+
n1n3 = create_tensor()
|
|
243
|
+
n2n4 = create_tensor()
|
|
244
|
+
|
|
245
|
+
n1 = create_node([inp1], [n1n3], fpga=False)
|
|
246
|
+
n2 = create_node([inp2], [n2n4], fpga=False)
|
|
247
|
+
|
|
248
|
+
n3n5 = create_tensor()
|
|
249
|
+
n4n5 = create_tensor()
|
|
250
|
+
n4n6 = create_tensor()
|
|
251
|
+
|
|
252
|
+
n3 = create_node([n1n3], [n3n5], fpga=True)
|
|
253
|
+
n4 = create_node([n2n4], [n4n5, n4n6], fpga=False)
|
|
254
|
+
|
|
255
|
+
out1 = create_tensor()
|
|
256
|
+
|
|
257
|
+
n6 = create_node([n4n6], [out1], fpga=False)
|
|
258
|
+
|
|
259
|
+
n5n7 = create_tensor()
|
|
260
|
+
n5n8 = create_tensor()
|
|
261
|
+
|
|
262
|
+
n5 = create_node([n3n5, n4n5], [n5n7, n5n8], fpga=True)
|
|
263
|
+
|
|
264
|
+
out2 = create_tensor()
|
|
265
|
+
|
|
266
|
+
n7 = create_node([n5n7], [out2], fpga=True)
|
|
267
|
+
|
|
268
|
+
n8n9 = create_tensor()
|
|
269
|
+
|
|
270
|
+
n8 = create_node([n5n8], [n8n9], fpga=True)
|
|
271
|
+
|
|
272
|
+
n9n10 = create_tensor()
|
|
273
|
+
|
|
274
|
+
n9 = create_node([n8n9], [n9n10], fpga=True, name="n9")
|
|
275
|
+
|
|
276
|
+
n10n11 = create_tensor()
|
|
277
|
+
n10n12 = create_tensor()
|
|
278
|
+
|
|
279
|
+
n10 = create_node([n9n10], [n10n11, n10n12], fpga=False, name="n10")
|
|
280
|
+
|
|
281
|
+
out3 = create_tensor()
|
|
282
|
+
|
|
283
|
+
n11 = create_node([n10n11], [out3], fpga=False, name="n11")
|
|
284
|
+
|
|
285
|
+
out4 = create_tensor()
|
|
286
|
+
|
|
287
|
+
n12 = create_node([n10n12], [out4], fpga=True, name="n12")
|
|
288
|
+
|
|
289
|
+
mul_graph = helper.make_graph(
|
|
290
|
+
nodes=[n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12],
|
|
291
|
+
name="g2",
|
|
292
|
+
inputs=[inp1, inp2],
|
|
293
|
+
outputs=[out1, out2, out3, out4],
|
|
294
|
+
value_info=[n1n3, n2n4, n3n5, n4n5, n4n6, n5n7, n5n8, n8n9, n9n10, n10n11, n10n12],
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
model = qonnx_make_model(mul_graph)
|
|
298
|
+
model = ModelWrapper(model)
|
|
299
|
+
|
|
300
|
+
with pytest.raises(FINNUserError):
|
|
301
|
+
step_create_dataflow_partition(model, None)
|
|
Binary file
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Copyright (c) 2020, Xilinx
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
# and/or other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# * Neither the name of FINN nor the names of its
|
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
|
16
|
+
# this software without specific prior written permission.
|
|
17
|
+
#
|
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
import pytest
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import os
|
|
32
|
+
import torch
|
|
33
|
+
from brevitas.export import export_qonnx
|
|
34
|
+
from brevitas.nn import QuantIdentity, QuantReLU, TruncAvgPool2d
|
|
35
|
+
from qonnx.core.datatype import DataType
|
|
36
|
+
from qonnx.core.modelwrapper import ModelWrapper
|
|
37
|
+
from qonnx.transformation.infer_datatypes import InferDataTypes
|
|
38
|
+
from qonnx.transformation.infer_shapes import InferShapes
|
|
39
|
+
from qonnx.util.basic import gen_finn_dt_tensor
|
|
40
|
+
from qonnx.util.cleanup import cleanup as qonnx_cleanup
|
|
41
|
+
|
|
42
|
+
import finn.core.onnx_exec as oxe
|
|
43
|
+
from finn.transformation.qonnx.convert_qonnx_to_finn import ConvertQONNXtoFINN
|
|
44
|
+
from finn.util.basic import make_build_dir
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.brevitas_export
|
|
48
|
+
@pytest.mark.parametrize("kernel_size", [2, 3])
|
|
49
|
+
@pytest.mark.parametrize("stride", [1, 2])
|
|
50
|
+
@pytest.mark.parametrize("signed", [True]) # TODO: Add unsigned test case
|
|
51
|
+
@pytest.mark.parametrize("bit_width", [2, 4])
|
|
52
|
+
@pytest.mark.parametrize("input_bit_width", [4, 8, 16])
|
|
53
|
+
@pytest.mark.parametrize("channels", [2, 4])
|
|
54
|
+
@pytest.mark.parametrize("idim", [7, 8])
|
|
55
|
+
def test_brevitas_avg_pool_export(
|
|
56
|
+
kernel_size,
|
|
57
|
+
stride,
|
|
58
|
+
signed,
|
|
59
|
+
bit_width,
|
|
60
|
+
input_bit_width,
|
|
61
|
+
channels,
|
|
62
|
+
idim,
|
|
63
|
+
):
|
|
64
|
+
build_dir = make_build_dir(prefix="test_brevitas_avg_pool_export")
|
|
65
|
+
export_onnx_path = os.path.join(build_dir, "test.onnx")
|
|
66
|
+
if signed:
|
|
67
|
+
quant_node = QuantIdentity(
|
|
68
|
+
bit_width=input_bit_width,
|
|
69
|
+
return_quant_tensor=True,
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
quant_node = QuantReLU(
|
|
73
|
+
bit_width=input_bit_width,
|
|
74
|
+
return_quant_tensor=True,
|
|
75
|
+
)
|
|
76
|
+
quant_avgpool = TruncAvgPool2d(
|
|
77
|
+
kernel_size=kernel_size,
|
|
78
|
+
stride=stride,
|
|
79
|
+
bit_width=bit_width,
|
|
80
|
+
return_quant_tensor=False,
|
|
81
|
+
float_to_int_impl_type="FLOOR",
|
|
82
|
+
)
|
|
83
|
+
model_brevitas = torch.nn.Sequential(quant_node, quant_avgpool)
|
|
84
|
+
model_brevitas.eval()
|
|
85
|
+
|
|
86
|
+
# determine input
|
|
87
|
+
input_shape = (1, channels, idim, idim)
|
|
88
|
+
input_array = gen_finn_dt_tensor(DataType["FLOAT32"], input_shape)
|
|
89
|
+
|
|
90
|
+
input_tensor = torch.from_numpy(input_array).float()
|
|
91
|
+
|
|
92
|
+
# export
|
|
93
|
+
export_qonnx(
|
|
94
|
+
model_brevitas,
|
|
95
|
+
export_path=export_onnx_path,
|
|
96
|
+
input_t=input_tensor,
|
|
97
|
+
)
|
|
98
|
+
model = ModelWrapper(export_onnx_path)
|
|
99
|
+
model.save(export_onnx_path)
|
|
100
|
+
|
|
101
|
+
qonnx_cleanup(export_onnx_path, out_file=export_onnx_path)
|
|
102
|
+
model = ModelWrapper(export_onnx_path)
|
|
103
|
+
model = model.transform(ConvertQONNXtoFINN())
|
|
104
|
+
model = model.transform(InferShapes())
|
|
105
|
+
model = model.transform(InferDataTypes())
|
|
106
|
+
|
|
107
|
+
# reference brevitas output
|
|
108
|
+
ref_output_array = model_brevitas(input_tensor).detach().numpy()
|
|
109
|
+
# finn output
|
|
110
|
+
idict = {model.graph.input[0].name: input_array}
|
|
111
|
+
odict = oxe.execute_onnx(model, idict, True)
|
|
112
|
+
finn_output = odict[model.graph.output[0].name]
|
|
113
|
+
# compare outputs
|
|
114
|
+
assert np.isclose(ref_output_array, finn_output).all()
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Copyright (c) 2020, Xilinx
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
# and/or other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# * Neither the name of FINN nor the names of its
|
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
|
16
|
+
# this software without specific prior written permission.
|
|
17
|
+
#
|
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
|
|
29
|
+
import pytest
|
|
30
|
+
|
|
31
|
+
import numpy as np
|
|
32
|
+
import os
|
|
33
|
+
import torch
|
|
34
|
+
from brevitas.export import export_qonnx
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
from qonnx.core.modelwrapper import ModelWrapper
|
|
37
|
+
from qonnx.transformation.fold_constants import FoldConstants
|
|
38
|
+
from qonnx.transformation.general import GiveUniqueNodeNames, RemoveStaticGraphInputs
|
|
39
|
+
from qonnx.transformation.infer_shapes import InferShapes
|
|
40
|
+
from qonnx.util.cleanup import cleanup as qonnx_cleanup
|
|
41
|
+
|
|
42
|
+
import finn.core.onnx_exec as oxe
|
|
43
|
+
from finn.transformation.qonnx.convert_qonnx_to_finn import ConvertQONNXtoFINN
|
|
44
|
+
from finn.util.basic import make_build_dir
|
|
45
|
+
from tests.testing_util.test import get_test_model_trained
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.brevitas_export
|
|
49
|
+
@pytest.mark.parametrize("abits", [1, 2])
|
|
50
|
+
@pytest.mark.parametrize("wbits", [1, 2])
|
|
51
|
+
def test_brevitas_cnv_export_exec(wbits, abits):
|
|
52
|
+
if wbits > abits:
|
|
53
|
+
pytest.skip("No wbits > abits cases at the moment")
|
|
54
|
+
build_dir = make_build_dir("test_brevitas_cnv_export_exec")
|
|
55
|
+
export_onnx_path = os.path.join(build_dir, "test_brevitas_cnv.onnx")
|
|
56
|
+
cnv = get_test_model_trained("CNV", wbits, abits)
|
|
57
|
+
ishape = (1, 3, 32, 32)
|
|
58
|
+
export_qonnx(cnv, torch.randn(ishape), export_onnx_path)
|
|
59
|
+
qonnx_cleanup(export_onnx_path, out_file=export_onnx_path)
|
|
60
|
+
model = ModelWrapper(export_onnx_path)
|
|
61
|
+
model = model.transform(ConvertQONNXtoFINN())
|
|
62
|
+
model = model.transform(GiveUniqueNodeNames())
|
|
63
|
+
model = model.transform(InferShapes())
|
|
64
|
+
model = model.transform(FoldConstants())
|
|
65
|
+
model = model.transform(RemoveStaticGraphInputs())
|
|
66
|
+
assert len(model.graph.input) == 1
|
|
67
|
+
assert len(model.graph.output) == 1
|
|
68
|
+
cifar_path = (
|
|
69
|
+
Path(__file__).parent.parent / "example_data" / "cifar10" / "cifar10-test-data-class3.npz"
|
|
70
|
+
)
|
|
71
|
+
input_tensor = np.load(cifar_path)["arr_0"].astype(np.float32)
|
|
72
|
+
input_tensor = input_tensor / 255
|
|
73
|
+
assert input_tensor.shape == (1, 3, 32, 32)
|
|
74
|
+
# run using FINN-based execution
|
|
75
|
+
input_dict = {model.graph.input[0].name: input_tensor}
|
|
76
|
+
output_dict = oxe.execute_onnx(model, input_dict, True)
|
|
77
|
+
produced = output_dict[model.graph.output[0].name]
|
|
78
|
+
# do forward pass in PyTorch/Brevitas
|
|
79
|
+
input_tensor = torch.from_numpy(input_tensor).float()
|
|
80
|
+
expected = cnv.forward(input_tensor).detach().numpy()
|
|
81
|
+
assert np.isclose(produced, expected, atol=1e-3).all()
|
|
82
|
+
assert np.argmax(produced) == 3
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Copyright (c) 2020, Xilinx
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
# and/or other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# * Neither the name of FINN nor the names of its
|
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
|
16
|
+
# this software without specific prior written permission.
|
|
17
|
+
#
|
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
|
|
29
|
+
import pytest
|
|
30
|
+
|
|
31
|
+
import brevitas.onnx as bo
|
|
32
|
+
import numpy as np
|
|
33
|
+
import onnx
|
|
34
|
+
import onnx.numpy_helper as nph
|
|
35
|
+
import os
|
|
36
|
+
import torch
|
|
37
|
+
from brevitas.export import export_qonnx
|
|
38
|
+
from brevitas.quant_tensor import _unpack_quant_tensor
|
|
39
|
+
from pkgutil import get_data
|
|
40
|
+
from qonnx.core.modelwrapper import ModelWrapper
|
|
41
|
+
from qonnx.util.cleanup import cleanup as qonnx_cleanup
|
|
42
|
+
|
|
43
|
+
import finn.core.onnx_exec as oxe
|
|
44
|
+
from finn.transformation.qonnx.convert_qonnx_to_finn import ConvertQONNXtoFINN
|
|
45
|
+
from finn.util.basic import make_build_dir
|
|
46
|
+
from tests.testing_util.test import get_test_model_trained
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@pytest.mark.brevitas_export
|
|
50
|
+
@pytest.mark.parametrize("QONNX_FINN_conversion", [False, True])
|
|
51
|
+
def test_brevitas_debug(QONNX_FINN_conversion):
|
|
52
|
+
build_dir = make_build_dir("test_brevitas_debug")
|
|
53
|
+
finn_onnx = os.path.join(build_dir, "test_brevitas_debug.onnx")
|
|
54
|
+
fc = get_test_model_trained("TFC", 2, 2)
|
|
55
|
+
ishape = (1, 1, 28, 28)
|
|
56
|
+
dbg_hook = bo.enable_debug(fc, proxy_level=True)
|
|
57
|
+
export_qonnx(fc, torch.randn(ishape), finn_onnx)
|
|
58
|
+
# DebugMarkers have the brevitas.onnx domain, so that needs adjusting
|
|
59
|
+
model = ModelWrapper(finn_onnx)
|
|
60
|
+
dbg_nodes = model.get_nodes_by_op_type("DebugMarker")
|
|
61
|
+
for dbg_node in dbg_nodes:
|
|
62
|
+
dbg_node.domain = "qonnx.custom_op.general"
|
|
63
|
+
model.save(finn_onnx)
|
|
64
|
+
qonnx_cleanup(finn_onnx, out_file=finn_onnx)
|
|
65
|
+
if QONNX_FINN_conversion:
|
|
66
|
+
model = ModelWrapper(finn_onnx)
|
|
67
|
+
model = model.transform(ConvertQONNXtoFINN())
|
|
68
|
+
model.save(finn_onnx)
|
|
69
|
+
model = ModelWrapper(finn_onnx)
|
|
70
|
+
assert len(model.graph.input) == 1
|
|
71
|
+
assert len(model.graph.output) == 1
|
|
72
|
+
# load one of the test vectors
|
|
73
|
+
raw_i = get_data("qonnx.data", "onnx/mnist-conv/test_data_set_0/input_0.pb")
|
|
74
|
+
input_tensor = onnx.load_tensor_from_string(raw_i)
|
|
75
|
+
# run using FINN-based execution
|
|
76
|
+
input_dict = {model.graph.input[0].name: nph.to_array(input_tensor)}
|
|
77
|
+
output_dict = oxe.execute_onnx(model, input_dict, return_full_exec_context=True)
|
|
78
|
+
produced = output_dict[model.graph.output[0].name]
|
|
79
|
+
# run using PyTorch/Brevitas
|
|
80
|
+
input_tensor = torch.from_numpy(nph.to_array(input_tensor)).float()
|
|
81
|
+
assert input_tensor.shape == (1, 1, 28, 28)
|
|
82
|
+
# do forward pass in PyTorch/Brevitas
|
|
83
|
+
expected = fc.forward(input_tensor).detach().numpy()
|
|
84
|
+
assert np.isclose(produced, expected, atol=1e-3).all()
|
|
85
|
+
# check all tensors at debug markers
|
|
86
|
+
names_brevitas = set(dbg_hook.values.keys())
|
|
87
|
+
names_finn = set(output_dict.keys())
|
|
88
|
+
names_common = names_brevitas.intersection(names_finn)
|
|
89
|
+
# The different exports return debug markers in different numbers and places
|
|
90
|
+
print(len(names_common))
|
|
91
|
+
if not QONNX_FINN_conversion:
|
|
92
|
+
assert len(names_common) == 12
|
|
93
|
+
else:
|
|
94
|
+
assert len(names_common) == 8
|
|
95
|
+
for dbg_name in names_common:
|
|
96
|
+
tensor_pytorch = _unpack_quant_tensor(dbg_hook.values[dbg_name]).detach().numpy()
|
|
97
|
+
tensor_finn = output_dict[dbg_name]
|
|
98
|
+
assert np.isclose(tensor_finn, tensor_pytorch, atol=1e-5).all()
|