Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include evolutionary-keras #737

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
36 changes: 36 additions & 0 deletions doc/sphinx/source/n3fit/backends.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Backend selection
=================

One of the advantages of ``n3fit`` is the possibility to select different backends
for training the neural network.

Currently implemented in ``n3fit`` we can find:

- [Keras-Tensorflow](#keras-tensorflow)
- [Evolutionary Algorithms](#evolutionary-algorithms)

Keras-Tensorflow
----------------
The main and default backend for ``n3fit`` is the [TensorFlow](https://www.tensorflow.org/)
library developed by Google.


Evolutionary Algorithms
-----------------------
As part of the validation process followed during the development of ``n3fit`` we developed the
[evolutionary-keras](https://evolutionary-keras.readthedocs.io) [[1](https://arxiv.org/abs/2002.06587)] library.

This library extends [Tensorflow](#keras-tensorflow) for its use with evolutionary algorithms such as the [NGA](https://evolutionary-keras.readthedocs.io/en/latest/optimizers.html#nodal-genetic-algorithm-nga)
used in previous versions of [NNPDF](http://arxiv.org/abs/1410.8849) or the [CMA-ES](https://evolutionary-keras.readthedocs.io/en/latest/optimizers.html#covariance-matrix-adaptation-evolution-strategy-cma-es) used in some [spin-off studies](https://arxiv.org/abs/1706.07049).

The evolutionary strategies can be used by adding the keyword ``backend: evolutionary_keras`` to the ``fitting`` section in the runcard.

```yaml
fitting:
backend: evolutionary_keras
optimizer:
optimizer_name: 'NGA'
sigma_init: 15
population_size: 80
mutation_rate: 0.05
```
1 change: 1 addition & 0 deletions doc/sphinx/source/n3fit/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ n3fit

introduction
methodology
backends
hyperopt
runcard_detailed
142 changes: 142 additions & 0 deletions n3fit/runcards/Basic_nga.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#
# Configuration file for n3fit
#

############################################################
description: Basic runcard

############################################################
# frac: training fraction
# ewk: apply ewk k-factors
# sys: systematics treatment (see systypes)
experiments:
- experiment: ALL
datasets:
- { dataset: SLACP, frac: 0.5}
- { dataset: NMCPD, frac: 0.5 }
- { dataset: CMSJETS11, frac: 0.5, sys: 10 }

############################################################
datacuts:
t0pdfset : NNPDF31_nlo_as_0118 # PDF set to generate t0 covmat
q2min : 3.49 # Q2 minimum
w2min : 12.5 # W2 minimum
combocuts : NNPDF31 # NNPDF3.0 final kin. cuts
jetptcut_tev : 0 # jet pt cut for tevatron
jetptcut_lhc : 0 # jet pt cut for lhc
wptcut_lhc : 30.0 # Minimum pT for W pT diff distributions
jetycut_tev : 1e30 # jet rap. cut for tevatron
jetycut_lhc : 1e30 # jet rap. cut for lhc
dymasscut_min: 0 # dy inv.mass. min cut
dymasscut_max: 1e30 # dy inv.mass. max cut
jetcfactcut : 1e30 # jet cfact. cut

############################################################
theory:
theoryid: 53 # database id

############################################################
fitting:
trvlseed: 1
nnseed: 2
mcseed: 3
epochs: 900
save: False
savefile: 'weights.hd5'
load: False
loadfile: 'weights.hd5'
plot: False

seed : 9453862133528 # set the seed for the random generator
genrep : True # on = generate MC replicas, off = use real data
rngalgo : 0 # 0 = ranlux, 1 = cmrg, see randomgenerator.cc

backend: 'evolutionary_keras'

parameters: # This defines the parameter dictionary that is passed to the Model Trainer
nodes_per_layer: [15, 10, 8]
activation_per_layer: ['sigmoid', 'sigmoid', 'linear']
initializer: 'glorot_normal'
optimizer:
optimizer_name: 'NGA'
sigma_init: 15
population_size: 80
mutation_rate: 0.05
epochs: 900
positivity:
multiplier: 1.05 # When any of the multiplier and/or the initial is not set
initial: # the poslambda will be used instead to compute these values per dataset
stopping_patience: 0.30 # percentage of the number of epochs
layer_type: 'dense'
dropout: 0.0
threshold_chi2: 5.0

# NN23(QED) = sng=0,g=1,v=2,t3=3,ds=4,sp=5,sm=6,(pht=7)
# EVOL(QED) = sng=0,g=1,v=2,v3=3,v8=4,t3=5,t8=6,(pht=7)
# EVOLS(QED)= sng=0,g=1,v=2,v8=4,t3=4,t8=5,ds=6,(pht=7)
# FLVR(QED) = g=0, u=1, ubar=2, d=3, dbar=4, s=5, sbar=6, (pht=7)
fitbasis: NN31IC # EVOL (7), EVOLQED (8), etc.
basis:
# remeber to change the name of PDF accordingly with fitbasis
# pos: True for NN squared
# mutsize: mutation size
# mutprob: mutation probability
# smallx, largex: preprocessing ranges
- { fl: sng, pos: False, mutsize: [15], mutprob: [0.05], smallx: [1.05,1.19], largex: [1.47,2.70], trainable: False }
- { fl: g, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.94,1.25], largex: [0.11,5.87], trainable: False }
- { fl: v, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.54,0.75], largex: [1.15,2.76], trainable: False }
- { fl: v3, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.21,0.57], largex: [1.35,3.08], trainable: False }
- { fl: v8, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.52,0.76], largex: [0.77,3.56], trainable: False }
- { fl: t3, pos: False, mutsize: [15], mutprob: [0.05], smallx: [-0.37,1.52], largex: [1.74,3.39], trainable: False }
- { fl: t8, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.56,1.29], largex: [1.45,3.03], trainable: False }
- { fl: cp, pos: False, mutsize: [15], mutprob: [0.05], smallx: [0.12,1.19], largex: [1.83,6.70], trainable: False }

############################################################
stopping:
stopmethod: LOOKBACK # Stopping method
lbdelta : 0 # Delta for look-back stopping
mingen : 0 # Minimum number of generations
window : 500 # Window for moving average
minchi2 : 3.5 # Minimum chi2
minchi2exp: 6.0 # Minimum chi2 for experiments
nsmear : 200 # Smear for stopping
deltasm : 200 # Delta smear for stopping
rv : 2 # Ratio for validation stopping
rt : 0.5 # Ratio for training stopping
epsilon : 1e-6 # Gradient epsilon

############################################################
positivity:
posdatasets:
- { dataset: POSF2U, poslambda: 1e6 } # Positivity Lagrange Multiplier
- { dataset: POSFLL, poslambda: 1e4 }

############################################################
integrability:
integdatasets:
- {dataset: INTEGXT3, poslambda: 1e2}

############################################################
closuretest:
filterseed : 0 # Random seed to be used in filtering data partitions
fakedata : False # on = to use FAKEPDF to generate pseudo-data
fakepdf : MSTW2008nlo68cl # Theory input for pseudo-data
errorsize : 1.0 # uncertainties rescaling
fakenoise : False # on = to add random fluctuations to pseudo-data
rancutprob : 1.0 # Fraction of data to be included in the fit
rancutmethod: 0 # Method to select rancutprob data fraction
rancuttrnval: False # 0(1) to output training(valiation) chi2 in report
printpdf4gen: False # To print info on PDFs during minimization

############################################################
lhagrid:
nx : 150
xmin: 1e-9
xmed: 0.1
xmax: 1.0
nq : 50
qmax: 1e5

############################################################
debug: true
maxcores: 8
5 changes: 5 additions & 0 deletions n3fit/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
'':['*.fitinfo', '*.yml'],
'tests/regressions': ['*'],
},
extras_require={
'ga' : [
'evolutionary-keras',
],
},

