From 2a49b6052c857fc706fb79d2d04dd79d4725e164 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 12:36:04 +0100 Subject: [PATCH 01/71] Move replica loop into generate_nn function --- n3fit/src/n3fit/model_gen.py | 70 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index ae6ed01182..6ca13d463b 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -670,7 +670,6 @@ def pdfNN_layer_generator( sumrule_layer = lambda x: x # Only these layers change from replica to replica: - nn_replicas = [] preprocessing_factor_replicas = [] for i_replica, replica_seed in enumerate(seed): preprocessing_factor_replicas.append( @@ -682,21 +681,19 @@ def pdfNN_layer_generator( large_x=not subtract_one, ) ) - nn_replicas.append( - generate_nn( - layer_type=layer_type, - input_dimensions=nn_input_dimensions, - nodes=nodes, - activations=activations, - initializer_name=initializer_name, - replica_seed=replica_seed, - dropout=dropout, - regularizer=regularizer, - regularizer_args=regularizer_args, - last_layer_nodes=last_layer_nodes, - name=f"NN_{i_replica}", - ) - ) + + nn_replicas = generate_nn( + layer_type=layer_type, + input_dimensions=nn_input_dimensions, + nodes=nodes, + activations=activations, + initializer_name=initializer_name, + replica_seeds=seed, + dropout=dropout, + regularizer=regularizer, + regularizer_args=regularizer_args, + last_layer_nodes=last_layer_nodes, + ) # Apply NN layers for all replicas to a given input grid def neural_network_replicas(x, postfix=""): @@ -784,40 +781,41 @@ def generate_nn( nodes: List[int], activations: List[str], initializer_name: str, - replica_seed: int, + replica_seeds: List[int], dropout: float, regularizer: str, regularizer_args: dict, last_layer_nodes: int, - name: str, ) -> MetaModel: """ Create the part of the model that contains all of the actual neural network layers. """ + x = Input(shape=(None, input_dimensions), batch_size=1, name='xgrids_processed') + common_args = { 'nodes_in': input_dimensions, 'nodes': nodes, 'activations': activations, 'initializer_name': initializer_name, - 'seed': replica_seed, } - if layer_type == "dense": - reg = regularizer_selector(regularizer, **regularizer_args) - list_of_pdf_layers = generate_dense_network( - **common_args, dropout_rate=dropout, regularizer=reg - ) - elif layer_type == "dense_per_flavour": - list_of_pdf_layers = generate_dense_per_flavour_network( - **common_args, basis_size=last_layer_nodes - ) - # Note: using a Sequential model would be more appropriate, but it would require - # creating a MetaSequential model. - x = Input(shape=(None, input_dimensions), batch_size=1, name='xgrids_processed') - pdf = x - for layer in list_of_pdf_layers: - pdf = layer(pdf) + models = [] + for i_replica, replica_seed in enumerate(replica_seeds): + if layer_type == "dense": + reg = regularizer_selector(regularizer, **regularizer_args) + list_of_pdf_layers = generate_dense_network( + **common_args, dropout_rate=dropout, regularizer=reg, seed=replica_seed + ) + elif layer_type == "dense_per_flavour": + list_of_pdf_layers = generate_dense_per_flavour_network( + **common_args, basis_size=last_layer_nodes, seed=replica_seed + ) + + pdf = x + for layer in list_of_pdf_layers: + pdf = layer(pdf) + + models.append(MetaModel({'NN_input': x}, pdf, name=f"NN_{i_replica}")) - model = MetaModel({'NN_input': x}, pdf, name=name) - return model + return models From 9c23fa5c51d13969da5fca53a2665701a39761e3 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:02:15 +0100 Subject: [PATCH 02/71] Simplify handling of dropout --- n3fit/src/n3fit/model_gen.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 6ca13d463b..aef8c0ee78 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -317,16 +317,7 @@ def generate_dense_network( the output layer for the basis choice) """ list_of_pdf_layers = [] - number_of_layers = len(nodes) - if dropout_rate > 0: - dropout_layer = number_of_layers - 2 - else: - dropout_layer = -1 for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - # if we have dropout set up, add it to the list - if dropout_rate > 0 and i == dropout_layer: - list_of_pdf_layers.append(base_layer_selector("dropout", rate=dropout_rate)) - # select the initializer and move the seed init = MetaLayer.select_initializer(initializer_name, seed=seed + i) @@ -343,6 +334,12 @@ def generate_dense_network( list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) + + # add dropout as second to last layer + if dropout_rate > 0: + dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout_rate) + list_of_pdf_layers.insert(dropout_layer, -2) + return list_of_pdf_layers From 683e3540bc794cbc457b8a8a383bf881dbcf1e1e Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:15:07 +0100 Subject: [PATCH 03/71] Factor out layer_generator in generate_dense_network --- n3fit/src/n3fit/model_gen.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index aef8c0ee78..fbdafcb2af 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -316,12 +316,9 @@ def generate_dense_network( for the next to last layer (i.e., the last layer of the dense network before getting to the output layer for the basis choice) """ - list_of_pdf_layers = [] - for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - # select the initializer and move the seed - init = MetaLayer.select_initializer(initializer_name, seed=seed + i) - # set the arguments that will define the layer + def layer_generator(nodes_in, nodes_out, activation, seed): + init = MetaLayer.select_initializer(initializer_name, seed=seed) arguments = { "kernel_initializer": init, "units": int(nodes_out), @@ -329,9 +326,11 @@ def generate_dense_network( "input_shape": (nodes_in,), "kernel_regularizer": regularizer, } + return base_layer_selector("dense", **arguments) - layer = base_layer_selector("dense", **arguments) - + list_of_pdf_layers = [] + for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): + layer = layer_generator(nodes_in, nodes_out, activation, seed + i) list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) From d02e1185d7edb41d2c3ea0ae643aa98f5e6ecd30 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:31:54 +0100 Subject: [PATCH 04/71] Refactor dense_per_flavor_network --- n3fit/src/n3fit/model_gen.py | 52 +++++++++++++++++------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index fbdafcb2af..06570c45b6 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -349,23 +349,17 @@ def generate_dense_per_flavour_network( For each flavour generates a dense network of the chosen size """ - list_of_pdf_layers = [] - number_of_layers = len(nodes) - current_seed = seed - for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - initializers = [] - for _ in range(basis_size): - # select the initializer and move the seed - initializers.append(MetaLayer.select_initializer(initializer_name, seed=current_seed)) - current_seed += 1 - - # set the arguments that will define the layer - # but careful, the last layer must be nodes = 1 - # TODO the mismatch is due to the fact that basis_size - # is set to the number of nodes of the last layer when it should - # come from the runcard - if i == number_of_layers - 1: - nodes_out = 1 + # set the arguments that will define the layer + # but careful, the last layer must be nodes = 1 + # TODO the mismatch is due to the fact that basis_size + # is set to the number of nodes of the last layer when it should + # come from the runcard + nodes[-1] = 1 + + def layer_generator(nodes_in, nodes_out, activation, seed): + initializers = [ + MetaLayer.select_initializer(initializer_name, seed=seed + b) for b in range(basis_size) + ] arguments = { "kernel_initializer": initializers, "units": nodes_out, @@ -373,22 +367,24 @@ def generate_dense_per_flavour_network( "input_shape": (nodes_in,), "basis_size": basis_size, } + return base_layer_selector("dense_per_flavour", **arguments) - layer = base_layer_selector("dense_per_flavour", **arguments) + list_of_pdf_layers = [] + for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): + layer = layer_generator(nodes_in, nodes_out, activation, seed + i) + list_of_pdf_layers.append(layer) + nodes_in = int(nodes_out) - if i == number_of_layers - 1: - # For the last layer, apply concatenate - concat = base_layer_selector("concatenate") + # For the last layer, apply concatenate + last_layer = list_of_pdf_layers[-1] + concat = base_layer_selector("concatenate") - def output_layer(ilayer): - result = layer(ilayer) - return concat(result) + def concatenated_last_layer(inputs): + result = last_layer(inputs) + return concat(result) - list_of_pdf_layers.append(output_layer) - else: - list_of_pdf_layers.append(layer) + list_of_pdf_layers[-1] = concatenated_last_layer - nodes_in = int(nodes_out) return list_of_pdf_layers From f907d7fab218f649d55ed50d08e55c5f0b5545a1 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:39:16 +0100 Subject: [PATCH 05/71] Move setting of last nodes to generate_nn --- n3fit/src/n3fit/model_gen.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 06570c45b6..fb74890c2d 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -349,12 +349,6 @@ def generate_dense_per_flavour_network( For each flavour generates a dense network of the chosen size """ - # set the arguments that will define the layer - # but careful, the last layer must be nodes = 1 - # TODO the mismatch is due to the fact that basis_size - # is set to the number of nodes of the last layer when it should - # come from the runcard - nodes[-1] = 1 def layer_generator(nodes_in, nodes_out, activation, seed): initializers = [ @@ -785,6 +779,14 @@ def generate_nn( """ x = Input(shape=(None, input_dimensions), batch_size=1, name='xgrids_processed') + if layer_type == "dense_per_flavour": + # set the arguments that will define the layer + # but careful, the last layer must be nodes = 1 + # TODO the mismatch is due to the fact that basis_size + # is set to the number of nodes of the last layer when it should + # come from the runcard + nodes[-1] = 1 + common_args = { 'nodes_in': input_dimensions, 'nodes': nodes, From aa76bc77458d330e80cd8b1c127254c2563501d7 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:44:43 +0100 Subject: [PATCH 06/71] Add constant arguments --- n3fit/src/n3fit/model_gen.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index fb74890c2d..8fc4a9374f 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -787,29 +787,32 @@ def generate_nn( # come from the runcard nodes[-1] = 1 - common_args = { + constant_args = { 'nodes_in': input_dimensions, 'nodes': nodes, 'activations': activations, 'initializer_name': initializer_name, } + if layer_type == "dense_per_flavour": + constant_args['basis_size'] = last_layer_nodes + if layer_type == "dense": + constant_args['dropout_rate'] = dropout + reg = regularizer_selector(regularizer, **regularizer_args) + constant_args['regularizer'] = reg models = [] for i_replica, replica_seed in enumerate(replica_seeds): if layer_type == "dense": - reg = regularizer_selector(regularizer, **regularizer_args) - list_of_pdf_layers = generate_dense_network( - **common_args, dropout_rate=dropout, regularizer=reg, seed=replica_seed - ) + list_of_pdf_layers = generate_dense_network(**constant_args, seed=replica_seed) elif layer_type == "dense_per_flavour": list_of_pdf_layers = generate_dense_per_flavour_network( - **common_args, basis_size=last_layer_nodes, seed=replica_seed + **constant_args, seed=replica_seed ) + # apply layers to create model pdf = x for layer in list_of_pdf_layers: pdf = layer(pdf) - models.append(MetaModel({'NN_input': x}, pdf, name=f"NN_{i_replica}")) return models From 1ad7960b9f56622afc3b6ccbd111890635af7036 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:46:58 +0100 Subject: [PATCH 07/71] Add constant arguments --- n3fit/src/n3fit/model_gen.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 8fc4a9374f..a1f9f963d1 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -795,19 +795,16 @@ def generate_nn( } if layer_type == "dense_per_flavour": constant_args['basis_size'] = last_layer_nodes + layers_generator = generate_dense_per_flavour_network if layer_type == "dense": constant_args['dropout_rate'] = dropout reg = regularizer_selector(regularizer, **regularizer_args) constant_args['regularizer'] = reg + layers_generator = generate_dense_network models = [] for i_replica, replica_seed in enumerate(replica_seeds): - if layer_type == "dense": - list_of_pdf_layers = generate_dense_network(**constant_args, seed=replica_seed) - elif layer_type == "dense_per_flavour": - list_of_pdf_layers = generate_dense_per_flavour_network( - **constant_args, seed=replica_seed - ) + list_of_pdf_layers = layers_generator(**constant_args, seed=replica_seed) # apply layers to create model pdf = x From 7758497da4b438543e6e9765d760f80c23601443 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:50:43 +0100 Subject: [PATCH 08/71] Move dropout to generate_nn --- n3fit/src/n3fit/model_gen.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index a1f9f963d1..e8de611aa8 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -306,15 +306,10 @@ def generate_dense_network( activations: List[str], initializer_name: str = "glorot_normal", seed: int = 0, - dropout_rate: float = 0.0, regularizer: str = None, ): """ Generates a dense network - - the dropout rate, if selected, is set - for the next to last layer (i.e., the last layer of the dense network before getting to - the output layer for the basis choice) """ def layer_generator(nodes_in, nodes_out, activation, seed): @@ -334,11 +329,6 @@ def layer_generator(nodes_in, nodes_out, activation, seed): list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) - # add dropout as second to last layer - if dropout_rate > 0: - dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout_rate) - list_of_pdf_layers.insert(dropout_layer, -2) - return list_of_pdf_layers @@ -797,7 +787,6 @@ def generate_nn( constant_args['basis_size'] = last_layer_nodes layers_generator = generate_dense_per_flavour_network if layer_type == "dense": - constant_args['dropout_rate'] = dropout reg = regularizer_selector(regularizer, **regularizer_args) constant_args['regularizer'] = reg layers_generator = generate_dense_network @@ -806,6 +795,11 @@ def generate_nn( for i_replica, replica_seed in enumerate(replica_seeds): list_of_pdf_layers = layers_generator(**constant_args, seed=replica_seed) + # add dropout as second to last layer + if dropout > 0: + dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout) + list_of_pdf_layers.insert(dropout_layer, -2) + # apply layers to create model pdf = x for layer in list_of_pdf_layers: From 2d388d922d795f24b67a62ba2b6fd0108b7fe0f9 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 13:55:42 +0100 Subject: [PATCH 09/71] Move concatenation of per_flavor layers into generate_nn --- n3fit/src/n3fit/model_gen.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index e8de611aa8..40beedb8b7 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -359,16 +359,6 @@ def layer_generator(nodes_in, nodes_out, activation, seed): list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) - # For the last layer, apply concatenate - last_layer = list_of_pdf_layers[-1] - concat = base_layer_selector("concatenate") - - def concatenated_last_layer(inputs): - result = last_layer(inputs) - return concat(result) - - list_of_pdf_layers[-1] = concatenated_last_layer - return list_of_pdf_layers @@ -800,6 +790,17 @@ def generate_nn( dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout) list_of_pdf_layers.insert(dropout_layer, -2) + # In case of per flavour network, concatenate at the last layer + if layer_type == "dense_per_flavour": + last_layer = list_of_pdf_layers[-1] + concat = base_layer_selector("concatenate") + + def concatenated_last_layer(inputs): + result = last_layer(inputs) + return concat(result) + + list_of_pdf_layers[-1] = concatenated_last_layer + # apply layers to create model pdf = x for layer in list_of_pdf_layers: From 1ef87dc1a300ace72181ec0e0421e19890b985ad Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 14:05:19 +0100 Subject: [PATCH 10/71] Make the two layer generators almost equal --- n3fit/src/n3fit/model_gen.py | 47 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 40beedb8b7..6e0252bd6c 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -311,21 +311,23 @@ def generate_dense_network( """ Generates a dense network """ + layer_type = "dense" + custom_args = {"kernel_regularizer": regularizer} - def layer_generator(nodes_in, nodes_out, activation, seed): - init = MetaLayer.select_initializer(initializer_name, seed=seed) - arguments = { - "kernel_initializer": init, - "units": int(nodes_out), - "activation": activation, - "input_shape": (nodes_in,), - "kernel_regularizer": regularizer, - } - return base_layer_selector("dense", **arguments) + def initializer_generator(initializer_name, seed): + return MetaLayer.select_initializer(initializer_name, seed=seed) list_of_pdf_layers = [] for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - layer = layer_generator(nodes_in, nodes_out, activation, seed + i) + init = initializer_generator(initializer_name, seed + i) + layer = base_layer_selector( + layer_type, + kernel_initializer=init, + units=nodes_out, + activation=activation, + input_shape=(nodes_in,), + **custom_args, + ) list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) @@ -339,23 +341,26 @@ def generate_dense_per_flavour_network( For each flavour generates a dense network of the chosen size """ + layer_type = "dense_per_flavour" + custom_args = {"basis_size": basis_size} - def layer_generator(nodes_in, nodes_out, activation, seed): + def initializer_generator(initializer_name, seed): initializers = [ MetaLayer.select_initializer(initializer_name, seed=seed + b) for b in range(basis_size) ] - arguments = { - "kernel_initializer": initializers, - "units": nodes_out, - "activation": activation, - "input_shape": (nodes_in,), - "basis_size": basis_size, - } - return base_layer_selector("dense_per_flavour", **arguments) + return initializers list_of_pdf_layers = [] for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - layer = layer_generator(nodes_in, nodes_out, activation, seed + i) + init = initializer_generator(initializer_name, seed + i) + layer = base_layer_selector( + layer_type, + kernel_initializer=init, + units=nodes_out, + activation=activation, + input_shape=(nodes_in,), + **custom_args, + ) list_of_pdf_layers.append(layer) nodes_in = int(nodes_out) From 806e2c15686582c125300e2899567f7f55e71eb3 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 14:19:07 +0100 Subject: [PATCH 11/71] remove separate dense and dense_per_flavor functions --- n3fit/src/n3fit/model_gen.py | 114 +++++++++-------------------------- 1 file changed, 30 insertions(+), 84 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 6e0252bd6c..3b9cdd8b19 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -299,74 +299,6 @@ def observable_generator( return layer_info -# Network generation functions -def generate_dense_network( - nodes_in: int, - nodes: int, - activations: List[str], - initializer_name: str = "glorot_normal", - seed: int = 0, - regularizer: str = None, -): - """ - Generates a dense network - """ - layer_type = "dense" - custom_args = {"kernel_regularizer": regularizer} - - def initializer_generator(initializer_name, seed): - return MetaLayer.select_initializer(initializer_name, seed=seed) - - list_of_pdf_layers = [] - for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - init = initializer_generator(initializer_name, seed + i) - layer = base_layer_selector( - layer_type, - kernel_initializer=init, - units=nodes_out, - activation=activation, - input_shape=(nodes_in,), - **custom_args, - ) - list_of_pdf_layers.append(layer) - nodes_in = int(nodes_out) - - return list_of_pdf_layers - - -def generate_dense_per_flavour_network( - nodes_in, nodes, activations, initializer_name="glorot_normal", seed=0, basis_size=8 -): - """ - For each flavour generates a dense network of the chosen size - - """ - layer_type = "dense_per_flavour" - custom_args = {"basis_size": basis_size} - - def initializer_generator(initializer_name, seed): - initializers = [ - MetaLayer.select_initializer(initializer_name, seed=seed + b) for b in range(basis_size) - ] - return initializers - - list_of_pdf_layers = [] - for i, (nodes_out, activation) in enumerate(zip(nodes, activations)): - init = initializer_generator(initializer_name, seed + i) - layer = base_layer_selector( - layer_type, - kernel_initializer=init, - units=nodes_out, - activation=activation, - input_shape=(nodes_in,), - **custom_args, - ) - list_of_pdf_layers.append(layer) - nodes_in = int(nodes_out) - - return list_of_pdf_layers - - def generate_pdf_model( nodes: List[int] = None, activations: List[str] = None, @@ -655,7 +587,7 @@ def pdfNN_layer_generator( nn_replicas = generate_nn( layer_type=layer_type, - input_dimensions=nn_input_dimensions, + nodes_in=nn_input_dimensions, nodes=nodes, activations=activations, initializer_name=initializer_name, @@ -748,7 +680,7 @@ def compute_unnormalized_pdf(x, postfix=""): def generate_nn( layer_type: str, - input_dimensions: int, + nodes_in: int, nodes: List[int], activations: List[str], initializer_name: str, @@ -762,8 +694,9 @@ def generate_nn( Create the part of the model that contains all of the actual neural network layers. """ - x = Input(shape=(None, input_dimensions), batch_size=1, name='xgrids_processed') + x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') + custom_args = {} if layer_type == "dense_per_flavour": # set the arguments that will define the layer # but careful, the last layer must be nodes = 1 @@ -771,24 +704,37 @@ def generate_nn( # is set to the number of nodes of the last layer when it should # come from the runcard nodes[-1] = 1 + custom_args['basis_size'] = last_layer_nodes - constant_args = { - 'nodes_in': input_dimensions, - 'nodes': nodes, - 'activations': activations, - 'initializer_name': initializer_name, - } - if layer_type == "dense_per_flavour": - constant_args['basis_size'] = last_layer_nodes - layers_generator = generate_dense_per_flavour_network - if layer_type == "dense": + def initializer_generator(initializer_name, seed): + initializers = [ + MetaLayer.select_initializer(initializer_name, seed=seed + b) + for b in range(basis_size) + ] + return initializers + + elif layer_type == "dense": reg = regularizer_selector(regularizer, **regularizer_args) - constant_args['regularizer'] = reg - layers_generator = generate_dense_network + custom_args['regularizer'] = reg + + def initializer_generator(initializer_name, seed): + return MetaLayer.select_initializer(initializer_name, seed=seed) models = [] for i_replica, replica_seed in enumerate(replica_seeds): - list_of_pdf_layers = layers_generator(**constant_args, seed=replica_seed) + list_of_pdf_layers = [] + for i_layer, (nodes_out, activation) in enumerate(zip(nodes, activations)): + init = initializer_generator(initializer_name, replica_seed + i_layer) + layer = base_layer_selector( + layer_type, + kernel_initializer=init, + units=nodes_out, + activation=activation, + input_shape=(nodes_in,), + **custom_args, + ) + list_of_pdf_layers.append(layer) + nodes_in = int(nodes_out) # add dropout as second to last layer if dropout > 0: From bdbc3c36440ad5b6d117bc3d752211e3be6fe4d7 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 14:24:10 +0100 Subject: [PATCH 12/71] Add documentation. --- n3fit/src/n3fit/model_gen.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 3b9cdd8b19..349f8bd26c 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -692,7 +692,35 @@ def generate_nn( ) -> MetaModel: """ Create the part of the model that contains all of the actual neural network - layers. + layers, for each replica. + + Parameters + ---------- + layer_type: str + Type of layer to use. Can be "dense" or "dense_per_flavour". + nodes_in: int + Number of nodes in the input layer. + nodes: List[int] + Number of nodes in each hidden layer. + activations: List[str] + Activation function to use in each hidden layer. + initializer_name: str + Name of the initializer to use. + replica_seeds: List[int] + List of seeds to use for each replica. + dropout: float + Dropout rate to use (if 0, no dropout is used). + regularizer: str + Name of the regularizer to use. + regularizer_args: dict + Arguments to pass to the regularizer. + last_layer_nodes: int + Number of nodes in the last layer. + + Returns + ------- + nn_replicas: List[MetaModel] + List of MetaModel objects, one for each replica. """ x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') From e3f9f0c0f8c242b4c0cc74b5d2d555d52bcbf1e2 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 14:37:07 +0100 Subject: [PATCH 13/71] Simplify per_flavor layer concatenation --- n3fit/src/n3fit/model_gen.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 349f8bd26c..9eee37101e 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -771,14 +771,10 @@ def initializer_generator(initializer_name, seed): # In case of per flavour network, concatenate at the last layer if layer_type == "dense_per_flavour": - last_layer = list_of_pdf_layers[-1] concat = base_layer_selector("concatenate") - - def concatenated_last_layer(inputs): - result = last_layer(inputs) - return concat(result) - - list_of_pdf_layers[-1] = concatenated_last_layer + list_of_pdf_layers[-1] = [ + lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1] + ] # apply layers to create model pdf = x From 3d9070f3fc24d3cc686643c93ffcc22702c55c2c Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 14:52:44 +0100 Subject: [PATCH 14/71] Reverse order of loops over replicas and layers --- n3fit/src/n3fit/model_gen.py | 60 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 9eee37101e..7c39bc3cb1 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -748,12 +748,16 @@ def initializer_generator(initializer_name, seed): def initializer_generator(initializer_name, seed): return MetaLayer.select_initializer(initializer_name, seed=seed) - models = [] - for i_replica, replica_seed in enumerate(replica_seeds): - list_of_pdf_layers = [] - for i_layer, (nodes_out, activation) in enumerate(zip(nodes, activations)): - init = initializer_generator(initializer_name, replica_seed + i_layer) - layer = base_layer_selector( + # First create all the layers... + # list_of_pdf_layers[d][r] is the layer at depth d for replica r + list_of_pdf_layers = [] + for i_layer, (nodes_out, activation) in enumerate(zip(nodes, activations)): + inits = [ + initializer_generator(initializer_name, replica_seed + i_layer) + for replica_seed in replica_seeds + ] + layers = [ + base_layer_selector( layer_type, kernel_initializer=init, units=nodes_out, @@ -761,25 +765,31 @@ def initializer_generator(initializer_name, seed): input_shape=(nodes_in,), **custom_args, ) - list_of_pdf_layers.append(layer) - nodes_in = int(nodes_out) - - # add dropout as second to last layer - if dropout > 0: - dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout) - list_of_pdf_layers.insert(dropout_layer, -2) - - # In case of per flavour network, concatenate at the last layer - if layer_type == "dense_per_flavour": - concat = base_layer_selector("concatenate") - list_of_pdf_layers[-1] = [ - lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1] - ] + for init in inits + ] + list_of_pdf_layers.append(layers) + nodes_in = int(nodes_out) + + # add dropout as second to last layer + if dropout > 0: + dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout) + list_of_pdf_layers.insert(dropout_layer, -2) + + # In case of per flavour network, concatenate at the last layer + if layer_type == "dense_per_flavour": + concat = base_layer_selector("concatenate") + list_of_pdf_layers[-1] = [lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1]] + + # ... then apply them to the input to create the models + xs = [layer(x) for layer in list_of_pdf_layers[0]] + for layers in list_of_pdf_layers[1:]: + if type(layers) is list: + xs = [layer(x) for layer, x in zip(layers, xs)] + else: + xs = [layers(x) for x in xs] - # apply layers to create model - pdf = x - for layer in list_of_pdf_layers: - pdf = layer(pdf) - models.append(MetaModel({'NN_input': x}, pdf, name=f"NN_{i_replica}")) + models = [ + MetaModel({'NN_input': x}, pdf, name=f"NN_{i_replica}") for i_replica, pdf in enumerate(xs) + ] return models From c8300c872299a464ed0cf023ed92f2932981dcc4 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 15:10:25 +0100 Subject: [PATCH 15/71] Fixes for dropout --- n3fit/src/n3fit/model_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 7c39bc3cb1..12b33e2738 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -772,8 +772,8 @@ def initializer_generator(initializer_name, seed): # add dropout as second to last layer if dropout > 0: - dropout_layer = MetaLayer.base_layer_selector("dropout", rate=dropout) - list_of_pdf_layers.insert(dropout_layer, -2) + dropout_layer = base_layer_selector("dropout", rate=dropout) + list_of_pdf_layers.insert(-2, dropout_layer) # In case of per flavour network, concatenate at the last layer if layer_type == "dense_per_flavour": From 0cf23f294257f485183b8d054993e1b8786dff28 Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 8 Dec 2023 15:26:59 +0100 Subject: [PATCH 16/71] Fixes for per_flavour --- n3fit/src/n3fit/model_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 12b33e2738..c4c9319ab0 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -732,7 +732,7 @@ def generate_nn( # is set to the number of nodes of the last layer when it should # come from the runcard nodes[-1] = 1 - custom_args['basis_size'] = last_layer_nodes + basis_size = last_layer_nodes def initializer_generator(initializer_name, seed): initializers = [ From b0a8e3b2b14f6cb6dcb65234784e8bc81e2cb429 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 07:50:08 +0100 Subject: [PATCH 17/71] Fix issue with copying over nodes for per_flavour layer --- n3fit/src/n3fit/model_gen.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index c4c9319ab0..3845fd7b22 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -722,6 +722,7 @@ def generate_nn( nn_replicas: List[MetaModel] List of MetaModel objects, one for each replica. """ + nodes_local = nodes.copy() # make a local copy so we can modify it x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') custom_args = {} @@ -731,7 +732,7 @@ def generate_nn( # TODO the mismatch is due to the fact that basis_size # is set to the number of nodes of the last layer when it should # come from the runcard - nodes[-1] = 1 + nodes_local[-1] = 1 basis_size = last_layer_nodes def initializer_generator(initializer_name, seed): @@ -751,7 +752,7 @@ def initializer_generator(initializer_name, seed): # First create all the layers... # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] - for i_layer, (nodes_out, activation) in enumerate(zip(nodes, activations)): + for i_layer, (nodes_out, activation) in enumerate(zip(nodes_local, activations)): inits = [ initializer_generator(initializer_name, replica_seed + i_layer) for replica_seed in replica_seeds From 97d2efef66cdb3c63192a140ea1a05018099de67 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 08:08:04 +0100 Subject: [PATCH 18/71] Fix seeds in per_flavour layer --- n3fit/src/n3fit/model_gen.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 3845fd7b22..feab58190e 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -735,7 +735,8 @@ def generate_nn( nodes_local[-1] = 1 basis_size = last_layer_nodes - def initializer_generator(initializer_name, seed): + def initializer_generator(initializer_name, seed, i_layer): + seed += i_layer * basis_size initializers = [ MetaLayer.select_initializer(initializer_name, seed=seed + b) for b in range(basis_size) @@ -746,7 +747,8 @@ def initializer_generator(initializer_name, seed): reg = regularizer_selector(regularizer, **regularizer_args) custom_args['regularizer'] = reg - def initializer_generator(initializer_name, seed): + def initializer_generator(initializer_name, seed, i_layer): + seed += i_layer return MetaLayer.select_initializer(initializer_name, seed=seed) # First create all the layers... @@ -754,7 +756,7 @@ def initializer_generator(initializer_name, seed): list_of_pdf_layers = [] for i_layer, (nodes_out, activation) in enumerate(zip(nodes_local, activations)): inits = [ - initializer_generator(initializer_name, replica_seed + i_layer) + initializer_generator(initializer_name, replica_seed, i_layer) for replica_seed in replica_seeds ] layers = [ From 4c4a2d5757209f14e08e685d3120770185054f8c Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 08:09:31 +0100 Subject: [PATCH 19/71] Add error for combination of dropout with per_flavour layers --- n3fit/src/n3fit/model_gen.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index feab58190e..427274e6e6 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -722,6 +722,9 @@ def generate_nn( nn_replicas: List[MetaModel] List of MetaModel objects, one for each replica. """ + if dropout > 0 and layer_type == "dense_per_flavour": + raise ValueError("Dropout is not supported for dense_per_flavour layers") + nodes_local = nodes.copy() # make a local copy so we can modify it x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') From 2287194a27c32628a0b4d368fb693b220ce98a44 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 08:50:00 +0100 Subject: [PATCH 20/71] Add basis_size argument to per_flavour layer --- n3fit/src/n3fit/model_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 427274e6e6..8b41f03959 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -737,6 +737,7 @@ def generate_nn( # come from the runcard nodes_local[-1] = 1 basis_size = last_layer_nodes + custom_args['basis_size'] = basis_size def initializer_generator(initializer_name, seed, i_layer): seed += i_layer * basis_size From 2f68e3d5d2d825e8ecf231949072f128bd98cbe8 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 08:51:19 +0100 Subject: [PATCH 21/71] Fix model_gen tests to use new generate_nn in favor of now removed generate_dense and generate_dense_per_flavour --- n3fit/src/n3fit/tests/test_modelgen.py | 60 ++++++++++---------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index 4cec4574ee..f76e022810 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -5,62 +5,48 @@ It checks that both the number of layers and the shape of the weights of the layers are what is expected """ -import numpy as np -import n3fit.model_gen -from n3fit.backends import MetaModel -from n3fit.backends import operations as op +from n3fit.model_gen import generate_nn INSIZE = 16 -OUT_SIZES = (4, 3) +OUT_SIZES = [4, 3] BASIS_SIZE = 3 +COMMON_ARGS = { + "nodes_in": INSIZE, + "nodes": OUT_SIZES, + "activations": ["sigmoid", "tanh"], + "initializer_name": "glorot_uniform", + "replica_seeds": [0], + "dropout": 0.0, + "regularizer": None, + "regularizer_args": {}, + "last_layer_nodes": BASIS_SIZE, +} + def test_generate_dense_network(): - nodes_in = INSIZE - nodes_out = OUT_SIZES - activations = ["sigmoid", "tanh"] - layers = n3fit.model_gen.generate_dense_network(nodes_in, nodes_out, activations) - arr = np.random.rand(1, INSIZE) - input_layer = op.numpy_to_input(arr) - curr_layer = input_layer - for layer in layers: - curr_layer = layer(curr_layer) - modelito = MetaModel({"input": input_layer}, curr_layer) + nn = generate_nn("dense", **COMMON_ARGS)[0] + # The number of layers should be input layer + len(OUT_SIZES) - assert len(modelito.layers) == len(OUT_SIZES) + 1 + assert len(nn.layers) == len(OUT_SIZES) + 1 # Check that the number of parameters is as expected # We expect 4 weights where the two first ones are # (INSIZE, OUT_SIZE[0]) (OUT_SIZE[0],) # and the second one # (OUT_SIZE[0], OUT_SIZE[1]) (OUT_SIZE[1],) - expected_sizes = [ - (INSIZE, OUT_SIZES[0]), - (OUT_SIZES[0],), - OUT_SIZES, - (OUT_SIZES[1],), - ] - for weight, esize in zip(modelito.weights, expected_sizes): + expected_sizes = [(INSIZE, OUT_SIZES[0]), (OUT_SIZES[0],), OUT_SIZES, (OUT_SIZES[1],)] + for weight, esize in zip(nn.weights, expected_sizes): assert weight.shape == esize def test_generate_dense_per_flavour_network(): - nodes_in = INSIZE - nodes_out = OUT_SIZES - activations = ["sigmoid", "tanh"] - layers = n3fit.model_gen.generate_dense_per_flavour_network( - nodes_in, nodes_out, activations, basis_size=BASIS_SIZE - ) - arr = np.random.rand(1, INSIZE) - input_layer = op.numpy_to_input(arr) - curr_layer = input_layer - for layer in layers: - curr_layer = layer(curr_layer) - modelito = MetaModel({"input": input_layer}, curr_layer) + nn = generate_nn("dense_per_flavour", **COMMON_ARGS)[0] + # The number of layers should be input + BASIS_SIZE*len(OUT_SIZES) + concatenate - assert len(modelito.layers) == BASIS_SIZE * len(OUT_SIZES) + 2 + assert len(nn.layers) == BASIS_SIZE * len(OUT_SIZES) + 2 # The shape for this network of denses for flavours will depend on the basis_size expected_sizes = [] expected_sizes += BASIS_SIZE * [(INSIZE, OUT_SIZES[0]), (OUT_SIZES[0],)] expected_sizes += BASIS_SIZE * [(OUT_SIZES[0], 1), (1,)] - for weight, esize in zip(modelito.weights, expected_sizes): + for weight, esize in zip(nn.weights, expected_sizes): assert weight.shape == esize From 4dd1649917380c7a1a56057c83a8e535724470ea Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 10:49:48 +0100 Subject: [PATCH 22/71] Allow for nodes to be a tuple --- n3fit/src/n3fit/model_gen.py | 6 +++--- n3fit/src/n3fit/tests/test_modelgen.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 8b41f03959..2cd1ebea1c 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -725,7 +725,7 @@ def generate_nn( if dropout > 0 and layer_type == "dense_per_flavour": raise ValueError("Dropout is not supported for dense_per_flavour layers") - nodes_local = nodes.copy() # make a local copy so we can modify it + nodes_list = list(nodes) # so we can modify it x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') custom_args = {} @@ -735,7 +735,7 @@ def generate_nn( # TODO the mismatch is due to the fact that basis_size # is set to the number of nodes of the last layer when it should # come from the runcard - nodes_local[-1] = 1 + nodes_list[-1] = 1 basis_size = last_layer_nodes custom_args['basis_size'] = basis_size @@ -758,7 +758,7 @@ def initializer_generator(initializer_name, seed, i_layer): # First create all the layers... # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] - for i_layer, (nodes_out, activation) in enumerate(zip(nodes_local, activations)): + for i_layer, (nodes_out, activation) in enumerate(zip(nodes_list, activations)): inits = [ initializer_generator(initializer_name, replica_seed, i_layer) for replica_seed in replica_seeds diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index f76e022810..d50b98728a 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -8,7 +8,7 @@ from n3fit.model_gen import generate_nn INSIZE = 16 -OUT_SIZES = [4, 3] +OUT_SIZES = (4, 3) BASIS_SIZE = 3 COMMON_ARGS = { From 6bd6466a8d0d37bbcbcc39f4dbea5cc9aa871136 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 11 Dec 2023 15:39:23 +0100 Subject: [PATCH 23/71] Move dropout, per_flavour check to checks --- n3fit/src/n3fit/checks.py | 7 +++++++ n3fit/src/n3fit/model_gen.py | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index 7b509f0065..31b1fae2cb 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -114,6 +114,13 @@ def check_dropout(parameters): if dropout is not None and not 0.0 <= dropout <= 1.0: raise CheckError(f"Dropout must be between 0 and 1, got: {dropout}") + layer_type = parameters.get("layer_type") + if dropout is not None and dropout > 0.0 and layer_type == "dense_per_flavour": + raise CheckError( + "Dropout is not compatible with the dense_per_flavour layer type, " + "please use instead the dense layer type" + ) + def check_tensorboard(tensorboard): """Check that the tensorbard callback can be enabled correctly""" diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 2cd1ebea1c..064ddae271 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -722,9 +722,6 @@ def generate_nn( nn_replicas: List[MetaModel] List of MetaModel objects, one for each replica. """ - if dropout > 0 and layer_type == "dense_per_flavour": - raise ValueError("Dropout is not supported for dense_per_flavour layers") - nodes_list = list(nodes) # so we can modify it x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') From 2cd9e52f555a147aba21c8daee01f76a09e0e676 Mon Sep 17 00:00:00 2001 From: Aron Jansen Date: Thu, 14 Dec 2023 10:12:22 +0100 Subject: [PATCH 24/71] Clarify layer type check Co-authored-by: Juan M. Cruz-Martinez --- n3fit/src/n3fit/checks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index 31b1fae2cb..f33213d5a0 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -118,7 +118,7 @@ def check_dropout(parameters): if dropout is not None and dropout > 0.0 and layer_type == "dense_per_flavour": raise CheckError( "Dropout is not compatible with the dense_per_flavour layer type, " - "please use instead the dense layer type" + "please use instead `parameters::layer_type: dense`" ) From 1ae1b84a6b95b10bff0b80c49fd6738d8ed1bb45 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 14 Dec 2023 10:18:34 +0100 Subject: [PATCH 25/71] Clarify naming in nn_generator --- n3fit/src/n3fit/model_gen.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 064ddae271..7e8a2d406a 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -723,7 +723,7 @@ def generate_nn( List of MetaModel objects, one for each replica. """ nodes_list = list(nodes) # so we can modify it - x = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') + x_input = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') custom_args = {} if layer_type == "dense_per_flavour": @@ -785,15 +785,16 @@ def initializer_generator(initializer_name, seed, i_layer): list_of_pdf_layers[-1] = [lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1]] # ... then apply them to the input to create the models - xs = [layer(x) for layer in list_of_pdf_layers[0]] + pdfs = [layer(x_input) for layer in list_of_pdf_layers[0]] for layers in list_of_pdf_layers[1:]: if type(layers) is list: - xs = [layer(x) for layer, x in zip(layers, xs)] + pdfs = [layer(x) for layer, x in zip(layers, pdfs)] else: - xs = [layers(x) for x in xs] + pdfs = [layers(x) for x in pdfs] models = [ - MetaModel({'NN_input': x}, pdf, name=f"NN_{i_replica}") for i_replica, pdf in enumerate(xs) + MetaModel({'NN_input': x_input}, pdf, name=f"NN_{i_replica}") + for i_replica, pdf in enumerate(pdfs) ] return models From e7a7cb411d0185aee5c120e67c89ba6743fedcee Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 14 Dec 2023 10:24:28 +0100 Subject: [PATCH 26/71] Remove initializer_name argument --- n3fit/src/n3fit/model_gen.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 7e8a2d406a..0aecdd00bd 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -736,7 +736,7 @@ def generate_nn( basis_size = last_layer_nodes custom_args['basis_size'] = basis_size - def initializer_generator(initializer_name, seed, i_layer): + def initializer_generator(seed, i_layer): seed += i_layer * basis_size initializers = [ MetaLayer.select_initializer(initializer_name, seed=seed + b) @@ -748,7 +748,7 @@ def initializer_generator(initializer_name, seed, i_layer): reg = regularizer_selector(regularizer, **regularizer_args) custom_args['regularizer'] = reg - def initializer_generator(initializer_name, seed, i_layer): + def initializer_generator(seed, i_layer): seed += i_layer return MetaLayer.select_initializer(initializer_name, seed=seed) @@ -756,10 +756,7 @@ def initializer_generator(initializer_name, seed, i_layer): # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] for i_layer, (nodes_out, activation) in enumerate(zip(nodes_list, activations)): - inits = [ - initializer_generator(initializer_name, replica_seed, i_layer) - for replica_seed in replica_seeds - ] + inits = [initializer_generator(replica_seed, i_layer) for replica_seed in replica_seeds] layers = [ base_layer_selector( layer_type, From 07c1e7d9eaa63a122e115d0247de0ccd16434f98 Mon Sep 17 00:00:00 2001 From: Aron Jansen Date: Thu, 14 Dec 2023 10:27:00 +0100 Subject: [PATCH 27/71] clarify comment Co-authored-by: Juan M. Cruz-Martinez --- n3fit/src/n3fit/model_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 0aecdd00bd..747a46a2cb 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -781,7 +781,7 @@ def initializer_generator(seed, i_layer): concat = base_layer_selector("concatenate") list_of_pdf_layers[-1] = [lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1]] - # ... then apply them to the input to create the models + # Apply all layers to the input to create the models pdfs = [layer(x_input) for layer in list_of_pdf_layers[0]] for layers in list_of_pdf_layers[1:]: if type(layers) is list: From 25b8308cb660dcb96d543021dc88f4256d7796f4 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 14 Dec 2023 10:29:49 +0100 Subject: [PATCH 28/71] Add comment on shared layers --- n3fit/src/n3fit/model_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 747a46a2cb..0c0e92a695 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -784,6 +784,7 @@ def initializer_generator(seed, i_layer): # Apply all layers to the input to create the models pdfs = [layer(x_input) for layer in list_of_pdf_layers[0]] for layers in list_of_pdf_layers[1:]: + # Since some layers (dropout) are shared, we have to treat them separately if type(layers) is list: pdfs = [layer(x) for layer, x in zip(layers, pdfs)] else: From 692014b55082e8198e0d860cc52db3e397d44612 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 14 Dec 2023 10:45:05 +0100 Subject: [PATCH 29/71] Rewrite comprehension over replica seeds --- n3fit/src/n3fit/model_gen.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 0c0e92a695..09f337dbca 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -756,17 +756,16 @@ def initializer_generator(seed, i_layer): # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] for i_layer, (nodes_out, activation) in enumerate(zip(nodes_list, activations)): - inits = [initializer_generator(replica_seed, i_layer) for replica_seed in replica_seeds] layers = [ base_layer_selector( layer_type, - kernel_initializer=init, + kernel_initializer=initializer_generator(replica_seed, i_layer), units=nodes_out, activation=activation, input_shape=(nodes_in,), **custom_args, ) - for init in inits + for replica_seed in replica_seeds ] list_of_pdf_layers.append(layers) nodes_in = int(nodes_out) From 903c75b7024a926dc2d6e4c316ab7f6dcb4b164b Mon Sep 17 00:00:00 2001 From: Aron Date: Fri, 15 Dec 2023 09:44:18 +0100 Subject: [PATCH 30/71] Add check on layer type --- n3fit/src/n3fit/checks.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index f33213d5a0..885785a268 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -108,6 +108,16 @@ def check_initializer(initializer): raise CheckError(f"Initializer {initializer} not accepted by {MetaLayer}") +def check_layer_type_implemented(parameters): + """Checks whether the layer_type is implemented""" + layer_type = parameters.get("layer_type") + implemented_types = ["dense", "dense_per_flavour"] + if layer_type not in implemented_types: + raise CheckError( + f"Layer type {layer_type} not implemented, must be one of {implemented_types}" + ) + + def check_dropout(parameters): """Checks the dropout setup (positive and smaller than 1.0)""" dropout = parameters.get("dropout") @@ -175,6 +185,7 @@ def wrapper_check_NN(basis, tensorboard, save, load, parameters): check_consistent_layers(parameters) check_basis_with_layers(basis, parameters) check_stopping(parameters) + check_layer_type_implemented(parameters) check_dropout(parameters) check_lagrange_multipliers(parameters, "integrability") check_lagrange_multipliers(parameters, "positivity") From a8fcfd39b4876aec9f37fb5e0bd40fd6c0d065ac Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 25 Oct 2023 08:13:20 +0200 Subject: [PATCH 31/71] Merge prefactors into single layer --- .../n3fit/backends/keras_backend/MetaModel.py | 46 +++++++++++++++++-- n3fit/src/n3fit/layers/preprocessing.py | 16 +++++-- n3fit/src/n3fit/model_gen.py | 28 ++++------- 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 1b0990bb03..eea235191a 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -358,7 +358,7 @@ def get_replica_weights(self, i_replica): ] prepro_weights = [ tf.Variable(w, name=w.name) - for w in self.get_layer(f"{PREPROCESSING_PREFIX}_{i_replica}").weights + for w in get_layer_replica_weights(self.get_layer(PREPROCESSING_PREFIX), i_replica) ] weights = {NN_PREFIX: NN_weights, PREPROCESSING_PREFIX: prepro_weights} @@ -379,8 +379,10 @@ def set_replica_weights(self, weights, i_replica=0): the replica number to set, defaulting to 0 """ self.get_layer(f"{NN_PREFIX}_{i_replica}").set_weights(weights[NN_PREFIX]) - self.get_layer(f"{PREPROCESSING_PREFIX}_{i_replica}").set_weights( - weights[PREPROCESSING_PREFIX] + set_layer_replica_weights( + layer=self.get_layer(PREPROCESSING_PREFIX), + weights=weights[PREPROCESSING_PREFIX], + i_replica=i_replica, ) def split_replicas(self): @@ -459,3 +461,41 @@ def append_weights(name, node): weights_ordered.append(w_h5) return weights_ordered + + +def get_layer_replica_weights(layer, i_replica: int): + """ + Get the weights for the given single replica `i_replica`, + from a `layer` that has weights for all replicas. + + Parameters + ---------- + layer: MetaLayer + the layer to get the weights from + i_replica: int + the replica number + + Returns + ------- + weights: list + list of weights for the replica + """ + return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] + + +def set_layer_replica_weights(layer, weights, i_replica: int): + """ + Set the weights for the given single replica `i_replica`, + from a `layer` that has weights for all replicas. + + Parameters + ---------- + layer: MetaLayer + the layer to set the weights for + weights: list + list of weights for the replica + i_replica: int + the replica number + """ + for w, w_new in zip(layer.weights, weights): + w[i_replica].assign(w_new[0]) diff --git a/n3fit/src/n3fit/layers/preprocessing.py b/n3fit/src/n3fit/layers/preprocessing.py index 77ea760607..f8ab1f8f55 100644 --- a/n3fit/src/n3fit/layers/preprocessing.py +++ b/n3fit/src/n3fit/layers/preprocessing.py @@ -33,6 +33,8 @@ class Preprocessing(MetaLayer): Whether large x preprocessing factor should be active seed: int seed for the initializer of the random alpha and beta values + num_replicas: int (default 1) + The number of replicas """ def __init__( @@ -40,6 +42,7 @@ def __init__( flav_info: Optional[list] = None, seed: int = 0, large_x: bool = True, + num_replicas: int = 1, **kwargs, ): if flav_info is None: @@ -49,6 +52,8 @@ def __init__( self.flav_info = flav_info self.seed = seed self.large_x = large_x + self.num_replicas = num_replicas + self.alphas = [] self.betas = [] super().__init__(**kwargs) @@ -87,7 +92,7 @@ def generate_weight(self, name: str, kind: str, dictionary: dict, set_to_zero: b # Generate the new trainable (or not) parameter newpar = self.builder_helper( name=name, - kernel_shape=(1,), + kernel_shape=(self.num_replicas, 1), initializer=initializer, trainable=trainable, constraint=constraint, @@ -117,9 +122,12 @@ def call(self, x): Returns ------- - prefactor: tensor(shape=[1,N,F]) + prefactor: tensor(shape=[1,R,N,F]) """ - alphas = op.stack(self.alphas, axis=1) - betas = op.stack(self.betas, axis=1) + # weight tensors of shape (R, 1, F) + alphas = op.stack(self.alphas, axis=-1) + betas = op.stack(self.betas, axis=-1) + + x = op.batchit(x, batch_dimension=0) return x ** (1 - alphas) * (1 - x) ** betas diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 09f337dbca..83b8a24afd 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -572,18 +572,14 @@ def pdfNN_layer_generator( else: sumrule_layer = lambda x: x - # Only these layers change from replica to replica: - preprocessing_factor_replicas = [] - for i_replica, replica_seed in enumerate(seed): - preprocessing_factor_replicas.append( - Preprocessing( - flav_info=flav_info, - input_shape=(1,), - name=f"preprocessing_factor_{i_replica}", - seed=replica_seed + number_of_layers, - large_x=not subtract_one, - ) - ) + compute_preprocessing_factor = Preprocessing( + flav_info=flav_info, + input_shape=(1,), + name="preprocessing_factor", + seed=seed[0] + number_of_layers, + large_x=not subtract_one, + num_replicas=num_replicas, + ) nn_replicas = generate_nn( layer_type=layer_type, @@ -613,12 +609,6 @@ def neural_network_replicas(x, postfix=""): return NNs_x - # Apply preprocessing factors for all replicas to a given input grid - def preprocessing_replicas(x, postfix=""): - return Lambda(lambda pfs: op.stack(pfs, axis=1), name=f"prefactors{postfix}")( - [pf(x) for pf in preprocessing_factor_replicas] - ) - def compute_unnormalized_pdf(x, postfix=""): # Preprocess the input grid x_nn_input = extract_nn_input(x) @@ -629,7 +619,7 @@ def compute_unnormalized_pdf(x, postfix=""): NNs_x = neural_network_replicas(x_processed, postfix=postfix) # Compute the preprocessing factor - preprocessing_factors_x = preprocessing_replicas(x_original, postfix=postfix) + preprocessing_factors_x = compute_preprocessing_factor(x_original) # Apply the preprocessing factor pref_NNs_x = apply_preprocessing_factor([preprocessing_factors_x, NNs_x]) From 661d39af092b449e93400a4f65b14b78e8cbd6a8 Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 5 Dec 2023 15:30:14 +0100 Subject: [PATCH 32/71] Add replica dimension to preprocessing factor in test --- n3fit/src/n3fit/tests/test_preprocessing.py | 80 +++++++++++---------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/n3fit/src/n3fit/tests/test_preprocessing.py b/n3fit/src/n3fit/tests/test_preprocessing.py index 3bf6a8966c..0280011343 100644 --- a/n3fit/src/n3fit/tests/test_preprocessing.py +++ b/n3fit/src/n3fit/tests/test_preprocessing.py @@ -22,45 +22,47 @@ def test_preprocessing(): test_prefactors = [ [ [ - 3.7446213e-01, - 1.9785003e-01, - 2.7931085e-01, - 2.0784079e-01, - 4.5369801e-01, - 2.7796263e-01, - 5.4610312e-01, - 2.4907256e-02, - ], - [ - 6.2252983e-04, - 3.0504008e-05, - 4.5713778e-03, - 1.0905267e-03, - 4.0506415e-02, - 5.9004971e-05, - 4.5114113e-03, - 2.6757403e-09, - ], - [ - 4.1631009e-02, - 1.0586979e-02, - 8.3202787e-02, - 4.3506064e-02, - 2.2559988e-01, - 1.5161950e-02, - 1.0105091e-01, - 1.4808348e-04, - ], - [ - 1.1616933e-01, - 4.2717375e-02, - 1.5620175e-01, - 9.7478621e-02, - 3.2600221e-01, - 5.8901049e-02, - 2.1937098e-01, - 1.8343410e-03, - ], + [ + 3.7446213e-01, + 1.9785003e-01, + 2.7931085e-01, + 2.0784079e-01, + 4.5369801e-01, + 2.7796263e-01, + 5.4610312e-01, + 2.4907256e-02, + ], + [ + 6.2252983e-04, + 3.0504008e-05, + 4.5713778e-03, + 1.0905267e-03, + 4.0506415e-02, + 5.9004971e-05, + 4.5114113e-03, + 2.6757403e-09, + ], + [ + 4.1631009e-02, + 1.0586979e-02, + 8.3202787e-02, + 4.3506064e-02, + 2.2559988e-01, + 1.5161950e-02, + 1.0105091e-01, + 1.4808348e-04, + ], + [ + 1.1616933e-01, + 4.2717375e-02, + 1.5620175e-01, + 9.7478621e-02, + 3.2600221e-01, + 5.8901049e-02, + 2.1937098e-01, + 1.8343410e-03, + ], + ] ] ] prefactors = prepro(test_x) From 664125380c08a004154cec4b60b822c88b5327fa Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 5 Dec 2023 15:43:41 +0100 Subject: [PATCH 33/71] Update preprocessing layer in vpinterface --- n3fit/src/n3fit/vpinterface.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/vpinterface.py b/n3fit/src/n3fit/vpinterface.py index 7e2e754e0f..6de7693682 100644 --- a/n3fit/src/n3fit/vpinterface.py +++ b/n3fit/src/n3fit/vpinterface.py @@ -224,13 +224,7 @@ def get_preprocessing_factors(self, replica=None): if replica is None: replica = 1 # Replicas start counting in 1 so: - preprocessing_layers = self._models[replica - 1].get_layer_re(r"preprocessing_factor_\d") - if len(preprocessing_layers) > 1: - # We really don't want to fail at this point, but print a warning at least... - log.warning("More than one preprocessing layer found within the model!") - elif len(preprocessing_layers) < 1: - log.warning("No preprocessing layer found within the model!") - preprocessing_layer = preprocessing_layers[0] + preprocessing_layer = self._models[replica - 1].get_layer("preprocessing_factor") alphas_and_betas = None if self.fit_basis is not None: From 633a5c4aa09b68ce5915cc7edd418b7980fc91dc Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 13 Dec 2023 17:22:37 +0100 Subject: [PATCH 34/71] Remove assigning of weight slices --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index eea235191a..33c461960b 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -497,5 +497,8 @@ def set_layer_replica_weights(layer, weights, i_replica: int): i_replica: int the replica number """ - for w, w_new in zip(layer.weights, weights): - w[i_replica].assign(w_new[0]) + full_weights = [w.numpy() for w in layer.weights] + for w_old, w_new in zip(full_weights, weights): + w_old[i_replica : i_replica + 1] = w_new + + layer.set_weights(full_weights) From 019fd56f2d4e25c21705959f9cb9438b6db0381c Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 8 Jan 2024 13:33:56 +0100 Subject: [PATCH 35/71] Simplify loading weights from file --- .../n3fit/backends/keras_backend/MetaModel.py | 48 ++----------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 33c461960b..c6e2db98e8 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -413,55 +413,13 @@ def load_identical_replicas(self, model_file): """ From a single replica model, load the same weights into all replicas. """ - weights = self._format_weights_from_file(model_file) + single_replica = self.single_replica_generator() + single_replica.load_weights(model_file) + weights = single_replica.get_replica_weights(0) for i_replica in range(self.num_replicas): self.set_replica_weights(weights, i_replica) - def _format_weights_from_file(self, model_file): - """Read weights from a .h5 file and format into a dictionary of tf.Variables""" - weights = {} - - with h5py.File(model_file, 'r') as f: - # look at layers of the form NN_i and take the lowest i - i_replica = 0 - while f"{NN_PREFIX}_{i_replica}" not in f: - i_replica += 1 - - weights[NN_PREFIX] = self._extract_weights( - f[f"{NN_PREFIX}_{i_replica}"], NN_PREFIX, i_replica - ) - weights[PREPROCESSING_PREFIX] = self._extract_weights( - f[f"{PREPROCESSING_PREFIX}_{i_replica}"], PREPROCESSING_PREFIX, i_replica - ) - - return weights - - def _extract_weights(self, h5_group, weights_key, i_replica): - """Extract weights from a h5py group, turning them into Tensorflow variables""" - weights = [] - - def append_weights(name, node): - if isinstance(node, h5py.Dataset): - weight_name = node.name.split("/", 2)[-1] - weight_name = weight_name.replace(f"{NN_PREFIX}_{i_replica}", f"{NN_PREFIX}_0") - weight_name = weight_name.replace( - f"{PREPROCESSING_PREFIX}_{i_replica}", f"{PREPROCESSING_PREFIX}_0" - ) - weights.append(tf.Variable(node[()], name=weight_name)) - - h5_group.visititems(append_weights) - - # have to put them in the same order - weights_ordered = [] - weights_model_order = [w.name for w in self.get_replica_weights(0)[weights_key]] - for w in weights_model_order: - for w_h5 in weights: - if w_h5.name == w: - weights_ordered.append(w_h5) - - return weights_ordered - def get_layer_replica_weights(layer, i_replica: int): """ From 3c7607e4adf7f41e52534bc9c1be918f145773e4 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 8 Jan 2024 13:56:09 +0100 Subject: [PATCH 36/71] Update regression data --- .../n3fit/tests/regressions/quickcard_1.json | 84 +++++++++--------- .../n3fit/tests/regressions/quickcard_2.json | 84 +++++++++--------- .../src/n3fit/tests/regressions/weights_1.h5 | Bin 29064 -> 31272 bytes .../src/n3fit/tests/regressions/weights_2.h5 | Bin 29064 -> 31272 bytes 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/n3fit/src/n3fit/tests/regressions/quickcard_1.json b/n3fit/src/n3fit/tests/regressions/quickcard_1.json index e1ab150b66..e2fa582162 100644 --- a/n3fit/src/n3fit/tests/regressions/quickcard_1.json +++ b/n3fit/src/n3fit/tests/regressions/quickcard_1.json @@ -2,94 +2,94 @@ "preprocessing": [ { "fl": "sng", - "smallx": 1.1307647228240967, - "largex": 2.6348154544830322, + "smallx": 1.0608619451522827, + "largex": 2.435075283050537, "trainable": true }, { "fl": "g", - "smallx": 1.1853630542755127, - "largex": 1.5627975463867188, + "smallx": 1.1140261888504028, + "largex": 5.703322887420654, "trainable": true }, { "fl": "v", - "smallx": 0.5399999022483826, - "largex": 2.004500150680542, + "smallx": 0.5908387899398804, + "largex": 1.4993104934692383, "trainable": true }, { "fl": "v3", - "smallx": 0.3061078190803528, - "largex": 2.6242549419403076, + "smallx": 0.391951322555542, + "largex": 1.71088707447052, "trainable": true }, { "fl": "v8", - "smallx": 0.5774596929550171, - "largex": 2.120253801345825, + "smallx": 0.6944140195846558, + "largex": 1.2567583322525024, "trainable": true }, { "fl": "t3", - "smallx": 1.3441987037658691, - "largex": 1.7566683292388916, + "smallx": 0.5058831572532654, + "largex": 2.0005972385406494, "trainable": true }, { "fl": "t8", - "smallx": 1.047775387763977, - "largex": 1.945939064025879, + "smallx": 0.7622368335723877, + "largex": 2.795137643814087, "trainable": true }, { "fl": "cp", - "smallx": 0.7400740385055542, - "largex": 3.461853504180908, + "smallx": 0.8536127209663391, + "largex": 6.6416802406311035, "trainable": true } ], "stop_epoch": 1100, "best_epoch": 1099, - "erf_tr": 31.587974548339844, - "erf_vl": 29.09645652770996, - "chi2": 20.467185974121094, + "erf_tr": 53.118446350097656, + "erf_vl": 49.94154357910156, + "chi2": 28.98702049255371, "pos_state": "POS_VETO", "arc_lengths": [ - 1.0353434175487572, - 1.1966792723668909, - 1.0884899669278114, - 1.3288290197461279, - 1.0839435375255841 + 0.9940337093523915, + 1.4350646487017111, + 1.1474061176395847, + 1.0115618588849309, + 1.241211877456066 ], "integrability": [ - 0.002641671162566972, - 0.002641671162561421, - 0.0002462610455011838, - 3.1516795754432665, - 0.003926577570384282 + 0.003768992610269112, + 0.003768992610274635, + 0.00012586315097173895, + 0.04072074079886079, + 0.006150423490908663 ], "timing": { "walltime": { - "Total": 17.712170839309692, + "Total": 66.50783586502075, "start": 0.0, - "replica_set": 0.1738264560699463, - "replica_fitted": 17.712095260620117, - "replica_set_to_replica_fitted": 17.53826880455017 + "replica_set": 0.25814390182495117, + "replica_fitted": 66.5077497959137, + "replica_set_to_replica_fitted": 66.24960589408875 }, "cputime": { - "Total": 18.391021507999998, + "Total": 88.704174, "start": 0.0, - "replica_set": 0.173584666, - "replica_fitted": 18.390944242, - "replica_set_to_replica_fitted": 18.217359576 + "replica_set": 0.5755660000000002, + "replica_fitted": 88.704084, + "replica_set_to_replica_fitted": 88.128518 } }, "version": { - "keras": "2.11.0", - "tensorflow": "2.11.0, mkl=False", - "numpy": "1.24.3", - "nnpdf": "4.0.6.744+ga791d281e-dev", - "validphys": "4.0.6.744+ga791d281e-dev" + "keras": "2.9.0", + "tensorflow": "2.9.2, mkl=False", + "numpy": "1.22.3", + "nnpdf": "4.0.7.131+g2e302ad7a-dev", + "validphys": "4.0.7.131+g2e302ad7a-dev" } } \ No newline at end of file diff --git a/n3fit/src/n3fit/tests/regressions/quickcard_2.json b/n3fit/src/n3fit/tests/regressions/quickcard_2.json index d59c97a5f5..9aa3c9c518 100644 --- a/n3fit/src/n3fit/tests/regressions/quickcard_2.json +++ b/n3fit/src/n3fit/tests/regressions/quickcard_2.json @@ -2,94 +2,94 @@ "preprocessing": [ { "fl": "sng", - "smallx": 1.1108688116073608, - "largex": 2.6956193447113037, + "smallx": 1.1373717784881592, + "largex": 2.2215213775634766, "trainable": true }, { "fl": "g", - "smallx": 0.9399998784065247, - "largex": 1.621421217918396, + "smallx": 1.1855839490890503, + "largex": 1.0370781421661377, "trainable": true }, { "fl": "v", - "smallx": 0.7499998211860657, - "largex": 1.7185953855514526, + "smallx": 0.7131961584091187, + "largex": 1.2988507747650146, "trainable": true }, { "fl": "v3", - "smallx": 0.215017169713974, - "largex": 1.3573191165924072, + "smallx": 0.3124141991138458, + "largex": 1.678762674331665, "trainable": true }, { "fl": "v8", - "smallx": 0.7532474994659424, - "largex": 2.389765977859497, + "smallx": 0.5946128368377686, + "largex": 2.5053675174713135, "trainable": true }, { "fl": "t3", - "smallx": 1.4219000339508057, - "largex": 2.273611545562744, + "smallx": -0.3436424136161804, + "largex": 3.272998094558716, "trainable": true }, { "fl": "t8", - "smallx": 1.0386217832565308, - "largex": 1.7531665563583374, + "smallx": 0.8454508781433105, + "largex": 2.545261859893799, "trainable": true }, { "fl": "cp", - "smallx": 0.23516468703746796, - "largex": 2.7976953983306885, + "smallx": 0.7453753352165222, + "largex": 2.8414509296417236, "trainable": true } ], "stop_epoch": 1100, "best_epoch": 1099, - "erf_tr": 4.962428092956543, - "erf_vl": 5.63330078125, - "chi2": 3.5181877613067627, + "erf_tr": 175.88507080078125, + "erf_vl": 144.5820770263672, + "chi2": 102.0027084350586, "pos_state": "POS_VETO", "arc_lengths": [ - 1.324828406611252, - 1.1113330992990824, - 1.0539862831681286, - 4.888539270923742, - 1.067708667365969 + 1.0492436979844655, + 1.6211160857702436, + 1.46553459899021, + 1.0124231018671561, + 1.0749082174254012 ], "integrability": [ - 0.029175871051850266, - 0.02917587105184627, - 0.0003802012824946077, - 12.767466306686401, - 0.029576309956610758 + 0.018149158218885852, + 0.018149158218875916, + 4.653956193745312e-05, + 0.05125390924513323, + 0.004193901346297602 ], "timing": { "walltime": { - "Total": 17.551416397094727, + "Total": 65.60019397735596, "start": 0.0, - "replica_set": 0.17304396629333496, - "replica_fitted": 17.551299571990967, - "replica_set_to_replica_fitted": 17.378255605697632 + "replica_set": 0.3589169979095459, + "replica_fitted": 65.6001501083374, + "replica_set_to_replica_fitted": 65.24123311042786 }, "cputime": { - "Total": 18.186233694000002, + "Total": 86.516851, "start": 0.0, - "replica_set": 0.17282558100000145, - "replica_fitted": 18.186119053, - "replica_set_to_replica_fitted": 18.013293472 + "replica_set": 0.8151540000000015, + "replica_fitted": 86.516799, + "replica_set_to_replica_fitted": 85.701645 } }, "version": { - "keras": "2.11.0", - "tensorflow": "2.11.0, mkl=False", - "numpy": "1.24.3", - "nnpdf": "4.0.6.744+ga791d281e-dev", - "validphys": "4.0.6.744+ga791d281e-dev" + "keras": "2.9.0", + "tensorflow": "2.9.2, mkl=False", + "numpy": "1.22.3", + "nnpdf": "4.0.7.131+g2e302ad7a-dev", + "validphys": "4.0.7.131+g2e302ad7a-dev" } } \ No newline at end of file diff --git a/n3fit/src/n3fit/tests/regressions/weights_1.h5 b/n3fit/src/n3fit/tests/regressions/weights_1.h5 index 2c5b02e71eed2ab94b30aa51f0cfb9264fc4ba55..50f4ab15f725b63e0070723b3960f33b91f7e174 100644 GIT binary patch literal 31272 zcmeHQ33wDm7VgP`10-?<67GQo4T|B)V1VwL;f@QNfPe-SCV>n|AS59fLO_KfC`S0u zfE-y}F|Z0zZt*~vsUVjDxj~2s$bx(XffaWV1M0fnUGGh1n&~8qkYu6z`$*NR_g)=; zzxQgYy1RHavfqHfI?d{E(xumPeq4Pyi+_HHD|8wwK^pn7kkLV!18IQ|%jmdToWu)( z^7>G}!Iu>jgW~Wf`}gNKUk>ZX6x3W5gkr%^mdOG-7BUBsuch}C0+IcD50M5G3-)pq zMwcJWGCI+6z1f+50OQ+1UQN#Mgr^*ca}B^=m3AG#>2-dhkd6!Bf<)_1j+<&tx1_{P zv}VYvO~uYgo+SNaUDnIxIvt||WQr5D*(H}U5xGp#Ogs^t%h#2XZ70<9txc!~K)9 zZhzG5AhIbFIs>vSF6mU`($*GC5aS!DX~}(p0LG;l7_R}+Sjj2fu6S!ohSk!IV`(^~ zMu-g@7vUybnXFFKl>8X&4&zj4Go~F0c3Dwf1N%k~mSc|`a4=RuybzV6qB1O5mZTJ$ zH9@WlrgauS#FDgh>$teFw$yZsElG@hmZ&J!B24cru1Iq6<1E(9)a1!F(T^=-;xdw0 zoRs63$j3M+$qg7(CLsH>$Y(!LI4)^oTB-=-#Ef*-jvN=oEaG4r7iO`frioEQ>{Eut z5|&`KCE2VK@pfQ)QBju8QVkHoSo{=eaXe}1sbj4f8A&M#7B)0VPKu$@h2s)&k!kD~ z_9M%ZoSKkTh9AJn$q0&_l1879o)nMcm9ZCV5>@0&ihM=Hle6X`lW0K-BdWr(r4@?=~*h!49Dc0nkof~-7H@fuY`9hTO)DL&* z%kziG_iVqLOJAO!Zqe`N(r*myw}#Z)edrXIoR%18$&3&O)CA;Ol_x*OY6EdDxbpSe zx{39pJyl%4EY88S!BwLFHmU#Mrd%cJm&Cc|mGA%9G*JQFzvB93ajs=$@C5v&{$RbR z=k&0?1{d;{&ZF8Uh*u8Uh*u8Uh*u8Uh*u8Ul9`fnib6{iMAxTnCrJ0vXq( z23TmCVF6tq8sBPU8I&slS|7p6as9;g@RSP$IPt=ZlA(jI|3 zU&_1l*&cu_A#yygiuOT6U}1!I`%@T4AbcRZ!j#1? zUswFv1aS)MQ|^bNb*FV;Rij)U(3>7*JGb(9cF}6vP4GgX2c*k)DE?Cb6&j1ws#XBVNeSBDjde~v})x{c^NES$9 zqNK6BYEoubKCXShSO$k`;~4k!xG|K& z-SHs_?pd20C`qKjzt843?r21GH}{h7CfuN{=SG+=&%5ayz33IXyvN7Rc42+V%fC#f z-4<-7UFRRg*r2gmc>!<_3HrP19*I=ZcPcVc_wJ-WI_C|U9FaXxHc(?f zf1%ad3-s3$obc(I{X))2fsUMY!O2e^DSXyGPq=yTec|xG*EokQnMC^5YHeDOd`);E z@-+D&bC$sOSxNlAXhJi(wIm&y9-~9fou^}WU8llRQ>erAi15*lNN? zl}o0CX3}Z@Tue?~ewpsL?qAsanNDQ>3v-<}ViwS~-|lrBi+_p?@A5JK@o!%Xr|K;i z2EFqz2_HK`2x_@Xc=eN=bmp8{!g>48wDGB2a^PY%ofD8lOP@E;iEsNACgy|`&hK@O zeBLFStZcuXnh!4(eE!wj8MAN^9X+)@DH;A1jXi#pF14H`*II8Bb{k)#%O1Z$_cRYO zeUuSMzdw}kY#Z8^EKaRW8ZR47H~rfCM#OZbr3EwSj!+Zf z*GBS99le|z&gAiR_NP0?@3}yp?%dM!^7JLda-*1BA9h68S1?!zXz~W#+N7>&%ie?Z zz`iBq(E}Su_H=*Y>`Sw$J$JZc%V!-)t*4HXlgTFG%XzIygZ|mhsde5Z+dF?FoLy+9 z`oA7^Mm0S{b{`FKOgW;bzR_#xrnbYJ@s}SLik~|~LVj*ZqbD?S`VA}+#-FN1@;_Wd ze`%IaKYf1$Es1MEqkCSUr=8K{$?+XXtzth?lKm4Ow!_GWd}HMOmKz=RrAEiTJx2b- zETdyr!|wcwHActMT}FQ0P9s0)@(7afL!oo%#RPhAie0E1xQ|@5yeRD2ypU{vXoTQ% ztSvdezo}_b=x_A&xd#iEue?Mv*EBboZ9%5Jr5(uPwM`1wG_GxWxc3p~n@x5L->&c> zqu%io`ZV26@+|X6{NFOE`NT@nce9CX3Fb-B~;FkHV2ur?QNPW>Rri>7sBcuqA}A3 z@xFD|JJbKX(|PoCL$W$+yi<3~M11yNA&&e>!UN4_lERmAY1?)`(m7vjp?ed4BZ1f6 zq??ob({J>TIlpYYkv!kuM;Myf%QX6#2dN1dw`TmOF+GsTdZXbbLe^;_!*7zP2{+`72_J2nf8(1%4 zlW23>}oi$->S|6$o0k!pZF|1#)CwF?ieXBpSg%Pe3 z(U0*lwvxVm{|;)y#uS4~PZ(m&S|{d&A@bf+^w-WEz4Pza(p&AybDltZ!u0m-C>dVm zV0K%EcTQQh2ISP{3FZD%Me{^rH#QiwyBaVwtqWC%fZ9C4b@l8-RnHUX$7q*I`u6>M zA^5jh+HQ2aYSuilKHRNqUb2WwjN(3d5xuX9Dw-z{H%xEej*h}Bd=CSAcIY0PCpgvb7^-&^TI=c&sKOp!4Be@|9Il2QJx5>`A;I)5lY`J|53hI zQ{Dcu&jv@_n=F_MfYL7)o{kOY=^qO3mwoyTHlKO^8Wq))fC3JvqXG{$h(|jvZow~-;&_( z%>tO8iU6Og@^{UTZ@DE}fg1woCoxcl>#+6x-Gs#Ko%Un&i?qJ1om^;7^9xVhHL7|L zQ1gqTNYDP(SseK(%tf(q9<4j zC4*R6-To8#Bfj)!?}^%5!;?=i(^Oo58A;=j*7Q%Oj4%>$yH^<5N3#2iwhp44#i;OHH#RTQjZ6 zmWiqH;$QY%T!ss$G*rCHDSrQm_r(tDLcCwfbs|3ZD1x_;P)_-~ITreTRUxPR9f7#y zLwv;gl=1Q|!|;cz$Mu8$FRZFi@Cz}{!#R20pW{^Y{UbiL!PFpC4?$RZK-=1lmLB}e zpWgt#jY!Mqy8zu*!IyaMd`Z{6J}K{BpFzQItl&#$61nS3XAZgRhbZ{cnL+M+=}aJZ zed){}cRu@+4v`Rt?!?N%GKiguZX8wdi(FAT!Z&f-~)ZvU~mR;6;x@4*_ECvfmYX#FTZ() z7RTj1Q@$M9Y3HZQmn#5v+PL!Nih!M)SiT&xb1db{zrI91DsgAT4;de7O){ z=Zq|0ZWFNW>{x77;bP$AC#j0aj4WX1#g;FZhwOOFcu!-XxM-AjK9*LWpM}&&yFy%) zNAtQJ?JJA89VIN&GM^n4?8eWOjv6lGmysOPmybGj&quk%hdy)o&D_6FC$(1uxLk2>yQ7fK6`6XBkisF@Gxk2h~`{2&$ZL= z@W3Nf!@~oQjv5{wcyz9jcxdmzh&M^QR1v`Eln0ZUNHOdORMq<^ntiI?8jT?$ptf(d zev&6VcY5Cn{UR-uwUZ0&X@22}yGB(H0&0FyWb^FL-SUeZ*uO1+_NvM+)b^7Lrm}I{ zVffm-;%NsO<%xir|LAe!5ybDb|FC^pe=Zm5KLhU@V>`{w`Ajqv(w5#-c5UcV8=V#^kswxis7kfL=Qvd(} literal 29064 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 Q7d(PgJY4Y5)d@WQ4;SlD;{X5v diff --git a/n3fit/src/n3fit/tests/regressions/weights_2.h5 b/n3fit/src/n3fit/tests/regressions/weights_2.h5 index e5a8adea8692c6ef3fab1d8947de89455ce607ca..ecaa78ee2cb6cd15f62a07599eca19fe5d77314f 100644 GIT binary patch literal 31272 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 literal 29064 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 Date: Tue, 9 Jan 2024 12:35:52 +0100 Subject: [PATCH 37/71] Always return a single NNs model for all replicas, adjust weight getting and setting accordingly --- .../n3fit/backends/keras_backend/MetaModel.py | 59 +++++++++++++------ n3fit/src/n3fit/model_gen.py | 31 +++++----- n3fit/src/n3fit/model_trainer.py | 2 +- n3fit/src/n3fit/tests/test_modelgen.py | 4 +- 4 files changed, 60 insertions(+), 36 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index c6e2db98e8..de6a8fcad5 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -46,7 +46,8 @@ } NN_PREFIX = "NN" -PREPROCESSING_PREFIX = "preprocessing_factor" +NN_LAYER = "NNs" +PREPROESSING_LAYER = "preprocessing_factor" # Some keys need to work for everyone for k, v in optimizers.items(): @@ -353,14 +354,12 @@ def get_replica_weights(self, i_replica): dict dictionary with the weights of the replica """ - NN_weights = [ - tf.Variable(w, name=w.name) for w in self.get_layer(f"{NN_PREFIX}_{i_replica}").weights - ] - prepro_weights = [ - tf.Variable(w, name=w.name) - for w in get_layer_replica_weights(self.get_layer(PREPROCESSING_PREFIX), i_replica) - ] - weights = {NN_PREFIX: NN_weights, PREPROCESSING_PREFIX: prepro_weights} + weights = {} + for layer_type in [NN_LAYER, PREPROESSING_LAYER]: + weights[layer_type] = [ + tf.Variable(w, name=w.name) + for w in get_layer_replica_weights(self.get_layer(layer_type), i_replica) + ] return weights @@ -378,12 +377,10 @@ def set_replica_weights(self, weights, i_replica=0): i_replica: int the replica number to set, defaulting to 0 """ - self.get_layer(f"{NN_PREFIX}_{i_replica}").set_weights(weights[NN_PREFIX]) - set_layer_replica_weights( - layer=self.get_layer(PREPROCESSING_PREFIX), - weights=weights[PREPROCESSING_PREFIX], - i_replica=i_replica, - ) + for layer_type in [NN_LAYER, PREPROESSING_LAYER]: + set_layer_replica_weights( + layer=self.get_layer(layer_type), weights=weights[layer_type], i_replica=i_replica + ) def split_replicas(self): """ @@ -421,6 +418,25 @@ def load_identical_replicas(self, model_file): self.set_replica_weights(weights, i_replica) +def stacked_single_replicas(layer): + """ + Check if the layer consists of stacked single replicas (Only happens for NN layers) + + Parameters + ---------- + layer: MetaLayer + the layer to check + + Returns + ------- + bool + True if the layer consists of stacked single replicas + """ + if not isinstance(layer, MetaModel): + return False + return f"{NN_PREFIX}_0" in [sublayer.name for sublayer in layer.layers] + + def get_layer_replica_weights(layer, i_replica: int): """ Get the weights for the given single replica `i_replica`, @@ -438,13 +454,18 @@ def get_layer_replica_weights(layer, i_replica: int): weights: list list of weights for the replica """ - return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] + if stacked_single_replicas(layer): + weights = layer.get_layer(f"{NN_PREFIX}_{i_replica}").weights + else: + weights = [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] + + return weights def set_layer_replica_weights(layer, weights, i_replica: int): """ Set the weights for the given single replica `i_replica`, - from a `layer` that has weights for all replicas. + for a `layer` that has weights for all replicas. Parameters ---------- @@ -455,6 +476,10 @@ def set_layer_replica_weights(layer, weights, i_replica: int): i_replica: int the replica number """ + if stacked_single_replicas(layer): + layer.get_layer(f"{NN_PREFIX}_{i_replica}").set_weights(weights) + return + full_weights = [w.numpy() for w in layer.weights] for w_old, w_new in zip(full_weights, weights): w_old[i_replica : i_replica + 1] = w_new diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 83b8a24afd..6825d1cfba 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -596,15 +596,11 @@ def pdfNN_layer_generator( # Apply NN layers for all replicas to a given input grid def neural_network_replicas(x, postfix=""): - NNs_x = Lambda(lambda nns: op.stack(nns, axis=1), name=f"NNs{postfix}")( - [nn(x) for nn in nn_replicas] - ) + NNs_x = nn_replicas(x) if subtract_one: x_eq_1_processed = process_input(layer_x_eq_1) - NNs_x_1 = Lambda(lambda nns: op.stack(nns, axis=1), name=f"NNs{postfix}_x_1")( - [nn(x_eq_1_processed) for nn in nn_replicas] - ) + NNs_x_1 = nn_replicas(x_eq_1_processed) NNs_x = subtract_one_layer([NNs_x, NNs_x_1]) return NNs_x @@ -660,11 +656,10 @@ def compute_unnormalized_pdf(x, postfix=""): if photons: PDFs = layer_photon(PDFs) - if replica_axis: - pdf_model = MetaModel(model_input, PDFs, name=f"PDFs", scaler=scaler) - else: - pdf_model = MetaModel(model_input, PDFs[:, 0], name=f"PDFs", scaler=scaler) + if not replica_axis: + PDFs = Lambda(lambda pdfs: pdfs[:, 0], name="remove_replica_axis")(PDFs) + pdf_model = MetaModel(model_input, PDFs, name=f"PDFs", scaler=scaler) return pdf_model @@ -709,8 +704,8 @@ def generate_nn( Returns ------- - nn_replicas: List[MetaModel] - List of MetaModel objects, one for each replica. + nn_replicas: MetaModel + Single model containing all replicas. """ nodes_list = list(nodes) # so we can modify it x_input = Input(shape=(None, nodes_in), batch_size=1, name='xgrids_processed') @@ -734,7 +729,7 @@ def initializer_generator(seed, i_layer): ] return initializers - elif layer_type == "dense": + else: # "dense" reg = regularizer_selector(regularizer, **regularizer_args) custom_args['regularizer'] = reg @@ -772,6 +767,7 @@ def initializer_generator(seed, i_layer): # Apply all layers to the input to create the models pdfs = [layer(x_input) for layer in list_of_pdf_layers[0]] + for layers in list_of_pdf_layers[1:]: # Since some layers (dropout) are shared, we have to treat them separately if type(layers) is list: @@ -779,9 +775,12 @@ def initializer_generator(seed, i_layer): else: pdfs = [layers(x) for x in pdfs] - models = [ - MetaModel({'NN_input': x_input}, pdf, name=f"NN_{i_replica}") + # Wrap the pdfs in a MetaModel to enable getting/setting of weights later + pdfs = [ + MetaModel({'NN_input': x_input}, pdf, name=f"NN_{i_replica}")(x_input) for i_replica, pdf in enumerate(pdfs) ] + pdfs = Lambda(lambda nns: op.stack(nns, axis=1), name=f"stack_replicas")(pdfs) + model = MetaModel({'NN_input': x_input}, pdfs, name=f"NNs") - return models + return model diff --git a/n3fit/src/n3fit/model_trainer.py b/n3fit/src/n3fit/model_trainer.py index 99e9f013db..35457166e0 100644 --- a/n3fit/src/n3fit/model_trainer.py +++ b/n3fit/src/n3fit/model_trainer.py @@ -454,7 +454,7 @@ def _model_generation(self, xinput, pdf_model, partition, partition_idx): training.summary() pdf_model = training.get_layer("PDFs") pdf_model.summary() - nn_model = pdf_model.get_layer("NN_0") + nn_model = pdf_model.get_layer("NNs") nn_model.summary() # We may have fits without sumrules imposed try: diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index d50b98728a..1178b59b71 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -25,7 +25,7 @@ def test_generate_dense_network(): - nn = generate_nn("dense", **COMMON_ARGS)[0] + nn = generate_nn("dense", **COMMON_ARGS).get_layer("NN_0") # The number of layers should be input layer + len(OUT_SIZES) assert len(nn.layers) == len(OUT_SIZES) + 1 @@ -40,7 +40,7 @@ def test_generate_dense_network(): def test_generate_dense_per_flavour_network(): - nn = generate_nn("dense_per_flavour", **COMMON_ARGS)[0] + nn = generate_nn("dense_per_flavour", **COMMON_ARGS).get_layer("NN_0") # The number of layers should be input + BASIS_SIZE*len(OUT_SIZES) + concatenate assert len(nn.layers) == BASIS_SIZE * len(OUT_SIZES) + 2 From 4e18e92db58515f16730c4bf71f567bc69d1c4ad Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 10 Jan 2024 14:11:18 +0100 Subject: [PATCH 38/71] Revert "Update regression data" This reverts commit 6f793687f2608c5af041ba989202460dff615220. --- .../n3fit/tests/regressions/quickcard_1.json | 84 +++++++++--------- .../n3fit/tests/regressions/quickcard_2.json | 84 +++++++++--------- .../src/n3fit/tests/regressions/weights_1.h5 | Bin 31272 -> 29064 bytes .../src/n3fit/tests/regressions/weights_2.h5 | Bin 31272 -> 29064 bytes 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/n3fit/src/n3fit/tests/regressions/quickcard_1.json b/n3fit/src/n3fit/tests/regressions/quickcard_1.json index e2fa582162..e1ab150b66 100644 --- a/n3fit/src/n3fit/tests/regressions/quickcard_1.json +++ b/n3fit/src/n3fit/tests/regressions/quickcard_1.json @@ -2,94 +2,94 @@ "preprocessing": [ { "fl": "sng", - "smallx": 1.0608619451522827, - "largex": 2.435075283050537, + "smallx": 1.1307647228240967, + "largex": 2.6348154544830322, "trainable": true }, { "fl": "g", - "smallx": 1.1140261888504028, - "largex": 5.703322887420654, + "smallx": 1.1853630542755127, + "largex": 1.5627975463867188, "trainable": true }, { "fl": "v", - "smallx": 0.5908387899398804, - "largex": 1.4993104934692383, + "smallx": 0.5399999022483826, + "largex": 2.004500150680542, "trainable": true }, { "fl": "v3", - "smallx": 0.391951322555542, - "largex": 1.71088707447052, + "smallx": 0.3061078190803528, + "largex": 2.6242549419403076, "trainable": true }, { "fl": "v8", - "smallx": 0.6944140195846558, - "largex": 1.2567583322525024, + "smallx": 0.5774596929550171, + "largex": 2.120253801345825, "trainable": true }, { "fl": "t3", - "smallx": 0.5058831572532654, - "largex": 2.0005972385406494, + "smallx": 1.3441987037658691, + "largex": 1.7566683292388916, "trainable": true }, { "fl": "t8", - "smallx": 0.7622368335723877, - "largex": 2.795137643814087, + "smallx": 1.047775387763977, + "largex": 1.945939064025879, "trainable": true }, { "fl": "cp", - "smallx": 0.8536127209663391, - "largex": 6.6416802406311035, + "smallx": 0.7400740385055542, + "largex": 3.461853504180908, "trainable": true } ], "stop_epoch": 1100, "best_epoch": 1099, - "erf_tr": 53.118446350097656, - "erf_vl": 49.94154357910156, - "chi2": 28.98702049255371, + "erf_tr": 31.587974548339844, + "erf_vl": 29.09645652770996, + "chi2": 20.467185974121094, "pos_state": "POS_VETO", "arc_lengths": [ - 0.9940337093523915, - 1.4350646487017111, - 1.1474061176395847, - 1.0115618588849309, - 1.241211877456066 + 1.0353434175487572, + 1.1966792723668909, + 1.0884899669278114, + 1.3288290197461279, + 1.0839435375255841 ], "integrability": [ - 0.003768992610269112, - 0.003768992610274635, - 0.00012586315097173895, - 0.04072074079886079, - 0.006150423490908663 + 0.002641671162566972, + 0.002641671162561421, + 0.0002462610455011838, + 3.1516795754432665, + 0.003926577570384282 ], "timing": { "walltime": { - "Total": 66.50783586502075, + "Total": 17.712170839309692, "start": 0.0, - "replica_set": 0.25814390182495117, - "replica_fitted": 66.5077497959137, - "replica_set_to_replica_fitted": 66.24960589408875 + "replica_set": 0.1738264560699463, + "replica_fitted": 17.712095260620117, + "replica_set_to_replica_fitted": 17.53826880455017 }, "cputime": { - "Total": 88.704174, + "Total": 18.391021507999998, "start": 0.0, - "replica_set": 0.5755660000000002, - "replica_fitted": 88.704084, - "replica_set_to_replica_fitted": 88.128518 + "replica_set": 0.173584666, + "replica_fitted": 18.390944242, + "replica_set_to_replica_fitted": 18.217359576 } }, "version": { - "keras": "2.9.0", - "tensorflow": "2.9.2, mkl=False", - "numpy": "1.22.3", - "nnpdf": "4.0.7.131+g2e302ad7a-dev", - "validphys": "4.0.7.131+g2e302ad7a-dev" + "keras": "2.11.0", + "tensorflow": "2.11.0, mkl=False", + "numpy": "1.24.3", + "nnpdf": "4.0.6.744+ga791d281e-dev", + "validphys": "4.0.6.744+ga791d281e-dev" } } \ No newline at end of file diff --git a/n3fit/src/n3fit/tests/regressions/quickcard_2.json b/n3fit/src/n3fit/tests/regressions/quickcard_2.json index 9aa3c9c518..d59c97a5f5 100644 --- a/n3fit/src/n3fit/tests/regressions/quickcard_2.json +++ b/n3fit/src/n3fit/tests/regressions/quickcard_2.json @@ -2,94 +2,94 @@ "preprocessing": [ { "fl": "sng", - "smallx": 1.1373717784881592, - "largex": 2.2215213775634766, + "smallx": 1.1108688116073608, + "largex": 2.6956193447113037, "trainable": true }, { "fl": "g", - "smallx": 1.1855839490890503, - "largex": 1.0370781421661377, + "smallx": 0.9399998784065247, + "largex": 1.621421217918396, "trainable": true }, { "fl": "v", - "smallx": 0.7131961584091187, - "largex": 1.2988507747650146, + "smallx": 0.7499998211860657, + "largex": 1.7185953855514526, "trainable": true }, { "fl": "v3", - "smallx": 0.3124141991138458, - "largex": 1.678762674331665, + "smallx": 0.215017169713974, + "largex": 1.3573191165924072, "trainable": true }, { "fl": "v8", - "smallx": 0.5946128368377686, - "largex": 2.5053675174713135, + "smallx": 0.7532474994659424, + "largex": 2.389765977859497, "trainable": true }, { "fl": "t3", - "smallx": -0.3436424136161804, - "largex": 3.272998094558716, + "smallx": 1.4219000339508057, + "largex": 2.273611545562744, "trainable": true }, { "fl": "t8", - "smallx": 0.8454508781433105, - "largex": 2.545261859893799, + "smallx": 1.0386217832565308, + "largex": 1.7531665563583374, "trainable": true }, { "fl": "cp", - "smallx": 0.7453753352165222, - "largex": 2.8414509296417236, + "smallx": 0.23516468703746796, + "largex": 2.7976953983306885, "trainable": true } ], "stop_epoch": 1100, "best_epoch": 1099, - "erf_tr": 175.88507080078125, - "erf_vl": 144.5820770263672, - "chi2": 102.0027084350586, + "erf_tr": 4.962428092956543, + "erf_vl": 5.63330078125, + "chi2": 3.5181877613067627, "pos_state": "POS_VETO", "arc_lengths": [ - 1.0492436979844655, - 1.6211160857702436, - 1.46553459899021, - 1.0124231018671561, - 1.0749082174254012 + 1.324828406611252, + 1.1113330992990824, + 1.0539862831681286, + 4.888539270923742, + 1.067708667365969 ], "integrability": [ - 0.018149158218885852, - 0.018149158218875916, - 4.653956193745312e-05, - 0.05125390924513323, - 0.004193901346297602 + 0.029175871051850266, + 0.02917587105184627, + 0.0003802012824946077, + 12.767466306686401, + 0.029576309956610758 ], "timing": { "walltime": { - "Total": 65.60019397735596, + "Total": 17.551416397094727, "start": 0.0, - "replica_set": 0.3589169979095459, - "replica_fitted": 65.6001501083374, - "replica_set_to_replica_fitted": 65.24123311042786 + "replica_set": 0.17304396629333496, + "replica_fitted": 17.551299571990967, + "replica_set_to_replica_fitted": 17.378255605697632 }, "cputime": { - "Total": 86.516851, + "Total": 18.186233694000002, "start": 0.0, - "replica_set": 0.8151540000000015, - "replica_fitted": 86.516799, - "replica_set_to_replica_fitted": 85.701645 + "replica_set": 0.17282558100000145, + "replica_fitted": 18.186119053, + "replica_set_to_replica_fitted": 18.013293472 } }, "version": { - "keras": "2.9.0", - "tensorflow": "2.9.2, mkl=False", - "numpy": "1.22.3", - "nnpdf": "4.0.7.131+g2e302ad7a-dev", - "validphys": "4.0.7.131+g2e302ad7a-dev" + "keras": "2.11.0", + "tensorflow": "2.11.0, mkl=False", + "numpy": "1.24.3", + "nnpdf": "4.0.6.744+ga791d281e-dev", + "validphys": "4.0.6.744+ga791d281e-dev" } } \ No newline at end of file diff --git a/n3fit/src/n3fit/tests/regressions/weights_1.h5 b/n3fit/src/n3fit/tests/regressions/weights_1.h5 index 50f4ab15f725b63e0070723b3960f33b91f7e174..2c5b02e71eed2ab94b30aa51f0cfb9264fc4ba55 100644 GIT binary patch literal 29064 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 Q7d(PgJY4Y5)d@WQ4;SlD;{X5v literal 31272 zcmeHQ33wDm7VgP`10-?<67GQo4T|B)V1VwL;f@QNfPe-SCV>n|AS59fLO_KfC`S0u zfE-y}F|Z0zZt*~vsUVjDxj~2s$bx(XffaWV1M0fnUGGh1n&~8qkYu6z`$*NR_g)=; zzxQgYy1RHavfqHfI?d{E(xumPeq4Pyi+_HHD|8wwK^pn7kkLV!18IQ|%jmdToWu)( z^7>G}!Iu>jgW~Wf`}gNKUk>ZX6x3W5gkr%^mdOG-7BUBsuch}C0+IcD50M5G3-)pq zMwcJWGCI+6z1f+50OQ+1UQN#Mgr^*ca}B^=m3AG#>2-dhkd6!Bf<)_1j+<&tx1_{P zv}VYvO~uYgo+SNaUDnIxIvt||WQr5D*(H}U5xGp#Ogs^t%h#2XZ70<9txc!~K)9 zZhzG5AhIbFIs>vSF6mU`($*GC5aS!DX~}(p0LG;l7_R}+Sjj2fu6S!ohSk!IV`(^~ zMu-g@7vUybnXFFKl>8X&4&zj4Go~F0c3Dwf1N%k~mSc|`a4=RuybzV6qB1O5mZTJ$ zH9@WlrgauS#FDgh>$teFw$yZsElG@hmZ&J!B24cru1Iq6<1E(9)a1!F(T^=-;xdw0 zoRs63$j3M+$qg7(CLsH>$Y(!LI4)^oTB-=-#Ef*-jvN=oEaG4r7iO`frioEQ>{Eut z5|&`KCE2VK@pfQ)QBju8QVkHoSo{=eaXe}1sbj4f8A&M#7B)0VPKu$@h2s)&k!kD~ z_9M%ZoSKkTh9AJn$q0&_l1879o)nMcm9ZCV5>@0&ihM=Hle6X`lW0K-BdWr(r4@?=~*h!49Dc0nkof~-7H@fuY`9hTO)DL&* z%kziG_iVqLOJAO!Zqe`N(r*myw}#Z)edrXIoR%18$&3&O)CA;Ol_x*OY6EdDxbpSe zx{39pJyl%4EY88S!BwLFHmU#Mrd%cJm&Cc|mGA%9G*JQFzvB93ajs=$@C5v&{$RbR z=k&0?1{d;{&ZF8Uh*u8Uh*u8Uh*u8Uh*u8Ul9`fnib6{iMAxTnCrJ0vXq( z23TmCVF6tq8sBPU8I&slS|7p6as9;g@RSP$IPt=ZlA(jI|3 zU&_1l*&cu_A#yygiuOT6U}1!I`%@T4AbcRZ!j#1? zUswFv1aS)MQ|^bNb*FV;Rij)U(3>7*JGb(9cF}6vP4GgX2c*k)DE?Cb6&j1ws#XBVNeSBDjde~v})x{c^NES$9 zqNK6BYEoubKCXShSO$k`;~4k!xG|K& z-SHs_?pd20C`qKjzt843?r21GH}{h7CfuN{=SG+=&%5ayz33IXyvN7Rc42+V%fC#f z-4<-7UFRRg*r2gmc>!<_3HrP19*I=ZcPcVc_wJ-WI_C|U9FaXxHc(?f zf1%ad3-s3$obc(I{X))2fsUMY!O2e^DSXyGPq=yTec|xG*EokQnMC^5YHeDOd`);E z@-+D&bC$sOSxNlAXhJi(wIm&y9-~9fou^}WU8llRQ>erAi15*lNN? zl}o0CX3}Z@Tue?~ewpsL?qAsanNDQ>3v-<}ViwS~-|lrBi+_p?@A5JK@o!%Xr|K;i z2EFqz2_HK`2x_@Xc=eN=bmp8{!g>48wDGB2a^PY%ofD8lOP@E;iEsNACgy|`&hK@O zeBLFStZcuXnh!4(eE!wj8MAN^9X+)@DH;A1jXi#pF14H`*II8Bb{k)#%O1Z$_cRYO zeUuSMzdw}kY#Z8^EKaRW8ZR47H~rfCM#OZbr3EwSj!+Zf z*GBS99le|z&gAiR_NP0?@3}yp?%dM!^7JLda-*1BA9h68S1?!zXz~W#+N7>&%ie?Z zz`iBq(E}Su_H=*Y>`Sw$J$JZc%V!-)t*4HXlgTFG%XzIygZ|mhsde5Z+dF?FoLy+9 z`oA7^Mm0S{b{`FKOgW;bzR_#xrnbYJ@s}SLik~|~LVj*ZqbD?S`VA}+#-FN1@;_Wd ze`%IaKYf1$Es1MEqkCSUr=8K{$?+XXtzth?lKm4Ow!_GWd}HMOmKz=RrAEiTJx2b- zETdyr!|wcwHActMT}FQ0P9s0)@(7afL!oo%#RPhAie0E1xQ|@5yeRD2ypU{vXoTQ% ztSvdezo}_b=x_A&xd#iEue?Mv*EBboZ9%5Jr5(uPwM`1wG_GxWxc3p~n@x5L->&c> zqu%io`ZV26@+|X6{NFOE`NT@nce9CX3Fb-B~;FkHV2ur?QNPW>Rri>7sBcuqA}A3 z@xFD|JJbKX(|PoCL$W$+yi<3~M11yNA&&e>!UN4_lERmAY1?)`(m7vjp?ed4BZ1f6 zq??ob({J>TIlpYYkv!kuM;Myf%QX6#2dN1dw`TmOF+GsTdZXbbLe^;_!*7zP2{+`72_J2nf8(1%4 zlW23>}oi$->S|6$o0k!pZF|1#)CwF?ieXBpSg%Pe3 z(U0*lwvxVm{|;)y#uS4~PZ(m&S|{d&A@bf+^w-WEz4Pza(p&AybDltZ!u0m-C>dVm zV0K%EcTQQh2ISP{3FZD%Me{^rH#QiwyBaVwtqWC%fZ9C4b@l8-RnHUX$7q*I`u6>M zA^5jh+HQ2aYSuilKHRNqUb2WwjN(3d5xuX9Dw-z{H%xEej*h}Bd=CSAcIY0PCpgvb7^-&^TI=c&sKOp!4Be@|9Il2QJx5>`A;I)5lY`J|53hI zQ{Dcu&jv@_n=F_MfYL7)o{kOY=^qO3mwoyTHlKO^8Wq))fC3JvqXG{$h(|jvZow~-;&_( z%>tO8iU6Og@^{UTZ@DE}fg1woCoxcl>#+6x-Gs#Ko%Un&i?qJ1om^;7^9xVhHL7|L zQ1gqTNYDP(SseK(%tf(q9<4j zC4*R6-To8#Bfj)!?}^%5!;?=i(^Oo58A;=j*7Q%Oj4%>$yH^<5N3#2iwhp44#i;OHH#RTQjZ6 zmWiqH;$QY%T!ss$G*rCHDSrQm_r(tDLcCwfbs|3ZD1x_;P)_-~ITreTRUxPR9f7#y zLwv;gl=1Q|!|;cz$Mu8$FRZFi@Cz}{!#R20pW{^Y{UbiL!PFpC4?$RZK-=1lmLB}e zpWgt#jY!Mqy8zu*!IyaMd`Z{6J}K{BpFzQItl&#$61nS3XAZgRhbZ{cnL+M+=}aJZ zed){}cRu@+4v`Rt?!?N%GKiguZX8wdi(FAT!Z&f-~)ZvU~mR;6;x@4*_ECvfmYX#FTZ() z7RTj1Q@$M9Y3HZQmn#5v+PL!Nih!M)SiT&xb1db{zrI91DsgAT4;de7O){ z=Zq|0ZWFNW>{x77;bP$AC#j0aj4WX1#g;FZhwOOFcu!-XxM-AjK9*LWpM}&&yFy%) zNAtQJ?JJA89VIN&GM^n4?8eWOjv6lGmysOPmybGj&quk%hdy)o&D_6FC$(1uxLk2>yQ7fK6`6XBkisF@Gxk2h~`{2&$ZL= z@W3Nf!@~oQjv5{wcyz9jcxdmzh&M^QR1v`Eln0ZUNHOdORMq<^ntiI?8jT?$ptf(d zev&6VcY5Cn{UR-uwUZ0&X@22}yGB(H0&0FyWb^FL-SUeZ*uO1+_NvM+)b^7Lrm}I{ zVffm-;%NsO<%xir|LAe!5ybDb|FC^pe=Zm5KLhU@V>`{w`Ajqv(w5#-c5UcV8=V#^kswxis7kfL=Qvd(} diff --git a/n3fit/src/n3fit/tests/regressions/weights_2.h5 b/n3fit/src/n3fit/tests/regressions/weights_2.h5 index ecaa78ee2cb6cd15f62a07599eca19fe5d77314f..e5a8adea8692c6ef3fab1d8947de89455ce607ca 100644 GIT binary patch literal 29064 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 From 47d5cab3d3712c81683470fb364c6a576cff047c Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 10 Jan 2024 14:32:31 +0100 Subject: [PATCH 39/71] Change structure of regression weights --- .../src/n3fit/tests/regressions/weights_1.h5 | Bin 29064 -> 31272 bytes .../src/n3fit/tests/regressions/weights_2.h5 | Bin 29064 -> 31272 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/n3fit/src/n3fit/tests/regressions/weights_1.h5 b/n3fit/src/n3fit/tests/regressions/weights_1.h5 index 2c5b02e71eed2ab94b30aa51f0cfb9264fc4ba55..82a4ca8556b08cd89afd9919963055e515989dd6 100644 GIT binary patch literal 31272 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 delta 3394 zcmZuzO-vg{6rLR$*xdqgn*?kJ?1i+!A;B>uR4z&zM+8KnNe%fkG{VMU{zAYBQRGt~ zQVyhQ)j02hsz!07s6tf_j(kB?4jg*mP*wPbDpjItrJ|~;5-A7N_R#tDu3fKW&%Ez_ z^L}RDzS*_c%F3_GLmytbnQpzZFM|<#E)DhcAcWIjxLmPH4o&j`1y1paFZZC5v2u|BP1p36*sAjm-C3WV*K6B3F<(^&#wO+!<1p=lN;{HaeY};ihVYmf@EHL#c#sdPX6ZQkMc8 zMq37-C_>&7vhy$p9tu3!&L@($D&+N(9A{aR=^9OmJd&3Y{x=#pzRZVi6!7zzBu0ds z5|PP+eJRdf@|?%`x?o#6f0v~gY~%<#R4r^2q^cHJ)toM20MX5&Plx}MpE|KYyV|1I zVVL|^z&+JVw&$tpgL9Hjs)!Pr24}T;MTcR{%Z`^?kg=qwKpu7^WUOTpLKBJk z#YD9IM0{p!v5VNK5xApB-*Mu4;?{g(t}7td$&s(`D6HSd*Ts2l5kWeT2Bcvb2-6pq zBlMf>E;e_Q}H9 zgMv}KmJ(R)6K&~Q({FwGwS?d-?{_>|@arnOmJ&o!@@#6%e7gdN;DLVF%#YX-gg;81VN)7Hed+vp>VCO}L(DzSjO6;= zby!Os5k$HhHu9=U51R2V*MuM)yb0e`)eShiI1&`0ig0^= zlZ3(AGz12nOQr|zDaZ%p5JAh>N|VS4-d-o4NM2!kgduwA&}Tz5NXZjba}4bYg~$|b zmGpSCU}#GwXRMpILm|1XBP=;322H_edPh}KFs9YZ=7CbtxrM0|LKiMX15m9wF&REk z-H*bq#)-*j??5y@wm7p$!<@O1Tp-=`#^Nn1!JTlkvX;(2fn;|j_}y--o?-QYBd6i- z_EFeqaLk590m;lt%R#o!*oV}l+22=$yf(mb@fx9(kGU-EWre&on9lzQf#U}FJR>+9 zg8QClI84ge1IacO@4f##U#sL|#;l4rL-2#|g>HHPcf}DLIL~9>93ZjZh4AqaY(ER% z9)E^Y7o-*ABWeX=J_FYL{rFlpy!OA)%@CNO$VG1G5qF0f!X$%<~n_T$0B6 zhM2MJsagE}IcVs71~FGN|FnUO%hAp*3{fET60v@K&|PCYC-n4|s)Yx(LlyMCtA)J1 z1!6-5YeSBvW`fI4pC&S;KPekzYJhUls~B+aqIb!vqb-=~C6_iRtDb%`8RRGR^s=(* zX_Xn|C-w9~vg+wIWRRcKlS{`_M4$(6CAi>cdn4^E^=gE!L&!J6N6RPb-Zc*O@c|{L z_#{&NiK;3b-keG2M;|#W;jhcOd*><#g$|i+p65OM@MBl|wcpNhnjQY}KZa1mfu|SP z(MD7pj*3H8cHvdr3mXLUT_>2n$rqu%8+mY#)x}YxTGw00Ang2cK z%+B0<$8>AwuGOm4t0Ksk(I`|9YA9L!^A}v<<9P|v$d7}J0a6#F?jW8q2$ckx7Y5}u zpnX#?FUW_A{rYt2A_&0(wvQ=P^EMEU1^?ukOrYZ+vjh2hdQ%}_?eb7>c|dVsFQ;L2 z%X;yQL9*OHc4q9#`A(46k~4MpmjiL3CfKXmu0sT)p@Jl25JH4d$-0x`$Jx_t$?;?C z=}OhQk}|R<$^W>@My1?f;8ci02~ur-DWzOQDU<67Kv$Krm3(N~S>?WwUs=kA`p|MU z#l4{ZZ4xcFf%0-+wR~vVRqybj<+_SqP+#s#2@pV6lxW4DftGa(5iE*M2C0)!>EE#U z;iK)zBLqzxq&o8D+io?94iT)-PIaZ7(e||XbX$f!Ej=+MS>hMho~#>=v$~vz`=?}m z{%F~OwJsMr0J1zT88qWkZhbC@@eQi!$t{8a#-%|pUK6BovQzq8BkalPc3W$Kr%{kb zLu?R)wmz~Y$r_}ZvLB<}VVnxD$7@@`E{kicTc=(EFQm$`vFWx|J$`^fm=j+8W;BTVMDUpOua7llT> zP>)PoQp%{zLi_+$K|xSbN*?{Fw8RlOUIlxpC8>&X$uUsAuw92_Hz{c&lTx1I;=-LJ zZ{N{cY9H;X`1TcX0j3S11o}H<{lQIz60|Ri3wM=V|KX`p1$6)7+gHSeyGw#6;4kZg z?P9%v_lx5%i+gb?0X`Wr{-%=X!`qj|g+?Wj=lYM5B(}9 zCLnKuG$1})A6^0EGSTsY))O589RVEy9RVEy9RVEy9RVGI>xn?$*j}CGy)aw{7r+7; z*QF*{Xj)(aT?0DLjpiAYI|8(^EicFQlhDpzE*xlU2VNe|6TuSWFP8wci-15mPjLT5 zjaP`^hW*TH(jG&Y@RU7qRDz>$qgZo46ZVO5Ujb7Ef4Eulnp#-)cbkUD3=BFhNiq6<5yNof4N+s4@4BJ+W(b+LE2GNumC^| z0*}mwAYOp`zPQh*rh}!}CQH^dHB{oAAee+Zjl!Li0ELRu9g_J$LA*gD?63tJ;!Ip5 z6C^QF(^y_QDYvU2?>=B0heNY-jC)4h7}J!zwHVvSE*0lSKPJAu{W6&mHj7;lkLPUp zV=FOsh@iW6zU*<%526Qa-z6?T`-Zqax|uk8)pD}({2015b|_o@%L?(qH-&)pr(GnqXCCQL^P9;uV%Avk#KTY1kNd6`do~_GmJFXm+I_!@2phBMm4B=t?{4lU z3Xde@JaKL+3;p_-dD^{;=vTil@r1nAmAo18q51WVZnLB35;6F9of$p)~c*1?=q}`E2_46Uo$HFOo);ma&1aq%+&NYHa0UHyioHUKV~LP3-@Nh2^w( zjCD8UlNo)2XlSePtU>Z=a@yuLpV-rY<+WVKE?zvCGtX5~EI1iMQ#LfBqRAw#-IYY9 zS9_LSSol7vJhXsC8ebu%szbzz4{ReJSt8h*n^&^f+a{3xXMX4~OK3=qRX%4M8|*eO z>@$V65AR2pUFt%Owe4opf=_Z@xKx*ZzvlrlmL<^sqbIW}gXfdXot0?h#49vs_;coC zpNuu{?>v!x`AjG)IF_BWc;FB0vo8B$QqRsJQxhl&rtZH}OD>zl!SNM5uO5DjYzfYx-&}lz&NwoMI@~oa@7kSo z&9@JFW)7__PWx;mS(MvQ?DE+#dT7A_wsTVyITY#kyjAy0I(bd4oT)?4ZTxHNPv(#b zubLnJtg~m_`R*~h5<9XhE4IY+f8JpJYUumy+j>d#UyqF=;+&UR;^a@+p)tKlp79{F z)@w?487q^D?JALsJCe*}$L`Cizy3W&JH@i*wQ@AFG5UtXCX^*Mw1!$+)q2UB;w~0pOaJJ@3BUA z5BBUcY$pl5Pq8XfoV5DuYuPu3Psz{)OUV~c-y?2`sY##f)t>EHQ(2r8dB$_>t!y$O zZZ-S8aRxbYqAnemwVy4$?Dh=UTAfs#oojy4Q(ruHZy);jWHb5b)vrjxxy59A)+5B) zGD>{jb&*7EwVGepGTU7Bqw4gjqwlf31Mi~~m)%DTOj+ze<>O|u`6RQBUP(HSUrMcg zwy?zq+feKIiJrZy$B;D-E%F$D{+7)On!y%scAB#?*Rl5Z^&lMX`)y=Hw#}lu$2YS~{`E;Z<Em?r%)m&?trfxb(dr0XI|5h#uH?V0@jWQ~J&EbH z|BlQzaV=rvz^k&$n=20)t@k$6>yP5r+m_~hH2Ax-Jd91(q4W^YT5spW`V}>~-s|nF z{h2R}aGi*LjE}L^^tJnUXd^zRLAdmUA(pRoqN@cWA2>ySZPhF=|5h!%+OGWP3A86n zuicK4;8hN8w}p7S3bW-Pr!`Ng_n(TJClXro!JyrhgQ4jvlp+FJ^MnxTuS99j6X?fi zmumXj{d*qxw?*D=^tsB{JdqvcqgsG0;xb5ep8|;9Qbonh6Nnq8*KS9<;1xcT3SXCs zE?ZLTI|gT4u9p+kF z_*Du1-gLwKln3~fmcQ$MeAO+{3w#hjKN$pNxDLzi;v*zwueTqgU!->8{mg~_bieS& zU8l+h0WH7Cv-<0Eqx{0vmG|R@{z}U)wC20Go?IU%3}2sD00=z^h=7*=7{QLP(v9+; zyzab*BRzOp*8XGd!}V~&fVux@pYwC1KbOb(m{a=STLl5N|CnIl)?WSy1UlzImO#H! zZKwNJE`q}IYVh0{^|?Iib8*z?&0y2&^L4b&<&nk_@LV6Q@oAmAgZ*Yg2G7TFq@>!C z>>2hX+nAIQ(qH~vT)G#hRIGS|Q~drB?~4=Gg?PWz>qLC+kq2)fp`7}6a~$Y>S|z9c z9f7zkgZPN;spI7hhT(5FkLw5HBfP0_@Czx2vY*2}R2x+hr?S&IN3De9>}NU~hP=Xt}bp ztAcWAS7nFCB^?jRR13e)7VhPiTfX8>+1W=09S=YIFqTU^)a!L4gx`Xpkbwl}X#T6}=h3pZS37igs;=IQL^Rcw-{4A_o z+7;rWKAP9(XkSId=O|%?R`~p=U>|;leAI9uzmODoedVZQAHH&wu|fl1Ir~{I;71*M zNvO}yp7!z!N#uJgDD{<-r<$7yw>0UTXyzVzg*f|+2LW*@sP~9 zaGqS(9?f(-{P1X1F7eRcgOP5MerY0r&nb5#aglu34=AnoQFQy%yfr#Q zLO^TZD*H))c&_)p75YVL3h!qw^r!oUKkhnJHVA0>MV`Z7pBv>DF4(_yLw}{^7h3zt z?s0tFP8hyEulU=6PWdCC+CKpA8)HA}_r=^G=Tg0&qW-;> x4|2=kyDw}n59lNC|K;U@TyJ=uk8%7FM|<#E)8^bA%x8@Jf1{3ho<;|LZ|s8kb7G7y8@94 z6|z{>*Mxd441Zvsw$jYyC3xlZ<7^A)j*usUoCH;niVl$9=*ZahB}C2+lZs1p35LuW7=82KOBM7vCU~iy|tAbuzF(g-qGhnbcR1X^l;$ zw6|=sgUt8aWV*J}CYO;p^&#wO+!<1p=lMzn*4x~g;iYPXmf)8@Ln()Ex`rW&9vimRx9tu3w$|sVyBILDG9A{aR=_*Z$Jd&3Y{@3d`zQl)46bka0B*uiC z7Lmz=eJRdf^4!Pxx^Rn`zsph#*K>p&sund0QbiN2Xl{=%faqq?=Vb77kUDWdtJ$j4FZ44dnWhC$1-N%_V2sLvo!QrCzSz$JdYYx+8*g zAPq>vG7zROxJT$s5x^b?1^1#J38#UkT~8t(nN3ZN#P5V@^z303N@fOS9HhA=Z*#%{ z!6;gL`&41=LBZI&mJ--|LA1qdEx)y;*AjxewBNB*!LO&}T1pTF%d@Gn@@)?tf(QCx zD?egO6m@ZocdYzGZ5HnhA^7YOSbiqkL;gK}2!M>@eAo^z%uyYG8pPPR_mu1u!N}yy zs(Ibq4&*jx16W65uXf6E-tMn4-mW7(VnVmxTMqB~8N4R)+46(8d(KR_wTGfnEJ1^} zNz0z$Ufj8U?>^iV7E0lo*Cr7}jf(LkELOY+hC@A8+hHN1EAgp#Y~C&3qGMEey6=7~MozI_ptFxu4p)FU|XT)Q?ZZyZhp!BMZ|DG?D2Wsd>^}Z!FxR65NS4DywGx38Xs9A?WpD^(?Co z96JMlw+_R4oogm43P@&FTn@5*CO)Jlt^U3&1Act(<(E_PwMG~WY^Pc$RIzdCzp z!v~a_eex3dL*|JoFmKh$OAY@tpYN_Rqq^-&e4 zQzR2DEb{_$%nzncy>%x*5FmluZyEbOQVcWUO<|^ tYWGYUTh5)FQQ*s9HPcqwv{tmPlIVf|p`r0UyLoOPGf@J}PVNC8{|5r+V{ZTe From e3ef5f0d055c3811bbe342cd9696f1434ebea556 Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 10 Jan 2024 15:14:55 +0100 Subject: [PATCH 40/71] Remove now unused postfix --- n3fit/src/n3fit/model_gen.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 6825d1cfba..d96e96f5cb 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -594,8 +594,8 @@ def pdfNN_layer_generator( last_layer_nodes=last_layer_nodes, ) - # Apply NN layers for all replicas to a given input grid - def neural_network_replicas(x, postfix=""): + # The NN subtracted by NN(1), if applicable + def nn_subtracted(x): NNs_x = nn_replicas(x) if subtract_one: @@ -605,14 +605,14 @@ def neural_network_replicas(x, postfix=""): return NNs_x - def compute_unnormalized_pdf(x, postfix=""): + def compute_unnormalized_pdf(x): # Preprocess the input grid x_nn_input = extract_nn_input(x) x_processed = process_input(x_nn_input) x_original = extract_original(x) # Compute the neural network output - NNs_x = neural_network_replicas(x_processed, postfix=postfix) + NNs_x = nn_subtracted(x_processed) # Compute the preprocessing factor preprocessing_factors_x = compute_preprocessing_factor(x_original) @@ -632,7 +632,7 @@ def compute_unnormalized_pdf(x, postfix=""): PDFs_unnormalized = compute_unnormalized_pdf(pdf_input) if impose_sumrule: - PDFs_integration_grid = compute_unnormalized_pdf(integrator_input, postfix="_x_integ") + PDFs_integration_grid = compute_unnormalized_pdf(integrator_input) if photons: # add batch and flavor dimensions From 3ddf629716b1fef979e6e9e466b853f27f3f6794 Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 10 Jan 2024 15:21:41 +0100 Subject: [PATCH 41/71] Update regression weights --- .../src/n3fit/tests/regressions/weights_1.h5 | Bin 31272 -> 29232 bytes .../src/n3fit/tests/regressions/weights_2.h5 | Bin 31272 -> 29232 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/n3fit/src/n3fit/tests/regressions/weights_1.h5 b/n3fit/src/n3fit/tests/regressions/weights_1.h5 index 82a4ca8556b08cd89afd9919963055e515989dd6..7f9f9301844822e6cb8ab0e0271f2bc8f538119f 100644 GIT binary patch delta 2086 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 Date: Wed, 10 Jan 2024 17:34:53 +0100 Subject: [PATCH 42/71] Give explicit shape to scatter_to_one --- n3fit/src/n3fit/layers/msr_normalization.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/layers/msr_normalization.py b/n3fit/src/n3fit/layers/msr_normalization.py index 0755cad0b4..719089cce3 100644 --- a/n3fit/src/n3fit/layers/msr_normalization.py +++ b/n3fit/src/n3fit/layers/msr_normalization.py @@ -40,6 +40,7 @@ def __init__(self, mode: str = "ALL", replicas: int = 1, **kwargs): else: raise ValueError(f"Mode {mode} not accepted for sum rules") + self.replicas = replicas indices = [] self.divisor_indices = [] if self._msr_enabled: @@ -83,6 +84,7 @@ def call(self, pdf_integrated, photon_integral): reshape = lambda x: op.transpose(x[0]) y = reshape(pdf_integrated) photon_integral = reshape(photon_integral) + numerators = [] if self._msr_enabled: @@ -96,8 +98,10 @@ def call(self, pdf_integrated, photon_integral): divisors = op.gather(y, self.divisor_indices, axis=0) # Fill in the rest of the flavours with 1 + # (Note: using y.shape in the output_shape below gives an error in Python 3.11) + num_flavours = y.shape[0] norm_constants = op.scatter_to_one( - numerators / divisors, indices=self.indices, output_shape=y.shape + numerators / divisors, indices=self.indices, output_shape=(num_flavours, self.replicas) ) return op.batchit(op.transpose(norm_constants), batch_dimension=1) From 25de95c05d9da3e19a993db211780a7f5a012bcf Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 07:48:22 +0100 Subject: [PATCH 43/71] Update developing weights structure --- n3fit/runcards/examples/developing_weights.h5 | Bin 41420 -> 41348 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/n3fit/runcards/examples/developing_weights.h5 b/n3fit/runcards/examples/developing_weights.h5 index 542fca06f960ec56e2db2a210f06c3c058c1bec0..385ea55a758dc81092dad551d29cdb1f94fab8d9 100644 GIT binary patch delta 3754 zcmZ`*Uu;uV7(e$6x7*te%GPaNH`+Tkw<%*Q*uhvpCo#srfEh?MW^oi+V595)l`#lx z1vZ#C=E{eEKu}B;s+EiBU{^AjAhv7BR*c&v(wby|*Pj$;~<6 z_xpW+&cE;6Z@;GFU(=a-WjyiBYji<@mnUn>iJS1&B04g4RSa(3PCZt%`%-)5U3f&j zw!kqV$Kg!APir5Mk^)6}^;Hka3MMPWL0rsfBzPh`*cA=-hKD$-Tp{2)zh+DmHpJ)^ zlvSZbozo)Q*f`%JBh6)z5zDj41#Dbok6J4lEp*T_rJ374D z%rio~wJwqJURK?(py>*QAGJCq4-~skSpijc-v*oYX!C+T# zq+9G9-vNfZAZV{xgBC`Jy*x;(&SDvxIj3dtqvBPTBSI#$qX^k8< zHg0M3Gr17Hx0l#AH60BPM#GU-|4R6i%LlrHL#>RkisPHpxRc|Xn+$w4$D7l55yzX; zcrlj)Y1zg3fi%Aa23A#Wd1x#MY*|28tLSZ3~9~QkXIuhS21_tlc5g}ji5xr6J zJ`=p+w8JY$1!2B7k@^($JXJGOfxjl|`AuIx#`BSt1IyA%w32c$8(Q(zSvZy{D_)p| zqc1DIDhp>AJU8is{{}p^79RsyQ`wq6RzRSS4AXm;<0kcpD3m$>hkPbpsx>>b92k!rU^$`|IFh`x1@&A+&3j#v8HJp`Qly18sYH z=+au4+jB=Va|BPFmo7CiyZzv)FV)PX@Nv`rmB%Mel0~nMR@l@%89`^FC+X5&aP-a6 zjt&{^?_DyQ4(h-TTc}!CgwlyS4rcgZFM`b_4;Oz!Z4FUDh$n-w9}4MgkYzUt^Jm|n z_o~5pZkFx~$yome)3F>AJ8TbYg`tkIl5uYfrL%|OoBTtXc^#m&AS$3cJsdJ`fC(-3 za>zXM3_5SC98Bj`@dBl;0Zxj6(4Lw=5?#CoTAo*1lyg|_H@*H8;|ABIn>#Ut_+Cz( z5|0Udiblqd;)pwT|R|Baz($53h@=uksHwA&zU| z_&}wh%cx(FD_Ap)`c9^QX$JKpQor>A>gSk#_9E(Em-@&!>a(+IFhY+e?yE`HwH^ij zXsn<71_mxA zqZJz|4P1q5fzY}FVqCj9SqzPPWEMxU2m3*3E*mrJqR<*a{$SM)n_+DhL7|@!9SO)H zYVgd$EC>sdw>%*R1~2jvm-mvXn*#VubmVtg9t`60djfD>75y#A>&yzg??VB^ZX{BT c{8!1eG+%=&H~4E{l1*stCWmBVEH8xq2L`+q^Z)<= delta 4346 zcmZ`+T}&HS7QQo1VC)b|6G8?EW*`ZekQ(!o1Za|yO?S(-G<8*Jx9X}LOzdD&$M%Au zPL;)Onnu|y+r^xuOLwy=l~Bb)R6(7GJkScOdFVq_d8Iz^5LJ2T1FE7Zl`0jj^04=J ze%$y<JS}a_ClLIY~oqT|020= zb8e;&yyxBWa66nj-y)~HPnvW2%a96vl4CuQCg*;W@D-a5tXT zSm;JP-(jIiY&$J`^xG7#9a8*Yv%a-j@v zjGl2Jl>y6Ta6EQNMsAuJwTWbAPEldlsisM|WNc+G)aC8*`taPrX=)nJ6TvfjVmy=> zk28RVh^GQSI~h$z647&d7sG`MR;N>XFftVhhQzk~%7ad(K=5fYF)O7D3l@dgTgmw%qF^XC5z;%+Q^ox8cp^TTWYvT*yL=aV z`ic6}`Vm?_7%Vb;h?dc>6m=UZEt2oq^+W@DCoNZui9MtNV0t%^e;z+YiVpKSGa`t@ z5|c?>3AJPa9wIWv??iR*w9+coLm&R#0|BK`YJm5Y#wK!B$PmSK>Xc4u5s@=PMh*N| zsc#@Wjne$&;dx4r#z#{KH9?cJQEG-0&fU^p$U1jz>*{zrG#(2@`+fUhh0-IDz(haR zv7h4I2HryP?hb*sQoPf^Jp^y>H1Ia=gD4c5CIdz20G6+=HkKpQ&KES1Fm~y_jzBaK z4(L<8#2Y#e!pgS21Q`h>8Su=L*Ce}*HD22q0(6vEW7_fA*I>NBoKx3h#?D^k(zZJg6>NUTUB{!!(zx41XreYZ_%|_|aU@a4ShHiaH6hNP91}_U`=j0ydi;BuJ$30avzYmLd0Fj-d&8ZcN^LBW%I41X}1@rv5H@l zk3V24H-u(1n9aYO9af!#9*aZHAFeP;$$c9BMS|saRUT-Chwn5?I^+Y-5*x0K!(671 z1O?xot8v{IRdNg-j@GoJ{Y*k@WpCld50@An7D=UEn8{SyY1Y2sE^QoO$<(}*ZSDZ+ z%g)<;!!o%yL(j?ba3>Wqx04DDa9_F5LJxR94m!3XKYaP|?zCx$`PIu_Xq|6^;bu`h z3tVoEYZr26W|)A&HeoP@Ws z1qB|yufVNqYK6GrNl$?5E>*@aw^9f9uGMbC-zL9%NgoMJL?&S2S~U!Pq)AKJ{3m!r zG-u&C9)np4+A+8hcxz6rN~_#q5s_yXo);M{kR_~uLuJh zL&N}Nykm0WBs}o0y3CN^+jrdZydNtXriaIjA@{Cty570KzZJPz5tMrB4Ob$`Y~I{% z*xX16o3k-$)9)XXAD@I({~hPz`?df`h(nhdD|#iHKb%{C?ap@j=mqS`x@-7(hG-5$ z_k)W<_tgt59*+je;EQtR1$=KU!f1RtX#EvBmIpAPZWMQ*4j{0N$KKFvZO!E^e-#62W; zffesA!b$(J>LVT6Dvz&*v`v8Y539gIOj{L@PZlfgEy78kvf@5WlYdnrAaWgA^>rZ_ z32X4bb9Fn8{+-AnG{|1))<5B^nLn%)=1JF4U|CjNio~#re`WLdh?ngnfBM)^dC_qR zWR}oM-i>P<*Tm0%se)*xUtV|t{L?jXFRj4$!An>T{5b8Bul_@n(ZLxyODpotPw>pO z#7#v1P53jIKl2~L4|D#-tAvl$$%`Kmz7ar{@U4~?ZI*4&QfcUBX=u4Lbjt>13(Gch zw{55mS}hH&*&v*`3I&OFv^Yzmo%yRGU;L0{VUuTPb%F5jVgC8+gul-D*KZI$?f~-D zYlJ_~`H$xb|NIq2zB5N=*8JVE*~c9uxB9m+3C;v7jm`bWCSqHCw=`5J4SiP{S}zUV HvqAp{l7xg; From 22405600c30ef0cb11f3fd10efe0439f3edac0f9 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 14:34:12 +0100 Subject: [PATCH 44/71] fix prefix typo --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index de6a8fcad5..33c10fc8e9 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -47,7 +47,7 @@ NN_PREFIX = "NN" NN_LAYER = "NNs" -PREPROESSING_LAYER = "preprocessing_factor" +PREPROCESSING_LAYER = "preprocessing_factor" # Some keys need to work for everyone for k, v in optimizers.items(): @@ -355,7 +355,7 @@ def get_replica_weights(self, i_replica): dictionary with the weights of the replica """ weights = {} - for layer_type in [NN_LAYER, PREPROESSING_LAYER]: + for layer_type in [NN_LAYER, PREPROCESSING_LAYER]: weights[layer_type] = [ tf.Variable(w, name=w.name) for w in get_layer_replica_weights(self.get_layer(layer_type), i_replica) @@ -377,7 +377,7 @@ def set_replica_weights(self, weights, i_replica=0): i_replica: int the replica number to set, defaulting to 0 """ - for layer_type in [NN_LAYER, PREPROESSING_LAYER]: + for layer_type in [NN_LAYER, PREPROCESSING_LAYER]: set_layer_replica_weights( layer=self.get_layer(layer_type), weights=weights[layer_type], i_replica=i_replica ) From e38f359ef0f9437c38d8f628d15e4b28d5a71fdf Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 14:35:43 +0100 Subject: [PATCH 45/71] add double ticks --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 33c10fc8e9..363193dc3e 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -157,7 +157,7 @@ def perform_fit(self, x=None, y=None, epochs=1, **kwargs): of the model (the loss functions) to the partial losses. If the model was compiled with input and output data, they will not be passed through. - In this case by default the number of `epochs` will be set to 1 + In this case by default the number of ``epochs`` will be set to 1 ex: {'loss': [100], 'dataset_a_loss1' : [67], 'dataset_2_loss': [33]} @@ -229,7 +229,7 @@ def compile( ): """ Compile the model given an optimizer and a list of loss functions. - The optimizer must be one of those implemented in the `optimizer` attribute of this class. + The optimizer must be one of those implemented in the ``optimizer`` attribute of this class. Options: - A learning rate and a list of target outpout can be defined. @@ -439,8 +439,8 @@ def stacked_single_replicas(layer): def get_layer_replica_weights(layer, i_replica: int): """ - Get the weights for the given single replica `i_replica`, - from a `layer` that has weights for all replicas. + Get the weights for the given single replica ``i_replica``, + from a ``layer`` that has weights for all replicas. Parameters ---------- @@ -464,8 +464,8 @@ def get_layer_replica_weights(layer, i_replica: int): def set_layer_replica_weights(layer, weights, i_replica: int): """ - Set the weights for the given single replica `i_replica`, - for a `layer` that has weights for all replicas. + Set the weights for the given single replica ``i_replica``, + for a ``layer`` that has weights for all replicas. Parameters ---------- From a40c216cb1cc3a9ce9b9220f6f2835f2bbfcee93 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 14:39:44 +0100 Subject: [PATCH 46/71] rename layer name constants --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 363193dc3e..588ef3bdf8 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -46,8 +46,8 @@ } NN_PREFIX = "NN" -NN_LAYER = "NNs" -PREPROCESSING_LAYER = "preprocessing_factor" +NN_LAYER_ALL_REPLICAS = "NNs" +PREPROCESSING_LAYER_ALL_REPLICAS = "preprocessing_factor" # Some keys need to work for everyone for k, v in optimizers.items(): @@ -355,7 +355,7 @@ def get_replica_weights(self, i_replica): dictionary with the weights of the replica """ weights = {} - for layer_type in [NN_LAYER, PREPROCESSING_LAYER]: + for layer_type in [NN_LAYER_ALL_REPLICAS, PREPROCESSING_LAYER_ALL_REPLICAS]: weights[layer_type] = [ tf.Variable(w, name=w.name) for w in get_layer_replica_weights(self.get_layer(layer_type), i_replica) @@ -377,7 +377,7 @@ def set_replica_weights(self, weights, i_replica=0): i_replica: int the replica number to set, defaulting to 0 """ - for layer_type in [NN_LAYER, PREPROCESSING_LAYER]: + for layer_type in [NN_LAYER, PREPROCESSING_LAYER_ALL_REPLICAS]: set_layer_replica_weights( layer=self.get_layer(layer_type), weights=weights[layer_type], i_replica=i_replica ) From c095381f41193e3543ac44d5a81d5093f29ee27e Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 14:49:33 +0100 Subject: [PATCH 47/71] use constants defined in metamodel.py for layer names --- n3fit/src/n3fit/model_gen.py | 11 ++++++++--- n3fit/src/n3fit/model_trainer.py | 3 ++- n3fit/src/n3fit/tests/test_modelgen.py | 5 +++-- n3fit/src/n3fit/vpinterface.py | 3 ++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index d96e96f5cb..cf76eb7878 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -17,6 +17,11 @@ from n3fit.backends import Input, Lambda, MetaLayer, MetaModel, base_layer_selector from n3fit.backends import operations as op from n3fit.backends import regularizer_selector +from n3fit.backends.keras.metamodel import ( + NN_LAYER_ALL_REPLICAS, + NN_PREFIX, + PREPROCESSING_LAYER_ALL_REPLICAS, +) from n3fit.layers import ( DIS, DY, @@ -575,7 +580,7 @@ def pdfNN_layer_generator( compute_preprocessing_factor = Preprocessing( flav_info=flav_info, input_shape=(1,), - name="preprocessing_factor", + name=PREPROCESSING_LAYER_ALL_REPLICAS, seed=seed[0] + number_of_layers, large_x=not subtract_one, num_replicas=num_replicas, @@ -777,10 +782,10 @@ def initializer_generator(seed, i_layer): # Wrap the pdfs in a MetaModel to enable getting/setting of weights later pdfs = [ - MetaModel({'NN_input': x_input}, pdf, name=f"NN_{i_replica}")(x_input) + MetaModel({'NN_input': x_input}, pdf, name=f"{NN_PREFIX}_{i_replica}")(x_input) for i_replica, pdf in enumerate(pdfs) ] pdfs = Lambda(lambda nns: op.stack(nns, axis=1), name=f"stack_replicas")(pdfs) - model = MetaModel({'NN_input': x_input}, pdfs, name=f"NNs") + model = MetaModel({'NN_input': x_input}, pdfs, name=NN_LAYER_ALL_REPLICAS) return model diff --git a/n3fit/src/n3fit/model_trainer.py b/n3fit/src/n3fit/model_trainer.py index 35457166e0..d791584b60 100644 --- a/n3fit/src/n3fit/model_trainer.py +++ b/n3fit/src/n3fit/model_trainer.py @@ -17,6 +17,7 @@ from n3fit import model_gen from n3fit.backends import MetaModel, callbacks, clear_backend_state from n3fit.backends import operations as op +from n3fit.backends.keras.metamodel import NN_LAYER_ALL_REPLICAS import n3fit.hyper_optimization.penalties import n3fit.hyper_optimization.rewards from n3fit.scaler import generate_scaler @@ -454,7 +455,7 @@ def _model_generation(self, xinput, pdf_model, partition, partition_idx): training.summary() pdf_model = training.get_layer("PDFs") pdf_model.summary() - nn_model = pdf_model.get_layer("NNs") + nn_model = pdf_model.get_layer(NN_LAYER_ALL_REPLICAS) nn_model.summary() # We may have fits without sumrules imposed try: diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index 1178b59b71..6010069693 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -5,6 +5,7 @@ It checks that both the number of layers and the shape of the weights of the layers are what is expected """ +from n3fit.backends.keras.metamodel import NN_PREFIX from n3fit.model_gen import generate_nn INSIZE = 16 @@ -25,7 +26,7 @@ def test_generate_dense_network(): - nn = generate_nn("dense", **COMMON_ARGS).get_layer("NN_0") + nn = generate_nn("dense", **COMMON_ARGS).get_layer(f"{NN_PREFIX}_0") # The number of layers should be input layer + len(OUT_SIZES) assert len(nn.layers) == len(OUT_SIZES) + 1 @@ -40,7 +41,7 @@ def test_generate_dense_network(): def test_generate_dense_per_flavour_network(): - nn = generate_nn("dense_per_flavour", **COMMON_ARGS).get_layer("NN_0") + nn = generate_nn("dense_per_flavour", **COMMON_ARGS).get_layer(f"{NN_PREFIX}_0") # The number of layers should be input + BASIS_SIZE*len(OUT_SIZES) + concatenate assert len(nn.layers) == BASIS_SIZE * len(OUT_SIZES) + 2 diff --git a/n3fit/src/n3fit/vpinterface.py b/n3fit/src/n3fit/vpinterface.py index 6de7693682..80130fd141 100644 --- a/n3fit/src/n3fit/vpinterface.py +++ b/n3fit/src/n3fit/vpinterface.py @@ -24,6 +24,7 @@ import numpy as np import numpy.linalg as la +from n3fit.backends.keras.metamodel import PREPROCESSING_LAYER_ALL_REPLICAS from validphys.arclength import arc_lengths, integrability_number from validphys.core import PDF, MCStats from validphys.lhapdfset import LHAPDFSet @@ -224,7 +225,7 @@ def get_preprocessing_factors(self, replica=None): if replica is None: replica = 1 # Replicas start counting in 1 so: - preprocessing_layer = self._models[replica - 1].get_layer("preprocessing_factor") + preprocessing_layer = self._models[replica - 1].get_layer(PREPROCESSING_LAYER_ALL_REPLICAS) alphas_and_betas = None if self.fit_basis is not None: From 115e30c342fd30da1f3a2e75945e2d5114bef471 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 14:58:01 +0100 Subject: [PATCH 48/71] Explain need for is_stacked_single_replicas --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 588ef3bdf8..3776481d7e 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -418,9 +418,10 @@ def load_identical_replicas(self, model_file): self.set_replica_weights(weights, i_replica) -def stacked_single_replicas(layer): +def is_stacked_single_replicas(layer): """ - Check if the layer consists of stacked single replicas (Only happens for NN layers) + Check if the layer consists of stacked single replicas (Only happens for NN layers), + to determine how to extract single replica weights. Parameters ---------- @@ -454,7 +455,7 @@ def get_layer_replica_weights(layer, i_replica: int): weights: list list of weights for the replica """ - if stacked_single_replicas(layer): + if is_stacked_single_replicas(layer): weights = layer.get_layer(f"{NN_PREFIX}_{i_replica}").weights else: weights = [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] @@ -476,7 +477,7 @@ def set_layer_replica_weights(layer, weights, i_replica: int): i_replica: int the replica number """ - if stacked_single_replicas(layer): + if is_stacked_single_replicas(layer): layer.get_layer(f"{NN_PREFIX}_{i_replica}").set_weights(weights) return From 8f4a596b8eb0d970bbdd1a9b91babe400875230d Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 15:02:38 +0100 Subject: [PATCH 49/71] shorten line --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 3776481d7e..af3eb2f893 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -378,9 +378,8 @@ def set_replica_weights(self, weights, i_replica=0): the replica number to set, defaulting to 0 """ for layer_type in [NN_LAYER, PREPROCESSING_LAYER_ALL_REPLICAS]: - set_layer_replica_weights( - layer=self.get_layer(layer_type), weights=weights[layer_type], i_replica=i_replica - ) + layer = self.get_layer(layer_type) + set_layer_replica_weights(layer=layer, weights=weights[layer_type], i_replica=i_replica) def split_replicas(self): """ From 3568bbbe8e532c6551140379163448bc9bff0c44 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 15:24:16 +0100 Subject: [PATCH 50/71] fix constant loading --- n3fit/src/n3fit/backends/__init__.py | 25 ++++++++++++++----------- n3fit/src/n3fit/model_gen.py | 12 ++++++++---- n3fit/src/n3fit/model_trainer.py | 2 +- n3fit/src/n3fit/tests/test_modelgen.py | 2 +- n3fit/src/n3fit/vpinterface.py | 2 +- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/n3fit/src/n3fit/backends/__init__.py b/n3fit/src/n3fit/backends/__init__.py index f49bbd0f53..3c48317a86 100644 --- a/n3fit/src/n3fit/backends/__init__.py +++ b/n3fit/src/n3fit/backends/__init__.py @@ -1,20 +1,23 @@ -from n3fit.backends.keras_backend.internal_state import ( - set_initial_state, - clear_backend_state, - set_eager -) +from n3fit.backends.keras_backend import callbacks, constraints, operations from n3fit.backends.keras_backend.MetaLayer import MetaLayer -from n3fit.backends.keras_backend.MetaModel import MetaModel +from n3fit.backends.keras_backend.MetaModel import ( + NN_LAYER_ALL_REPLICAS, + NN_PREFIX, + PREPROCESSING_LAYER_ALL_REPLICAS, + MetaModel, +) from n3fit.backends.keras_backend.base_layers import ( + Concatenate, Input, - concatenate, Lambda, base_layer_selector, + concatenate, regularizer_selector, - Concatenate, ) -from n3fit.backends.keras_backend import operations -from n3fit.backends.keras_backend import constraints -from n3fit.backends.keras_backend import callbacks +from n3fit.backends.keras_backend.internal_state import ( + clear_backend_state, + set_eager, + set_initial_state, +) print("Using Keras backend") diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index cf76eb7878..fc180f392f 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -14,14 +14,18 @@ import numpy as np -from n3fit.backends import Input, Lambda, MetaLayer, MetaModel, base_layer_selector -from n3fit.backends import operations as op -from n3fit.backends import regularizer_selector -from n3fit.backends.keras.metamodel import ( +from n3fit.backends import ( NN_LAYER_ALL_REPLICAS, NN_PREFIX, PREPROCESSING_LAYER_ALL_REPLICAS, + Input, + Lambda, + MetaLayer, + MetaModel, + base_layer_selector, ) +from n3fit.backends import operations as op +from n3fit.backends import regularizer_selector from n3fit.layers import ( DIS, DY, diff --git a/n3fit/src/n3fit/model_trainer.py b/n3fit/src/n3fit/model_trainer.py index d791584b60..acbcc8b3cd 100644 --- a/n3fit/src/n3fit/model_trainer.py +++ b/n3fit/src/n3fit/model_trainer.py @@ -17,7 +17,7 @@ from n3fit import model_gen from n3fit.backends import MetaModel, callbacks, clear_backend_state from n3fit.backends import operations as op -from n3fit.backends.keras.metamodel import NN_LAYER_ALL_REPLICAS +from n3fit.backends import NN_LAYER_ALL_REPLICAS import n3fit.hyper_optimization.penalties import n3fit.hyper_optimization.rewards from n3fit.scaler import generate_scaler diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index 6010069693..ffdaa254b6 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -5,7 +5,7 @@ It checks that both the number of layers and the shape of the weights of the layers are what is expected """ -from n3fit.backends.keras.metamodel import NN_PREFIX +from n3fit.backends import NN_PREFIX from n3fit.model_gen import generate_nn INSIZE = 16 diff --git a/n3fit/src/n3fit/vpinterface.py b/n3fit/src/n3fit/vpinterface.py index 80130fd141..12e5aca374 100644 --- a/n3fit/src/n3fit/vpinterface.py +++ b/n3fit/src/n3fit/vpinterface.py @@ -24,7 +24,7 @@ import numpy as np import numpy.linalg as la -from n3fit.backends.keras.metamodel import PREPROCESSING_LAYER_ALL_REPLICAS +from n3fit.backends import PREPROCESSING_LAYER_ALL_REPLICAS from validphys.arclength import arc_lengths, integrability_number from validphys.core import PDF, MCStats from validphys.lhapdfset import LHAPDFSet From 7de2b59b75fc1ce8fd22abc4b1ad02e222999b31 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 15:32:29 +0100 Subject: [PATCH 51/71] Simplify get_replica_weights --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index af3eb2f893..ea32e9c58f 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -356,10 +356,8 @@ def get_replica_weights(self, i_replica): """ weights = {} for layer_type in [NN_LAYER_ALL_REPLICAS, PREPROCESSING_LAYER_ALL_REPLICAS]: - weights[layer_type] = [ - tf.Variable(w, name=w.name) - for w in get_layer_replica_weights(self.get_layer(layer_type), i_replica) - ] + layer = self.get_layer(layer_type) + weights[layer_type] = get_layer_replica_weights(layer, i_replica) return weights @@ -377,7 +375,7 @@ def set_replica_weights(self, weights, i_replica=0): i_replica: int the replica number to set, defaulting to 0 """ - for layer_type in [NN_LAYER, PREPROCESSING_LAYER_ALL_REPLICAS]: + for layer_type in [NN_LAYER_ALL_REPLICAS, PREPROCESSING_LAYER_ALL_REPLICAS]: layer = self.get_layer(layer_type) set_layer_replica_weights(layer=layer, weights=weights[layer_type], i_replica=i_replica) From 3fba42fdf982432f65582951bbf52b96d019ff78 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 15:35:23 +0100 Subject: [PATCH 52/71] NNs -> all_NNs --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index ea32e9c58f..521df17f22 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -46,7 +46,7 @@ } NN_PREFIX = "NN" -NN_LAYER_ALL_REPLICAS = "NNs" +NN_LAYER_ALL_REPLICAS = "all_NNs" PREPROCESSING_LAYER_ALL_REPLICAS = "preprocessing_factor" # Some keys need to work for everyone From a1c46ecf01ab0dc31938dcb02988196f8b5b8699 Mon Sep 17 00:00:00 2001 From: Aron Jansen Date: Mon, 22 Jan 2024 15:37:40 +0100 Subject: [PATCH 53/71] Clarify get_layer_replica_weights Co-authored-by: Juan M. Cruz-Martinez --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 521df17f22..158042085f 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -440,6 +440,10 @@ def get_layer_replica_weights(layer, i_replica: int): Get the weights for the given single replica ``i_replica``, from a ``layer`` that has weights for all replicas. + Note that the layer could be a complete a complete NN with many separated sub_layers + each of which containing weights for all replicas together. + This functions separates the per-replica weights and returns the list of weight as if the + input ``layer`` were made of _only_ replica ``i_replica``. Parameters ---------- layer: MetaLayer From 3557ee699e5c279084fc42f9cc4f894068d285c4 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 22 Jan 2024 15:39:14 +0100 Subject: [PATCH 54/71] Clarify set_layer_replica_weights --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 158042085f..99269d1af6 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -466,8 +466,9 @@ def get_layer_replica_weights(layer, i_replica: int): def set_layer_replica_weights(layer, weights, i_replica: int): """ - Set the weights for the given single replica ``i_replica``, - for a ``layer`` that has weights for all replicas. + Set the weights for the given single replica ``i_replica``. + When the input ``layer`` contains weights for many replicas, ensures that + only those corresponding to replica ``i_replica`` are updated. Parameters ---------- From 2001e6331f1894d2bad964ab3a1433b93ce4c13b Mon Sep 17 00:00:00 2001 From: Aron Jansen Date: Mon, 22 Jan 2024 15:42:12 +0100 Subject: [PATCH 55/71] Remove comment about python 3.11 Co-authored-by: Juan M. Cruz-Martinez --- n3fit/src/n3fit/layers/msr_normalization.py | 1 - 1 file changed, 1 deletion(-) diff --git a/n3fit/src/n3fit/layers/msr_normalization.py b/n3fit/src/n3fit/layers/msr_normalization.py index 719089cce3..01a3648cb7 100644 --- a/n3fit/src/n3fit/layers/msr_normalization.py +++ b/n3fit/src/n3fit/layers/msr_normalization.py @@ -98,7 +98,6 @@ def call(self, pdf_integrated, photon_integral): divisors = op.gather(y, self.divisor_indices, axis=0) # Fill in the rest of the flavours with 1 - # (Note: using y.shape in the output_shape below gives an error in Python 3.11) num_flavours = y.shape[0] norm_constants = op.scatter_to_one( numerators / divisors, indices=self.indices, output_shape=(num_flavours, self.replicas) From be2938780d637b682440f673141ad45e0023312e Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 25 Oct 2023 08:13:20 +0200 Subject: [PATCH 56/71] Merge prefactors into single layer --- .../n3fit/backends/keras_backend/MetaModel.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 99269d1af6..1108ce2358 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -464,6 +464,26 @@ def get_layer_replica_weights(layer, i_replica: int): return weights +def get_layer_replica_weights(layer, i_replica: int): + """ + Get the weights for the given single replica `i_replica`, + from a `layer` that has weights for all replicas. + + Parameters + ---------- + layer: MetaLayer + the layer to get the weights from + i_replica: int + the replica number + + Returns + ------- + weights: list + list of weights for the replica + """ + return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] + + def set_layer_replica_weights(layer, weights, i_replica: int): """ Set the weights for the given single replica ``i_replica``. From 92d21a3a3af543d9d879f0e2d7f85a28dd06e8c6 Mon Sep 17 00:00:00 2001 From: Aron Date: Mon, 8 Jan 2024 17:01:07 +0100 Subject: [PATCH 57/71] Add MultiDense layer --- .../backends/keras_backend/base_layers.py | 65 ++++---- .../backends/keras_backend/multi_dense.py | 142 ++++++++++++++++++ n3fit/src/n3fit/tests/test_multidense.py | 45 ++++++ 3 files changed, 225 insertions(+), 27 deletions(-) create mode 100644 n3fit/src/n3fit/backends/keras_backend/multi_dense.py create mode 100644 n3fit/src/n3fit/tests/test_multidense.py diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 14215e9cf6..ffac67946b 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -17,34 +17,44 @@ The names of the layer and the activation function are the ones to be used in the n3fit runcard. """ -from tensorflow.keras.layers import Lambda, LSTM, Dropout, Concatenate -from tensorflow.keras.layers import concatenate, Input # pylint: disable=unused-import +from tensorflow import expand_dims, math, nn +from tensorflow.keras.layers import ( # pylint: disable=unused-import + Dropout, + Input, + Lambda, + concatenate, +) from tensorflow.keras.layers import Dense as KerasDense -from tensorflow import expand_dims +from tensorflow.keras.layers import LSTM, Concatenate # pylint: disable=unused-import from tensorflow.keras.regularizers import l1_l2 -from tensorflow import nn, math from n3fit.backends import MetaLayer +from n3fit.backends.keras_backend.multi_dense import MultiDense + # Custom activation functions def square_activation(x): - """ Squares the input """ - return x*x + """Squares the input""" + return x * x + def modified_tanh(x): - """ A non-saturating version of the tanh function """ - return math.abs(x)*nn.tanh(x) + """A non-saturating version of the tanh function""" + return math.abs(x) * nn.tanh(x) + def leaky_relu(x): - """ Computes the Leaky ReLU activation function """ + """Computes the Leaky ReLU activation function""" return nn.leaky_relu(x, alpha=0.2) + custom_activations = { - "square" : square_activation, + "square": square_activation, "leaky_relu": leaky_relu, "modified_tanh": modified_tanh, } + def LSTM_modified(**kwargs): """ LSTM asks for a sample X timestep X features kind of thing so we need to reshape the input @@ -61,9 +71,11 @@ def ReshapedLSTM(input_tensor): return ReshapedLSTM + class Dense(KerasDense, MetaLayer): pass + def dense_per_flavour(basis_size=8, kernel_initializer="glorot_normal", **dense_kwargs): """ Generates a list of layers which can take as an input either one single layer @@ -122,7 +134,7 @@ def apply_dense(xinput): "kernel_initializer": "glorot_normal", "units": 5, "activation": "sigmoid", - "kernel_regularizer": None + "kernel_regularizer": None, }, ), "dense_per_flavour": ( @@ -143,31 +155,28 @@ def apply_dense(xinput): "concatenate": (Concatenate, {}), } -regularizers = { - 'l1_l2': (l1_l2, {'l1': 0., 'l2': 0.}) - } +regularizers = {'l1_l2': (l1_l2, {'l1': 0.0, 'l2': 0.0})} + def base_layer_selector(layer_name, **kwargs): """ - Given a layer name, looks for it in the `layers` dictionary and returns an instance. + Given a layer name, looks for it in the `layers` dictionary and returns an instance. - The layer dictionary defines a number of defaults - but they can be overwritten/enhanced through kwargs + The layer dictionary defines a number of defaults + but they can be overwritten/enhanced through kwargs - Parameters - ---------- - `layer_name - str with the name of the layer - `**kwargs` - extra optional arguments to pass to the layer (beyond their defaults) + Parameters + ---------- + `layer_name + str with the name of the layer + `**kwargs` + extra optional arguments to pass to the layer (beyond their defaults) """ try: layer_tuple = layers[layer_name] except KeyError as e: raise NotImplementedError( - "Layer not implemented in keras_backend/base_layers.py: {0}".format( - layer_name - ) + "Layer not implemented in keras_backend/base_layers.py: {0}".format(layer_name) ) from e layer_class = layer_tuple[0] @@ -182,6 +191,7 @@ def base_layer_selector(layer_name, **kwargs): return layer_class(**layer_args) + def regularizer_selector(reg_name, **kwargs): """Given a regularizer name looks in the `regularizer` dictionary and return an instance. @@ -204,7 +214,8 @@ def regularizer_selector(reg_name, **kwargs): reg_tuple = regularizers[reg_name] except KeyError: raise NotImplementedError( - "Regularizer not implemented in keras_backend/base_layers.py: {0}".format(reg_name)) + "Regularizer not implemented in keras_backend/base_layers.py: {0}".format(reg_name) + ) reg_class = reg_tuple[0] reg_args = reg_tuple[1] diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py new file mode 100644 index 0000000000..1068aa84ff --- /dev/null +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -0,0 +1,142 @@ +import tensorflow as tf +from tensorflow.keras.initializers import Initializer +from tensorflow.keras.layers import Dense + + +class MultiDense(Dense): + """ + Dense layer for multiple replicas at the same time. + + Inputs to this layer may contain multiple replicas, for the later layers. + In this case, the `replica_input` argument should be set to `True`, which is the default. + The input shape in this case is (batch_size, replicas, gridsize, features). + For the first layer, there are no replicas yet, and so the `replica_input` argument + should be set to `False`. + The input shape in this case is (batch_size, gridsize, features). + + The kernel initializer is set using the custom arguments `initializer_class` and + `seed`. The `seed` is incremented by 1 for each replica. + + + Example + ------- + + >>> from tensorflow.keras import Sequential + >>> from tensorflow.keras.layers import Dense + >>> from tensorflow.keras.initializers import GlorotUniform + >>> import tensorflow as tf + >>> replicas = 2 + >>> multi_dense_model = Sequential([ + >>> MultiDense(units=8, replicas=replicas, seed=42, replica_input=False, initializer_class=GlorotUniform), + >>> MultiDense(units=4, replicas=replicas, seed=52, initializer_class=GlorotUniform), + >>> ]) + >>> single_models = [ + >>> Sequential([ + >>> Dense(units=8, kernel_initializer=GlorotUniform(seed=42 + r)), + >>> Dense(units=4, kernel_initializer=GlorotUniform(seed=52 + r)), + >>> ]) + >>> for r in range(replicas) + >>> ] + >>> gridsize, features = 100, 2 + >>> multi_dense_model.build(input_shape=(None, gridsize, features)) + >>> for single_model in single_models: + >>> single_model.build(input_shape=(None, gridsize, features)) + >>> test_input = tf.random.uniform(shape=(1, gridsize, features)) + >>> multi_dense_output = multi_dense_model(test_input) + >>> single_dense_output = tf.stack([single_model(test_input) for single_model in single_models], axis=1) + >>> tf.reduce_all(tf.equal(multi_dense_output, single_dense_output)) + + Parameters + ---------- + replicas: int + Number of replicas. + seed: int + Seed for the random number generator. + initializer_class: Initializer + Initializer class for the kernel. + replica_input: bool (default: True) + Whether the input already contains multiple replicas. + """ + + def __init__( + self, + replicas: int, + seed: int, + initializer_class: Initializer, + replica_input: bool = True, + **kwargs + ): + super().__init__(**kwargs) + self.replicas = replicas + self.seed = seed + self.initializer_class = initializer_class + self.replica_input = replica_input + + def build(self, input_shape): + """ + Build weight matrix of shape (replicas, input_dim, units). + Weights are initialized on a per-replica basis, with incrementing seed. + """ + # Remove the replica axis from the input shape. + if self.replica_input: + input_shape = input_shape[:1] + input_shape[2:] + + # Create and concatenate separate weights per replica. + replica_kernels = [] + replica_biases = [] + for r in range(self.replicas): + self.kernel_initializer = self.initializer_class(self.seed + r) + super().build(input_shape) + replica_kernels.append(self.kernel) + replica_biases.append(self.bias) + self.kernel = tf.Variable(tf.stack(replica_kernels, axis=0)) + if self.use_bias: + self.bias = tf.Variable(tf.expand_dims(tf.stack(replica_biases, axis=0), axis=1)) + + def call(self, inputs): + """ + Compute output of shape (batch_size, replicas, gridsize, units). + + For the first layer, (self.replica_input is False), this is equivalent to + applying each replica separately and concatenating along the last axis. + If the input already contains multiple replica outputs, it is equivalent + to applying each replica to its corresponding input. + """ + if inputs.dtype.base_dtype != self._compute_dtype_object.base_dtype: + inputs = tf.cast(inputs, dtype=self._compute_dtype_object) + + input_axes = 'brnf' if self.replica_input else 'bnf' + einrule = input_axes + ',rfg->brng' + outputs = tf.einsum(einrule, inputs, self.kernel) + + # Reshape the output back to the original ndim of the input. + if not tf.executing_eagerly(): + output_shape = self.compute_output_shape(inputs.shape.as_list()) + outputs.set_shape(output_shape) + + if self.use_bias: + outputs = outputs + self.bias + + if self.activation is not None: + outputs = self.activation(outputs) + + return outputs + + def compute_output_shape(self, input_shape): + # Remove the replica axis from the input shape. + if self.replica_input: + input_shape = input_shape[:1] + input_shape[2:] + + output_shape = super().compute_output_shape(input_shape) + + # Add back the replica axis to the output shape. + output_shape = output_shape[:1] + [self.replicas] + output_shape[1:] + + return output_shape + + def get_config(self): + config = super().get_config() + config.update( + {"replicas": self.replicas, "replica_input": self.replica_input, "seed": self.seed} + ) + return config diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py new file mode 100644 index 0000000000..f8998d5e9b --- /dev/null +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -0,0 +1,45 @@ +import numpy as np +import tensorflow as tf +from tensorflow.keras import Sequential +from tensorflow.keras.initializers import GlorotUniform +from tensorflow.keras.layers import Dense + +from n3fit.backends.keras_backend.multi_dense import MultiDense + + +def test_multidense(): + replicas = 2 + multi_dense_model = Sequential( + [ + MultiDense( + units=8, + replicas=replicas, + seed=42, + replica_input=False, + initializer_class=GlorotUniform, + ), + MultiDense(units=4, replicas=replicas, seed=52, initializer_class=GlorotUniform), + ] + ) + single_models = [ + Sequential( + [ + Dense(units=8, kernel_initializer=GlorotUniform(seed=42 + r)), + Dense(units=4, kernel_initializer=GlorotUniform(seed=52 + r)), + ] + ) + for r in range(replicas) + ] + + gridsize, features = 100, 3 + multi_dense_model.build(input_shape=(None, gridsize, features)) + for single_model in single_models: + single_model.build(input_shape=(None, gridsize, features)) + + test_input = tf.random.uniform(shape=(1, gridsize, features)) + multi_dense_output = multi_dense_model(test_input) + single_dense_output = tf.stack( + [single_model(test_input) for single_model in single_models], axis=1 + ) + + np.allclose(multi_dense_output, single_dense_output) From efcfc6a1366d828cd39f9e858c2bed2a1586e25c Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 9 Jan 2024 12:04:32 +0100 Subject: [PATCH 58/71] Add MultiDense layer improvements --- .../n3fit/backends/keras_backend/MetaModel.py | 20 ---- .../backends/keras_backend/base_layers.py | 12 ++ .../backends/keras_backend/multi_dense.py | 107 ++++++++++++------ n3fit/src/n3fit/checks.py | 6 +- n3fit/src/n3fit/tests/test_multidense.py | 43 ++++++- 5 files changed, 123 insertions(+), 65 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 1108ce2358..99269d1af6 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -464,26 +464,6 @@ def get_layer_replica_weights(layer, i_replica: int): return weights -def get_layer_replica_weights(layer, i_replica: int): - """ - Get the weights for the given single replica `i_replica`, - from a `layer` that has weights for all replicas. - - Parameters - ---------- - layer: MetaLayer - the layer to get the weights from - i_replica: int - the replica number - - Returns - ------- - weights: list - list of weights for the replica - """ - return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] - - def set_layer_replica_weights(layer, weights, i_replica: int): """ Set the weights for the given single replica ``i_replica``. diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index ffac67946b..43f7622e99 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -127,6 +127,18 @@ def apply_dense(xinput): layers = { + "multi_dense": ( + MultiDense, + { + "input_shape": (1,), + "replica_seeds": None, + "kernel_initializer": "glorot_normal", + "units": 5, + "activation": "sigmoid", + "kernel_regularizer": None, + "replica_input": True, + }, + ), "dense": ( Dense, { diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py index 1068aa84ff..97d472e87e 100644 --- a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -1,3 +1,5 @@ +from typing import List + import tensorflow as tf from tensorflow.keras.initializers import Initializer from tensorflow.keras.layers import Dense @@ -14,8 +16,8 @@ class MultiDense(Dense): should be set to `False`. The input shape in this case is (batch_size, gridsize, features). - The kernel initializer is set using the custom arguments `initializer_class` and - `seed`. The `seed` is incremented by 1 for each replica. + Weights are initialized using a `replica_seeds` list of seeds, and are identical to the + weights of a list of single dense layers with the same `replica_seeds`. Example @@ -27,8 +29,8 @@ class MultiDense(Dense): >>> import tensorflow as tf >>> replicas = 2 >>> multi_dense_model = Sequential([ - >>> MultiDense(units=8, replicas=replicas, seed=42, replica_input=False, initializer_class=GlorotUniform), - >>> MultiDense(units=4, replicas=replicas, seed=52, initializer_class=GlorotUniform), + >>> MultiDense(units=8, replica_seeds=[42, 43], replica_input=False, kernel_initializer=GlorotUniform(seed=0)), + >>> MultiDense(units=4, replica_seeds=[52, 53], kernel_initializer=GlorotUniform(seed=0)), >>> ]) >>> single_models = [ >>> Sequential([ @@ -48,11 +50,9 @@ class MultiDense(Dense): Parameters ---------- - replicas: int - Number of replicas. - seed: int - Seed for the random number generator. - initializer_class: Initializer + replica_seeds: List[int] + List of seeds per replica for the kernel initializer. + kernel_initializer: Initializer Initializer class for the kernel. replica_input: bool (default: True) Whether the input already contains multiple replicas. @@ -60,38 +60,43 @@ class MultiDense(Dense): def __init__( self, - replicas: int, - seed: int, - initializer_class: Initializer, + replica_seeds: List[int], + kernel_initializer: Initializer, replica_input: bool = True, **kwargs ): super().__init__(**kwargs) - self.replicas = replicas - self.seed = seed - self.initializer_class = initializer_class + self.replicas = len(replica_seeds) + self.replica_seeds = replica_seeds + self.kernel_initializer = MultiInitializer( + single_initializer=kernel_initializer, replica_seeds=replica_seeds + ) + self.bias_initializer = MultiInitializer( + single_initializer=self.bias_initializer, replica_seeds=replica_seeds + ) self.replica_input = replica_input def build(self, input_shape): - """ - Build weight matrix of shape (replicas, input_dim, units). - Weights are initialized on a per-replica basis, with incrementing seed. - """ - # Remove the replica axis from the input shape. - if self.replica_input: - input_shape = input_shape[:1] + input_shape[2:] - - # Create and concatenate separate weights per replica. - replica_kernels = [] - replica_biases = [] - for r in range(self.replicas): - self.kernel_initializer = self.initializer_class(self.seed + r) - super().build(input_shape) - replica_kernels.append(self.kernel) - replica_biases.append(self.bias) - self.kernel = tf.Variable(tf.stack(replica_kernels, axis=0)) + input_dim = input_shape[-1] + self.kernel = self.add_weight( + name="kernel", + shape=(self.replicas, input_dim, self.units), + initializer=self.kernel_initializer, + regularizer=self.kernel_regularizer, + constraint=self.kernel_constraint, + ) if self.use_bias: - self.bias = tf.Variable(tf.expand_dims(tf.stack(replica_biases, axis=0), axis=1)) + self.bias = self.add_weight( + name="bias", + shape=(self.replicas, 1, self.units), + initializer=self.bias_initializer, + regularizer=self.bias_regularizer, + constraint=self.bias_constraint, + ) + else: + self.bias = None + self.input_spec.axes = {-1: input_dim} + self.built = True def call(self, inputs): """ @@ -136,7 +141,37 @@ def compute_output_shape(self, input_shape): def get_config(self): config = super().get_config() - config.update( - {"replicas": self.replicas, "replica_input": self.replica_input, "seed": self.seed} - ) + config.update({"replica_input": self.replica_input, "replica_seeds": self.replica_seeds}) return config + + +class MultiInitializer(Initializer): + """ + Multi replica initializer that exactly replicates a stack of single replica initializers. + + Weights are stacked on the first axis, and per replica seeds are added to a base seed of the + given single replica initializer. + + Parameters + ---------- + single_initializer: Initializer + Initializer class for the kernel. + replica_seeds: List[int] + List of seeds per replica for the kernel initializer. + """ + + def __init__(self, single_initializer: Initializer, replica_seeds: List[int]): + self.single_initializer = single_initializer + self.base_seed = single_initializer.seed if hasattr(single_initializer, "seed") else None + self.replica_seeds = replica_seeds + + def __call__(self, shape, dtype=None, **kwargs): + shape = shape[1:] # Remove the replica axis from the shape. + per_replica_weights = [] + for replica_seed in self.replica_seeds: + if self.base_seed is not None: + self.single_initializer.seed = self.base_seed + replica_seed + + per_replica_weights.append(self.single_initializer(shape, dtype, **kwargs)) + + return tf.stack(per_replica_weights, axis=0) diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index 885785a268..7c0f57d672 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -111,7 +111,7 @@ def check_initializer(initializer): def check_layer_type_implemented(parameters): """Checks whether the layer_type is implemented""" layer_type = parameters.get("layer_type") - implemented_types = ["dense", "dense_per_flavour"] + implemented_types = ["dense", "multi_dense", "dense_per_flavour"] if layer_type not in implemented_types: raise CheckError( f"Layer type {layer_type} not implemented, must be one of {implemented_types}" @@ -385,8 +385,8 @@ def check_consistent_parallel(parameters, parallel_models, same_trvl_per_replica "Replicas cannot be run in parallel with different training/validation " " masks, please set `same_trvl_per_replica` to True in the runcard" ) - if parameters.get("layer_type") != "dense": - raise CheckError("Parallelization has only been tested with layer_type=='dense'") + if parameters.get("layer_type") == "dense_per_flavour": + raise CheckError("Parallelization has not been tested with layer_type=='dense_per_flavour'") @make_argcheck diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py index f8998d5e9b..14bbdb9817 100644 --- a/n3fit/src/n3fit/tests/test_multidense.py +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -5,6 +5,7 @@ from tensorflow.keras.layers import Dense from n3fit.backends.keras_backend.multi_dense import MultiDense +from n3fit.model_gen import generate_nn def test_multidense(): @@ -13,19 +14,18 @@ def test_multidense(): [ MultiDense( units=8, - replicas=replicas, - seed=42, + replica_seeds=[42, 43], replica_input=False, - initializer_class=GlorotUniform, + kernel_initializer=GlorotUniform(seed=0), ), - MultiDense(units=4, replicas=replicas, seed=52, initializer_class=GlorotUniform), + MultiDense(units=4, replica_seeds=[52, 53], kernel_initializer=GlorotUniform(seed=100)), ] ) single_models = [ Sequential( [ Dense(units=8, kernel_initializer=GlorotUniform(seed=42 + r)), - Dense(units=4, kernel_initializer=GlorotUniform(seed=52 + r)), + Dense(units=4, kernel_initializer=GlorotUniform(seed=52 + r + 100)), ] ) for r in range(replicas) @@ -42,4 +42,35 @@ def test_multidense(): [single_model(test_input) for single_model in single_models], axis=1 ) - np.allclose(multi_dense_output, single_dense_output) + np.testing.assert_allclose(multi_dense_output, single_dense_output) + + +def test_initializers(): + input_shape = (None, 3, 1) + dense_layers = [] + for r in range(2): + dense_layer = Dense(units=2, kernel_initializer=GlorotUniform(seed=42 + r)) + dense_layer.build(input_shape=input_shape) + dense_layers.append(dense_layer) + stacked_weights = tf.stack([dense_layer.weights[0] for dense_layer in dense_layers], axis=0) + + multi_dense_layer = MultiDense( + units=2, + replica_seeds=[0, 1], + replica_input=False, + kernel_initializer=GlorotUniform(seed=42), + ) + multi_dense_layer.build(input_shape=input_shape) + + multi_dense_weights = multi_dense_layer.weights[0].numpy() + stacked_weights = stacked_weights.numpy() + + np.testing.assert_allclose(multi_dense_weights, stacked_weights) + + +def main(): + test_initializers() + + +if __name__ == '__main__': + main() From 0e3dd2c0ccfc89d3dc2fc30912d412e334cab51b Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 9 Jan 2024 14:54:54 +0100 Subject: [PATCH 59/71] Recreate initializer per replica to make sure seed is properly set --- n3fit/src/n3fit/backends/keras_backend/multi_dense.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py index 97d472e87e..5045711537 100644 --- a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -161,7 +161,8 @@ class MultiInitializer(Initializer): """ def __init__(self, single_initializer: Initializer, replica_seeds: List[int]): - self.single_initializer = single_initializer + self.initializer_class = type(single_initializer) + self.initializer_config = single_initializer.get_config() self.base_seed = single_initializer.seed if hasattr(single_initializer, "seed") else None self.replica_seeds = replica_seeds @@ -170,8 +171,9 @@ def __call__(self, shape, dtype=None, **kwargs): per_replica_weights = [] for replica_seed in self.replica_seeds: if self.base_seed is not None: - self.single_initializer.seed = self.base_seed + replica_seed + self.initializer_config["seed"] = self.base_seed + replica_seed + single_initializer = self.initializer_class.from_config(self.initializer_config) - per_replica_weights.append(self.single_initializer(shape, dtype, **kwargs)) + per_replica_weights.append(single_initializer(shape, dtype, **kwargs)) return tf.stack(per_replica_weights, axis=0) From 4e81bf6354b19c71a69f93f0c7327b6a2c537cd4 Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 9 Jan 2024 15:45:20 +0100 Subject: [PATCH 60/71] Add tolerences to test --- n3fit/src/n3fit/tests/test_multidense.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py index 14bbdb9817..ed848ffedc 100644 --- a/n3fit/src/n3fit/tests/test_multidense.py +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -42,7 +42,7 @@ def test_multidense(): [single_model(test_input) for single_model in single_models], axis=1 ) - np.testing.assert_allclose(multi_dense_output, single_dense_output) + np.testing.assert_allclose(multi_dense_output, single_dense_output, atol=1e-6, rtol=1e-4) def test_initializers(): From 08a3a186f6f8632d6b5b4235f5d9a402499997aa Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 9 Jan 2024 16:23:41 +0100 Subject: [PATCH 61/71] Add multi_dense path in generate_nn --- n3fit/src/n3fit/model_gen.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index fc180f392f..4546155874 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -750,17 +750,28 @@ def initializer_generator(seed, i_layer): # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] for i_layer, (nodes_out, activation) in enumerate(zip(nodes_list, activations)): - layers = [ - base_layer_selector( + if layer_type == "multi_dense": + layers = base_layer_selector( layer_type, - kernel_initializer=initializer_generator(replica_seed, i_layer), + replica_seeds=replica_seeds, + kernel_initializer=initializer_generator(0, i_layer), units=nodes_out, activation=activation, - input_shape=(nodes_in,), + replica_input=(i_layer != 0), **custom_args, ) - for replica_seed in replica_seeds - ] + else: + layers = [ + base_layer_selector( + layer_type, + kernel_initializer=initializer_generator(replica_seed, i_layer), + units=nodes_out, + activation=activation, + input_shape=(nodes_in,), + **custom_args, + ) + for replica_seed in replica_seeds + ] list_of_pdf_layers.append(layers) nodes_in = int(nodes_out) @@ -775,6 +786,14 @@ def initializer_generator(seed, i_layer): list_of_pdf_layers[-1] = [lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1]] # Apply all layers to the input to create the models + if layer_type == "multi_dense": + pdfs = x_input + for layer in list_of_pdf_layers: + pdfs = layer(pdfs) + model = MetaModel({'NN_input': x_input}, pdfs, name=f"NNs") + + return model + pdfs = [layer(x_input) for layer in list_of_pdf_layers[0]] for layers in list_of_pdf_layers[1:]: From a84d8acac2d2efae4f63c0369cc0310580551ce6 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 08:30:23 +0100 Subject: [PATCH 62/71] Add MultiDropout --- .../backends/keras_backend/base_layers.py | 11 +++------- .../backends/keras_backend/multi_dense.py | 21 ++++++++++++++++++- n3fit/src/n3fit/tests/test_multidense.py | 21 ++++++++++++++----- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 43f7622e99..3f1726fe16 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -18,18 +18,13 @@ """ from tensorflow import expand_dims, math, nn -from tensorflow.keras.layers import ( # pylint: disable=unused-import - Dropout, - Input, - Lambda, - concatenate, -) from tensorflow.keras.layers import Dense as KerasDense +from tensorflow.keras.layers import Input, Lambda, concatenate # pylint: disable=unused-import from tensorflow.keras.layers import LSTM, Concatenate # pylint: disable=unused-import from tensorflow.keras.regularizers import l1_l2 from n3fit.backends import MetaLayer -from n3fit.backends.keras_backend.multi_dense import MultiDense +from n3fit.backends.keras_backend.multi_dense import MultiDense, MultiDropout # Custom activation functions @@ -163,7 +158,7 @@ def apply_dense(xinput): LSTM_modified, {"kernel_initializer": "glorot_normal", "units": 5, "activation": "sigmoid"}, ), - "dropout": (Dropout, {"rate": 0.0}), + "dropout": (MultiDropout, {"rate": 0.0}), "concatenate": (Concatenate, {}), } diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py index 5045711537..3e7dbdf4ec 100644 --- a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -2,7 +2,7 @@ import tensorflow as tf from tensorflow.keras.initializers import Initializer -from tensorflow.keras.layers import Dense +from tensorflow.keras.layers import Dense, Dropout class MultiDense(Dense): @@ -177,3 +177,22 @@ def __call__(self, shape, dtype=None, **kwargs): per_replica_weights.append(single_initializer(shape, dtype, **kwargs)) return tf.stack(per_replica_weights, axis=0) + + +class MultiDropout(Dropout): + """ + Dropout that broadcasts to the replica axis, to make sure that the dropout rate is constant + per replica. + + Input shape: (batch_size, replicas, gridsize, features) + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.replica_axis = 1 + + def _get_noise_shape(self, inputs): + input_shape = list(inputs.shape) + noise_shape = input_shape[: self.replica_axis] + [1] + input_shape[self.replica_axis + 1 :] + return noise_shape diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py index ed848ffedc..42a77e314e 100644 --- a/n3fit/src/n3fit/tests/test_multidense.py +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -4,7 +4,7 @@ from tensorflow.keras.initializers import GlorotUniform from tensorflow.keras.layers import Dense -from n3fit.backends.keras_backend.multi_dense import MultiDense +from n3fit.backends.keras_backend.multi_dense import MultiDense, MultiDropout from n3fit.model_gen import generate_nn @@ -68,9 +68,20 @@ def test_initializers(): np.testing.assert_allclose(multi_dense_weights, stacked_weights) -def main(): - test_initializers() +def test_dropout(): + replicas = 100 + x_size = 10 + features = 1 + input_shape = (1, replicas, x_size, features) + test_input = tf.ones(shape=input_shape) + dropout_layer = MultiDropout(rate=0.5, seed=44) -if __name__ == '__main__': - main() + test_output = dropout_layer(test_input, training=True) + + # Check that for every replica the same x values are dropped + zero_indices_first_replica = np.where(test_output.numpy()[0, 0, :, 0] == 0) + nonzero_indices_first_replica = np.where(test_output.numpy()[0, 0, :, 0] != 0) + + assert np.all(test_output.numpy()[:, :, zero_indices_first_replica, :] == 0) + assert np.all(test_output.numpy()[:, :, nonzero_indices_first_replica, :] != 0) From ef336e1547e2b162824db8ea29541c20f7d4d053 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 09:05:51 +0100 Subject: [PATCH 63/71] Replace old dense layer everywhere --- .../backends/keras_backend/base_layers.py | 7 ++++--- n3fit/src/n3fit/checks.py | 7 +++---- n3fit/src/n3fit/model_gen.py | 4 ++-- .../src/n3fit/tests/regressions/weights_1.h5 | Bin 29232 -> 29232 bytes .../src/n3fit/tests/regressions/weights_2.h5 | Bin 29232 -> 29232 bytes n3fit/src/n3fit/tests/test_modelgen.py | 13 +++++++------ 6 files changed, 16 insertions(+), 15 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 3f1726fe16..2a8d9b66a7 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -92,7 +92,7 @@ def dense_per_flavour(basis_size=8, kernel_initializer="glorot_normal", **dense_ # Need to generate a list of dense layers dense_basis = [ - base_layer_selector("dense", kernel_initializer=initializer, **dense_kwargs) + base_layer_selector("single_dense", kernel_initializer=initializer, **dense_kwargs) for initializer in kernel_initializer ] @@ -122,7 +122,7 @@ def apply_dense(xinput): layers = { - "multi_dense": ( + "dense": ( MultiDense, { "input_shape": (1,), @@ -134,7 +134,8 @@ def apply_dense(xinput): "replica_input": True, }, ), - "dense": ( + # This one is only used inside dense_per_flavour + "single_dense": ( Dense, { "input_shape": (1,), diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index 7c0f57d672..d93f3b1d9a 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -111,7 +111,7 @@ def check_initializer(initializer): def check_layer_type_implemented(parameters): """Checks whether the layer_type is implemented""" layer_type = parameters.get("layer_type") - implemented_types = ["dense", "multi_dense", "dense_per_flavour"] + implemented_types = ["dense", "dense_per_flavour"] if layer_type not in implemented_types: raise CheckError( f"Layer type {layer_type} not implemented, must be one of {implemented_types}" @@ -427,10 +427,9 @@ def check_fiatlux_pdfs_id(replicas, fiatlux): f"Cannot generate a photon replica with id larger than the number of replicas of the PDFs set {luxset.name}:\nreplica id={max_id}, replicas of {luxset.name} = {pdfs_ids}" ) + @make_argcheck def check_multireplica_qed(replicas, fiatlux): if fiatlux is not None: if len(replicas) > 1: - raise CheckError( - "At the moment, running a multireplica QED fits is not allowed." - ) + raise CheckError("At the moment, running a multireplica QED fits is not allowed.") diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 4546155874..467e2ef54d 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -750,7 +750,7 @@ def initializer_generator(seed, i_layer): # list_of_pdf_layers[d][r] is the layer at depth d for replica r list_of_pdf_layers = [] for i_layer, (nodes_out, activation) in enumerate(zip(nodes_list, activations)): - if layer_type == "multi_dense": + if layer_type == "dense": layers = base_layer_selector( layer_type, replica_seeds=replica_seeds, @@ -786,7 +786,7 @@ def initializer_generator(seed, i_layer): list_of_pdf_layers[-1] = [lambda x: concat(layer(x)) for layer in list_of_pdf_layers[-1]] # Apply all layers to the input to create the models - if layer_type == "multi_dense": + if layer_type == "dense": pdfs = x_input for layer in list_of_pdf_layers: pdfs = layer(pdfs) diff --git a/n3fit/src/n3fit/tests/regressions/weights_1.h5 b/n3fit/src/n3fit/tests/regressions/weights_1.h5 index 7f9f9301844822e6cb8ab0e0271f2bc8f538119f..9ffdaea7f343830a67cf36c433d6d7b3c0fe91e1 100644 GIT binary patch delta 740 zcmdn+gmD89X|OVCY(A*Z&ctXj*^ph_GPg9RBr`rGHLo}|-k5=b0hw=t#y17>8G#rC z6eb@GliWOu{U2k!2t))`tA0{uVzHG0NQw_CFNQ^(seX29QC?~eNF_g19-DclNahKk znwN=YF~UGWJO&yg87PEmAc}d$NDkZ_z{SDL)WEelk++O%lf(wbK(LoMAlgBufSnHI zgKS5Z2RR#Ao)=9X6igzU8KvGcF-lDSD5DOHCrMdGMt%#RI56CqAtBE=*-%cL5kzKA zP6*(bcp`1GgR#J74S6q4c{G(^eTW$2pS;jdd~%0I6ja~l0?k!Sn5OH1P1ng}%$RsE z7h<-q7b5|)xgciiA+7LH_u}K$5_wD00B@1 z`bn9I#a0Fk3@~v46nRtq?9`&X)Ep}VeyBK19Ynt=Tt7@7jE0#H(=Q0oZwa>uqQDq# zfDqIIR0E9R4%pnl#lg(9fot*z=Dj7 zj8Msi8i|Y@6A$)oF3?=X1l9-(Hm=EzI#7+eA&iU?le3v+CvVUTf-2X)1X0cfHi&_N wV{)L8_~ZtoAdp>?<>a|G2N-)XqS?nWxzNaSvXH3+*pSH!!X!3tFm12_0I>UQ#{d8T diff --git a/n3fit/src/n3fit/tests/regressions/weights_2.h5 b/n3fit/src/n3fit/tests/regressions/weights_2.h5 index 51061a63f24a1d41d1d392f048a5ac31d231212f..18c593da9eb1def31cadbdbc74d654c561c4dc64 100644 GIT binary patch delta 740 zcmdn+gmD89X|OVCY(A*Z&ctXj*^ph_GPg9RBr`rGHLo}|-k5=b0hw=t#y17>8G#rC z6eb@GliWOu{U2k!2t))`tA0{uVzHG0NQw_CFNQ^(seX29QC?~eNF_g19-DclNahKk znwN=YF~UGWJO&yg87PEmAc}d$NDkZ_z{SDL)WEelk++O%lf(wbK(LoMAlgBufSnHI zgKS5Z2RR#Ao)=9X6igzU8KvGcF-lDSD5DOHCrMdGMt%#RI56CqAtBE=*-%cL5kzKA zP6*(bcp`1GgR#J74S6q4c{G(^eTW$2pS;jdd~%0I6ja~l0?k!Sn5OH1P1ng}%$RsE z7h<-q7b5|)xgciiA+7LH_u}K$5_wD00B@1 z`bn9I#a0Fk3@~v46nRtq?9`&X)Ep}VeyBK19Ynt=Tt7@7jE0#H(=Q0oZwa>uqQDq# zfDqIIR0E9R4%pnl#lg(9fot*z=Dj7 zj8Msi8i|Y@6A$)oF3?=X1l9-(Hm=EzI#7+eA&iU?le3v+CvVUTf-2X)1X0cfHi&_N wV{)L8_~ZtoAdp>?<>a|G2N-)XqS?nWxzNaSvXH3+*pSH!!X!3tFm12_0I>UQ#{d8T diff --git a/n3fit/src/n3fit/tests/test_modelgen.py b/n3fit/src/n3fit/tests/test_modelgen.py index ffdaa254b6..c87523f838 100644 --- a/n3fit/src/n3fit/tests/test_modelgen.py +++ b/n3fit/src/n3fit/tests/test_modelgen.py @@ -26,16 +26,17 @@ def test_generate_dense_network(): - nn = generate_nn("dense", **COMMON_ARGS).get_layer(f"{NN_PREFIX}_0") + nn = generate_nn("dense", **COMMON_ARGS) # The number of layers should be input layer + len(OUT_SIZES) assert len(nn.layers) == len(OUT_SIZES) + 1 # Check that the number of parameters is as expected - # We expect 4 weights where the two first ones are - # (INSIZE, OUT_SIZE[0]) (OUT_SIZE[0],) - # and the second one - # (OUT_SIZE[0], OUT_SIZE[1]) (OUT_SIZE[1],) - expected_sizes = [(INSIZE, OUT_SIZES[0]), (OUT_SIZES[0],), OUT_SIZES, (OUT_SIZES[1],)] + expected_sizes = [ + (1, INSIZE, OUT_SIZES[0]), + (1, 1, OUT_SIZES[0]), + (1, *OUT_SIZES), + (1, 1, OUT_SIZES[1]), + ] for weight, esize in zip(nn.weights, expected_sizes): assert weight.shape == esize From 737ed2b6d5099a74c2b6c40e682c4ffae6ed2220 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 13:02:35 +0100 Subject: [PATCH 64/71] Remove MultiDropout, not necessary --- .../backends/keras_backend/base_layers.py | 11 ++++++++--- .../backends/keras_backend/multi_dense.py | 19 ------------------- n3fit/src/n3fit/tests/test_multidense.py | 19 ------------------- 3 files changed, 8 insertions(+), 41 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 2a8d9b66a7..36a2016fee 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -18,13 +18,18 @@ """ from tensorflow import expand_dims, math, nn +from tensorflow.keras.layers import ( # pylint: disable=unused-import + Dropout, + Input, + Lambda, + concatenate, +) from tensorflow.keras.layers import Dense as KerasDense -from tensorflow.keras.layers import Input, Lambda, concatenate # pylint: disable=unused-import from tensorflow.keras.layers import LSTM, Concatenate # pylint: disable=unused-import from tensorflow.keras.regularizers import l1_l2 from n3fit.backends import MetaLayer -from n3fit.backends.keras_backend.multi_dense import MultiDense, MultiDropout +from n3fit.backends.keras_backend.multi_dense import MultiDense # Custom activation functions @@ -159,7 +164,7 @@ def apply_dense(xinput): LSTM_modified, {"kernel_initializer": "glorot_normal", "units": 5, "activation": "sigmoid"}, ), - "dropout": (MultiDropout, {"rate": 0.0}), + "dropout": (Dropout, {"rate": 0.0}), "concatenate": (Concatenate, {}), } diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py index 3e7dbdf4ec..871ad8dfa6 100644 --- a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -177,22 +177,3 @@ def __call__(self, shape, dtype=None, **kwargs): per_replica_weights.append(single_initializer(shape, dtype, **kwargs)) return tf.stack(per_replica_weights, axis=0) - - -class MultiDropout(Dropout): - """ - Dropout that broadcasts to the replica axis, to make sure that the dropout rate is constant - per replica. - - Input shape: (batch_size, replicas, gridsize, features) - - """ - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.replica_axis = 1 - - def _get_noise_shape(self, inputs): - input_shape = list(inputs.shape) - noise_shape = input_shape[: self.replica_axis] + [1] + input_shape[self.replica_axis + 1 :] - return noise_shape diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py index 42a77e314e..4ffbfc4a53 100644 --- a/n3fit/src/n3fit/tests/test_multidense.py +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -66,22 +66,3 @@ def test_initializers(): stacked_weights = stacked_weights.numpy() np.testing.assert_allclose(multi_dense_weights, stacked_weights) - - -def test_dropout(): - replicas = 100 - x_size = 10 - features = 1 - input_shape = (1, replicas, x_size, features) - test_input = tf.ones(shape=input_shape) - - dropout_layer = MultiDropout(rate=0.5, seed=44) - - test_output = dropout_layer(test_input, training=True) - - # Check that for every replica the same x values are dropped - zero_indices_first_replica = np.where(test_output.numpy()[0, 0, :, 0] == 0) - nonzero_indices_first_replica = np.where(test_output.numpy()[0, 0, :, 0] != 0) - - assert np.all(test_output.numpy()[:, :, zero_indices_first_replica, :] == 0) - assert np.all(test_output.numpy()[:, :, nonzero_indices_first_replica, :] != 0) From a5c6b11fd00c3417a395a70b79b3d585b2d68742 Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 13:46:10 +0100 Subject: [PATCH 65/71] Update developing weights structure --- n3fit/runcards/examples/developing_weights.h5 | Bin 41348 -> 41348 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/n3fit/runcards/examples/developing_weights.h5 b/n3fit/runcards/examples/developing_weights.h5 index 385ea55a758dc81092dad551d29cdb1f94fab8d9..2749393b421910762e0844381d5628511d4026cc 100644 GIT binary patch delta 933 zcmZoU%+zw2X@dqUqs8Wh8Q&QvE3gYNdQ3KC7x&C9%_+%@Pf5)yPK`HVU|>Mzo1*c} z(D>#+J|hr=fWYR7?CebSVh|pRF=qPNsYQ9IIaUS?417>|5v=NxG82nIsu&pfq4L`i_Ppi*E`V1^_H#>s(l;*20N zlQCoB!Q4p_Y@6-mLpV8L$|k?76=ODHV3_>AR&??TjVQ3H%@Z_NF=3jd12#zq$t2wn zMpToOVJ7LpOwzBC!!SwF4`h;}AHpO)e{_>1p(a%XKut;rTqmFob2ij>V81dj0M&v4 vG_)BQC#xpG&7N#0&$U@5*$d63K($~$novfF delta 751 zcmZoU%+zw2X@dsqXRqvOKjf2{(`Yy04fU6Wu~8NzH!XxltNa}^U;JB-4I4Jt;&-R>LIl1SIL33DnqqOPB!#| zXyx Date: Thu, 11 Jan 2024 14:10:41 +0100 Subject: [PATCH 66/71] Remove MultiDropout once more --- n3fit/src/n3fit/tests/test_multidense.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/tests/test_multidense.py b/n3fit/src/n3fit/tests/test_multidense.py index 4ffbfc4a53..b912c0bd82 100644 --- a/n3fit/src/n3fit/tests/test_multidense.py +++ b/n3fit/src/n3fit/tests/test_multidense.py @@ -4,7 +4,7 @@ from tensorflow.keras.initializers import GlorotUniform from tensorflow.keras.layers import Dense -from n3fit.backends.keras_backend.multi_dense import MultiDense, MultiDropout +from n3fit.backends.keras_backend.multi_dense import MultiDense from n3fit.model_gen import generate_nn From c07a49bf230d0938d3bb0ec6e1ab862557c38951 Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 23 Jan 2024 14:07:46 +0100 Subject: [PATCH 67/71] Fix naming inconsistency wrt parallel-prefactor --- n3fit/src/n3fit/model_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 467e2ef54d..5a69fe9396 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -790,7 +790,7 @@ def initializer_generator(seed, i_layer): pdfs = x_input for layer in list_of_pdf_layers: pdfs = layer(pdfs) - model = MetaModel({'NN_input': x_input}, pdfs, name=f"NNs") + model = MetaModel({'NN_input': x_input}, pdfs, name=NN_LAYER_ALL_REPLICAS) return model From c77add691a5dddb8a79d324923e903a166a62373 Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 25 Oct 2023 08:13:20 +0200 Subject: [PATCH 68/71] Merge prefactors into single layer --- .../n3fit/backends/keras_backend/MetaModel.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 99269d1af6..1108ce2358 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -464,6 +464,26 @@ def get_layer_replica_weights(layer, i_replica: int): return weights +def get_layer_replica_weights(layer, i_replica: int): + """ + Get the weights for the given single replica `i_replica`, + from a `layer` that has weights for all replicas. + + Parameters + ---------- + layer: MetaLayer + the layer to get the weights from + i_replica: int + the replica number + + Returns + ------- + weights: list + list of weights for the replica + """ + return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] + + def set_layer_replica_weights(layer, weights, i_replica: int): """ Set the weights for the given single replica ``i_replica``. From 304b40089634bc5dfb8cfb5b2404040b342042f1 Mon Sep 17 00:00:00 2001 From: Aron Date: Tue, 9 Jan 2024 12:04:32 +0100 Subject: [PATCH 69/71] Add MultiDense layer improvements --- .../n3fit/backends/keras_backend/MetaModel.py | 20 ------------------- .../backends/keras_backend/base_layers.py | 12 +++++++++++ .../backends/keras_backend/multi_dense.py | 8 +++----- n3fit/src/n3fit/checks.py | 2 +- 4 files changed, 16 insertions(+), 26 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 1108ce2358..99269d1af6 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -464,26 +464,6 @@ def get_layer_replica_weights(layer, i_replica: int): return weights -def get_layer_replica_weights(layer, i_replica: int): - """ - Get the weights for the given single replica `i_replica`, - from a `layer` that has weights for all replicas. - - Parameters - ---------- - layer: MetaLayer - the layer to get the weights from - i_replica: int - the replica number - - Returns - ------- - weights: list - list of weights for the replica - """ - return [tf.Variable(w[i_replica : i_replica + 1], name=w.name) for w in layer.weights] - - def set_layer_replica_weights(layer, weights, i_replica: int): """ Set the weights for the given single replica ``i_replica``. diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 36a2016fee..2942f9de50 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -127,6 +127,18 @@ def apply_dense(xinput): layers = { + "multi_dense": ( + MultiDense, + { + "input_shape": (1,), + "replica_seeds": None, + "kernel_initializer": "glorot_normal", + "units": 5, + "activation": "sigmoid", + "kernel_regularizer": None, + "replica_input": True, + }, + ), "dense": ( MultiDense, { diff --git a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py index 871ad8dfa6..8640a72c00 100644 --- a/n3fit/src/n3fit/backends/keras_backend/multi_dense.py +++ b/n3fit/src/n3fit/backends/keras_backend/multi_dense.py @@ -161,8 +161,7 @@ class MultiInitializer(Initializer): """ def __init__(self, single_initializer: Initializer, replica_seeds: List[int]): - self.initializer_class = type(single_initializer) - self.initializer_config = single_initializer.get_config() + self.single_initializer = single_initializer self.base_seed = single_initializer.seed if hasattr(single_initializer, "seed") else None self.replica_seeds = replica_seeds @@ -171,9 +170,8 @@ def __call__(self, shape, dtype=None, **kwargs): per_replica_weights = [] for replica_seed in self.replica_seeds: if self.base_seed is not None: - self.initializer_config["seed"] = self.base_seed + replica_seed - single_initializer = self.initializer_class.from_config(self.initializer_config) + self.single_initializer.seed = self.base_seed + replica_seed - per_replica_weights.append(single_initializer(shape, dtype, **kwargs)) + per_replica_weights.append(self.single_initializer(shape, dtype, **kwargs)) return tf.stack(per_replica_weights, axis=0) diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index d93f3b1d9a..f3a76f28e6 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -111,7 +111,7 @@ def check_initializer(initializer): def check_layer_type_implemented(parameters): """Checks whether the layer_type is implemented""" layer_type = parameters.get("layer_type") - implemented_types = ["dense", "dense_per_flavour"] + implemented_types = ["dense", "multi_dense", "dense_per_flavour"] if layer_type not in implemented_types: raise CheckError( f"Layer type {layer_type} not implemented, must be one of {implemented_types}" From a658304e5a652e79ee7867773c69d4fee9749c4f Mon Sep 17 00:00:00 2001 From: Aron Date: Thu, 11 Jan 2024 09:05:51 +0100 Subject: [PATCH 70/71] Replace old dense layer everywhere --- .../src/n3fit/backends/keras_backend/base_layers.py | 12 ------------ n3fit/src/n3fit/checks.py | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 2942f9de50..36a2016fee 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -127,18 +127,6 @@ def apply_dense(xinput): layers = { - "multi_dense": ( - MultiDense, - { - "input_shape": (1,), - "replica_seeds": None, - "kernel_initializer": "glorot_normal", - "units": 5, - "activation": "sigmoid", - "kernel_regularizer": None, - "replica_input": True, - }, - ), "dense": ( MultiDense, { diff --git a/n3fit/src/n3fit/checks.py b/n3fit/src/n3fit/checks.py index f3a76f28e6..d93f3b1d9a 100644 --- a/n3fit/src/n3fit/checks.py +++ b/n3fit/src/n3fit/checks.py @@ -111,7 +111,7 @@ def check_initializer(initializer): def check_layer_type_implemented(parameters): """Checks whether the layer_type is implemented""" layer_type = parameters.get("layer_type") - implemented_types = ["dense", "multi_dense", "dense_per_flavour"] + implemented_types = ["dense", "dense_per_flavour"] if layer_type not in implemented_types: raise CheckError( f"Layer type {layer_type} not implemented, must be one of {implemented_types}" From 0fa674dc4f6b902b46569bca54136aff4df105d4 Mon Sep 17 00:00:00 2001 From: Aron Date: Wed, 30 Aug 2023 14:50:38 +0200 Subject: [PATCH 71/71] Avoid TensorFlow overhead by making one step a batch rather than an epoch. Avoids memory overhead by only combining up to 100 steps into one epoch, and not changing anything when using only 1 replica (i.e. on CPU). --- .../n3fit/backends/keras_backend/MetaModel.py | 38 +++++++++- .../n3fit/backends/keras_backend/callbacks.py | 75 +++++++++++++++---- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index 99269d1af6..48b4e7e3aa 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -5,6 +5,7 @@ backend-dependent calls. """ +import logging import re import h5py @@ -16,6 +17,8 @@ import n3fit.backends.keras_backend.operations as op +log = logging.getLogger(__name__) + # Check the TF version to check if legacy-mode is needed (TF < 2.2) tf_version = tf.__version__.split(".") if int(tf_version[0]) == 2 and int(tf_version[1]) < 2: @@ -170,10 +173,36 @@ def perform_fit(self, x=None, y=None, epochs=1, **kwargs): x_params = self._parse_input(x) if y is None: y = self.target_tensors - history = super().fit(x=x_params, y=y, epochs=epochs, **kwargs) + + # Avoids Tensorflow overhead that happens at every epoch, by putting multiple steps in an epoch + steps_per_epoch = self.determine_steps_per_epoch(epochs) + + for k, v in x_params.items(): + x_params[k] = tf.repeat(v, steps_per_epoch, axis=0) + y = [tf.repeat(yi, steps_per_epoch, axis=0) for yi in y] + + history = super().fit( + x=x_params, y=y, epochs=epochs // steps_per_epoch, batch_size=1, **kwargs + ) loss_dict = history.history return loss_dict + def determine_steps_per_epoch(self, epochs): + num_replicas = self.output_shape[0][0] + # in this case we're most likely running on the CPU and this is not worth it + if num_replicas == 1: + return 1 + + # On the GPU, run with + for divisor in [10, 100]: + if epochs % divisor != 0: + steps_per_epoch = divisor // 10 + log.warning( + f"Epochs {epochs} not divisible by {divisor}, using {steps_per_epoch} steps per epoch" + ) + return steps_per_epoch + return 100 + def predict(self, x=None, **kwargs): """Call super().predict with the right input arguments""" x = self._parse_input(x) @@ -199,10 +228,15 @@ def compute_losses(self): out_names = [f"{i}_loss" for i in self.output_names] out_names.insert(0, "loss") + inputs = self._parse_input(None) + # get rid of the repetitions by number of epochs made in perform_fit + for k, v in inputs.items(): + inputs[k] = v[:1] + # Compile a evaluation function @tf.function def losses_fun(): - predictions = self(self._parse_input(None)) + predictions = self(inputs) # If we only have one dataset the output changes if len(out_names) == 2: predictions = [predictions] diff --git a/n3fit/src/n3fit/backends/keras_backend/callbacks.py b/n3fit/src/n3fit/backends/keras_backend/callbacks.py index 7349d6be36..d49089c0e7 100644 --- a/n3fit/src/n3fit/backends/keras_backend/callbacks.py +++ b/n3fit/src/n3fit/backends/keras_backend/callbacks.py @@ -4,20 +4,64 @@ The callbacks defined in this module can be passed to the ``callbacks`` argument of the ``perform_fit`` method as a list. - For the most typical usage: ``on_epoch_end``, + For the most typical usage: ``on_batch_end``, they must take as input an epoch number and a log of the partial losses. + + Note: the terminology used everywhere refers to a single training step as a single epoch. + It turns out that to avoid tensorflow overhead, it is beneficial to write a step as a + single batch instead. So callbacks must use ``on_batch_end``. """ import logging from time import time + import numpy as np import tensorflow as tf -from tensorflow.keras.callbacks import TensorBoard, Callback +from tensorflow.keras.callbacks import Callback, TensorBoard log = logging.getLogger(__name__) -class TimerCallback(Callback): +class CallbackStep(Callback): + """ + Wrapper around the keras Callback that keeps track of how the steps are divided + between epochs and batches. + The callback will call ``on_step_end`` instead of ``on_batch_end``. + """ + + def __init__(self): + super().__init__() + self.steps_in_epoch = 0 + self.epochs_finished = 0 + self.steps_per_epoch = 0 # will be defined in the first epoch + self._previous_logs = {} + + def on_epoch_end(self, epoch, logs=None): + if self.steps_per_epoch == 0: + self.steps_per_epoch = self.steps_in_epoch + self.steps_in_epoch = 0 + self.epochs_finished += 1 + + def on_batch_end(self, batch, logs=None): + step_number = self.steps_in_epoch + self.epochs_finished * self.steps_per_epoch + self.on_step_end(step_number, logs) + self.steps_in_epoch += 1 + + def correct_logs(self, logs: dict) -> dict: + """ + The logs that get computed by default are an average over batches. + This converts it into the logs for the current step. + """ + corrected_logs = {} + for k in logs.keys(): + previous_total = self._previous_logs.get(k, 0.0) * self.steps_in_epoch + current_total = logs[k] * (self.steps_in_epoch + 1) + corrected_logs[k] = current_total - previous_total + self._previous_logs = logs + return corrected_logs + + +class TimerCallback(CallbackStep): """Callback to be used during debugging to time the fit""" def __init__(self, count_range=100): @@ -29,8 +73,8 @@ def __init__(self, count_range=100): self.starting_time = None self.last_time = 0 - def on_epoch_end(self, epoch, logs=None): - """ At the end of every epoch it checks the time """ + def on_step_end(self, epoch, logs=None): + """At the end of every epoch it checks the time""" new_time = time() if epoch == 0: # The first epoch is only useful for starting @@ -45,18 +89,18 @@ def on_epoch_end(self, epoch, logs=None): self.last_time = new_time def on_train_end(self, logs=None): - """ Print the results """ + """Print the results""" total_time = time() - self.starting_time n_times = len(self.all_times) # Skip the first 100 epochs to avoid fluctuations due to compilations of part of the code # by epoch 100 all parts of the code have usually been called so it's a good compromise - mean = np.mean(self.all_times[min(110, n_times-1):]) - std = np.std(self.all_times[min(110, n_times-1):]) + mean = np.mean(self.all_times[min(110, n_times - 1) :]) + std = np.std(self.all_times[min(110, n_times - 1) :]) log.info(f"> > Average time per epoch: {mean:.5} +- {std:.5} s") log.info(f"> > > Total time: {total_time/60:.5} min") -class StoppingCallback(Callback): +class StoppingCallback(CallbackStep): """ Given a ``stopping_object``, the callback will monitor the validation chi2 and will stop the training model when the conditions given by ``stopping_object`` @@ -76,10 +120,11 @@ def __init__(self, stopping_object, log_freq=100): self.log_freq = log_freq self.stopping_object = stopping_object - def on_epoch_end(self, epoch, logs=None): - """ Function to be called at the end of every epoch """ + def on_step_end(self, epoch, logs=None): + """Function to be called at the end of every epoch""" print_stats = ((epoch + 1) % self.log_freq) == 0 # Note that the input logs correspond to the fit before the weights are updated + logs = self.correct_logs(logs) self.stopping_object.monitor_chi2(logs, epoch, print_stats=print_stats) if self.stopping_object.stop_here(): self.model.stop_training = True @@ -92,7 +137,7 @@ def on_train_end(self, logs=None): self.stopping_object.make_stop() -class LagrangeCallback(Callback): +class LagrangeCallback(CallbackStep): """ Updates the given datasets with its respective multipliers each ``update_freq`` epochs @@ -117,7 +162,7 @@ def __init__(self, datasets, multipliers, update_freq=100): self.updateable_weights = [] def on_train_begin(self, logs=None): - """ Save an instance of all relevant layers """ + """Save an instance of all relevant layers""" for layer_name in self.datasets: layer = self.model.get_layer(layer_name) self.updateable_weights.append(layer.weights) @@ -132,8 +177,8 @@ def _update_weights(self): for w in ws: w.assign(w * multiplier) - def on_epoch_end(self, epoch, logs=None): - """ Function to be called at the end of every epoch """ + def on_step_end(self, epoch, logs=None): + """Function to be called at the end of every epoch""" if (epoch + 1) % self.update_freq == 0: self._update_weights()