From 09a5e9be29a8b320f0affa0a53c032d3f8d6f683 Mon Sep 17 00:00:00 2001 From: juacrumar Date: Mon, 30 Mar 2020 09:52:45 +0200 Subject: [PATCH 01/17] add a square custom activation function --- .../backends/keras_backend/base_layers.py | 30 +++++++++++++++++-- .../layers/{Rotation.py => rotations.py} | 0 2 files changed, 28 insertions(+), 2 deletions(-) rename n3fit/src/n3fit/layers/{Rotation.py => rotations.py} (100%) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index cfbcf4aa06..06d041d20d 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -1,18 +1,41 @@ """ - For a layer to be used by n3fit it should be contained in the layers dictionary below + This module defines custom base layers to be used by the n3fit + Neural Network. + These layers can use the keras standard set of activation function + or implement their own. + + For a layer to be used by n3fit it should be contained in the `layers` dictionary defined below. This dictionary has the following structure: - 'name of the layer' : ( Layer_class, {dictionary of arguments: defaults} ) + 'name of the layer' : ( Layer_class, {dictionary of arguments: defaults} ) + + In order to add custom activation functions, they must be added to + the `custom_activations` dictionary with the following structure: + + 'name of the activation' : function + + The names of the layer and the activation function are the ones to be used in the n3fit runcard. """ from tensorflow.keras.layers import Dense, Lambda, LSTM, Dropout, Concatenate, concatenate from tensorflow.keras.layers import Dense as KerasDense from tensorflow import expand_dims +<<<<<<< HEAD from tensorflow.keras.regularizers import l1_l2 +======= +>>>>>>> 38e1ffdc... add a square custom activation function from n3fit.backends import MetaLayer +# Custom activation functions +def square_activation(x): + """ Squares the input """ + return x*x + +custom_activations = { + "square" : square_activation + } def LSTM_modified(**kwargs): """ @@ -143,6 +166,9 @@ def base_layer_selector(layer_name, **kwargs): layer_args = layer_tuple[1] for key, value in kwargs.items(): + # Check whether the activation function is a custom one + if key == "activation": + value = custom_activations.get(value, value) if key in layer_args.keys(): layer_args[key] = value diff --git a/n3fit/src/n3fit/layers/Rotation.py b/n3fit/src/n3fit/layers/rotations.py similarity index 100% rename from n3fit/src/n3fit/layers/Rotation.py rename to n3fit/src/n3fit/layers/rotations.py From 66c1ee4e9c31690856914459d2ca0aa8de30b52d Mon Sep 17 00:00:00 2001 From: juacrumar Date: Mon, 30 Mar 2020 10:00:13 +0200 Subject: [PATCH 02/17] add flavour basis --- n3fit/src/n3fit/layers/__init__.py | 2 +- n3fit/src/n3fit/layers/rotations.py | 36 +++++++++++++++++++++++++++++ n3fit/src/n3fit/model_gen.py | 24 ++++++++++++++----- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/layers/__init__.py b/n3fit/src/n3fit/layers/__init__.py index a07d7e1611..3615bc39f8 100644 --- a/n3fit/src/n3fit/layers/__init__.py +++ b/n3fit/src/n3fit/layers/__init__.py @@ -1,5 +1,5 @@ from n3fit.layers.Preprocessing import Preprocessing -from n3fit.layers.Rotation import Rotation +from n3fit.layers.rotations import Rotation, FlavourToEvolution from n3fit.layers.x_operations import xIntegrator, xDivide, xMultiply from n3fit.layers.MSR_Normalization import MSR_Normalization from n3fit.layers.DIS import DIS diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index caf1e05833..97462c698c 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -1,5 +1,41 @@ +""" + This module includes rotation layers +""" + from n3fit.backends import MetaLayer +class FlavourToEvolution(MetaLayer): + """ + Rotates from the evolution basis to + the evolution basis + """ + # TODO: add a custom __init__ that defines the rotation + + def call(self, x_raw): + # Let's decide that the input is + # u, ubar, d, dbar, s, sbar, c, g + # TODO: it needs to match + # + x_flav = self.transpose(x_raw) + u = x_flav[0] + ubar = x_flav[1] + d = x_flav[2] + dbar = x_flav[3] + s = x_flav[4] + sbar = x_flav[5] + c = x_flav[6] + g = x_flav[7] + cbar = c + sigma = u + ubar + d + dbar + s + sbar + c + cbar + v = u - ubar + d - dbar + s - sbar + c - cbar + v3 = u - ubar - d + dbar + v8 = u - ubar + d - dbar - 2*s + 2*sbar + t3 = u + ubar - d - dbar + t8 = u + ubar + d + dbar - 2*s - 2*sbar + pdf_evol = [sigma, g, v, v3, v8, t3, t8, c+cbar] + ret = self.concatenate(pdf_evol, target_shape=x_raw.shape) + return ret + class Rotation(MetaLayer): """ diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 7debae3aef..ace3a3a4ac 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -13,7 +13,7 @@ from n3fit.layers import DY from n3fit.layers import Mask from n3fit.layers import ObsRotation -from n3fit.layers import Preprocessing, Rotation +from n3fit.layers import Preprocessing, Rotation, FlavourToEvolution from n3fit.backends import operations from n3fit.backends import losses @@ -295,8 +295,12 @@ def pdfNN_layer_generator( out=14, seed=None, dropout=0.0, +<<<<<<< HEAD regularizer=None, regularizer_args=None, +======= + fitbasis=None, # TODO: maybe this can come directly in the basis object? otherwise it is necessary to pass this down from the runcard +>>>>>>> b239fb05... add flavour basis ): # pylint: disable=too-many-locals """ Generates the PDF model which takes as input a point in x (from 0 to 1) @@ -450,12 +454,20 @@ def dense_me(x): input_shape=(1,), name="pdf_prepro", flav_info=flav_info, seed=preproseed ) - # Apply preprocessing - def layer_fitbasis(x): - return operations.op_multiply([dense_me(x), layer_preproc(x)]) - # Evolution layer - layer_evln = Rotation(input_shape=(last_layer_nodes,), output_dim=out) + layer_evln = Rotation(input_shape=(pre,), output_dim=out) + + # Check what is the output basis of the NN and rotate to evolution basis + if fitbasis == "flavour": # TODO choose the name + basis_rotation = FlavourToEvolution() + else: + # otherwise, assume we are in the evolution basis when we come out of the NN + basis_rotation = lambda x: x + + # Apply preprocessing and basis + def layer_fitbasis(x): + ret = operations.op_multiply([dense_me(x), layer_preproc(x)]) + return basis_rotation(ret) # Rotation layer, changes from the 8-basis to the 14-basis def layer_pdf(x): From 0b04232470a56fdaa7a428182f84ddbcb6ac6bd5 Mon Sep 17 00:00:00 2001 From: juacrumar Date: Wed, 1 Apr 2020 17:59:05 +0200 Subject: [PATCH 03/17] fix rebase --- 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 ace3a3a4ac..1be07280ad 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -455,7 +455,7 @@ def dense_me(x): ) # Evolution layer - layer_evln = Rotation(input_shape=(pre,), output_dim=out) + layer_evln = Rotation(input_shape=(last_layer_nodes,), output_dim=out) # Check what is the output basis of the NN and rotate to evolution basis if fitbasis == "flavour": # TODO choose the name From 26b8b9eccb8e0279d72608d541e766a1079ff98a Mon Sep 17 00:00:00 2001 From: tgiani Date: Mon, 6 Apr 2020 17:07:10 +0100 Subject: [PATCH 04/17] adding init and moving rotation to pdfbasis --- n3fit/src/n3fit/layers/rotations.py | 40 +++++++++++++--------------- n3fit/src/n3fit/model_gen.py | 14 +++------- validphys2/src/validphys/pdfbases.py | 21 +++++++++++++++ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index 97462c698c..599e6cb183 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -3,36 +3,34 @@ """ from n3fit.backends import MetaLayer +from validphys.pdfbases import flavtoev class FlavourToEvolution(MetaLayer): """ - Rotates from the evolution basis to - the evolution basis + Rotates from the flavour basis to + the evolution basis. """ - # TODO: add a custom __init__ that defines the rotation - + def __init__( + self, + flav_info=None, + **kwargs, + ): + if flav_info is None: + flav_info = [] + self.flav_info = flav_info + super().__init__(**kwargs) + def call(self, x_raw): # Let's decide that the input is # u, ubar, d, dbar, s, sbar, c, g # TODO: it needs to match - # + x_flav = self.transpose(x_raw) - u = x_flav[0] - ubar = x_flav[1] - d = x_flav[2] - dbar = x_flav[3] - s = x_flav[4] - sbar = x_flav[5] - c = x_flav[6] - g = x_flav[7] - cbar = c - sigma = u + ubar + d + dbar + s + sbar + c + cbar - v = u - ubar + d - dbar + s - sbar + c - cbar - v3 = u - ubar - d + dbar - v8 = u - ubar + d - dbar - 2*s + 2*sbar - t3 = u + ubar - d - dbar - t8 = u + ubar + d + dbar - 2*s - 2*sbar - pdf_evol = [sigma, g, v, v3, v8, t3, t8, c+cbar] + #check the fit basis looking at the first flavour in the basis dictionary of the runcard + if(self.flav_info[0]['fl'] == 'u'): + pdf_evol = flavtoev(x_flav) + else: + pdf_evol = x_flav ret = self.concatenate(pdf_evol, target_shape=x_raw.shape) return ret diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 1be07280ad..2e176093d6 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -295,12 +295,8 @@ def pdfNN_layer_generator( out=14, seed=None, dropout=0.0, -<<<<<<< HEAD regularizer=None, regularizer_args=None, -======= - fitbasis=None, # TODO: maybe this can come directly in the basis object? otherwise it is necessary to pass this down from the runcard ->>>>>>> b239fb05... add flavour basis ): # pylint: disable=too-many-locals """ Generates the PDF model which takes as input a point in x (from 0 to 1) @@ -457,13 +453,9 @@ def dense_me(x): # Evolution layer layer_evln = Rotation(input_shape=(last_layer_nodes,), output_dim=out) - # Check what is the output basis of the NN and rotate to evolution basis - if fitbasis == "flavour": # TODO choose the name - basis_rotation = FlavourToEvolution() - else: - # otherwise, assume we are in the evolution basis when we come out of the NN - basis_rotation = lambda x: x - + # Basis rotation + basis_rotation = FlavourToEvolution(flav_info=flav_info) + # Apply preprocessing and basis def layer_fitbasis(x): ret = operations.op_multiply([dense_me(x), layer_preproc(x)]) diff --git a/validphys2/src/validphys/pdfbases.py b/validphys2/src/validphys/pdfbases.py index 6131b6fe25..dcd9fcafed 100644 --- a/validphys2/src/validphys/pdfbases.py +++ b/validphys2/src/validphys/pdfbases.py @@ -394,3 +394,24 @@ def from_mapping(cls, mapping, *, aliases=None, default_elements=None): r'\bar{d}': {'dbar':1}, 'c': {'c':1}, }) + + +def flavtoev(x_flav): + """Rotates from the flavour to the evolution basis""" + u = x_flav[0] + ubar = x_flav[1] + d = x_flav[2] + dbar = x_flav[3] + s = x_flav[4] + sbar = x_flav[5] + c = x_flav[6] + g = x_flav[7] + cbar = c + sigma = u + ubar + d + dbar + s + sbar + c + cbar + v = u - ubar + d - dbar + s - sbar + c - cbar + v3 = u - ubar - d + dbar + v8 = u - ubar + d - dbar - 2*s + 2*sbar + t3 = u + ubar - d - dbar + t8 = u + ubar + d + dbar - 2*s - 2*sbar + pdf_evol = [sigma, g, v, v3, v8, t3, t8, c+cbar] + return pdf_evol From 06c3a948bb825719a4d70bfcdb4352bced5bebbb Mon Sep 17 00:00:00 2001 From: tgiani Date: Tue, 7 Apr 2020 16:51:00 +0100 Subject: [PATCH 05/17] implementation of rotation function in pdfbases --- .../n3fit/backends/keras_backend/MetaLayer.py | 3 ++ n3fit/src/n3fit/layers/rotations.py | 28 ++++------ validphys2/src/validphys/pdfbases.py | 54 +++++++++++++------ 3 files changed, 51 insertions(+), 34 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py b/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py index 156d22a87b..059fb933b1 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py @@ -191,3 +191,6 @@ def permute_dimensions(self, tensor, permutation, **kwargs): does the permutation: axis_0 -> axis_1, axis_1 -> axis_0, axis_2 -> axis_2 """ return K.permute_dimensions(tensor, permutation, **kwargs) + + def reshape(self, tensor, target_shape): + return tf.reshape(tensor, target_shape) \ No newline at end of file diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index 599e6cb183..44779833b6 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -1,38 +1,28 @@ """ This module includes rotation layers """ - from n3fit.backends import MetaLayer -from validphys.pdfbases import flavtoev +from validphys.pdfbases import rotation class FlavourToEvolution(MetaLayer): """ Rotates from the flavour basis to - the evolution basis. + the evolution basis. """ def __init__( self, - flav_info=None, + flav_info, **kwargs, ): - if flav_info is None: - flav_info = [] - self.flav_info = flav_info + rotation_matrix = rotation(flav_info) + self.rotation_matrix = self.np_to_tensor(rotation_matrix) super().__init__(**kwargs) - def call(self, x_raw): - # Let's decide that the input is - # u, ubar, d, dbar, s, sbar, c, g - # TODO: it needs to match - + def call(self, x_raw): x_flav = self.transpose(x_raw) - #check the fit basis looking at the first flavour in the basis dictionary of the runcard - if(self.flav_info[0]['fl'] == 'u'): - pdf_evol = flavtoev(x_flav) - else: - pdf_evol = x_flav - ret = self.concatenate(pdf_evol, target_shape=x_raw.shape) - return ret + pdf_evol = self.tensor_product(self.rotation_matrix, x_flav, 1) + return self.reshape(pdf_evol, x_raw.shape) + class Rotation(MetaLayer): diff --git a/validphys2/src/validphys/pdfbases.py b/validphys2/src/validphys/pdfbases.py index dcd9fcafed..a049e74b83 100644 --- a/validphys2/src/validphys/pdfbases.py +++ b/validphys2/src/validphys/pdfbases.py @@ -396,22 +396,46 @@ def from_mapping(cls, mapping, *, aliases=None, default_elements=None): }) -def flavtoev(x_flav): - """Rotates from the flavour to the evolution basis""" - u = x_flav[0] - ubar = x_flav[1] - d = x_flav[2] - dbar = x_flav[3] - s = x_flav[4] - sbar = x_flav[5] - c = x_flav[6] - g = x_flav[7] - cbar = c - sigma = u + ubar + d + dbar + s + sbar + c + cbar - v = u - ubar + d - dbar + s - sbar + c - cbar +def rotation(flav_info): + """Returnd a rotation matrix which takes from the flavour to the evolution basis, + from (u, ubar, d, dbar, s, sbar, c, g) to (sigma, g, v, v3, v8, t3, t8, cp) + with + cp = c + cbar = 2c + and + sigma = u + ubar + d + dbar + s + sbar + cp + v = u - ubar + d - dbar + s - sbar + c - cbar v3 = u - ubar - d + dbar v8 = u - ubar + d - dbar - 2*s + 2*sbar t3 = u + ubar - d - dbar t8 = u + ubar + d + dbar - 2*s - 2*sbar - pdf_evol = [sigma, g, v, v3, v8, t3, t8, c+cbar] - return pdf_evol + + If the input is already in the evolution basis it returns the identity. + """ + sigma = {'u': 1, 'ubar': 1, 'd': 1, 'dbar': 1, 's': 1, 'sbar': 1, 'c': 2, 'g': 0 } + v = {'u': 1, 'ubar': -1, 'd': 1, 'dbar': -1, 's': 1, 'sbar': -1, 'c': 0, 'g': 0 } + v3 = {'u': 1, 'ubar': -1, 'd': -1, 'dbar': 1, 's': 0, 'sbar': 0, 'c': 0, 'g': 0 } + v8 = {'u': 1, 'ubar': -1, 'd': 1, 'dbar': -1, 's': -2, 'sbar': 2, 'c': 0, 'g': 0 } + t3 = {'u': 1, 'ubar': 1, 'd': -1, 'dbar': -1, 's': 0, 'sbar': 0, 'c': 0, 'g': 0 } + t8 = {'u': 1, 'ubar': 1, 'd': 1, 'dbar': 1, 's': -2, 'sbar': -2, 'c': 0, 'g': 0 } + cp = {'u': 0, 'ubar': 0, 'd': 0, 'dbar': 0, 's': 0, 'sbar': 0, 'c': 2, 'g': 0 } + g = {'u': 0, 'ubar': 0, 'd': 0, 'dbar': 0, 's': 0, 'sbar': 0, 'c': 0, 'g': 1 } + flist = [sigma, g, v, v3, v8, t3, t8, cp] + + evol_basis = False + mat = [] + for f in flist: + for flav_dict in flav_info: + try: + flav_name = flav_dict["fl"] + mat.append(f[flav_name]) + # if one of the keys in the dictionary is not a key in flist + # it means we are already in the evolution basis + except KeyError: + evol_basis = True + break + if evol_basis: + mat = np.identity(8) + break + + mat = np.asarray(mat) + return mat.reshape(8,8) From 1ec4b668f7e674aeec5eabbb7db46caa6c297995 Mon Sep 17 00:00:00 2001 From: tgiani Date: Tue, 7 Apr 2020 17:21:13 +0100 Subject: [PATCH 06/17] removing reshape of the output --- n3fit/src/n3fit/backends/keras_backend/MetaLayer.py | 3 +-- n3fit/src/n3fit/layers/rotations.py | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py b/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py index 059fb933b1..a91fd761d8 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaLayer.py @@ -192,5 +192,4 @@ def permute_dimensions(self, tensor, permutation, **kwargs): """ return K.permute_dimensions(tensor, permutation, **kwargs) - def reshape(self, tensor, target_shape): - return tf.reshape(tensor, target_shape) \ No newline at end of file + \ No newline at end of file diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index 44779833b6..f4a9fe19b9 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -18,13 +18,10 @@ def __init__( self.rotation_matrix = self.np_to_tensor(rotation_matrix) super().__init__(**kwargs) - def call(self, x_raw): - x_flav = self.transpose(x_raw) - pdf_evol = self.tensor_product(self.rotation_matrix, x_flav, 1) - return self.reshape(pdf_evol, x_raw.shape) + def call(self, x_raw): + return self.tensor_product(x_raw, self.rotation_matrix, 1) - class Rotation(MetaLayer): """ Applies a transformation from the dimension-8 fit basis From 5700ef4430dcc1a854a5f300c74a273c6ddad854 Mon Sep 17 00:00:00 2001 From: tgiani Date: Wed, 29 Apr 2020 09:47:53 +0100 Subject: [PATCH 07/17] small fix --- n3fit/src/n3fit/backends/keras_backend/base_layers.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/base_layers.py b/n3fit/src/n3fit/backends/keras_backend/base_layers.py index 06d041d20d..0c6b977962 100644 --- a/n3fit/src/n3fit/backends/keras_backend/base_layers.py +++ b/n3fit/src/n3fit/backends/keras_backend/base_layers.py @@ -20,12 +20,9 @@ from tensorflow.keras.layers import Dense, Lambda, LSTM, Dropout, Concatenate, concatenate from tensorflow.keras.layers import Dense as KerasDense from tensorflow import expand_dims -<<<<<<< HEAD from tensorflow.keras.regularizers import l1_l2 -======= ->>>>>>> 38e1ffdc... add a square custom activation function from n3fit.backends import MetaLayer # Custom activation functions From 63f30d259b6c6d239693910835f86d19ca666a6a Mon Sep 17 00:00:00 2001 From: tgiani Date: Wed, 29 Apr 2020 18:18:29 +0100 Subject: [PATCH 08/17] fixing rotation and adding test --- n3fit/src/n3fit/layers/rotations.py | 3 ++- n3fit/src/n3fit/tests/test_layers.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index f4a9fe19b9..7223358375 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -19,7 +19,8 @@ def __init__( super().__init__(**kwargs) def call(self, x_raw): - return self.tensor_product(x_raw, self.rotation_matrix, 1) + rotation_matrix_T = self.transpose(self.rotation_matrix) + return self.tensor_product(x_raw, rotation_matrix_T, 1) class Rotation(MetaLayer): diff --git a/n3fit/src/n3fit/tests/test_layers.py b/n3fit/src/n3fit/tests/test_layers.py index 4b6c03d8ec..73513e80d1 100644 --- a/n3fit/src/n3fit/tests/test_layers.py +++ b/n3fit/src/n3fit/tests/test_layers.py @@ -6,6 +6,8 @@ import numpy as np from n3fit.backends import operations as op import n3fit.layers as layers +from validphys.pdfbases import rotation + FLAVS = 3 XSIZE = 4 @@ -144,3 +146,27 @@ def test_DY(): lumi_masked = lumi_perm[mask] reference = np.tensordot(fk, lumi_masked, axes=3) assert np.allclose(result, reference, THRESHOLD) + + +def test_rotation(): + # Input dictionary to build the rotation matrix using vp2 functions + flav_info = [ + {'fl':'u'}, + {'fl':'ubar'}, + {'fl':'d'}, + {'fl':'dbar'}, + {'fl':'s'}, + {'fl':'sbar'}, + {'fl':'c'}, + {'fl':'g'}, +] + # Apply the rotation to a numpy vector + x = np.ones(8) + mat = rotation(flav_info) + res_np = np.dot(mat,x) + + # Apply the rotation through the rotation layer + x = op.numpy_to_tensor(x) + rotmat = layers.FlavourToEvolution(flav_info) + res_layer = rotmat(x) + assert np.alltrue(res_np==res_layer) \ No newline at end of file From b71da145411e692eb7bf0675159cab701195bd2d Mon Sep 17 00:00:00 2001 From: tgiani Date: Thu, 30 Apr 2020 09:10:09 +0100 Subject: [PATCH 09/17] avoid transposition in call function --- n3fit/src/n3fit/layers/rotations.py | 3 +-- n3fit/src/n3fit/tests/test_layers.py | 8 ++++---- validphys2/src/validphys/pdfbases.py | 12 +++++++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/n3fit/src/n3fit/layers/rotations.py b/n3fit/src/n3fit/layers/rotations.py index 7223358375..f4a9fe19b9 100644 --- a/n3fit/src/n3fit/layers/rotations.py +++ b/n3fit/src/n3fit/layers/rotations.py @@ -19,8 +19,7 @@ def __init__( super().__init__(**kwargs) def call(self, x_raw): - rotation_matrix_T = self.transpose(self.rotation_matrix) - return self.tensor_product(x_raw, rotation_matrix_T, 1) + return self.tensor_product(x_raw, self.rotation_matrix, 1) class Rotation(MetaLayer): diff --git a/n3fit/src/n3fit/tests/test_layers.py b/n3fit/src/n3fit/tests/test_layers.py index 73513e80d1..7ad17dbd50 100644 --- a/n3fit/src/n3fit/tests/test_layers.py +++ b/n3fit/src/n3fit/tests/test_layers.py @@ -160,10 +160,10 @@ def test_rotation(): {'fl':'c'}, {'fl':'g'}, ] - # Apply the rotation to a numpy vector - x = np.ones(8) - mat = rotation(flav_info) - res_np = np.dot(mat,x) + # Apply the rotation using numpy tensordot + x = np.ones(8) # Vector in the flavour basis v_i + mat = rotation(flav_info) # Rotation matrix R_ij, i=flavour, j=evolution + res_np = np.tensordot(mat,x,(0,0)) # Vector in the evolution basis u_j=R_ij*vi # Apply the rotation through the rotation layer x = op.numpy_to_tensor(x) diff --git a/validphys2/src/validphys/pdfbases.py b/validphys2/src/validphys/pdfbases.py index a049e74b83..6067befc10 100644 --- a/validphys2/src/validphys/pdfbases.py +++ b/validphys2/src/validphys/pdfbases.py @@ -397,9 +397,10 @@ def from_mapping(cls, mapping, *, aliases=None, default_elements=None): def rotation(flav_info): - """Returnd a rotation matrix which takes from the flavour to the evolution basis, - from (u, ubar, d, dbar, s, sbar, c, g) to (sigma, g, v, v3, v8, t3, t8, cp) - with + """Return a rotation matrix R_{ij} which takes from the flavour to the evolution basis, + from (u, ubar, d, dbar, s, sbar, c, g) to (sigma, g, v, v3, v8, t3, t8, cp), where + i is the flavour index and j is the evolution index. + The evolution basis is defined as cp = c + cbar = 2c and sigma = u + ubar + d + dbar + s + sbar + cp @@ -437,5 +438,6 @@ def rotation(flav_info): mat = np.identity(8) break - mat = np.asarray(mat) - return mat.reshape(8,8) + mat = np.asarray(mat).reshape(8,8) + # Return the transpose of the matrix, to have the first index referring to flavour + return mat.transpose() From 15042292d765b5d8724a2c296215d08099598ceb Mon Sep 17 00:00:00 2001 From: tgiani Date: Thu, 30 Apr 2020 09:25:45 +0100 Subject: [PATCH 10/17] fixing sumrule flag to run a fit without sumrules --- n3fit/src/n3fit/ModelTrainer.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/ModelTrainer.py b/n3fit/src/n3fit/ModelTrainer.py index ddaa165015..90264be0de 100644 --- a/n3fit/src/n3fit/ModelTrainer.py +++ b/n3fit/src/n3fit/ModelTrainer.py @@ -12,7 +12,7 @@ import numpy as np import n3fit.model_gen as model_gen import n3fit.msr as msr_constraints -from n3fit.backends import MetaModel, clear_backend_state +from n3fit.backends import MetaModel, clear_backend_state, operations from n3fit.stopping import Stopping log = logging.getLogger(__name__) @@ -465,15 +465,18 @@ def _generate_pdf( regularizer_args=regularizer_args ) - integrator_input = None if self.impose_sumrule: # Impose the sumrule # Inyect here momentum sum rule, effecively modifying layer_pdf layer_pdf, integrator_input = msr_constraints.msr_impose( layers["fitbasis"], layer_pdf ) - self.input_list.append(integrator_input) + else: + nx = int(2e3) + xgrid, dum = msr_constraints.gen_integration_input(nx) + integrator_input = operations.numpy_to_input(xgrid) + self.input_list.append(integrator_input) self.layer_pdf = layer_pdf return layers, integrator_input From 537499c4bc08b1ca2a99b0299c9a8ca7600cee1e Mon Sep 17 00:00:00 2001 From: tgiani Date: Thu, 30 Apr 2020 10:23:25 +0100 Subject: [PATCH 11/17] adding check on basis labels --- n3fit/src/n3fit/performfit.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/n3fit/src/n3fit/performfit.py b/n3fit/src/n3fit/performfit.py index c155966807..0ae115691f 100644 --- a/n3fit/src/n3fit/performfit.py +++ b/n3fit/src/n3fit/performfit.py @@ -81,9 +81,21 @@ def check_consistent_hyperscan_options(hyperopt, hyperscan, fitting): if hyperopt is not None and fitting["genrep"]: raise CheckError("During hyperoptimization we cannot generate replicas (genrep=false)") +@make_argcheck +def check_consistent_basis(fitting): + allowed_labels = [ + 'u','ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g', + 'sng', 'v', 'v3', 'v8', 't3', 't8', 'cp' + ] + for flav_dict in fitting['basis']: + flav_name = flav_dict['fl'] + if flav_name not in allowed_labels: + raise CheckError(f"{flav_name} is not a valid flavour name") + # Action to be called by valid phys # All information defining the NN should come here in the "parameters" dict @check_consistent_hyperscan_options +@check_consistent_basis def performfit( fitting, experiments, From 7822e556dd77cde4312dec897fcd536542e283ba Mon Sep 17 00:00:00 2001 From: tgiani Date: Fri, 1 May 2020 19:52:08 +0100 Subject: [PATCH 12/17] small change to test and fix for n3fit speed issue --- n3fit/src/n3fit/backends/keras_backend/MetaModel.py | 4 ++-- n3fit/src/n3fit/tests/test_layers.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py index b61dd12d08..07855a5697 100644 --- a/n3fit/src/n3fit/backends/keras_backend/MetaModel.py +++ b/n3fit/src/n3fit/backends/keras_backend/MetaModel.py @@ -239,8 +239,8 @@ def compile( if target_output is not None: if not isinstance(target_output, list): target_output = [target_output] - self.target_tensors = target_output - super(MetaModel, self).compile(optimizer=opt, loss=loss) + self.target_tensors = None # TODO TF 2.2 target_output + super(MetaModel, self).compile(optimizer=opt, target_tensors=target_output, loss=loss) def set_masks_to(self, names, val=0.0): """ Set all mask value to the selected value diff --git a/n3fit/src/n3fit/tests/test_layers.py b/n3fit/src/n3fit/tests/test_layers.py index 7ad17dbd50..e19e77366f 100644 --- a/n3fit/src/n3fit/tests/test_layers.py +++ b/n3fit/src/n3fit/tests/test_layers.py @@ -162,11 +162,13 @@ def test_rotation(): ] # Apply the rotation using numpy tensordot x = np.ones(8) # Vector in the flavour basis v_i + x = np.expand_dims(x,axis=[0,1]) # Give to the input the shape (1,1,8) mat = rotation(flav_info) # Rotation matrix R_ij, i=flavour, j=evolution - res_np = np.tensordot(mat,x,(0,0)) # Vector in the evolution basis u_j=R_ij*vi + res_np = np.tensordot(x,mat,(2,0)) # Vector in the evolution basis u_j=R_ij*vi # Apply the rotation through the rotation layer x = op.numpy_to_tensor(x) rotmat = layers.FlavourToEvolution(flav_info) res_layer = rotmat(x) - assert np.alltrue(res_np==res_layer) \ No newline at end of file + assert np.alltrue(res_np==res_layer) + \ No newline at end of file From 863aff1402f17c8c27328934521ae51c7e8eab4e Mon Sep 17 00:00:00 2001 From: tgiani Date: Tue, 5 May 2020 14:49:11 +0100 Subject: [PATCH 13/17] check on basis dictionary entries --- n3fit/src/n3fit/performfit.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/performfit.py b/n3fit/src/n3fit/performfit.py index 0ae115691f..b4c84f0418 100644 --- a/n3fit/src/n3fit/performfit.py +++ b/n3fit/src/n3fit/performfit.py @@ -83,14 +83,29 @@ def check_consistent_hyperscan_options(hyperopt, hyperscan, fitting): @make_argcheck def check_consistent_basis(fitting): - allowed_labels = [ - 'u','ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g', + fitbasis = fitting["fitbasis"] + if fitbasis == 'flavour': + allowed_labels = [ + 'u','ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g' + ] + elif fitbasis == 'evolution': + allowed_labels = [ 'sng', 'v', 'v3', 'v8', 't3', 't8', 'cp' ] + else: + raise CheckError(f"{fitbasis} is not a valid fitbasis") + + # Check that there are no duplicate flavours + flavs = [d['fl'] for d in fitting['basis']] + if len(set(flavs)) != len(flavs): + raise CheckError(f"Repeated flavour names: check basis dictionary") + + # Check that the flavours given in the runcard correspond to the + # allowed distribution of the declared fitbasis for flav_dict in fitting['basis']: flav_name = flav_dict['fl'] if flav_name not in allowed_labels: - raise CheckError(f"{flav_name} is not a valid flavour name") + raise CheckError(f"{flav_name} is not a valid flavour name of {fitbasis} basis") # Action to be called by valid phys # All information defining the NN should come here in the "parameters" dict From a844e1b5750d29442b1f934540a4c39d3f9b409c Mon Sep 17 00:00:00 2001 From: tgiani Date: Mon, 11 May 2020 14:13:23 +0100 Subject: [PATCH 14/17] fixing tests after merging --- n3fit/src/n3fit/layers/Rotations.py | 4 ++-- n3fit/src/n3fit/layers/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/n3fit/src/n3fit/layers/Rotations.py b/n3fit/src/n3fit/layers/Rotations.py index 57e80ca7bd..45b2afe5ab 100644 --- a/n3fit/src/n3fit/layers/Rotations.py +++ b/n3fit/src/n3fit/layers/Rotations.py @@ -17,11 +17,11 @@ def __init__( **kwargs, ): rotation_matrix = rotation(flav_info) - self.rotation_matrix = self.np_to_tensor(rotation_matrix) + self.rotation_matrix = op.numpy_to_tensor(rotation_matrix) super().__init__(**kwargs) def call(self, x_raw): - return self.tensor_product(x_raw, self.rotation_matrix, 1) + return op.tensor_product(x_raw, self.rotation_matrix, 1) class Rotation(MetaLayer): diff --git a/n3fit/src/n3fit/layers/__init__.py b/n3fit/src/n3fit/layers/__init__.py index f9c29d2a53..e618690431 100644 --- a/n3fit/src/n3fit/layers/__init__.py +++ b/n3fit/src/n3fit/layers/__init__.py @@ -1,5 +1,5 @@ from n3fit.layers.Preprocessing import Preprocessing -from n3fit.layers.rotations import Rotation, FlavourToEvolution +from n3fit.layers.Rotations import Rotation, FlavourToEvolution from n3fit.layers.x_operations import xIntegrator, xDivide from n3fit.layers.MSR_Normalization import MSR_Normalization from n3fit.layers.DIS import DIS From 451cb795e4a1a376ac9ba03184ceb80126d96518 Mon Sep 17 00:00:00 2001 From: tgiani Date: Mon, 11 May 2020 15:13:44 +0100 Subject: [PATCH 15/17] small modification of test on basis entries to avoid breaking test --- n3fit/src/n3fit/performfit.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/n3fit/src/n3fit/performfit.py b/n3fit/src/n3fit/performfit.py index 3ae2f0d10d..36063692eb 100644 --- a/n3fit/src/n3fit/performfit.py +++ b/n3fit/src/n3fit/performfit.py @@ -88,12 +88,10 @@ def check_consistent_basis(fitting): allowed_labels = [ 'u','ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g' ] - elif fitbasis == 'evolution': + else: allowed_labels = [ - 'sng', 'v', 'v3', 'v8', 't3', 't8', 'cp' + 'sng', 'g', 'v', 'v3', 'v8', 't3', 't8', 'cp' ] - else: - raise CheckError(f"{fitbasis} is not a valid fitbasis") # Check that there are no duplicate flavours flavs = [d['fl'] for d in fitting['basis']] From f78b973da08fbfdfb2991c6d667400cfb311dc0b Mon Sep 17 00:00:00 2001 From: juacrumar Date: Tue, 12 May 2020 10:02:50 +0200 Subject: [PATCH 16/17] Rotation -> FkRotation, created a Rotation layer to inherit from --- n3fit/src/n3fit/layers/Rotations.py | 51 ++++++++++++++++++++-------- n3fit/src/n3fit/layers/__init__.py | 2 +- n3fit/src/n3fit/model_gen.py | 4 +-- n3fit/src/n3fit/tests/test_layers.py | 31 ++++++++--------- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/n3fit/src/n3fit/layers/Rotations.py b/n3fit/src/n3fit/layers/Rotations.py index 45b2afe5ab..82e5105a2e 100644 --- a/n3fit/src/n3fit/layers/Rotations.py +++ b/n3fit/src/n3fit/layers/Rotations.py @@ -3,28 +3,47 @@ """ from n3fit.backends import MetaLayer from n3fit.backends import operations as op -from validphys.pdfbases import rotation +from validphys import pdfbases -class FlavourToEvolution(MetaLayer): - """ +class Rotation(MetaLayer): + """ + Rotates the input through some user defined rotation matrix. + Given an input matrix M_{m,n} with an input x_{m}, returns + y_{n} = x_{m}M_{m,n} + + Parameters + ---------- + rotation_matrix: np.array + rotation matrix + axes: int or list + if given a number, contracts as many indices as given + if given a list (of tuples) contracts indices according to op.tensor_product + """ + + def __init__(self, rotation_matrix, axes=1, **kwargs): + self.rotation_matrix = op.numpy_to_tensor(rotation_matrix) + self.axes = axes + super().__init__(**kwargs) + + def call(self, x_raw): + return op.tensor_product(x_raw, self.rotation_matrix, self.axes) + + +class FlavourToEvolution(Rotation): + """ Rotates from the flavour basis to - the evolution basis. + the evolution basis. """ + def __init__( - self, - flav_info, - **kwargs, + self, flav_info, **kwargs, ): - rotation_matrix = rotation(flav_info) - self.rotation_matrix = op.numpy_to_tensor(rotation_matrix) - super().__init__(**kwargs) - - def call(self, x_raw): - return op.tensor_product(x_raw, self.rotation_matrix, 1) - + rotation_matrix = pdfbases.rotation(flav_info) + super().__init__(rotation_matrix, axes=1, **kwargs) -class Rotation(MetaLayer): + +class FkRotation(MetaLayer): """ Applies a transformation from the dimension-8 evolution basis to the dimension-14 evolution basis used by the fktables. @@ -32,8 +51,10 @@ class Rotation(MetaLayer): The input to this layer is a `pdf_raw` variable which is expected to have a shape (1, None, 8), and it is then rotated to an output (1, None, 14) """ + # TODO: Generate a rotation matrix in the input and just do tf.tensordot in call # the matrix should be: (8, 14) so that we can just do tf.tensordot(pdf, rotmat, axes=1) + # i.e., create the matrix and inherit from the Rotation layer above def __init__(self, output_dim=14, **kwargs): self.output_dim = output_dim super().__init__(**kwargs, name="evolution") diff --git a/n3fit/src/n3fit/layers/__init__.py b/n3fit/src/n3fit/layers/__init__.py index e618690431..5fae6c64c1 100644 --- a/n3fit/src/n3fit/layers/__init__.py +++ b/n3fit/src/n3fit/layers/__init__.py @@ -1,5 +1,5 @@ from n3fit.layers.Preprocessing import Preprocessing -from n3fit.layers.Rotations import Rotation, FlavourToEvolution +from n3fit.layers.Rotations import FkRotation, FlavourToEvolution from n3fit.layers.x_operations import xIntegrator, xDivide from n3fit.layers.MSR_Normalization import MSR_Normalization from n3fit.layers.DIS import DIS diff --git a/n3fit/src/n3fit/model_gen.py b/n3fit/src/n3fit/model_gen.py index 249f9f6fe6..04fe443129 100644 --- a/n3fit/src/n3fit/model_gen.py +++ b/n3fit/src/n3fit/model_gen.py @@ -13,7 +13,7 @@ from n3fit.layers import DY from n3fit.layers import Mask from n3fit.layers import ObsRotation -from n3fit.layers import Preprocessing, Rotation, FlavourToEvolution +from n3fit.layers import Preprocessing, FkRotation, FlavourToEvolution from n3fit.backends import operations from n3fit.backends import losses @@ -461,7 +461,7 @@ def dense_me(x): ) # Evolution layer - layer_evln = Rotation(input_shape=(last_layer_nodes,), output_dim=out) + layer_evln = FkRotation(input_shape=(last_layer_nodes,), output_dim=out) # Basis rotation basis_rotation = FlavourToEvolution(flav_info=flav_info) diff --git a/n3fit/src/n3fit/tests/test_layers.py b/n3fit/src/n3fit/tests/test_layers.py index 5546e1f525..f9b953dfa2 100644 --- a/n3fit/src/n3fit/tests/test_layers.py +++ b/n3fit/src/n3fit/tests/test_layers.py @@ -151,24 +151,23 @@ def test_DY(): def test_rotation(): # Input dictionary to build the rotation matrix using vp2 functions flav_info = [ - {'fl':'u'}, - {'fl':'ubar'}, - {'fl':'d'}, - {'fl':'dbar'}, - {'fl':'s'}, - {'fl':'sbar'}, - {'fl':'c'}, - {'fl':'g'}, -] + {"fl": "u"}, + {"fl": "ubar"}, + {"fl": "d"}, + {"fl": "dbar"}, + {"fl": "s"}, + {"fl": "sbar"}, + {"fl": "c"}, + {"fl": "g"}, + ] # Apply the rotation using numpy tensordot - x = np.ones(8) # Vector in the flavour basis v_i - x = np.expand_dims(x,axis=[0,1]) # Give to the input the shape (1,1,8) - mat = rotation(flav_info) # Rotation matrix R_ij, i=flavour, j=evolution - res_np = np.tensordot(x,mat,(2,0)) # Vector in the evolution basis u_j=R_ij*vi - + x = np.ones(8) # Vector in the flavour basis v_i + x = np.expand_dims(x, axis=[0, 1]) # Give to the input the shape (1,1,8) + mat = rotation(flav_info) # Rotation matrix R_ij, i=flavour, j=evolution + res_np = np.tensordot(x, mat, (2, 0)) # Vector in the evolution basis u_j=R_ij*vi + # Apply the rotation through the rotation layer x = op.numpy_to_tensor(x) rotmat = layers.FlavourToEvolution(flav_info) res_layer = rotmat(x) - assert np.alltrue(res_np==res_layer) - \ No newline at end of file + assert np.alltrue(res_np == res_layer) From 4e8e80d9cf8917958ad45bb698b8d8e4203592b5 Mon Sep 17 00:00:00 2001 From: tgiani Date: Tue, 12 May 2020 10:39:02 +0100 Subject: [PATCH 17/17] use existing vp2 functionalities to check fitbasis --- n3fit/src/n3fit/performfit.py | 21 ++++----------------- validphys2/src/validphys/pdfbases.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/n3fit/src/n3fit/performfit.py b/n3fit/src/n3fit/performfit.py index 36063692eb..3511f795ba 100644 --- a/n3fit/src/n3fit/performfit.py +++ b/n3fit/src/n3fit/performfit.py @@ -4,6 +4,7 @@ # Backend-independent imports from collections import namedtuple +from validphys.pdfbases import check_basis import sys import logging import os.path @@ -84,27 +85,13 @@ def check_consistent_hyperscan_options(hyperopt, hyperscan, fitting): @make_argcheck def check_consistent_basis(fitting): fitbasis = fitting["fitbasis"] - if fitbasis == 'flavour': - allowed_labels = [ - 'u','ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g' - ] - else: - allowed_labels = [ - 'sng', 'g', 'v', 'v3', 'v8', 't3', 't8', 'cp' - ] - # Check that there are no duplicate flavours flavs = [d['fl'] for d in fitting['basis']] if len(set(flavs)) != len(flavs): raise CheckError(f"Repeated flavour names: check basis dictionary") - - # Check that the flavours given in the runcard correspond to the - # allowed distribution of the declared fitbasis - for flav_dict in fitting['basis']: - flav_name = flav_dict['fl'] - if flav_name not in allowed_labels: - raise CheckError(f"{flav_name} is not a valid flavour name of {fitbasis} basis") - + # Check that the basis given in the runcard is one of those defined in validphys.pdfbases + res = check_basis(fitbasis,flavs) + # Action to be called by valid phys # All information defining the NN should come here in the "parameters" dict @check_consistent_hyperscan_options diff --git a/validphys2/src/validphys/pdfbases.py b/validphys2/src/validphys/pdfbases.py index 7c5455504a..1b492def98 100644 --- a/validphys2/src/validphys/pdfbases.py +++ b/validphys2/src/validphys/pdfbases.py @@ -427,6 +427,19 @@ def from_mapping(cls, mapping, *, aliases=None, default_elements=None): 'v': 'V', 'v3': 'V3', 'v8': 'V8', 't3': 'T3', 't8': 'T8'}, default_elements=(r'\Sigma', 'gluon', 'V', 'V3', 'V8', 'T3', 'T8', r'c^+', )) +FLAVOUR = Basis.from_mapping( + { + 'u': {'u': 1}, + 'ubar': {'ubar': 1}, + 'd': {'d': 1}, + 'dbar': {'dbar': 1}, + 's': {'s': 1}, + 'sbar': {'sbar': 1}, + 'c': {'c': 1}, + 'g': {'g': 1}, + }, + default_elements=('u', 'ubar', 'd', 'dbar', 's', 'sbar', 'c', 'g', )) + pdg = Basis.from_mapping({ 'g/10': {'g':0.1}, 'u_{v}': {'u':1, 'ubar':-1},