entry_points = {'console_scripts':
['n3fit = n3fit.scripts.n3fit_exec:main',
Expand Down
54 changes: 35 additions & 19 deletions n3fit/src/n3fit/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
from n3fit.backends.keras_backend.internal_state import (
set_initial_state,
clear_backend_state,
)
from n3fit.backends.keras_backend.MetaLayer import MetaLayer
from n3fit.backends.keras_backend.MetaModel import MetaModel
from n3fit.backends.keras_backend.base_layers import (
Input,
concatenate,
Lambda,
base_layer_selector,
regularizer_selector,
Concatenate,
)
from n3fit.backends.keras_backend import losses
from n3fit.backends.keras_backend import operations
from n3fit.backends.keras_backend import constraints
from n3fit.backends.keras_backend import callbacks
# Make the chosen backend available from n3fit.backends
# These includes:
# set_initial_state, clear_backend_state
# meta classes: MetaLayer, MetaModel
# modules: backend_layers, losses, operations, constraints, callbacks
#

print("Using Keras backend")
# If no backend has been set the default is the tensorflow backend
from sys import modules as _modules

_backends_module = _modules[__name__]

from n3fit.backends.keras_backend.internal_state import set_backend as set_tf

set_tf(_backends_module)


def select_backend(backend_name):
"""Select the appropiate backend by overriding this module
Default is understood as TensorFlow
"""
if backend_name is None:
backend_name = "tf"
try:
backend_name = backend_name.lower()
except AttributeError:
raise ValueError(f"select_backend accepts only strings, received: {backend_name}")
# Now depenidng on the backend, we need to load the backend importer function
if backend_name == "evolutionary_keras":
from n3fit.backends.ga_backend.internal_state import set_backend

set_backend(_backends_module)
elif backend_name in ["tf", "tensorflow", "keras"]:
set_tf(_backends_module)
else:
raise ValueError(f"Backend {backend_name} not recognized")
26 changes: 26 additions & 0 deletions n3fit/src/n3fit/backends/ga_backend/MetaModel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
MetaModel class for evolutionary_keras

Extension of the backend MetaModel class to use evolutionary_keras.
The MetaModel class provided by this module is a multiple inheritance
of the keras_backend.MetaModel and the evolutionary_keras.EvolModel
"""

import n3fit.backends.keras_backend.MetaModel as tf_MetaModel
import evolutionary_keras.optimizers as Evolutionary_optimizers
from evolutionary_keras.models import EvolModel

# Add the evolutionary algorithms to the list of accepted optimizers
tf_MetaModel.optimizers["NGA"] = (
Evolutionary_optimizers.NGA,
{"sigma_init": 15, "population_size": 80, "mutation_rate": 0.05},
)
tf_MetaModel.optimizers["CMA"] = (
Evolutionary_optimizers.CMA,
{"sigma_init": 0.3, "population_size": None, "max_evaluations": None},
)

# Mix inheritance
class MetaModel(tf_MetaModel.MetaModel, EvolModel):

accepted_optimizers = tf_MetaModel.optimizers
Empty file.
17 changes: 17 additions & 0 deletions n3fit/src/n3fit/backends/ga_backend/internal_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Modify the internal state of the backend
"""
from n3fit.backends.ga_backend.MetaModel import MetaModel
from n3fit.backends import select_backend


def set_backend(module):
"""Overwrites the necessary modules and imports from the
backends module.
Receives a reference to the module to overwrite.
"""
# First ensure the backend is tensorflow
select_backend("Tensorflow")

# Now set the MetaModel and leave all the rest as the Tensorflow Standard
setattr(module, "MetaModel", MetaModel)
1 change: 1 addition & 0 deletions n3fit/src/n3fit/backends/keras_backend/MetaModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from tensorflow.keras import optimizers as Kopt
from n3fit.backends.keras_backend.operations import numpy_to_tensor


# 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:
Expand Down
39 changes: 36 additions & 3 deletions n3fit/src/n3fit/backends/keras_backend/internal_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,44 @@
import random as rn
import numpy as np
import tensorflow as tf

# for (very slow but fine grained) debugging turn eager mode on
# tf.config.run_functions_eagerly(True)
from tensorflow.keras import backend as K


def set_backend(module):
"""Overwrites the necessary modules and imports from the
backends module.
Receives a reference to the module to overwrite.
"""
from n3fit.backends.keras_backend.internal_state import (
set_initial_state,
clear_backend_state,
)

setattr(module, "set_initial_state", set_initial_state)
setattr(module, "clear_backend_state", clear_backend_state)

from n3fit.backends.keras_backend.MetaLayer import MetaLayer
from n3fit.backends.keras_backend.MetaModel import MetaModel

setattr(module, "MetaLayer", MetaLayer)
setattr(module, "MetaModel", MetaModel)

import n3fit.backends.keras_backend.base_layers as backend_layers
from n3fit.backends.keras_backend import losses
from n3fit.backends.keras_backend import operations
from n3fit.backends.keras_backend import constraints
from n3fit.backends.keras_backend import callbacks

setattr(module, "backend_layers", backend_layers)
setattr(module, "losses", losses)
setattr(module, "operations", operations)
setattr(module, "constraints", constraints)
setattr(module, "callbacks", callbacks)


def set_initial_state(seed=13):
"""
Sets the initial state of the backend
Expand All @@ -44,10 +77,10 @@ def set_initial_state(seed=13):

def clear_backend_state(max_cores=None):
"""
Clears the state of the backend and opens a new session.
Clears the state of the backend and opens a new session.

Note that this function needs to set the TF session, including threads and processes
i.e., this function must NEVER be called after setting the initial state.
Note that this function needs to set the TF session, including threads and processes
i.e., this function must NEVER be called after setting the initial state.
"""
print("Clearing session")

Expand Down
Loading