diff --git a/src/finn/custom_op/fpgadataflow/channelwise_op_batch.py b/src/finn/custom_op/fpgadataflow/channelwise_op_batch.py index e5a89f4cb60a92f4fe75bd060a1f3b30e9d1c34f..3ed76db2982e411b711be5bd78e39dd866332714 100644 --- a/src/finn/custom_op/fpgadataflow/channelwise_op_batch.py +++ b/src/finn/custom_op/fpgadataflow/channelwise_op_batch.py @@ -51,7 +51,7 @@ from . import templates def get_smallest_possible(vals): """Returns smallest (fewest bits) possible DataType that can represent value. Prefers unsigned integers where possible.""" - vals = np.array(vals) + vals = np.array(vals, dtype=np.float64) for v in vals: assert int(v) == v, "Error float value" diff --git a/src/finn/transformation/fpgadataflow/convert_to_hls_layers.py b/src/finn/transformation/fpgadataflow/convert_to_hls_layers.py index 3f42564f968f433688e942519f74251d4b2c34b8..9d70ca46906af3e299600669ec91090e56492bb8 100644 --- a/src/finn/transformation/fpgadataflow/convert_to_hls_layers.py +++ b/src/finn/transformation/fpgadataflow/convert_to_hls_layers.py @@ -1259,7 +1259,7 @@ class InferChannelwiseLinearLayer(Transformation): def get_smallest_possible(self, vals): """Returns smallest (fewest bits) possible DataType that can represent value. Prefers unsigned integers where possible.""" - vals = np.array(vals) + vals = np.array(vals, dtype=np.float64) for v in vals: assert int(v) == v, "Error float value" @@ -1535,7 +1535,9 @@ class InferGlobalAccPoolLayer(Transformation): model.make_new_valueinfo_name(), TensorProto.FLOAT, [1] ) model.graph.value_info.append(mul_value) - model.set_initializer(mul_value.name, np.array(1 / (vecs[1] * vecs[2]))) + model.set_initializer( + mul_value.name, np.array(1 / (vecs[1] * vecs[2]), dtype=np.float32) + ) new_mul = helper.make_node( "Mul", [pool_out, mul_value.name], diff --git a/src/finn/transformation/qonnx/qonnx_activation_handlers.py b/src/finn/transformation/qonnx/qonnx_activation_handlers.py index 406f7c0f50ea649890e079a79ff9c52a5f95764d..a50a5850779cadf7ab21b9c1c4dfdbb36232af42 100644 --- a/src/finn/transformation/qonnx/qonnx_activation_handlers.py +++ b/src/finn/transformation/qonnx/qonnx_activation_handlers.py @@ -32,6 +32,8 @@ from onnx import TensorProto, helper from qonnx.core.modelwrapper import ModelWrapper from qonnx.custom_op.registry import getCustomOp +np_default_dtype = np.float32 + class QuantActBaseHandler(ABC): """Base class for converting quantized activation expressed in the QONNX dialect @@ -163,17 +165,16 @@ class QuantActBaseHandler(ABC): if scale_scalar and bias_scalar and self._q_node.op_type == "BipolarQuant": # Get Quant parameters mul_scale = np.atleast_1d(mul_scale) - # ONNX only accepts 64bit floats as attributes - mul_scale = mul_scale.astype(dtype=np.float64) adder_bias = np.atleast_1d(adder_bias) - adder_bias = adder_bias.astype(dtype=np.float64) # Set Bias and scale - mt_inst.set_nodeattr("out_scale", mul_scale[0]) + # note calls to .item() to get Python float instead of numpy float + # ONNX attribute setting fails otherwise + mt_inst.set_nodeattr("out_scale", mul_scale[0].item()) # FINN applies scale first then bias, # which is the other way around in Brevitas, # we thus need to adjust the bias in the MultiThreshold node - finn_bias = adder_bias[0] * mul_scale[0] + finn_bias = adder_bias[0].item() * mul_scale[0].item() mt_inst.set_nodeattr("out_bias", finn_bias) # Set the output data type @@ -189,8 +190,7 @@ class QuantActBaseHandler(ABC): zero_bias = False if bias_scalar: adder_bias = np.atleast_1d(adder_bias) - # ONNX only accepts 64bit floats as attributes - adder_bias = adder_bias.astype(dtype=np.float64)[0] + adder_bias = adder_bias[0] add_shape = tuple() if adder_bias == 0.0: zero_bias = True @@ -233,7 +233,7 @@ class QuantActBaseHandler(ABC): unity_scale = False if scale_scalar: mul_scale = np.atleast_1d(mul_scale) - mul_scale = mul_scale.astype(dtype=np.float64)[0] + mul_scale = mul_scale[0] mul_shape = tuple() if mul_scale == 1.0: unity_scale = True @@ -312,7 +312,7 @@ class QuantReluHandler(QuantActBaseHandler): # No bias allowed for Relu activations, see: https://github.com/Xilinx/ # brevitas/blob/a5bfd6dc5e030f0047ac1ee47932b60e8e873e17/src/brevitas/ # export/onnx/finn/handler/act.py#L48 - bias = np.array([0.0]) + bias = np.array([0.0], dtype=np_default_dtype) return bias def _calculate_thresholds(self): @@ -338,7 +338,9 @@ class QuantReluHandler(QuantActBaseHandler): num_scale_channels = flat_scale.shape[0] step = np.abs(flat_scale).astype(np.float32) min_threshold = step / 2 - thresholds = np.empty((num_scale_channels, num_thresholds)).astype(np.float32) + thresholds = np.empty( + (num_scale_channels, num_thresholds), dtype=np_default_dtype + ) for c in range(num_scale_channels): for t in range(num_thresholds): thresholds[c][t] = min_threshold[c] + step[c] * t @@ -437,13 +439,13 @@ class QuantIdentityHandler(QuantActBaseHandler): # a5bfd6dc5e030f0047ac1ee47932b60e8e873e17/src/brevitas/export/ # onnx/finn/handler/act.py#L64 if bit_width == 1.0: - bias = np.array([-0.5]) + bias = np.array([-0.5], dtype=np_default_dtype) else: if narrow: min_non_scaled_val = -(2 ** (bit_width - 1) - 1) else: min_non_scaled_val = -(2 ** (bit_width - 1)) - bias = np.array([min_non_scaled_val]) + bias = np.array([min_non_scaled_val], dtype=np_default_dtype) return bias def _calculate_thresholds(self): @@ -462,7 +464,7 @@ class QuantIdentityHandler(QuantActBaseHandler): # blob/a5bfd6dc5e030f0047ac1ee47932b60e8e873e17/src/brevitas/ # export/onnx/finn/handler/act.py#L76 if bit_width == 1.0: - thresholds = np.empty([1, 1]) + thresholds = np.empty([1, 1], dtype=np_default_dtype) thresholds[0] = 0 return thresholds else: @@ -476,7 +478,9 @@ class QuantIdentityHandler(QuantActBaseHandler): num_scale_channels = flat_scale.shape[0] step = np.abs(flat_scale) half_step = step / 2.0 - thresholds = np.empty((num_scale_channels, num_thresholds)) + thresholds = np.empty( + (num_scale_channels, num_thresholds), dtype=np_default_dtype + ) # compute the value of the smallest threshold, we'll neg-bias all # generated thresholds by this much min_threshold = -half_step - step * ((num_thresholds // 2) - 1) diff --git a/tests/fpgadataflow/test_convert_to_hls_conv_fc_transition.py b/tests/fpgadataflow/test_convert_to_hls_conv_fc_transition.py index 6eb8b2b0056877f23c7fc7237b05581983f56579..001ffc08b6d2400c3047206f28adefd3b39f64f2 100755 --- a/tests/fpgadataflow/test_convert_to_hls_conv_fc_transition.py +++ b/tests/fpgadataflow/test_convert_to_hls_conv_fc_transition.py @@ -202,7 +202,7 @@ def test_convert_to_hls_conv_fc_transition(conv_config, depthwise, use_reshape): model.set_initializer( "matmul_param", gen_finn_dt_tensor(fc_weight_dt, fc_param_shape) ) - model.set_initializer("reshape_shape", np.array([1, -1])) + model.set_initializer("reshape_shape", np.array([1, -1], dtype=np.int64)) model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) diff --git a/tests/fpgadataflow/test_convert_to_hls_layers_synthetic.py b/tests/fpgadataflow/test_convert_to_hls_layers_synthetic.py index 155a124f416da1f3ce800cfd2be484a226af473f..35f082f55cb99c4fb6b63020f3adfb351e5effe2 100644 --- a/tests/fpgadataflow/test_convert_to_hls_layers_synthetic.py +++ b/tests/fpgadataflow/test_convert_to_hls_layers_synthetic.py @@ -127,12 +127,12 @@ def make_model(ch, ifmdim): model = ModelWrapper(model) # set initializers for scalar add/mul nodes - model.set_initializer(add0_node.input[1], np.array([0.0])) - model.set_initializer(add1_node.input[1], np.array([7.0])) - model.set_initializer(add2_node.input[1], np.array([8.0])) - model.set_initializer(mul1_node.input[1], np.array([2.0])) - model.set_initializer(mul2_node.input[1], np.array([2.0])) - model.set_initializer(reshape_node.input[1], np.array([1, -1])) + model.set_initializer(add0_node.input[1], np.array([0.0], dtype=np.float32)) + model.set_initializer(add1_node.input[1], np.array([7.0], dtype=np.float32)) + model.set_initializer(add2_node.input[1], np.array([8.0], dtype=np.float32)) + model.set_initializer(mul1_node.input[1], np.array([2.0], dtype=np.float32)) + model.set_initializer(mul2_node.input[1], np.array([2.0], dtype=np.float32)) + model.set_initializer(reshape_node.input[1], np.array([1, -1], dtype=np.int64)) return model diff --git a/tests/transformation/streamline/test_linear_past_eltwise.py b/tests/transformation/streamline/test_linear_past_eltwise.py index 5655dbb5c9333241f671957780f3ef0970de860b..12633d750bb405757efca0c028dece92b289b472 100644 --- a/tests/transformation/streamline/test_linear_past_eltwise.py +++ b/tests/transformation/streamline/test_linear_past_eltwise.py @@ -40,6 +40,7 @@ import finn.core.onnx_exec as oxe from finn.transformation.streamline.reorder import MoveLinearPastEltwiseAdd export_onnx_path = "test_linear_past_eltwise.onnx" +np_default_dtype = np.float32 # construct a synthetic graph to test: # topk insertion, topk conversion to hls, add conversion to hls @@ -81,10 +82,10 @@ def make_model(shape): model = ModelWrapper(model) # set initializers for scalar add/mul nodes - model.set_initializer(add1_node.input[1], np.array([7.0])) - model.set_initializer(add2_node.input[1], np.array([8.0])) - model.set_initializer(mul1_node.input[1], np.array([3.0])) - model.set_initializer(mul2_node.input[1], np.array([3.0])) + model.set_initializer(add1_node.input[1], np.array([7.0], dtype=np_default_dtype)) + model.set_initializer(add2_node.input[1], np.array([8.0], dtype=np_default_dtype)) + model.set_initializer(mul1_node.input[1], np.array([3.0], dtype=np_default_dtype)) + model.set_initializer(mul2_node.input[1], np.array([3.0], dtype=np_default_dtype)) return model diff --git a/tests/transformation/streamline/test_move_maxpool_past_multithreshold.py b/tests/transformation/streamline/test_move_maxpool_past_multithreshold.py index d1c1daabb56aa3a5cb39221784c8547f4bcc1261..bf25eee9e685d2536faf5bd25bc7b1aa36700463 100644 --- a/tests/transformation/streamline/test_move_maxpool_past_multithreshold.py +++ b/tests/transformation/streamline/test_move_maxpool_past_multithreshold.py @@ -112,7 +112,7 @@ def test_move_maxpool_past_multithreshold(): model = model.transform(InferShapes()) model = model.transform(InferDataTypes()) - model.set_initializer("thres1", np.array([[0]])) + model.set_initializer("thres1", np.array([[0]], dtype=np.float32)) model.set_initializer( "thres2", get_multithreshold_rand_params(*thres2_shape, seed=0) )