From 11601cd9baf8eddc66f37a31ae85cc9b0ae57516 Mon Sep 17 00:00:00 2001 From: nicologhielmetti Date: Wed, 4 Dec 2024 00:25:36 +0100 Subject: [PATCH 1/4] Added automatic inference of `param_t` constant for parametrised activations --- .../model/optimizer/passes/infer_precision.py | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/hls4ml/model/optimizer/passes/infer_precision.py b/hls4ml/model/optimizer/passes/infer_precision.py index bd439e4a0f..a704ff6cbf 100644 --- a/hls4ml/model/optimizer/passes/infer_precision.py +++ b/hls4ml/model/optimizer/passes/infer_precision.py @@ -2,6 +2,7 @@ from typing import Iterable import numpy as np +import struct from hls4ml.model.optimizer import ConfigurableOptimizerPass from hls4ml.model.types import ( @@ -561,15 +562,29 @@ def _infer_rnn_precision(self, node, types_to_infer): return inferred_types - def _infer_par_act_precision(self, node, types_to_infer): + def _infer_const_precision(self, node, type_to_infer, attr_name): inferred_types = [] + def get_man_exp(f): + f = np.abs(f) + s = struct.pack('>f', f) + l = struct.unpack('>l', s)[0] + bits = '{:032b}'.format(l) + m = bits[-23:] + e = bits[-23-8:-23] + return m, e + alpha = node.get_attr(attr_name) + m, e = get_man_exp(alpha) + I = int(e, 2) - 127 + 1 # -127 is the bias of the exponent + W = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent + if alpha < 0: + I += 1 + W += 1 + node.attributes[type_to_infer].precision = FixedPrecisionType(W, I, True if alpha < 0 else False) + inferred_types.append(type_to_infer) + return inferred_types - # For threshold relu, set the parameter precision to be the input precision by default; - # for other parametrized activations, just allow the default precision to be used. - # Can override these values in the configuration by explicitly setting them. - if 'param_t' in inferred_types and self.get_attr('activation').lower() == 'thresholdedrelu': - in_type = node.get_input_variable().type.precision - node.attributes['param_t'].type = in_type - inferred_types.append('param_t') - + def _infer_par_act_precision(self, node, types_to_infer): + inferred_types = [] + if 'param_t' in types_to_infer: + inferred_types.extend(self._infer_const_precision(node, 'param_t', 'activ_param')) return inferred_types From 72026fbc2b9b101cc79715ccef1c12cb9ae6019d Mon Sep 17 00:00:00 2001 From: nicologhielmetti Date: Wed, 4 Dec 2024 11:00:18 +0100 Subject: [PATCH 2/4] pre-commit fixes --- .../model/optimizer/passes/infer_precision.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hls4ml/model/optimizer/passes/infer_precision.py b/hls4ml/model/optimizer/passes/infer_precision.py index a704ff6cbf..cbe24a0451 100644 --- a/hls4ml/model/optimizer/passes/infer_precision.py +++ b/hls4ml/model/optimizer/passes/infer_precision.py @@ -1,8 +1,8 @@ import math +import struct from typing import Iterable import numpy as np -import struct from hls4ml.model.optimizer import ConfigurableOptimizerPass from hls4ml.model.types import ( @@ -564,22 +564,24 @@ def _infer_rnn_precision(self, node, types_to_infer): def _infer_const_precision(self, node, type_to_infer, attr_name): inferred_types = [] + def get_man_exp(f): f = np.abs(f) s = struct.pack('>f', f) - l = struct.unpack('>l', s)[0] - bits = '{:032b}'.format(l) + l_float = struct.unpack('>l', s)[0] + bits = f'{l_float:032b}' m = bits[-23:] - e = bits[-23-8:-23] + e = bits[-23 - 8 : -23] return m, e + alpha = node.get_attr(attr_name) m, e = get_man_exp(alpha) - I = int(e, 2) - 127 + 1 # -127 is the bias of the exponent - W = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent + I_bits = int(e, 2) - 127 + 1 # -127 is the bias of the exponent + W_bits = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent if alpha < 0: - I += 1 - W += 1 - node.attributes[type_to_infer].precision = FixedPrecisionType(W, I, True if alpha < 0 else False) + I_bits += 1 + W_bits += 1 + node.attributes[type_to_infer].precision = FixedPrecisionType(W_bits, I_bits, True if alpha < 0 else False) inferred_types.append(type_to_infer) return inferred_types From 10ec7a24ed9c9fdeea5da3dca71bfdb564e3b7c1 Mon Sep 17 00:00:00 2001 From: nicologhielmetti Date: Wed, 4 Dec 2024 11:43:36 +0100 Subject: [PATCH 3/4] Fix the case the param is a power of 2 --- .../model/optimizer/passes/infer_precision.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/hls4ml/model/optimizer/passes/infer_precision.py b/hls4ml/model/optimizer/passes/infer_precision.py index cbe24a0451..a07aaf2c51 100644 --- a/hls4ml/model/optimizer/passes/infer_precision.py +++ b/hls4ml/model/optimizer/passes/infer_precision.py @@ -574,14 +574,17 @@ def get_man_exp(f): e = bits[-23 - 8 : -23] return m, e - alpha = node.get_attr(attr_name) - m, e = get_man_exp(alpha) - I_bits = int(e, 2) - 127 + 1 # -127 is the bias of the exponent - W_bits = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent - if alpha < 0: - I_bits += 1 + param = node.get_attr(attr_name) + m, e = get_man_exp(param) + I_pos = int(e, 2) - 127 + 1 # -127 is the bias of the exponent + try: + W_bits = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent + except Exception: + W_bits = 1 # the value is a power of 2, 1 bit is needed, I_pos will offset the bit in the proper place + if param < 0: + I_pos += 1 W_bits += 1 - node.attributes[type_to_infer].precision = FixedPrecisionType(W_bits, I_bits, True if alpha < 0 else False) + node.attributes[type_to_infer].precision = FixedPrecisionType(W_bits, I_pos, True if param < 0 else False) inferred_types.append(type_to_infer) return inferred_types From 29f083129cda3cd3970c4af5d06771b48e23bc53 Mon Sep 17 00:00:00 2001 From: nicologhielmetti Date: Wed, 4 Dec 2024 15:04:40 +0100 Subject: [PATCH 4/4] Fix for a specific case related to no bits in the mantissa --- hls4ml/model/optimizer/passes/infer_precision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hls4ml/model/optimizer/passes/infer_precision.py b/hls4ml/model/optimizer/passes/infer_precision.py index a07aaf2c51..4030994aa5 100644 --- a/hls4ml/model/optimizer/passes/infer_precision.py +++ b/hls4ml/model/optimizer/passes/infer_precision.py @@ -581,7 +581,7 @@ def get_man_exp(f): W_bits = m.rindex('1') + 2 # + 1 for accounting the index starting from 0, +1 for the leading 1 of the exponent except Exception: W_bits = 1 # the value is a power of 2, 1 bit is needed, I_pos will offset the bit in the proper place - if param < 0: + if param < 0 and W_bits > 1: # for po2 values the increment is not needed I_pos += 1 W_bits += 1 node.attributes[type_to_infer].precision = FixedPrecisionType(W_bits, I_pos, True if param < 0 else False)