From 29b0be9d2e79d5bda26a4518d81fcc319fec0b74 Mon Sep 17 00:00:00 2001 From: Maciej Mikolaj Glowacki Date: Wed, 3 Jan 2024 13:14:45 +0000 Subject: [PATCH 1/4] big fix: removing batch dimension from output shapes as its not expected by --- hls4ml/converters/pytorch/convolution.py | 4 ++-- hls4ml/converters/pytorch/pooling.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hls4ml/converters/pytorch/convolution.py b/hls4ml/converters/pytorch/convolution.py index 5c0d4d2d4c..9c9c9b5ce8 100644 --- a/hls4ml/converters/pytorch/convolution.py +++ b/hls4ml/converters/pytorch/convolution.py @@ -47,7 +47,7 @@ def parse_conv1d_layer(operation, layer_name, input_names, input_shapes, node, c layer['pad_left'] = pad_left layer['pad_right'] = pad_right - output_shape = [input_shapes[0][0], layer['n_filt'], layer['out_width']] # Channel first as default + output_shape = [layer['n_filt'], layer['out_width']] # Channel first as default return layer, output_shape @@ -102,6 +102,6 @@ def parse_conv2d_layer(operation, layer_name, input_names, input_shapes, node, c class_object.dilation[1], ) - output_shape = [input_shapes[0][0], layer['n_filt'], layer['out_height'], layer['out_width']] + output_shape = [layer['n_filt'], layer['out_height'], layer['out_width']] return layer, output_shape diff --git a/hls4ml/converters/pytorch/pooling.py b/hls4ml/converters/pytorch/pooling.py index 8256a9ff87..fdf69cefcc 100644 --- a/hls4ml/converters/pytorch/pooling.py +++ b/hls4ml/converters/pytorch/pooling.py @@ -63,6 +63,7 @@ def parse_pooling_layer(operation, layer_name, input_names, input_shapes, node, output_shape = [input_shapes[0][0], layer['n_filt'], layer['n_out']] elif int(layer['class_name'][-2]) == 2: + print(input_shapes) (layer['in_height'], layer['in_width'], layer['n_filt']) = parse_data_format(input_shapes[0], layer['data_format']) if node.op == 'call_module': @@ -129,8 +130,8 @@ def parse_pooling_layer(operation, layer_name, input_names, input_shapes, node, ) if layer['data_format'] == 'channels_last': - output_shape = [input_shapes[0][0], layer['out_height'], layer['out_width'], layer['n_filt']] + output_shape = [layer['out_height'], layer['out_width'], layer['n_filt']] elif layer['data_format'] == 'channels_first': - output_shape = [input_shapes[0][0], layer['n_filt'], layer['out_height'], layer['out_width']] + output_shape = [layer['n_filt'], layer['out_height'], layer['out_width']] return layer, output_shape From c527ee3240f3b3bdad24f6b14c5147a5db76a559 Mon Sep 17 00:00:00 2001 From: Maciej Mikolaj Glowacki Date: Wed, 3 Jan 2024 13:16:03 +0000 Subject: [PATCH 2/4] adding support for pytorch upsample layers --- hls4ml/converters/pytorch/reshape.py | 28 ++++++++++++++++++++++++++++ hls4ml/model/layers.py | 9 +++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/hls4ml/converters/pytorch/reshape.py b/hls4ml/converters/pytorch/reshape.py index 5e5cde5261..2b872c7839 100644 --- a/hls4ml/converters/pytorch/reshape.py +++ b/hls4ml/converters/pytorch/reshape.py @@ -1,6 +1,7 @@ import numpy as np from hls4ml.converters.pytorch_to_hls import pytorch_handler +from hls4ml.converters.utils import parse_data_format reshape_layers = ['View'] @@ -106,3 +107,30 @@ def parse_flatten_layer(operation, layer_name, input_names, input_shapes, node, output_shape = layer['target_shape'] return layer, output_shape + + +@pytorch_handler('Upsample') +def handle_upsample(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): + + assert operation == 'Upsample' + layer = {} + layer['name'] = layer_name + layer['inputs'] = input_names + layer['class_name'] = 'Upsample' + layer['data_format'] = 'channels_first' # Pytorch default (can't change) + + # Input info + (layer['in_height'], layer['in_width'], layer['n_chan']) = parse_data_format( + input_shapes[0], 'channels_first' + ) # K + + layer['height_factor'] = int(class_object.scale_factor) + layer['width_factor'] = int(class_object.scale_factor) + layer['algorithm'] = class_object.mode + + layer['out_height'] = layer['in_height'] * layer['height_factor'] + layer['out_width'] = layer['in_width'] * layer['width_factor'] + + output_shape = [layer['n_chan'], layer['out_height'], layer['out_width']] + + return layer, output_shape \ No newline at end of file diff --git a/hls4ml/model/layers.py b/hls4ml/model/layers.py index 4c7c210a77..b6baacf7ef 100644 --- a/hls4ml/model/layers.py +++ b/hls4ml/model/layers.py @@ -914,11 +914,11 @@ class Resize(Layer): def initialize(self): inp = self.get_input_variable() if len(inp.shape) == 2: # 1D -> width + chan - shape = [self.get_attr('out_width'), self.get_attr('n_chan')] - dims = [f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] + shape = [self.get_attr('out_width'), self.get_attr('n_chan')] if self.get_attr('data_format') == 'channels_last' else [self.get_attr('n_chan'), self.get_attr('out_width')] + dims = [f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] if self.get_attr('data_format') == 'channels_last' else [f'N_CHAN_{self.index}', f'OUT_WIDTH_{self.index}'] elif len(inp.shape) == 3: # 2D -> height + width + chan - shape = [self.get_attr('out_height'), self.get_attr('out_width'), self.get_attr('n_chan')] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] + shape = [self.get_attr('out_height'), self.get_attr('out_width'), self.get_attr('n_chan')] if self.get_attr('data_format') == 'channels_last' else [self.get_attr('n_chan'), self.get_attr('out_height'), self.get_attr('out_width')] + dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] if self.get_attr('data_format') == 'channels_last' else [f'N_CHAN_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] self.add_output_variable(shape, dims, precision=inp.type.precision) @@ -1366,6 +1366,7 @@ def initialize(self): 'Resize': Resize, 'UpSampling1D': Resize, 'UpSampling2D': Resize, + 'Upsample': Resize, 'Transpose': Transpose, 'Embedding': Embedding, 'SimpleRNN': SimpleRNN, From 26ba8778a12bf3a3aecb5a99e86437f1cec99612 Mon Sep 17 00:00:00 2001 From: Maciej Mikolaj Glowacki Date: Thu, 11 Jan 2024 15:53:00 +0000 Subject: [PATCH 3/4] Apply black formatting --- hls4ml/converters/pytorch/reshape.py | 164 +-- hls4ml/model/layers.py | 1419 ++++++++++++++++---------- 2 files changed, 977 insertions(+), 606 deletions(-) diff --git a/hls4ml/converters/pytorch/reshape.py b/hls4ml/converters/pytorch/reshape.py index 2b872c7839..971713b52d 100644 --- a/hls4ml/converters/pytorch/reshape.py +++ b/hls4ml/converters/pytorch/reshape.py @@ -3,45 +3,63 @@ from hls4ml.converters.pytorch_to_hls import pytorch_handler from hls4ml.converters.utils import parse_data_format -reshape_layers = ['View'] +reshape_layers = ["View"] @pytorch_handler(*reshape_layers) -def parse_reshape_layer(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): - assert operation == 'View' +def parse_reshape_layer( + operation, + layer_name, + input_names, + input_shapes, + node, + class_object, + data_reader, + config, +): + assert operation == "View" layer = {} - layer['class_name'] = 'Reshape' - layer['name'] = layer_name - layer['inputs'] = input_names + layer["class_name"] = "Reshape" + layer["name"] = layer_name + layer["inputs"] = input_names - layer['target_shape'] = [int(i) for i in node.args[1:]] + layer["target_shape"] = [int(i) for i in node.args[1:]] # View can have -1 as one as the dimensions, # leaving it to us to deduce it from the other dimensions and the overall size - if -1 in layer['target_shape']: + if -1 in layer["target_shape"]: size = np.prod(input_shapes[0][1:]) - for i in range(0, len(layer['target_shape'])): - if layer['target_shape'][i] == -1: - cl = layer['target_shape'][:] + for i in range(0, len(layer["target_shape"])): + if layer["target_shape"][i] == -1: + cl = layer["target_shape"][:] cl.remove(-1) - layer['target_shape'][i] = int(size / np.prod(cl)) + layer["target_shape"][i] = int(size / np.prod(cl)) - output_shape = input_shapes[0][:1] + layer['target_shape'] + output_shape = input_shapes[0][:1] + layer["target_shape"] return layer, output_shape -@pytorch_handler('squeeze') -def parse_squeeze_layer(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): - assert operation == 'squeeze' +@pytorch_handler("squeeze") +def parse_squeeze_layer( + operation, + layer_name, + input_names, + input_shapes, + node, + class_object, + data_reader, + config, +): + assert operation == "squeeze" layer = {} - layer['class_name'] = 'Reshape' - layer['name'] = layer_name + layer["class_name"] = "Reshape" + layer["name"] = layer_name if len(node.args) > 1 or len(node.kwargs) > 0: # 'dim' argument is specified output_shape = [i for i in input_shapes[0]] - squeeze_dim = node.kwargs.get('dim', None) + squeeze_dim = node.kwargs.get("dim", None) if squeeze_dim is None: squeeze_dim = node.args[1] if isinstance(squeeze_dim, tuple): @@ -52,47 +70,65 @@ def parse_squeeze_layer(operation, layer_name, input_names, input_shapes, node, else: output_shape = [i for i in input_shapes[0] if i != 1] - layer['target_shape'] = output_shape.copy() - if layer['target_shape'][0] is None: - del layer['target_shape'][0] + layer["target_shape"] = output_shape.copy() + if layer["target_shape"][0] is None: + del layer["target_shape"][0] return layer, output_shape -@pytorch_handler('unsqueeze') -def parse_unsqueeze_layer(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): - assert operation == 'unsqueeze' +@pytorch_handler("unsqueeze") +def parse_unsqueeze_layer( + operation, + layer_name, + input_names, + input_shapes, + node, + class_object, + data_reader, + config, +): + assert operation == "unsqueeze" layer = {} - layer['class_name'] = 'Reshape' - layer['name'] = layer_name - layer['inputs'] = input_names + layer["class_name"] = "Reshape" + layer["name"] = layer_name + layer["inputs"] = input_names # Unlike in 'squeeze' in 'unsqueeze', dim argument must exist output_shape = [i for i in input_shapes[0]] if len(node.args) > 1: # Specified as unsqueeze(x, n) squeeze_dim = node.args[1] else: # Specified as unsqueeze(x, dim=n) - squeeze_dim = node.kwargs['dim'] + squeeze_dim = node.kwargs["dim"] # insert() will add an element before the index, unsqueeze expects the location index = output_shape.index(output_shape[squeeze_dim]) # + 1 output_shape.insert(index, 1) - layer['target_shape'] = output_shape.copy() - if layer['target_shape'][0] is None: - del layer['target_shape'][0] + layer["target_shape"] = output_shape.copy() + if layer["target_shape"][0] is None: + del layer["target_shape"][0] return layer, output_shape -@pytorch_handler('Flatten') -def parse_flatten_layer(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): - assert operation == 'Flatten' +@pytorch_handler("Flatten") +def parse_flatten_layer( + operation, + layer_name, + input_names, + input_shapes, + node, + class_object, + data_reader, + config, +): + assert operation == "Flatten" layer = {} - layer['class_name'] = 'Reshape' - layer['name'] = layer_name - layer['inputs'] = input_names + layer["class_name"] = "Reshape" + layer["name"] = layer_name + layer["inputs"] = input_names start_dim = class_object.start_dim end_dim = class_object.end_dim @@ -101,36 +137,46 @@ def parse_flatten_layer(operation, layer_name, input_names, input_shapes, node, else: end_dim = end_dim + 1 - layer['target_shape'] = ( - input_shapes[0][0:start_dim] + [np.prod(input_shapes[0][start_dim:end_dim])] + input_shapes[0][end_dim:] + layer["target_shape"] = ( + input_shapes[0][0:start_dim] + + [np.prod(input_shapes[0][start_dim:end_dim])] + + input_shapes[0][end_dim:] ) - output_shape = layer['target_shape'] + output_shape = layer["target_shape"] return layer, output_shape -@pytorch_handler('Upsample') -def handle_upsample(operation, layer_name, input_names, input_shapes, node, class_object, data_reader, config): - - assert operation == 'Upsample' +@pytorch_handler("Upsample") +def handle_upsample( + operation, + layer_name, + input_names, + input_shapes, + node, + class_object, + data_reader, + config, +): + assert operation == "Upsample" layer = {} - layer['name'] = layer_name - layer['inputs'] = input_names - layer['class_name'] = 'Upsample' - layer['data_format'] = 'channels_first' # Pytorch default (can't change) - + layer["name"] = layer_name + layer["inputs"] = input_names + layer["class_name"] = "Upsample" + layer["data_format"] = "channels_first" # Pytorch default (can't change) + # Input info - (layer['in_height'], layer['in_width'], layer['n_chan']) = parse_data_format( - input_shapes[0], 'channels_first' + (layer["in_height"], layer["in_width"], layer["n_chan"]) = parse_data_format( + input_shapes[0], "channels_first" ) # K - layer['height_factor'] = int(class_object.scale_factor) - layer['width_factor'] = int(class_object.scale_factor) - layer['algorithm'] = class_object.mode + layer["height_factor"] = int(class_object.scale_factor) + layer["width_factor"] = int(class_object.scale_factor) + layer["algorithm"] = class_object.mode - layer['out_height'] = layer['in_height'] * layer['height_factor'] - layer['out_width'] = layer['in_width'] * layer['width_factor'] + layer["out_height"] = layer["in_height"] * layer["height_factor"] + layer["out_width"] = layer["in_width"] * layer["width_factor"] - output_shape = [layer['n_chan'], layer['out_height'], layer['out_width']] + output_shape = [layer["n_chan"], layer["out_height"], layer["out_width"]] - return layer, output_shape \ No newline at end of file + return layer, output_shape diff --git a/hls4ml/model/layers.py b/hls4ml/model/layers.py index b6baacf7ef..60bded9e50 100644 --- a/hls4ml/model/layers.py +++ b/hls4ml/model/layers.py @@ -52,28 +52,32 @@ class Layer: """ _expected_attributes = [ - Attribute('index'), - ConfigurableAttribute('trace', default=False), - TypeAttribute('result'), + Attribute("index"), + ConfigurableAttribute("trace", default=False), + TypeAttribute("result"), ] @classproperty def expected_attributes(cls): """Returns the expected attributes of a class.""" all_attributes = [] - for base_cls in reversed(cls.mro()): # Iterate over all base classes in the hierarchy + for base_cls in reversed( + cls.mro() + ): # Iterate over all base classes in the hierarchy if cls == base_cls: # Skip adding attributes from self continue - if hasattr(base_cls, '_expected_attributes'): # Only consider classes with '_expected_attributes' defined + if hasattr( + base_cls, "_expected_attributes" + ): # Only consider classes with '_expected_attributes' defined all_attributes.extend(base_cls._expected_attributes) - if '_expected_attributes' in cls.__dict__: + if "_expected_attributes" in cls.__dict__: # Add new attributes defined in the class # TODO Support overriding attributes from parent class all_attributes.extend(cls._expected_attributes) return all_attributes def __init__(self, model, name, attributes, inputs, outputs=None): - if name == 'input': + if name == "input": raise RuntimeError( "No model layer should be named 'input' because that is a reserved;" + "layer name in ModelGraph; Please rename the layer in your model" @@ -89,7 +93,7 @@ def __init__(self, model, name, attributes, inputs, outputs=None): self.attributes = AttributeDict(self) self.attributes.update(attributes) - self.set_attr('index', self.index) + self.set_attr("index", self.index) self.weights = WeightMapping(self.attributes) self.variables = VariableMapping(self.attributes) @@ -107,11 +111,13 @@ def __init__(self, model, name, attributes, inputs, outputs=None): config_key, self.name, self.class_name ) ) - if config_key.endswith('_t') and isinstance( + if config_key.endswith("_t") and isinstance( config_value, str ): # TODO maybe move this to __setitem__ of AttributeDict? - precision = self.model.config.backend.convert_precision_string(config_value) - config_value = NamedType(self.name + '_' + config_key, precision) + precision = self.model.config.backend.convert_precision_string( + config_value + ) + config_value = NamedType(self.name + "_" + config_key, precision) self.attributes[config_key] = config_value self.initialize() @@ -122,7 +128,7 @@ def class_name(self, include_wrapped=False): if include_wrapped: return self.__class__.__name__ else: - if hasattr(self, '_wrapped'): + if hasattr(self, "_wrapped"): return self.__class__.__bases__[0].__name__ else: return self.__class__.__name__ @@ -148,7 +154,12 @@ def _validate_attributes(self): if not exp_attr.validate_value(attr_value): raise Exception( 'Unexpected value of attribute "{}" of layer "{}" ({}). Expected {}, got {} ({})'.format( - attr_name, self.name, self.class_name, exp_attr.value_type, type(attr_value), attr_value + attr_name, + self.name, + self.class_name, + exp_attr.value_type, + type(attr_value), + attr_value, ) ) else: @@ -158,7 +169,12 @@ def _validate_attributes(self): for attr_name, attr in all_attributes.items(): if attr.default is not None: if isinstance(attr, TypeAttribute): - self.set_attr(attr_name, self._wrap_precision_to_type(self.name + '_' + attr_name, attr.default)) + self.set_attr( + attr_name, + self._wrap_precision_to_type( + self.name + "_" + attr_name, attr.default + ), + ) else: self.set_attr(attr_name, attr.default) else: @@ -174,10 +190,16 @@ def _wrap_precision_to_type(self, name, precision): return NamedType(name=name, precision=precision) def _set_accum_t(self): - has_accum_t = any(a for a in self.expected_attributes if a.name == 'accum_t' and isinstance(a, TypeAttribute)) + has_accum_t = any( + a + for a in self.expected_attributes + if a.name == "accum_t" and isinstance(a, TypeAttribute) + ) if has_accum_t: - accum_t = NamedType(*reversed(self.model.config.get_precision(self, 'accum'))) - self.set_attr('accum_t', accum_t) + accum_t = NamedType( + *reversed(self.model.config.get_precision(self, "accum")) + ) + self.set_attr("accum_t", accum_t) def get_input_node(self, input_name=None): if input_name is None: @@ -185,7 +207,9 @@ def get_input_node(self, input_name=None): input_name = self.inputs[0] else: return None - nodes = [node for node in self.model.graph.values() if input_name in node.outputs] + nodes = [ + node for node in self.model.graph.values() if input_name in node.outputs + ] if len(nodes) == 0: return None else: @@ -236,63 +260,92 @@ def get_variables(self): return self.variables.values() def add_output_variable( - self, shape, dim_names, out_name=None, var_name='layer{index}_out', type_name='layer{index}_t', precision=None + self, + shape, + dim_names, + out_name=None, + var_name="layer{index}_out", + type_name="layer{index}_t", + precision=None, ): if out_name is None: out_name = self.outputs[0] if precision is None: - precision, _ = self.model.config.get_precision(self, var='result') - - out = TensorVariable(shape, dim_names, var_name=var_name, type_name=type_name, precision=precision, index=self.index) + precision, _ = self.model.config.get_precision(self, var="result") + + out = TensorVariable( + shape, + dim_names, + var_name=var_name, + type_name=type_name, + precision=precision, + index=self.index, + ) self.set_attr(out_name, out) def add_weights(self, quantizer=None, compression=False): self.add_weights_variable( - name='weight', var_name='w{index}', data='weight', quantizer=quantizer, compression=compression + name="weight", + var_name="w{index}", + data="weight", + quantizer=quantizer, + compression=compression, ) def add_bias(self, quantizer=None): - data = self.get_attr('bias_data', None) + data = self.get_attr("bias_data", None) precision = None type_name = None if data is None: data = np.zeros(self.get_output_variable().shape[-1]) precision = IntegerPrecisionType(width=1, signed=False) - type_name = 'bias{index}_t' + type_name = "bias{index}_t" quantizer = None # Don't quantize non-existant bias self.add_weights_variable( - name='bias', var_name='b{index}', type_name=type_name, precision=precision, data=data, quantizer=quantizer + name="bias", + var_name="b{index}", + type_name=type_name, + precision=precision, + data=data, + quantizer=quantizer, ) def add_weights_variable( - self, name, var_name=None, type_name=None, precision=None, data=None, quantizer=None, compression=False + self, + name, + var_name=None, + type_name=None, + precision=None, + data=None, + quantizer=None, + compression=False, ): if var_name is None: - var_name = name + '{index}' + var_name = name + "{index}" if precision is None: precision, _ = self.model.config.get_precision(self, var=name) elif type_name is None: # If precision is specified but no type name is given, assign a dedicated # type name made from variable name and layer index - type_name = name + '{index}_t' + type_name = name + "{index}_t" if type_name is None: _, type_name = self.model.config.get_precision(self, var=name) if data is None: - data = self.get_attr(name + '_data') + data = self.get_attr(name + "_data") elif isinstance(data, str): - data = self.get_attr(data + '_data') + data = self.get_attr(data + "_data") data_unquantized = data exponent_type = False if quantizer is not None: precision = quantizer.hls_type - type_name = name + '{index}_t' + type_name = name + "{index}_t" data = quantizer(data) if isinstance(quantizer.hls_type, ExponentPrecisionType): exponent_type = True @@ -305,16 +358,26 @@ def add_weights_variable( precision=precision, quantizer=quantizer, data=data, - reuse_factor=self.get_attr('reuse_factor', 1), + reuse_factor=self.get_attr("reuse_factor", 1), index=self.index, ) elif exponent_type: var = ExponentWeightVariable( - var_name, type_name=type_name, precision=precision, quantizer=quantizer, data=data, index=self.index + var_name, + type_name=type_name, + precision=precision, + quantizer=quantizer, + data=data, + index=self.index, ) else: var = WeightVariable( - var_name, type_name=type_name, precision=precision, quantizer=quantizer, data=data, index=self.index + var_name, + type_name=type_name, + precision=precision, + quantizer=quantizer, + data=data, + index=self.index, ) var.data_unquantized = data_unquantized @@ -330,27 +393,29 @@ def get_layer_precision(self): class Input(Layer): def initialize(self): - shape = self.attributes['input_shape'] + shape = self.attributes["input_shape"] if shape[0] is None: shape = shape[1:] - dims = [f'N_INPUT_{i}_{self.index}' for i in range(1, len(shape) + 1)] + dims = [f"N_INPUT_{i}_{self.index}" for i in range(1, len(shape) + 1)] if self.index == 1: - default_type_name = 'input_t' + default_type_name = "input_t" else: - default_type_name = f'input{self.index}_t' - type_name = self.attributes.get('type_name', default_type_name) - precision, _ = self.model.config.get_precision(self, var='result') - self.add_output_variable(shape, dims, var_name=self.name, type_name=type_name, precision=precision) + default_type_name = f"input{self.index}_t" + type_name = self.attributes.get("type_name", default_type_name) + precision, _ = self.model.config.get_precision(self, var="result") + self.add_output_variable( + shape, dims, var_name=self.name, type_name=type_name, precision=precision + ) class Reshape(Layer): _expected_attributes = [ - Attribute('target_shape', value_type=typing.Sequence), + Attribute("target_shape", value_type=typing.Sequence), ] def initialize(self): input_shape = self.get_input_variable(self.inputs[0]).shape - target_shape = self.get_attr('target_shape') + target_shape = self.get_attr("target_shape") if target_shape is None: # need to get it from the input shape_node = self.get_input_node(self.inputs[1]) @@ -358,7 +423,9 @@ def initialize(self): if shape_node: target_shape = shape_node.value[1:] else: - raise RuntimeError("Reshape for ONNX requires the target shape to be a second input.") + raise RuntimeError( + "Reshape for ONNX requires the target shape to be a second input." + ) # remove Nones -- is this ever triggered? if target_shape[0] is None: @@ -368,9 +435,9 @@ def initialize(self): shape = self._infer_output_shape(input_shape, target_shape) # update the target shape with chnges from above - self.set_attr('target_shape', shape) + self.set_attr("target_shape", shape) - dims = [f'N_SIZE_{i}_{self.index}' for i in range(len(shape))] + dims = [f"N_SIZE_{i}_{self.index}" for i in range(len(shape))] self.add_output_variable(shape, dims) @@ -385,141 +452,176 @@ def _infer_output_shape(self, input_shape, target_shape): class Dense(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('n_out'), - WeightAttribute('weight'), - WeightAttribute('bias'), - TypeAttribute('weight'), - TypeAttribute('bias'), + Attribute("n_in"), + Attribute("n_out"), + WeightAttribute("weight"), + WeightAttribute("bias"), + TypeAttribute("weight"), + TypeAttribute("bias"), ] def initialize(self): shape = self.get_input_variable().shape[:] - shape[-1] = self.attributes['n_out'] + shape[-1] = self.attributes["n_out"] if len(shape) > 1: - dims = [f'N_LAYER_{i}_{self.index}' for i in range(1, len(shape) + 1)] + dims = [f"N_LAYER_{i}_{self.index}" for i in range(1, len(shape) + 1)] else: - dims = [f'N_LAYER_{self.index}'] + dims = [f"N_LAYER_{self.index}"] self.add_output_variable(shape, dims) - self.add_weights(quantizer=self.get_attr('weight_quantizer'), compression=self.model.config.get_compression(self)) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_weights( + quantizer=self.get_attr("weight_quantizer"), + compression=self.model.config.get_compression(self), + ) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class Conv1D(Layer): _expected_attributes = [ - Attribute('in_width'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('n_filt'), - Attribute('filt_width'), - Attribute('stride_width'), - Attribute('pad_left'), - Attribute('pad_right'), - WeightAttribute('weight'), - WeightAttribute('bias'), - TypeAttribute('weight'), - TypeAttribute('bias'), + Attribute("in_width"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("n_filt"), + Attribute("filt_width"), + Attribute("stride_width"), + Attribute("pad_left"), + Attribute("pad_right"), + WeightAttribute("weight"), + WeightAttribute("bias"), + TypeAttribute("weight"), + TypeAttribute("bias"), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_width'], self.attributes['n_filt']] - dims = [f'N_OUTPUTS_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [self.attributes["out_width"], self.attributes["n_filt"]] + dims = [f"N_OUTPUTS_{self.index}", f"N_FILT_{self.index}"] else: - shape = [self.attributes['n_filt'], self.attributes['out_width']] - dims = [f'N_FILT_{self.index}', f'N_OUTPUTS_{self.index}'] + shape = [self.attributes["n_filt"], self.attributes["out_width"]] + dims = [f"N_FILT_{self.index}", f"N_OUTPUTS_{self.index}"] self.add_output_variable(shape, dims) - self.add_weights(quantizer=self.get_attr('weight_quantizer')) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_weights(quantizer=self.get_attr("weight_quantizer")) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class SeparableConv1D(Layer): _expected_attributes = [ - Attribute('in_width'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('n_filt'), - Attribute('filt_width'), - Attribute('stride_width'), - Attribute('pad_left'), - Attribute('pad_right'), - WeightAttribute('depthwise'), - WeightAttribute('pointwise'), - WeightAttribute('bias'), - TypeAttribute('depthwise'), - TypeAttribute('pointwise'), - TypeAttribute('bias'), + Attribute("in_width"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("n_filt"), + Attribute("filt_width"), + Attribute("stride_width"), + Attribute("pad_left"), + Attribute("pad_right"), + WeightAttribute("depthwise"), + WeightAttribute("pointwise"), + WeightAttribute("bias"), + TypeAttribute("depthwise"), + TypeAttribute("pointwise"), + TypeAttribute("bias"), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_width'], self.attributes['n_filt']] - dims = [f'N_OUTPUTS_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [self.attributes["out_width"], self.attributes["n_filt"]] + dims = [f"N_OUTPUTS_{self.index}", f"N_FILT_{self.index}"] else: - shape = [self.attributes['n_filt'], self.attributes['out_width']] - dims = [f'N_FILT_{self.index}', f'N_OUTPUTS_{self.index}'] + shape = [self.attributes["n_filt"], self.attributes["out_width"]] + dims = [f"N_FILT_{self.index}", f"N_OUTPUTS_{self.index}"] self.add_output_variable(shape, dims) - self.add_weights_variable(name='depthwise', var_name='d{index}', quantizer=self.get_attr('depthwise_quantizer')) - self.add_weights_variable(name='pointwise', var_name='p{index}', quantizer=self.get_attr('pointwise_quantizer')) + self.add_weights_variable( + name="depthwise", + var_name="d{index}", + quantizer=self.get_attr("depthwise_quantizer"), + ) + self.add_weights_variable( + name="pointwise", + var_name="p{index}", + quantizer=self.get_attr("pointwise_quantizer"), + ) - zero_bias_data = np.zeros((self.attributes['n_chan'],)) + zero_bias_data = np.zeros((self.attributes["n_chan"],)) precision = IntegerPrecisionType(width=1, signed=False) - self.add_weights_variable(name='zero_bias', var_name='z{index}', data=zero_bias_data, precision=precision) + self.add_weights_variable( + name="zero_bias", + var_name="z{index}", + data=zero_bias_data, + precision=precision, + ) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class DepthwiseConv1D(Conv1D): def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_width'], self.attributes['n_chan']] - dims = [f'OUT_HEIGHT_{self.index}', f'N_CHAN_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [self.attributes["out_width"], self.attributes["n_chan"]] + dims = [f"OUT_HEIGHT_{self.index}", f"N_CHAN_{self.index}"] else: - shape = [self.attributes['n_chan'], self.attributes['out_width']] - dims = [f'N_CHAN_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [self.attributes["n_chan"], self.attributes["out_width"]] + dims = [f"N_CHAN_{self.index}", f"OUT_WIDTH_{self.index}"] self.add_output_variable(shape, dims) self.add_weights_variable( - name='weight', var_name='w{index}', data='depthwise', quantizer=self.get_attr('depthwise_quantizer') + name="weight", + var_name="w{index}", + data="depthwise", + quantizer=self.get_attr("depthwise_quantizer"), ) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class Conv2D(Layer): _expected_attributes = [ - Attribute('in_height'), - Attribute('in_width'), - Attribute('out_height'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('n_filt'), - Attribute('filt_height'), - Attribute('filt_width'), - Attribute('stride_height'), - Attribute('stride_width'), - Attribute('pad_top'), - Attribute('pad_bottom'), - Attribute('pad_left'), - Attribute('pad_right'), - WeightAttribute('weight'), - WeightAttribute('bias'), - TypeAttribute('weight'), - TypeAttribute('bias'), + Attribute("in_height"), + Attribute("in_width"), + Attribute("out_height"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("n_filt"), + Attribute("filt_height"), + Attribute("filt_width"), + Attribute("stride_height"), + Attribute("stride_width"), + Attribute("pad_top"), + Attribute("pad_bottom"), + Attribute("pad_left"), + Attribute("pad_right"), + WeightAttribute("weight"), + WeightAttribute("bias"), + TypeAttribute("weight"), + TypeAttribute("bias"), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_height'], self.attributes['out_width'], self.attributes['n_filt']] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [ + self.attributes["out_height"], + self.attributes["out_width"], + self.attributes["n_filt"], + ] + dims = [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_FILT_{self.index}", + ] else: - shape = [self.attributes['n_filt'], self.attributes['out_height'], self.attributes['out_width']] - dims = [f'N_FILT_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [ + self.attributes["n_filt"], + self.attributes["out_height"], + self.attributes["out_width"], + ] + dims = [ + f"N_FILT_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] self.add_output_variable(shape, dims) - self.add_weights(quantizer=self.get_attr('weight_quantizer')) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_weights(quantizer=self.get_attr("weight_quantizer")) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class Conv2DBatchnorm(Conv2D): @@ -531,18 +633,18 @@ def _get_folded_weights(self): W_fold = gamma * W / sqrt(variance + epsilon) bias_fold = gamma * (bias - moving_mean) / sqrt(variance + epsilon) + beta """ - kernel = self.get_attr('weight_data') - bias = self.get_attr('bias_data') + kernel = self.get_attr("weight_data") + bias = self.get_attr("bias_data") if bias is None: bias = 0 # get batchnorm weights and moving stats - gamma = self.get_attr('gamma_data') - beta = self.get_attr('beta_data') - moving_mean = self.get_attr('mean_data') - moving_variance = self.get_attr('variance_data') + gamma = self.get_attr("gamma_data") + beta = self.get_attr("beta_data") + moving_mean = self.get_attr("mean_data") + moving_variance = self.get_attr("variance_data") # get the inversion factor so that we replace division by multiplication - inv = np.reciprocal(np.sqrt(moving_variance + self.get_attr('epsilon'))) + inv = np.reciprocal(np.sqrt(moving_variance + self.get_attr("epsilon"))) if gamma is not None: inv *= gamma @@ -557,213 +659,307 @@ def _get_folded_weights(self): def initialize(self): super().initialize() folded_weights, folded_bias = self._get_folded_weights() - if self.model.config.is_resource_strategy(self) and self.model.config.backend.name in [ - 'Vivado', - 'VivadoAccelerator', + if self.model.config.is_resource_strategy( + self + ) and self.model.config.backend.name in [ + "Vivado", + "VivadoAccelerator", ]: - self.weights['weight'].data_unquantized = np.transpose(folded_weights, axes=[3, 0, 1, 2]) - self.weights['weight'].data = self.get_attr('weight_quantizer')(self.weights['weight'].data_unquantized) + self.weights["weight"].data_unquantized = np.transpose( + folded_weights, axes=[3, 0, 1, 2] + ) + self.weights["weight"].data = self.get_attr("weight_quantizer")( + self.weights["weight"].data_unquantized + ) else: - self.weights['weight'].data_unquantized = folded_weights - self.weights['weight'].data = self.get_attr('weight_quantizer')(folded_weights) - self.weights['bias'].data_unquantized = folded_bias - bias_q = self.get_attr('bias_quantizer') + self.weights["weight"].data_unquantized = folded_weights + self.weights["weight"].data = self.get_attr("weight_quantizer")( + folded_weights + ) + self.weights["bias"].data_unquantized = folded_bias + bias_q = self.get_attr("bias_quantizer") if bias_q is not None: - self.weights['bias'].data = bias_q(folded_bias) + self.weights["bias"].data = bias_q(folded_bias) class SeparableConv2D(Layer): _expected_attributes = [ - Attribute('in_height'), - Attribute('in_width'), - Attribute('out_height'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('n_filt'), - Attribute('filt_height'), - Attribute('filt_width'), - Attribute('stride_height'), - Attribute('stride_width'), - Attribute('pad_top'), - Attribute('pad_bottom'), - Attribute('pad_left'), - Attribute('pad_right'), - WeightAttribute('depthwise'), - WeightAttribute('pointwise'), - WeightAttribute('bias'), - TypeAttribute('depthwise'), - TypeAttribute('pointwise'), - TypeAttribute('bias'), + Attribute("in_height"), + Attribute("in_width"), + Attribute("out_height"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("n_filt"), + Attribute("filt_height"), + Attribute("filt_width"), + Attribute("stride_height"), + Attribute("stride_width"), + Attribute("pad_top"), + Attribute("pad_bottom"), + Attribute("pad_left"), + Attribute("pad_right"), + WeightAttribute("depthwise"), + WeightAttribute("pointwise"), + WeightAttribute("bias"), + TypeAttribute("depthwise"), + TypeAttribute("pointwise"), + TypeAttribute("bias"), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_height'], self.attributes['out_width'], self.attributes['n_filt']] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [ + self.attributes["out_height"], + self.attributes["out_width"], + self.attributes["n_filt"], + ] + dims = [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_FILT_{self.index}", + ] else: - shape = [self.attributes['n_filt'], self.attributes['out_height'], self.attributes['out_width']] - dims = [f'N_FILT_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [ + self.attributes["n_filt"], + self.attributes["out_height"], + self.attributes["out_width"], + ] + dims = [ + f"N_FILT_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] self.add_output_variable(shape, dims) - self.add_weights_variable(name='depthwise', var_name='d{index}', quantizer=self.get_attr('depthwise_quantizer')) - self.add_weights_variable(name='pointwise', var_name='p{index}', quantizer=self.get_attr('pointwise_quantizer')) + self.add_weights_variable( + name="depthwise", + var_name="d{index}", + quantizer=self.get_attr("depthwise_quantizer"), + ) + self.add_weights_variable( + name="pointwise", + var_name="p{index}", + quantizer=self.get_attr("pointwise_quantizer"), + ) - zero_bias_data = np.zeros((self.attributes['n_chan'],)) + zero_bias_data = np.zeros((self.attributes["n_chan"],)) precision = IntegerPrecisionType(width=1, signed=False) - self.add_weights_variable(name='zero_bias', var_name='z{index}', data=zero_bias_data, precision=precision) + self.add_weights_variable( + name="zero_bias", + var_name="z{index}", + data=zero_bias_data, + precision=precision, + ) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class DepthwiseConv2D(Conv2D): def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_height'], self.attributes['out_width'], self.attributes['n_chan']] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [ + self.attributes["out_height"], + self.attributes["out_width"], + self.attributes["n_chan"], + ] + dims = [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_CHAN_{self.index}", + ] else: - shape = [self.attributes['n_chan'], self.attributes['out_height'], self.attributes['out_width']] - dims = [f'N_CHAN_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [ + self.attributes["n_chan"], + self.attributes["out_height"], + self.attributes["out_width"], + ] + dims = [ + f"N_CHAN_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] self.add_output_variable(shape, dims) self.add_weights_variable( - name='weight', var_name='w{index}', data='depthwise', quantizer=self.get_attr('depthwise_quantizer') + name="weight", + var_name="w{index}", + data="depthwise", + quantizer=self.get_attr("depthwise_quantizer"), ) - self.add_bias(quantizer=self.get_attr('bias_quantizer')) + self.add_bias(quantizer=self.get_attr("bias_quantizer")) class Pooling1D(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('n_out'), - Attribute('n_filt'), - Attribute('pool_width'), - Attribute('stride_width'), - Attribute('pad_left'), - Attribute('pad_right'), - Attribute('count_pad', value_type=bool, default=False), - ChoiceAttribute('pool_op', ['Max', 'Average'], configurable=False), + Attribute("n_in"), + Attribute("n_out"), + Attribute("n_filt"), + Attribute("pool_width"), + Attribute("stride_width"), + Attribute("pad_left"), + Attribute("pad_right"), + Attribute("count_pad", value_type=bool, default=False), + ChoiceAttribute("pool_op", ["Max", "Average"], configurable=False), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['n_out'], self.attributes['n_filt']] - dims = [f'N_OUTPUTS_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [self.attributes["n_out"], self.attributes["n_filt"]] + dims = [f"N_OUTPUTS_{self.index}", f"N_FILT_{self.index}"] else: - shape = [self.attributes['n_filt'], self.attributes['n_out']] - dims = [f'N_FILT_{self.index}', f'N_OUTPUTS_{self.index}'] + shape = [self.attributes["n_filt"], self.attributes["n_out"]] + dims = [f"N_FILT_{self.index}", f"N_OUTPUTS_{self.index}"] self.add_output_variable(shape, dims) - self.set_attr('pool_op', self.get_attr('class_name').split('Pooling')[0]) + self.set_attr("pool_op", self.get_attr("class_name").split("Pooling")[0]) class Pooling2D(Layer): _expected_attributes = [ - Attribute('in_height'), - Attribute('in_width'), - Attribute('out_height'), - Attribute('out_width'), - Attribute('n_filt'), - Attribute('pool_height'), - Attribute('pool_width'), - Attribute('stride_height'), - Attribute('stride_width'), - Attribute('pad_top'), - Attribute('pad_bottom'), - Attribute('pad_left'), - Attribute('pad_right'), - Attribute('count_pad', value_type=bool, default=False), - ChoiceAttribute('pool_op', ['Max', 'Average'], configurable=False), + Attribute("in_height"), + Attribute("in_width"), + Attribute("out_height"), + Attribute("out_width"), + Attribute("n_filt"), + Attribute("pool_height"), + Attribute("pool_width"), + Attribute("stride_height"), + Attribute("stride_width"), + Attribute("pad_top"), + Attribute("pad_bottom"), + Attribute("pad_left"), + Attribute("pad_right"), + Attribute("count_pad", value_type=bool, default=False), + ChoiceAttribute("pool_op", ["Max", "Average"], configurable=False), ] def initialize(self): - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_height'], self.attributes['out_width'], self.attributes['n_filt']] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_FILT_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [ + self.attributes["out_height"], + self.attributes["out_width"], + self.attributes["n_filt"], + ] + dims = [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_FILT_{self.index}", + ] else: - shape = [self.attributes['n_filt'], self.attributes['out_height'], self.attributes['out_width']] - dims = [f'N_FILT_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [ + self.attributes["n_filt"], + self.attributes["out_height"], + self.attributes["out_width"], + ] + dims = [ + f"N_FILT_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] self.add_output_variable(shape, dims) - self.set_attr('pool_op', self.get_attr('class_name').split('Pooling')[0]) + self.set_attr("pool_op", self.get_attr("class_name").split("Pooling")[0]) class GlobalPooling1D(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('n_filt'), - ChoiceAttribute('pool_op', ['Max', 'Average'], configurable=False), + Attribute("n_in"), + Attribute("n_filt"), + ChoiceAttribute("pool_op", ["Max", "Average"], configurable=False), ] def initialize(self): - shape = [self.attributes['n_filt']] - dims = [f'N_FILT_{self.index}'] + shape = [self.attributes["n_filt"]] + dims = [f"N_FILT_{self.index}"] self.add_output_variable(shape, dims) - self.set_attr('pool_op', self.get_attr('class_name').split('Pooling')[0].replace('Global', '')) + self.set_attr( + "pool_op", + self.get_attr("class_name").split("Pooling")[0].replace("Global", ""), + ) class GlobalPooling2D(Layer): _expected_attributes = [ - Attribute('in_height'), - Attribute('in_width'), - Attribute('n_filt'), - ChoiceAttribute('pool_op', ['Max', 'Average'], configurable=False), + Attribute("in_height"), + Attribute("in_width"), + Attribute("n_filt"), + ChoiceAttribute("pool_op", ["Max", "Average"], configurable=False), ] def initialize(self): - shape = [self.attributes['n_filt']] - dims = [f'N_FILT_{self.index}'] + shape = [self.attributes["n_filt"]] + dims = [f"N_FILT_{self.index}"] self.add_output_variable(shape, dims) - self.set_attr('pool_op', self.get_attr('class_name').split('Pooling')[0].replace('Global', '')) + self.set_attr( + "pool_op", + self.get_attr("class_name").split("Pooling")[0].replace("Global", ""), + ) class ZeroPadding1D(Layer): _expected_attributes = [ - Attribute('in_width'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('pad_left'), - Attribute('pad_right'), + Attribute("in_width"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("pad_left"), + Attribute("pad_right"), ] def initialize(self): inp = self.get_input_variable() - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_width'], self.attributes['n_chan']] - dims = [f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [self.attributes["out_width"], self.attributes["n_chan"]] + dims = [f"OUT_WIDTH_{self.index}", f"N_CHAN_{self.index}"] else: - shape = [self.attributes['n_chan'], self.attributes['out_width']] - dims = [f'N_CHAN_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [self.attributes["n_chan"], self.attributes["out_width"]] + dims = [f"N_CHAN_{self.index}", f"OUT_WIDTH_{self.index}"] self.add_output_variable(shape, dims, precision=inp.type.precision) class ZeroPadding2D(Layer): _expected_attributes = [ - Attribute('in_height'), - Attribute('in_width'), - Attribute('out_height'), - Attribute('out_width'), - Attribute('n_chan'), - Attribute('pad_top'), - Attribute('pad_bottom'), - Attribute('pad_left'), - Attribute('pad_right'), + Attribute("in_height"), + Attribute("in_width"), + Attribute("out_height"), + Attribute("out_width"), + Attribute("n_chan"), + Attribute("pad_top"), + Attribute("pad_bottom"), + Attribute("pad_left"), + Attribute("pad_right"), ] def initialize(self): inp = self.get_input_variable() - if self.get_attr('data_format') == 'channels_last': - shape = [self.attributes['out_height'], self.attributes['out_width'], self.attributes['n_chan']] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] + if self.get_attr("data_format") == "channels_last": + shape = [ + self.attributes["out_height"], + self.attributes["out_width"], + self.attributes["n_chan"], + ] + dims = [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_CHAN_{self.index}", + ] else: - shape = [self.attributes['n_chan'], self.attributes['out_height'], self.attributes['out_width']] - dims = [f'N_CHAN_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = [ + self.attributes["n_chan"], + self.attributes["out_height"], + self.attributes["out_width"], + ] + dims = [ + f"N_CHAN_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] self.add_output_variable(shape, dims, precision=inp.type.precision) class Activation(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('activation', value_type=str), + Attribute("n_in"), + Attribute("activation", value_type=str), ] def initialize(self): @@ -771,50 +967,54 @@ def initialize(self): shape = inp.shape dims = inp.dim_names self.add_output_variable(shape, dims) - self.set_attr('n_in', self.get_input_variable().size()) + self.set_attr("n_in", self.get_input_variable().size()) class ParametrizedActivation(Activation): def _get_act_function_name(self): - act = self.get_attr('activation').lower() - if act == 'leakyrelu': - return 'leaky_relu' - elif act == 'thresholdedrelu': - return 'thresholded_relu' + act = self.get_attr("activation").lower() + if act == "leakyrelu": + return "leaky_relu" + elif act == "thresholdedrelu": + return "thresholded_relu" else: return act # ELU activation class HardActivation(Activation): - ''' + """ Implements the hard sigmoid and tan function in keras and qkeras (Default parameters in qkeras are different, so should be configured) The hard sigmoid unction is clip(slope * x + shift, 0, 1), and the hard tanh function is 2 * hard_sigmoid - 1 - ''' + """ _expected_attributes = [ - Attribute('slope', value_type=float, default=0.2, configurable=False), - Attribute('shift', value_type=float, default=0.5, configurable=False), - TypeAttribute('slope_t'), - TypeAttribute('shift_t'), + Attribute("slope", value_type=float, default=0.2, configurable=False), + Attribute("shift", value_type=float, default=0.5, configurable=False), + TypeAttribute("slope_t"), + TypeAttribute("shift_t"), ] def initialize(self): super().initialize() - slope_prec = self.get_attr('slope_prec', FixedPrecisionType(width=16, integer=0, signed=False)) - shift_prec = self.get_attr('shift_prec', FixedPrecisionType(width=1, integer=0, signed=False)) - index = self.get_attr('index') - slope_t = NamedType(f'slope{index}_t', precision=slope_prec) - shift_t = NamedType(f'shift{index}_t', precision=shift_prec) - self.set_attr('slope_t', slope_t) - self.set_attr('shift_t', shift_t) + slope_prec = self.get_attr( + "slope_prec", FixedPrecisionType(width=16, integer=0, signed=False) + ) + shift_prec = self.get_attr( + "shift_prec", FixedPrecisionType(width=1, integer=0, signed=False) + ) + index = self.get_attr("index") + slope_t = NamedType(f"slope{index}_t", precision=slope_prec) + shift_t = NamedType(f"shift{index}_t", precision=shift_prec) + self.set_attr("slope_t", slope_t) + self.set_attr("shift_t", shift_t) class PReLU(Activation): def initialize(self): super().initialize() - self.add_weights_variable(name='alpha', var_name='a{index}') + self.add_weights_variable(name="alpha", var_name="a{index}") class Softmax(Activation): @@ -829,14 +1029,14 @@ def initialize(self): class BatchNormalization(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('n_filt', default=0), - WeightAttribute('scale'), - WeightAttribute('bias'), - TypeAttribute('scale'), - TypeAttribute('bias'), - Attribute('use_gamma', value_type=bool, default=True), - Attribute('use_beta', value_type=bool, default=True), + Attribute("n_in"), + Attribute("n_filt", default=0), + WeightAttribute("scale"), + WeightAttribute("bias"), + TypeAttribute("scale"), + TypeAttribute("bias"), + Attribute("use_gamma", value_type=bool, default=True), + Attribute("use_beta", value_type=bool, default=True), ] def initialize(self): @@ -845,16 +1045,16 @@ def initialize(self): dims = inp.dim_names self.add_output_variable(shape, dims) - gamma = self.get_attr('gamma_data') - beta = self.get_attr('beta_data') - mean = self.get_attr('mean_data') - var = self.get_attr('variance_data') + gamma = self.get_attr("gamma_data") + beta = self.get_attr("beta_data") + mean = self.get_attr("mean_data") + var = self.get_attr("variance_data") - scale = gamma / np.sqrt(var + self.get_attr('epsilon')) + scale = gamma / np.sqrt(var + self.get_attr("epsilon")) bias = beta - scale * mean - self.add_weights_variable(name='scale', var_name='s{index}', data=scale) - self.add_weights_variable(name='bias', var_name='b{index}', data=bias) + self.add_weights_variable(name="scale", var_name="s{index}", data=scale) + self.add_weights_variable(name="bias", var_name="b{index}", data=bias) class Merge(Layer): @@ -878,9 +1078,9 @@ def initialize(self): inp2 = self.get_input_variable(self.inputs[1]) assert inp1.shape == inp2.shape if len(inp1.shape) > 1: - raise Exception('ERROR: Dot of tensors with rank > 1 is not yet supported.') + raise Exception("ERROR: Dot of tensors with rank > 1 is not yet supported.") - self.add_output_variable(shape=[1], dim_names=[f'OUT_DOT_{self.index}']) + self.add_output_variable(shape=[1], dim_names=[f"OUT_DOT_{self.index}"]) class Concatenate(Merge): @@ -888,16 +1088,16 @@ def initialize(self): assert len(self.inputs) == 2 inp1 = self.get_input_variable(self.inputs[0]) inp2 = self.get_input_variable(self.inputs[1]) - axis = self.attributes['axis'] + axis = self.attributes["axis"] if axis > 0: axis -= 1 shape = inp1.shape[:] shape[axis] += inp2.shape[axis] rank = len(shape) if rank > 1: - dims = [f'OUT_CONCAT_{i}_{self.index}' for i in range(rank)] + dims = [f"OUT_CONCAT_{i}_{self.index}" for i in range(rank)] else: - dims = [f'OUT_CONCAT_{self.index}'] + dims = [f"OUT_CONCAT_{self.index}"] self.add_output_variable(shape, dims) @@ -914,217 +1114,283 @@ class Resize(Layer): def initialize(self): inp = self.get_input_variable() if len(inp.shape) == 2: # 1D -> width + chan - shape = [self.get_attr('out_width'), self.get_attr('n_chan')] if self.get_attr('data_format') == 'channels_last' else [self.get_attr('n_chan'), self.get_attr('out_width')] - dims = [f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] if self.get_attr('data_format') == 'channels_last' else [f'N_CHAN_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = ( + [self.get_attr("out_width"), self.get_attr("n_chan")] + if self.get_attr("data_format") == "channels_last" + else [self.get_attr("n_chan"), self.get_attr("out_width")] + ) + dims = ( + [f"OUT_WIDTH_{self.index}", f"N_CHAN_{self.index}"] + if self.get_attr("data_format") == "channels_last" + else [f"N_CHAN_{self.index}", f"OUT_WIDTH_{self.index}"] + ) elif len(inp.shape) == 3: # 2D -> height + width + chan - shape = [self.get_attr('out_height'), self.get_attr('out_width'), self.get_attr('n_chan')] if self.get_attr('data_format') == 'channels_last' else [self.get_attr('n_chan'), self.get_attr('out_height'), self.get_attr('out_width')] - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}', f'N_CHAN_{self.index}'] if self.get_attr('data_format') == 'channels_last' else [f'N_CHAN_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] + shape = ( + [ + self.get_attr("out_height"), + self.get_attr("out_width"), + self.get_attr("n_chan"), + ] + if self.get_attr("data_format") == "channels_last" + else [ + self.get_attr("n_chan"), + self.get_attr("out_height"), + self.get_attr("out_width"), + ] + ) + dims = ( + [ + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + f"N_CHAN_{self.index}", + ] + if self.get_attr("data_format") == "channels_last" + else [ + f"N_CHAN_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] + ) self.add_output_variable(shape, dims, precision=inp.type.precision) class Transpose(Layer): def initialize(self): inp = self.get_input_variable(self.inputs[0]) - perm = self.get_attr('perm') - self.set_attr('dim', f'{len(inp.shape)}d') + perm = self.get_attr("perm") + self.set_attr("dim", f"{len(inp.shape)}d") if len(perm) > 3: - raise Exception('ERROR: Transpose of tensors with rank > 3 is not yet supported.') + raise Exception( + "ERROR: Transpose of tensors with rank > 3 is not yet supported." + ) # ONNX double transpose specific, sometimes ONNX injects # useless double transpose layers when converting # from other frameworks if len(perm) == 1: shape = inp.shape # dummy shape - dims = ['DUMMY'] # dummy dims - self.set_attr('perm', [0]) + dims = ["DUMMY"] # dummy dims + self.set_attr("perm", [0]) else: shape = [inp.shape[i] for i in perm] - self.set_attr('perm_str', ','.join([str(i) for i in perm])) + self.set_attr("perm_str", ",".join([str(i) for i in perm])) if len(shape) == 2: - self.set_attr('perm_str', ','.join(['0'] + [str(i + 1) for i in perm])) - dims = [f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] - self.set_attr('depth', 1) - self.set_attr('height', inp.shape[0]) - self.set_attr('width', inp.shape[1]) + self.set_attr("perm_str", ",".join(["0"] + [str(i + 1) for i in perm])) + dims = [f"OUT_HEIGHT_{self.index}", f"OUT_WIDTH_{self.index}"] + self.set_attr("depth", 1) + self.set_attr("height", inp.shape[0]) + self.set_attr("width", inp.shape[1]) elif len(shape) > 2: - dims = [f'OUT_DEPTH_{self.index}', f'OUT_HEIGHT_{self.index}', f'OUT_WIDTH_{self.index}'] - self.set_attr('depth', inp.shape[0]) - self.set_attr('height', inp.shape[1]) - self.set_attr('width', inp.shape[2]) + dims = [ + f"OUT_DEPTH_{self.index}", + f"OUT_HEIGHT_{self.index}", + f"OUT_WIDTH_{self.index}", + ] + self.set_attr("depth", inp.shape[0]) + self.set_attr("height", inp.shape[1]) + self.set_attr("width", inp.shape[2]) self.add_output_variable(shape, dims, precision=inp.type.precision) class Embedding(Layer): _expected_attributes = [ - Attribute('n_in'), - Attribute('n_out'), - Attribute('vocab_size'), - WeightAttribute('embeddings'), - TypeAttribute('embeddings'), + Attribute("n_in"), + Attribute("n_out"), + Attribute("vocab_size"), + WeightAttribute("embeddings"), + TypeAttribute("embeddings"), ] def initialize(self): shape = self.get_input_variable().shape[:] - shape += [self.attributes['n_out']] + shape += [self.attributes["n_out"]] if len(shape) > 1: - dims = [f'N_LAYER_{i}_{self.index}' for i in range(1, len(shape) + 1)] + dims = [f"N_LAYER_{i}_{self.index}" for i in range(1, len(shape) + 1)] else: - dims = [f'N_LAYER_{self.index}'] + dims = [f"N_LAYER_{self.index}"] self.add_output_variable(shape, dims) - self.add_weights_variable(name='embeddings', var_name='e{index}') + self.add_weights_variable(name="embeddings", var_name="e{index}") class SimpleRNN(Layer): _expected_attributes = [ - Attribute('n_out'), - Attribute('activation', value_type=str), - Attribute('return_sequences', value_type=bool, default=False), - Attribute('return_state', value_type=bool, default=False), - ChoiceAttribute('direction', ['forward', 'backward'], default='forward'), - WeightAttribute('weight'), - WeightAttribute('bias'), - WeightAttribute('recurrent_weight'), - TypeAttribute('weight'), - TypeAttribute('bias'), - TypeAttribute('recurrent_weight'), + Attribute("n_out"), + Attribute("activation", value_type=str), + Attribute("return_sequences", value_type=bool, default=False), + Attribute("return_state", value_type=bool, default=False), + ChoiceAttribute("direction", ["forward", "backward"], default="forward"), + WeightAttribute("weight"), + WeightAttribute("bias"), + WeightAttribute("recurrent_weight"), + TypeAttribute("weight"), + TypeAttribute("bias"), + TypeAttribute("recurrent_weight"), ] def initialize(self): - if self.attributes['return_sequences']: - shape = [self.attributes['n_timesteps'], self.attributes['n_out']] - dims = [f'N_TIME_STEPS_{self.index}', f'N_OUT_{self.index}'] + if self.attributes["return_sequences"]: + shape = [self.attributes["n_timesteps"], self.attributes["n_out"]] + dims = [f"N_TIME_STEPS_{self.index}", f"N_OUT_{self.index}"] else: - shape = [self.attributes['n_out']] - dims = [f'N_OUT_{self.index}'] + shape = [self.attributes["n_out"]] + dims = [f"N_OUT_{self.index}"] self.add_output_variable(shape, dims) - if self.attributes['return_state']: - state_shape = [self.attributes['n_out']] - state_dims = [f'N_OUT_{self.index}'] + if self.attributes["return_state"]: + state_shape = [self.attributes["n_out"]] + state_dims = [f"N_OUT_{self.index}"] self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[1], var_name='layer{index}_h', type_name='layer{index}_h_t' + state_shape, + state_dims, + out_name=self.outputs[1], + var_name="layer{index}_h", + type_name="layer{index}_h_t", ) self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[2], var_name='layer{index}_c', type_name='layer{index}_c_t' + state_shape, + state_dims, + out_name=self.outputs[2], + var_name="layer{index}_c", + type_name="layer{index}_c_t", ) # weights self.add_weights() # recurrent weights - self.add_weights_variable(name='recurrent_weight', var_name='wr{index}') + self.add_weights_variable(name="recurrent_weight", var_name="wr{index}") # biases - self.add_weights_variable(name='bias', var_name='b{index}') + self.add_weights_variable(name="bias", var_name="b{index}") class LSTM(Layer): _expected_attributes = [ - Attribute('n_out'), - Attribute('activation', value_type=str), - Attribute('recurrent_activation', value_type=str), - Attribute('return_sequences', value_type=bool, default=False), - Attribute('return_state', value_type=bool, default=False), - ChoiceAttribute('direction', ['forward', 'backward'], default='forward'), - Attribute('time_major', value_type=bool, default=False), - WeightAttribute('weight'), - WeightAttribute('bias'), - WeightAttribute('recurrent_weight'), - WeightAttribute('recurrent_bias'), - TypeAttribute('weight'), - TypeAttribute('bias'), - TypeAttribute('recurrent_weight'), - TypeAttribute('recurrent_bias'), + Attribute("n_out"), + Attribute("activation", value_type=str), + Attribute("recurrent_activation", value_type=str), + Attribute("return_sequences", value_type=bool, default=False), + Attribute("return_state", value_type=bool, default=False), + ChoiceAttribute("direction", ["forward", "backward"], default="forward"), + Attribute("time_major", value_type=bool, default=False), + WeightAttribute("weight"), + WeightAttribute("bias"), + WeightAttribute("recurrent_weight"), + WeightAttribute("recurrent_bias"), + TypeAttribute("weight"), + TypeAttribute("bias"), + TypeAttribute("recurrent_weight"), + TypeAttribute("recurrent_bias"), ] def initialize(self): - if self.attributes['return_sequences']: - shape = [self.attributes['n_timesteps'], self.attributes['n_out']] - dims = [f'N_TIME_STEPS_{self.index}', f'N_OUT_{self.index}'] + if self.attributes["return_sequences"]: + shape = [self.attributes["n_timesteps"], self.attributes["n_out"]] + dims = [f"N_TIME_STEPS_{self.index}", f"N_OUT_{self.index}"] else: - shape = [self.attributes['n_out']] - dims = [f'N_OUT_{self.index}'] + shape = [self.attributes["n_out"]] + dims = [f"N_OUT_{self.index}"] self.add_output_variable(shape, dims) - if self.attributes['return_state']: - state_shape = [self.attributes['n_out']] - state_dims = [f'N_OUT_{self.index}'] + if self.attributes["return_state"]: + state_shape = [self.attributes["n_out"]] + state_dims = [f"N_OUT_{self.index}"] self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[1], var_name='layer{index}_h', type_name='layer{index}_h_t' + state_shape, + state_dims, + out_name=self.outputs[1], + var_name="layer{index}_h", + type_name="layer{index}_h_t", ) self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[2], var_name='layer{index}_c', type_name='layer{index}_c_t' + state_shape, + state_dims, + out_name=self.outputs[2], + var_name="layer{index}_c", + type_name="layer{index}_c_t", ) # weights self.add_weights() # recurrent weights - recurrent_weight = self.get_attr('recurrent_weight_data') - self.add_weights_variable(name='recurrent_weight', var_name='wr{index}', data=recurrent_weight) + recurrent_weight = self.get_attr("recurrent_weight_data") + self.add_weights_variable( + name="recurrent_weight", var_name="wr{index}", data=recurrent_weight + ) # biases - self.add_weights_variable(name='bias', var_name='b{index}') + self.add_weights_variable(name="bias", var_name="b{index}") recurrent_bias = np.zeros(recurrent_weight.shape[1]) - self.add_weights_variable(name='recurrent_bias', var_name='br{index}', data=recurrent_bias) + self.add_weights_variable( + name="recurrent_bias", var_name="br{index}", data=recurrent_bias + ) class GRU(Layer): _expected_attributes = [ - Attribute('n_out'), - Attribute('activation', value_type=str), - Attribute('recurrent_activation', value_type=str), - Attribute('return_sequences', value_type=bool, default=False), - Attribute('return_state', value_type=bool, default=False), - ChoiceAttribute('direction', ['forward', 'backward'], default='forward'), - Attribute('time_major', value_type=bool, default=False), - ChoiceAttribute('apply_reset_gate', ['before', 'after'], default='after'), - WeightAttribute('weight'), - WeightAttribute('bias'), - WeightAttribute('recurrent_weight'), - WeightAttribute('recurrent_bias'), - TypeAttribute('weight'), - TypeAttribute('bias'), - TypeAttribute('recurrent_weight'), - TypeAttribute('recurrent_bias'), + Attribute("n_out"), + Attribute("activation", value_type=str), + Attribute("recurrent_activation", value_type=str), + Attribute("return_sequences", value_type=bool, default=False), + Attribute("return_state", value_type=bool, default=False), + ChoiceAttribute("direction", ["forward", "backward"], default="forward"), + Attribute("time_major", value_type=bool, default=False), + ChoiceAttribute("apply_reset_gate", ["before", "after"], default="after"), + WeightAttribute("weight"), + WeightAttribute("bias"), + WeightAttribute("recurrent_weight"), + WeightAttribute("recurrent_bias"), + TypeAttribute("weight"), + TypeAttribute("bias"), + TypeAttribute("recurrent_weight"), + TypeAttribute("recurrent_bias"), ] def initialize(self): - if self.attributes['return_sequences']: - shape = [self.attributes['n_timesteps'], self.attributes['n_out']] - dims = [f'N_TIME_STEPS_{self.index}', f'N_OUT_{self.index}'] + if self.attributes["return_sequences"]: + shape = [self.attributes["n_timesteps"], self.attributes["n_out"]] + dims = [f"N_TIME_STEPS_{self.index}", f"N_OUT_{self.index}"] else: - shape = [self.attributes['n_out']] - dims = [f'N_OUT_{self.index}'] + shape = [self.attributes["n_out"]] + dims = [f"N_OUT_{self.index}"] self.add_output_variable(shape, dims) - if self.attributes['return_state']: - state_shape = [self.attributes['n_out']] - state_dims = [f'N_OUT_{self.index}'] + if self.attributes["return_state"]: + state_shape = [self.attributes["n_out"]] + state_dims = [f"N_OUT_{self.index}"] self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[1], var_name='layer{index}_h', type_name='layer{index}_h_t' + state_shape, + state_dims, + out_name=self.outputs[1], + var_name="layer{index}_h", + type_name="layer{index}_h_t", ) self.add_output_variable( - state_shape, state_dims, out_name=self.outputs[2], var_name='layer{index}_c', type_name='layer{index}_c_t' + state_shape, + state_dims, + out_name=self.outputs[2], + var_name="layer{index}_c", + type_name="layer{index}_c_t", ) # weights self.add_weights() # recurrent weights - self.add_weights_variable(name='recurrent_weight', var_name='wr{index}') + self.add_weights_variable(name="recurrent_weight", var_name="wr{index}") # biases - self.add_weights_variable(name='bias', var_name='b{index}') - self.add_weights_variable(name='recurrent_bias', var_name='br{index}') + self.add_weights_variable(name="bias", var_name="b{index}") + self.add_weights_variable(name="recurrent_bias", var_name="br{index}") class GarNet(Layer): @@ -1132,89 +1398,119 @@ class GarNet(Layer): def initialize(self): reuse_factor = self.model.config.get_reuse_factor(self) - if self.attributes['n_vertices'] % reuse_factor != 0: + if self.attributes["n_vertices"] % reuse_factor != 0: raise Exception( - 'GarNet vertex loop has no bound check;' - f'number of vertices must be divisible by the reuse factor ({reuse_factor}).' + "GarNet vertex loop has no bound check;" + f"number of vertices must be divisible by the reuse factor ({reuse_factor})." ) self._initialize_transforms() - if self.attributes['collapse']: + if self.attributes["collapse"]: shape = [self._output_features] - dims = [f'OUT_FEATURES_{self.index}'] + dims = [f"OUT_FEATURES_{self.index}"] else: - shape = [self.attributes['n_vertices'], self._output_features] - dims = [f'VERTICES_{self.index}', f'OUT_FEATURES_{self.index}'] + shape = [self.attributes["n_vertices"], self._output_features] + dims = [f"VERTICES_{self.index}", f"OUT_FEATURES_{self.index}"] self.add_output_variable(shape, dims) def _initialize_transforms(self): - n_propagate = self.attributes['n_propagate'] - n_aggregators = self.attributes['n_aggregators'] - n_out_features = self.attributes['n_out_features'] + n_propagate = self.attributes["n_propagate"] + n_aggregators = self.attributes["n_aggregators"] + n_out_features = self.attributes["n_out_features"] if self.ref_impl: weights_source = [ - ('input_transform', 'FLR', 'kernel'), - ('input_transform', 'FLR', 'bias'), - ('aggregator_distance', 'S', 'kernel'), - ('aggregator_distance', 'S', 'bias'), - ('output_transform', 'Fout', 'kernel'), - ('output_transform', 'Fout', 'bias'), + ("input_transform", "FLR", "kernel"), + ("input_transform", "FLR", "bias"), + ("aggregator_distance", "S", "kernel"), + ("aggregator_distance", "S", "bias"), + ("output_transform", "Fout", "kernel"), + ("output_transform", "Fout", "bias"), ] else: - quantize = self.get_attr('quantizer') is not None - kernel, bias = self._make_input_transform_weights(n_propagate, n_aggregators, n_out_features, quantize=quantize) + quantize = self.get_attr("quantizer") is not None + kernel, bias = self._make_input_transform_weights( + n_propagate, n_aggregators, n_out_features, quantize=quantize + ) self._add_variable( - 'input_transform_weights', 'input_transform_w{index}', kernel, frac_width=10, quantize=quantize + "input_transform_weights", + "input_transform_w{index}", + kernel, + frac_width=10, + quantize=quantize, + ) + self._add_variable( + "input_transform_biases", + "input_transform_b{index}", + bias, + frac_width=10, + quantize=quantize, ) - self._add_variable('input_transform_biases', 'input_transform_b{index}', bias, frac_width=10, quantize=quantize) # dummy - self.add_weights_variable(name='output_transform_weights', var_name='output_transform_w{index}', data=np.ones(1)) + self.add_weights_variable( + name="output_transform_weights", + var_name="output_transform_w{index}", + data=np.ones(1), + ) weights_source = [ - ('aggregator_distance', 'S', 'kernel'), - ('aggregator_distance', 'S', 'bias'), - ('output_transform', 'Fout', 'bias'), + ("aggregator_distance", "S", "kernel"), + ("aggregator_distance", "S", "bias"), + ("output_transform", "Fout", "bias"), ] for op_name, lname, wtype in weights_source: - data = self.get_attr(f'{lname}_{wtype}_data') - if wtype == 'kernel': + data = self.get_attr(f"{lname}_{wtype}_data") + if wtype == "kernel": data = data.transpose((1, 0)) - vtype = 'weights' + vtype = "weights" else: - vtype = 'biases' + vtype = "biases" - name = f'{op_name}_{vtype}' - var_name = f'{op_name}_{vtype[0]}{{index}}' + name = f"{op_name}_{vtype}" + var_name = f"{op_name}_{vtype[0]}{{index}}" self._add_variable(name, var_name, data, frac_width=10, quantize=False) - self._output_features = self.attributes['n_out_features'] + self._output_features = self.attributes["n_out_features"] - def _make_input_transform_weights(self, n_propagate, n_aggregators, n_out_features, quantize=False, sublayer=''): + def _make_input_transform_weights( + self, n_propagate, n_aggregators, n_out_features, quantize=False, sublayer="" + ): # Due to linearity of the input transform, input weights and biases can be contracted away at conversion time output_transform_kernel = self.get_attr( - f'Fout{sublayer}_kernel_data' + f"Fout{sublayer}_kernel_data" ) # [(n_aggregators, n_propagate), n_out_features] - output_transform_kernel = output_transform_kernel.reshape((n_aggregators, n_propagate, n_out_features)) + output_transform_kernel = output_transform_kernel.reshape( + (n_aggregators, n_propagate, n_out_features) + ) if quantize: - output_transform_kernel = self.get_attr('quantizer')(output_transform_kernel) + output_transform_kernel = self.get_attr("quantizer")( + output_transform_kernel + ) - input_transform_kernel = self.get_attr(f'FLR{sublayer}_kernel_data') # [n_in_features, n_propagate] + input_transform_kernel = self.get_attr( + f"FLR{sublayer}_kernel_data" + ) # [n_in_features, n_propagate] if quantize: - input_transform_kernel = self.get_attr('quantizer')(input_transform_kernel) - data = np.dot(input_transform_kernel, output_transform_kernel) # [n_in_features, n_aggregators, n_out_features] + input_transform_kernel = self.get_attr("quantizer")(input_transform_kernel) + data = np.dot( + input_transform_kernel, output_transform_kernel + ) # [n_in_features, n_aggregators, n_out_features] kernel = data.transpose((2, 1, 0)) - input_transform_bias = self.get_attr(f'FLR{sublayer}_bias_data') # [n_propagate] + input_transform_bias = self.get_attr( + f"FLR{sublayer}_bias_data" + ) # [n_propagate] if quantize: - input_transform_bias = self.get_attr('quantizer')(input_transform_bias) - data = np.dot(input_transform_bias, output_transform_kernel) # [n_aggregators, n_out_features] + input_transform_bias = self.get_attr("quantizer")(input_transform_bias) + data = np.dot( + input_transform_bias, output_transform_kernel + ) # [n_aggregators, n_out_features] bias = data.transpose((1, 0)) return kernel, bias @@ -1232,152 +1528,181 @@ def _add_variable(self, name, var_name, data, frac_width=10, quantize=False): else: width = int_width + frac_width precision = FixedPrecisionType( - width=width, integer=int_width, signed=signed, rounding_mode='AP_RND', saturation_mode='AP_SAT' + width=width, + integer=int_width, + signed=signed, + rounding_mode="AP_RND", + saturation_mode="AP_SAT", ) - self.add_weights_variable(name=name, var_name=var_name, data=data, precision=precision) + self.add_weights_variable( + name=name, var_name=var_name, data=data, precision=precision + ) class GarNetStack(GarNet): def _initialize_transforms(self): self._sublayer_weights = [] - quantize = self.get_attr('quantizer') is not None + quantize = self.get_attr("quantizer") is not None - for il in range(self.attributes['n_sublayers']): + for il in range(self.attributes["n_sublayers"]): sublayer_weights = {} - n_aggregators = self.attributes['n_aggregators'][il] - n_out_features = self.attributes['n_out_features'][il] - n_propagate = self.attributes['n_propagate'][il] + n_aggregators = self.attributes["n_aggregators"][il] + n_out_features = self.attributes["n_out_features"][il] + n_propagate = self.attributes["n_propagate"][il] kernel, bias = self._make_input_transform_weights( - n_propagate, n_aggregators, n_out_features, quantize=quantize, sublayer=il + n_propagate, + n_aggregators, + n_out_features, + quantize=quantize, + sublayer=il, ) - name = f'input_transform_{il}_weights' - self._add_variable(name, f'input_transform_{il}_w{{index}}', kernel, frac_width=10, quantize=quantize) - sublayer_weights['input_transform_weights'] = self.weights[name] + name = f"input_transform_{il}_weights" + self._add_variable( + name, + f"input_transform_{il}_w{{index}}", + kernel, + frac_width=10, + quantize=quantize, + ) + sublayer_weights["input_transform_weights"] = self.weights[name] - name = f'input_transform_{il}_biases' - self._add_variable(name, f'input_transform_{il}_b{{index}}', bias, frac_width=10, quantize=quantize) - sublayer_weights['input_transform_biases'] = self.weights[name] + name = f"input_transform_{il}_biases" + self._add_variable( + name, + f"input_transform_{il}_b{{index}}", + bias, + frac_width=10, + quantize=quantize, + ) + sublayer_weights["input_transform_biases"] = self.weights[name] weights_source = [ - ('aggregator_distance', f'S{il}', 'kernel'), - ('aggregator_distance', f'S{il}', 'bias'), - ('output_transform', f'Fout{il}', 'bias'), + ("aggregator_distance", f"S{il}", "kernel"), + ("aggregator_distance", f"S{il}", "bias"), + ("output_transform", f"Fout{il}", "bias"), ] for op_name, lname, wtype in weights_source: - data = self.get_attr(f'{lname}_{wtype}_data') - if wtype == 'kernel': + data = self.get_attr(f"{lname}_{wtype}_data") + if wtype == "kernel": data = data.transpose((1, 0)) - vtype = 'weights' + vtype = "weights" else: - vtype = 'biases' + vtype = "biases" - name = f'{op_name}_{il}_{vtype}' - var_name = f'{op_name}_{il}_{vtype[0]}{{index}}' + name = f"{op_name}_{il}_{vtype}" + var_name = f"{op_name}_{il}_{vtype[0]}{{index}}" self._add_variable(name, var_name, data, frac_width=10, quantize=False) - sublayer_weights[f'{op_name}_{vtype}'] = self.weights[name] + sublayer_weights[f"{op_name}_{vtype}"] = self.weights[name] self._sublayer_weights.append(sublayer_weights) - self._output_features = self.attributes['n_out_features'][-1] + self._output_features = self.attributes["n_out_features"][-1] class LayerGroup(Layer): _expected_attributes = [ - Attribute('layer_list', value_type=list), - Attribute('input_layers', value_type=list), - Attribute('output_layers', value_type=list), - Attribute('data_reader', value_type=object), - Attribute('output_shape', value_type=list), + Attribute("layer_list", value_type=list), + Attribute("input_layers", value_type=list), + Attribute("output_layers", value_type=list), + Attribute("data_reader", value_type=object), + Attribute("output_shape", value_type=list), ] def initialize(self): - shape = self.get_attr('output_shape') + shape = self.get_attr("output_shape") if shape[0] is None: shape.pop(0) - dims = [f'N_INPUT_{self.index}_{i+1}' for i in range(len(shape))] + dims = [f"N_INPUT_{self.index}_{i+1}" for i in range(len(shape))] self.add_output_variable(shape, dims) class SymbolicExpression(Layer): _expected_attributes = [ - Attribute('expression', value_type=list), - Attribute('n_symbols'), - Attribute('lut_functions', value_type=list, default=[]), + Attribute("expression", value_type=list), + Attribute("n_symbols"), + Attribute("lut_functions", value_type=list, default=[]), ] def initialize(self): - self.set_attr('expr_t', NamedType(*reversed(self.model.config.get_precision(self, 'expr')))) - self.add_output_variable([len(self.get_attr('expression'))], [f'N_OUTPUTS_{self.index}'], var_name='y') + self.set_attr( + "expr_t", + NamedType(*reversed(self.model.config.get_precision(self, "expr"))), + ) + self.add_output_variable( + [len(self.get_attr("expression"))], + [f"N_OUTPUTS_{self.index}"], + var_name="y", + ) layer_map = { - 'Input': Input, - 'InputLayer': Input, - 'Activation': Activation, - 'QActivation': Activation, - 'LeakyReLU': ParametrizedActivation, - 'ThresholdedReLU': ParametrizedActivation, - 'ELU': ParametrizedActivation, - 'PReLU': PReLU, - 'Softmax': Softmax, - 'TernaryTanh': TernaryTanh, - 'HardActivation': HardActivation, - 'Reshape': Reshape, - 'Dense': Dense, - 'BinaryDense': Dense, - 'TernaryDense': Dense, - 'QDense': Dense, - 'Conv1D': Conv1D, - 'QConv1D': Conv1D, - 'Conv2D': Conv2D, - 'BinaryConv2D': Conv2D, - 'QConv2D': Conv2D, - 'QConv2DBatchnorm': Conv2DBatchnorm, - 'SeparableConv1D': SeparableConv1D, - 'QSeparableConv1D': SeparableConv1D, - 'DepthwiseConv1D': DepthwiseConv1D, - 'SeparableConv2D': SeparableConv2D, - 'QSeparableConv2D': SeparableConv2D, - 'DepthwiseConv2D': DepthwiseConv2D, - 'QDepthwiseConv2D': DepthwiseConv2D, - 'BatchNormalization': BatchNormalization, - 'QBatchNormalization': BatchNormalization, - 'MaxPooling1D': Pooling1D, - 'AveragePooling1D': Pooling1D, - 'MaxPooling2D': Pooling2D, - 'AveragePooling2D': Pooling2D, - 'GlobalMaxPooling1D': GlobalPooling1D, - 'GlobalAveragePooling1D': GlobalPooling1D, - 'GlobalMaxPooling2D': GlobalPooling2D, - 'GlobalAveragePooling2D': GlobalPooling2D, - 'ZeroPadding1D': ZeroPadding1D, - 'ZeroPadding2D': ZeroPadding2D, - 'Merge': Merge, - 'Dot': Dot, - 'Concatenate': Concatenate, - 'Resize': Resize, - 'UpSampling1D': Resize, - 'UpSampling2D': Resize, - 'Upsample': Resize, - 'Transpose': Transpose, - 'Embedding': Embedding, - 'SimpleRNN': SimpleRNN, - 'LSTM': LSTM, - 'GRU': GRU, - 'GarNet': GarNet, - 'GarNetStack': GarNetStack, - 'LayerGroup': LayerGroup, - 'SymbolicExpression': SymbolicExpression, + "Input": Input, + "InputLayer": Input, + "Activation": Activation, + "QActivation": Activation, + "LeakyReLU": ParametrizedActivation, + "ThresholdedReLU": ParametrizedActivation, + "ELU": ParametrizedActivation, + "PReLU": PReLU, + "Softmax": Softmax, + "TernaryTanh": TernaryTanh, + "HardActivation": HardActivation, + "Reshape": Reshape, + "Dense": Dense, + "BinaryDense": Dense, + "TernaryDense": Dense, + "QDense": Dense, + "Conv1D": Conv1D, + "QConv1D": Conv1D, + "Conv2D": Conv2D, + "BinaryConv2D": Conv2D, + "QConv2D": Conv2D, + "QConv2DBatchnorm": Conv2DBatchnorm, + "SeparableConv1D": SeparableConv1D, + "QSeparableConv1D": SeparableConv1D, + "DepthwiseConv1D": DepthwiseConv1D, + "SeparableConv2D": SeparableConv2D, + "QSeparableConv2D": SeparableConv2D, + "DepthwiseConv2D": DepthwiseConv2D, + "QDepthwiseConv2D": DepthwiseConv2D, + "BatchNormalization": BatchNormalization, + "QBatchNormalization": BatchNormalization, + "MaxPooling1D": Pooling1D, + "AveragePooling1D": Pooling1D, + "MaxPooling2D": Pooling2D, + "AveragePooling2D": Pooling2D, + "GlobalMaxPooling1D": GlobalPooling1D, + "GlobalAveragePooling1D": GlobalPooling1D, + "GlobalMaxPooling2D": GlobalPooling2D, + "GlobalAveragePooling2D": GlobalPooling2D, + "ZeroPadding1D": ZeroPadding1D, + "ZeroPadding2D": ZeroPadding2D, + "Merge": Merge, + "Dot": Dot, + "Concatenate": Concatenate, + "Resize": Resize, + "UpSampling1D": Resize, + "UpSampling2D": Resize, + "Upsample": Resize, + "Transpose": Transpose, + "Embedding": Embedding, + "SimpleRNN": SimpleRNN, + "LSTM": LSTM, + "GRU": GRU, + "GarNet": GarNet, + "GarNetStack": GarNetStack, + "LayerGroup": LayerGroup, + "SymbolicExpression": SymbolicExpression, # TensorFlow-specific layers: - 'BiasAdd': BiasAdd, + "BiasAdd": BiasAdd, } From d2acbad424c69bf01c9738d1c98436d009209203 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:21:22 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit hooks --- hls4ml/converters/pytorch/reshape.py | 8 +- hls4ml/model/layers.py | 110 +++++++-------------------- 2 files changed, 29 insertions(+), 89 deletions(-) diff --git a/hls4ml/converters/pytorch/reshape.py b/hls4ml/converters/pytorch/reshape.py index 971713b52d..67387bb523 100644 --- a/hls4ml/converters/pytorch/reshape.py +++ b/hls4ml/converters/pytorch/reshape.py @@ -138,9 +138,7 @@ def parse_flatten_layer( end_dim = end_dim + 1 layer["target_shape"] = ( - input_shapes[0][0:start_dim] - + [np.prod(input_shapes[0][start_dim:end_dim])] - + input_shapes[0][end_dim:] + input_shapes[0][0:start_dim] + [np.prod(input_shapes[0][start_dim:end_dim])] + input_shapes[0][end_dim:] ) output_shape = layer["target_shape"] @@ -166,9 +164,7 @@ def handle_upsample( layer["data_format"] = "channels_first" # Pytorch default (can't change) # Input info - (layer["in_height"], layer["in_width"], layer["n_chan"]) = parse_data_format( - input_shapes[0], "channels_first" - ) # K + (layer["in_height"], layer["in_width"], layer["n_chan"]) = parse_data_format(input_shapes[0], "channels_first") # K layer["height_factor"] = int(class_object.scale_factor) layer["width_factor"] = int(class_object.scale_factor) diff --git a/hls4ml/model/layers.py b/hls4ml/model/layers.py index 60bded9e50..e7a7e9025d 100644 --- a/hls4ml/model/layers.py +++ b/hls4ml/model/layers.py @@ -61,14 +61,10 @@ class Layer: def expected_attributes(cls): """Returns the expected attributes of a class.""" all_attributes = [] - for base_cls in reversed( - cls.mro() - ): # Iterate over all base classes in the hierarchy + for base_cls in reversed(cls.mro()): # Iterate over all base classes in the hierarchy if cls == base_cls: # Skip adding attributes from self continue - if hasattr( - base_cls, "_expected_attributes" - ): # Only consider classes with '_expected_attributes' defined + if hasattr(base_cls, "_expected_attributes"): # Only consider classes with '_expected_attributes' defined all_attributes.extend(base_cls._expected_attributes) if "_expected_attributes" in cls.__dict__: # Add new attributes defined in the class @@ -114,9 +110,7 @@ def __init__(self, model, name, attributes, inputs, outputs=None): if config_key.endswith("_t") and isinstance( config_value, str ): # TODO maybe move this to __setitem__ of AttributeDict? - precision = self.model.config.backend.convert_precision_string( - config_value - ) + precision = self.model.config.backend.convert_precision_string(config_value) config_value = NamedType(self.name + "_" + config_key, precision) self.attributes[config_key] = config_value @@ -171,9 +165,7 @@ def _validate_attributes(self): if isinstance(attr, TypeAttribute): self.set_attr( attr_name, - self._wrap_precision_to_type( - self.name + "_" + attr_name, attr.default - ), + self._wrap_precision_to_type(self.name + "_" + attr_name, attr.default), ) else: self.set_attr(attr_name, attr.default) @@ -190,15 +182,9 @@ def _wrap_precision_to_type(self, name, precision): return NamedType(name=name, precision=precision) def _set_accum_t(self): - has_accum_t = any( - a - for a in self.expected_attributes - if a.name == "accum_t" and isinstance(a, TypeAttribute) - ) + has_accum_t = any(a for a in self.expected_attributes if a.name == "accum_t" and isinstance(a, TypeAttribute)) if has_accum_t: - accum_t = NamedType( - *reversed(self.model.config.get_precision(self, "accum")) - ) + accum_t = NamedType(*reversed(self.model.config.get_precision(self, "accum"))) self.set_attr("accum_t", accum_t) def get_input_node(self, input_name=None): @@ -207,9 +193,7 @@ def get_input_node(self, input_name=None): input_name = self.inputs[0] else: return None - nodes = [ - node for node in self.model.graph.values() if input_name in node.outputs - ] + nodes = [node for node in self.model.graph.values() if input_name in node.outputs] if len(nodes) == 0: return None else: @@ -403,9 +387,7 @@ def initialize(self): default_type_name = f"input{self.index}_t" type_name = self.attributes.get("type_name", default_type_name) precision, _ = self.model.config.get_precision(self, var="result") - self.add_output_variable( - shape, dims, var_name=self.name, type_name=type_name, precision=precision - ) + self.add_output_variable(shape, dims, var_name=self.name, type_name=type_name, precision=precision) class Reshape(Layer): @@ -423,9 +405,7 @@ def initialize(self): if shape_node: target_shape = shape_node.value[1:] else: - raise RuntimeError( - "Reshape for ONNX requires the target shape to be a second input." - ) + raise RuntimeError("Reshape for ONNX requires the target shape to be a second input.") # remove Nones -- is this ever triggered? if target_shape[0] is None: @@ -659,24 +639,16 @@ def _get_folded_weights(self): def initialize(self): super().initialize() folded_weights, folded_bias = self._get_folded_weights() - if self.model.config.is_resource_strategy( - self - ) and self.model.config.backend.name in [ + if self.model.config.is_resource_strategy(self) and self.model.config.backend.name in [ "Vivado", "VivadoAccelerator", ]: - self.weights["weight"].data_unquantized = np.transpose( - folded_weights, axes=[3, 0, 1, 2] - ) - self.weights["weight"].data = self.get_attr("weight_quantizer")( - self.weights["weight"].data_unquantized - ) + self.weights["weight"].data_unquantized = np.transpose(folded_weights, axes=[3, 0, 1, 2]) + self.weights["weight"].data = self.get_attr("weight_quantizer")(self.weights["weight"].data_unquantized) else: self.weights["weight"].data_unquantized = folded_weights - self.weights["weight"].data = self.get_attr("weight_quantizer")( - folded_weights - ) + self.weights["weight"].data = self.get_attr("weight_quantizer")(folded_weights) self.weights["bias"].data_unquantized = folded_bias bias_q = self.get_attr("bias_quantizer") if bias_q is not None: @@ -998,12 +970,8 @@ class HardActivation(Activation): def initialize(self): super().initialize() - slope_prec = self.get_attr( - "slope_prec", FixedPrecisionType(width=16, integer=0, signed=False) - ) - shift_prec = self.get_attr( - "shift_prec", FixedPrecisionType(width=1, integer=0, signed=False) - ) + slope_prec = self.get_attr("slope_prec", FixedPrecisionType(width=16, integer=0, signed=False)) + shift_prec = self.get_attr("shift_prec", FixedPrecisionType(width=1, integer=0, signed=False)) index = self.get_attr("index") slope_t = NamedType(f"slope{index}_t", precision=slope_prec) shift_t = NamedType(f"shift{index}_t", precision=shift_prec) @@ -1161,9 +1129,7 @@ def initialize(self): self.set_attr("dim", f"{len(inp.shape)}d") if len(perm) > 3: - raise Exception( - "ERROR: Transpose of tensors with rank > 3 is not yet supported." - ) + raise Exception("ERROR: Transpose of tensors with rank > 3 is not yet supported.") # ONNX double transpose specific, sometimes ONNX injects # useless double transpose layers when converting @@ -1321,17 +1287,13 @@ def initialize(self): # recurrent weights recurrent_weight = self.get_attr("recurrent_weight_data") - self.add_weights_variable( - name="recurrent_weight", var_name="wr{index}", data=recurrent_weight - ) + self.add_weights_variable(name="recurrent_weight", var_name="wr{index}", data=recurrent_weight) # biases self.add_weights_variable(name="bias", var_name="b{index}") recurrent_bias = np.zeros(recurrent_weight.shape[1]) - self.add_weights_variable( - name="recurrent_bias", var_name="br{index}", data=recurrent_bias - ) + self.add_weights_variable(name="recurrent_bias", var_name="br{index}", data=recurrent_bias) class GRU(Layer): @@ -1432,9 +1394,7 @@ def _initialize_transforms(self): else: quantize = self.get_attr("quantizer") is not None - kernel, bias = self._make_input_transform_weights( - n_propagate, n_aggregators, n_out_features, quantize=quantize - ) + kernel, bias = self._make_input_transform_weights(n_propagate, n_aggregators, n_out_features, quantize=quantize) self._add_variable( "input_transform_weights", @@ -1478,39 +1438,25 @@ def _initialize_transforms(self): self._output_features = self.attributes["n_out_features"] - def _make_input_transform_weights( - self, n_propagate, n_aggregators, n_out_features, quantize=False, sublayer="" - ): + def _make_input_transform_weights(self, n_propagate, n_aggregators, n_out_features, quantize=False, sublayer=""): # Due to linearity of the input transform, input weights and biases can be contracted away at conversion time output_transform_kernel = self.get_attr( f"Fout{sublayer}_kernel_data" ) # [(n_aggregators, n_propagate), n_out_features] - output_transform_kernel = output_transform_kernel.reshape( - (n_aggregators, n_propagate, n_out_features) - ) + output_transform_kernel = output_transform_kernel.reshape((n_aggregators, n_propagate, n_out_features)) if quantize: - output_transform_kernel = self.get_attr("quantizer")( - output_transform_kernel - ) + output_transform_kernel = self.get_attr("quantizer")(output_transform_kernel) - input_transform_kernel = self.get_attr( - f"FLR{sublayer}_kernel_data" - ) # [n_in_features, n_propagate] + input_transform_kernel = self.get_attr(f"FLR{sublayer}_kernel_data") # [n_in_features, n_propagate] if quantize: input_transform_kernel = self.get_attr("quantizer")(input_transform_kernel) - data = np.dot( - input_transform_kernel, output_transform_kernel - ) # [n_in_features, n_aggregators, n_out_features] + data = np.dot(input_transform_kernel, output_transform_kernel) # [n_in_features, n_aggregators, n_out_features] kernel = data.transpose((2, 1, 0)) - input_transform_bias = self.get_attr( - f"FLR{sublayer}_bias_data" - ) # [n_propagate] + input_transform_bias = self.get_attr(f"FLR{sublayer}_bias_data") # [n_propagate] if quantize: input_transform_bias = self.get_attr("quantizer")(input_transform_bias) - data = np.dot( - input_transform_bias, output_transform_kernel - ) # [n_aggregators, n_out_features] + data = np.dot(input_transform_bias, output_transform_kernel) # [n_aggregators, n_out_features] bias = data.transpose((1, 0)) return kernel, bias @@ -1535,9 +1481,7 @@ def _add_variable(self, name, var_name, data, frac_width=10, quantize=False): saturation_mode="AP_SAT", ) - self.add_weights_variable( - name=name, var_name=var_name, data=data, precision=precision - ) + self.add_weights_variable(name=name, var_name=var_name, data=data, precision=precision) class GarNetStack(GarNet):