nnpdf 4.1.0__py3-none-any.whl → 4.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- n3fit/backends/keras_backend/MetaModel.py +27 -26
- n3fit/backends/keras_backend/callbacks.py +16 -8
- n3fit/backends/keras_backend/internal_state.py +13 -2
- n3fit/backends/keras_backend/operations.py +26 -26
- n3fit/hyper_optimization/hyper_scan.py +3 -9
- n3fit/hyper_optimization/penalties.py +11 -8
- n3fit/hyper_optimization/rewards.py +65 -34
- n3fit/model_gen.py +344 -270
- n3fit/model_trainer.py +71 -105
- n3fit/performfit.py +2 -7
- n3fit/tests/regressions/quickcard_1.json +12 -28
- n3fit/tests/regressions/quickcard_3.json +12 -28
- n3fit/tests/regressions/quickcard_pol_1.json +10 -26
- n3fit/tests/regressions/quickcard_pol_3.json +9 -25
- n3fit/tests/regressions/quickcard_qed_1.json +11 -27
- n3fit/tests/regressions/quickcard_qed_3.json +11 -27
- n3fit/tests/test_hyperopt.py +6 -12
- n3fit/tests/test_layers.py +6 -6
- n3fit/tests/test_modelgen.py +73 -24
- n3fit/tests/test_multireplica.py +52 -16
- n3fit/tests/test_penalties.py +7 -8
- n3fit/tests/test_preprocessing.py +2 -2
- n3fit/tests/test_vpinterface.py +5 -10
- n3fit/vpinterface.py +88 -44
- {nnpdf-4.1.0.dist-info → nnpdf-4.1.1.dist-info}/METADATA +9 -3
- {nnpdf-4.1.0.dist-info → nnpdf-4.1.1.dist-info}/RECORD +105 -67
- {nnpdf-4.1.0.dist-info → nnpdf-4.1.1.dist-info}/WHEEL +1 -1
- nnpdf_data/_version.py +1 -1
- nnpdf_data/commondata/ATLAS_2JET_7TEV_R06/metadata.yaml +16 -5
- nnpdf_data/commondata/ATLAS_TTBAR_13P6TEV_TOT/data.yaml +2 -0
- nnpdf_data/commondata/ATLAS_TTBAR_13P6TEV_TOT/kinematics.yaml +13 -0
- nnpdf_data/commondata/ATLAS_TTBAR_13P6TEV_TOT/metadata.yaml +51 -0
- nnpdf_data/commondata/ATLAS_TTBAR_13P6TEV_TOT/uncertainties.yaml +17 -0
- nnpdf_data/commondata/ATLAS_TTBAR_5TEV_TOT/data.yaml +2 -0
- nnpdf_data/commondata/ATLAS_TTBAR_5TEV_TOT/kinematics.yaml +13 -0
- nnpdf_data/commondata/ATLAS_TTBAR_5TEV_TOT/metadata.yaml +52 -0
- nnpdf_data/commondata/ATLAS_TTBAR_5TEV_TOT/uncertainties.yaml +22 -0
- nnpdf_data/commondata/ATLAS_WPWM_13P6TEV_TOT/data.yaml +3 -0
- nnpdf_data/commondata/ATLAS_WPWM_13P6TEV_TOT/kinematics.yaml +17 -0
- nnpdf_data/commondata/ATLAS_WPWM_13P6TEV_TOT/metadata.yaml +57 -0
- nnpdf_data/commondata/ATLAS_WPWM_13P6TEV_TOT/uncertainties.yaml +8 -0
- nnpdf_data/commondata/ATLAS_Z0_13P6TEV_TOT/data.yaml +2 -0
- nnpdf_data/commondata/ATLAS_Z0_13P6TEV_TOT/kinematics.yaml +9 -0
- nnpdf_data/commondata/ATLAS_Z0_13P6TEV_TOT/metadata.yaml +54 -0
- nnpdf_data/commondata/ATLAS_Z0_13P6TEV_TOT/uncertainties.yaml +7 -0
- nnpdf_data/commondata/CMS_1JET_8TEV/metadata.yaml +7 -1
- nnpdf_data/commondata/CMS_2JET_7TEV/metadata.yaml +16 -19
- nnpdf_data/commondata/CMS_TTBAR_13P6TEV_TOT/data.yaml +2 -0
- nnpdf_data/commondata/CMS_TTBAR_13P6TEV_TOT/kinematics.yaml +13 -0
- nnpdf_data/commondata/CMS_TTBAR_13P6TEV_TOT/metadata.yaml +51 -0
- nnpdf_data/commondata/CMS_TTBAR_13P6TEV_TOT/uncertainties.yaml +12 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/data_d2Sig_dmttBar_dyttBar.yaml +17 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/data_dSig_dmttBar.yaml +8 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/data_dSig_dpTt.yaml +8 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/data_dSig_dyt.yaml +11 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/filter.py +260 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/kinematics_d2Sig_dmttBar_dyttBar.yaml +193 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/kinematics_dSig_dmttBar.yaml +57 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/kinematics_dSig_dpTt.yaml +57 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/kinematics_dSig_dyt.yaml +81 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/metadata.yaml +114 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/rawdata/mtt_abs_parton.yaml +828 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/rawdata/mttytt-abs_parton.yaml +1899 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/rawdata/ptt_abs_parton.yaml +828 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/rawdata/submission.yaml +47 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/rawdata/yt_abs_parton.yaml +1179 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/uncertainties_d2Sig_dmttBar_dyttBar.yaml +2282 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/uncertainties_dSig_dmttBar.yaml +1256 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/uncertainties_dSig_dpTt.yaml +1256 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_2L_138FB-1_DIF/uncertainties_dSig_dyt.yaml +1598 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_35P9FB-1_TOT/data.yaml +2 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_35P9FB-1_TOT/kinematics.yaml +13 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_35P9FB-1_TOT/metadata.yaml +51 -0
- nnpdf_data/commondata/CMS_TTBAR_13TEV_35P9FB-1_TOT/uncertainties.yaml +17 -0
- nnpdf_data/commondata/CMS_TTBAR_5TEV_TOT/metadata.yaml +1 -1
- nnpdf_data/commondata/NNPDF_POS_2P24GEV/metadata.yaml +60 -0
- nnpdf_data/commondata/dataset_names.yml +6 -1
- nnpdf_data/theory_cards/41000010.yaml +42 -0
- nnpdf_data/theory_cards/41000011.yaml +43 -0
- nnpdf_data/theory_cards/41000012.yaml +43 -0
- nnpdf_data/theory_cards/41000013.yaml +42 -0
- nnpdf_data/theory_cards/41000014.yaml +43 -0
- nnpdf_data/theory_cards/41000015.yaml +43 -0
- validphys/_version.py +1 -1
- validphys/config.py +30 -10
- validphys/convolution.py +37 -14
- validphys/coredata.py +15 -5
- validphys/covmats.py +9 -2
- validphys/dataplots.py +1 -1
- validphys/filters.py +17 -3
- validphys/fkparser.py +11 -1
- validphys/gridvalues.py +1 -0
- validphys/hessian2mc.py +5 -5
- validphys/lhaindex.py +5 -0
- validphys/loader.py +1 -1
- validphys/n3fit_data.py +107 -61
- validphys/nnprofile_default.yaml +2 -1
- validphys/pineparser.py +12 -2
- validphys/scripts/postfit.py +4 -4
- validphys/scripts/vp_pdfrename.py +8 -9
- validphys/tests/conftest.py +6 -2
- validphys/tests/test_hessian2mc.py +7 -5
- validphys/utils.py +1 -0
- n3fit/tests/regressions/quickcard_pol/filter.yml +0 -80
- n3fit/tests/regressions/quickcard_pol/nnfit/input/lockfile.yaml +0 -111
- n3fit/tests/regressions/quickcard_pol/nnfit/replica_1/quickcard_pol.exportgrid +0 -572
- n3fit/tests/regressions/quickcard_pol/nnfit/replica_1/quickcard_pol.json +0 -71
- n3fit/tests/regressions/quickcard_pol/nnfit/replica_3/quickcard_pol.exportgrid +0 -615
- n3fit/tests/regressions/quickcard_pol/nnfit/replica_3/quickcard_pol.json +0 -71
- n3fit/tests/regressions/weights.weights.h5 +0 -0
- n3fit/tests/regressions/weights_pol.weights.h5 +0 -0
- n3fit/tests/test +0 -1
- nnpdf_data/theory_cards/40000099.yaml +0 -41
- nnpdf_data/theory_cards/40000099.yml +0 -41
- {nnpdf-4.1.0.dist-info → nnpdf-4.1.1.dist-info}/entry_points.txt +0 -0
- {nnpdf-4.1.0.dist-info → nnpdf-4.1.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
MetaModel class
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Extension of the backend Model class containing some wrappers in order to absorb other
|
|
5
|
+
backend-dependent calls.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
import re
|
|
10
10
|
|
|
11
|
-
from keras import
|
|
11
|
+
from keras import backend as K
|
|
12
12
|
from keras import optimizers as Kopt
|
|
13
13
|
from keras.models import Model
|
|
14
14
|
import numpy as np
|
|
@@ -32,6 +32,16 @@ NN_PREFIX = "NN"
|
|
|
32
32
|
NN_LAYER_ALL_REPLICAS = "all_NNs"
|
|
33
33
|
PREPROCESSING_LAYER_ALL_REPLICAS = "preprocessing_factor"
|
|
34
34
|
|
|
35
|
+
# Running many steps in epoch eliminates some per-epoch overhead and has a big impact
|
|
36
|
+
# in GPU. In benchmarks, more than 100 steps doesn't seem to have any impact
|
|
37
|
+
# so this is the rationale for that number.
|
|
38
|
+
#
|
|
39
|
+
# For reasons that are not clear at the time of writing (13/08/2025) jax only accepts
|
|
40
|
+
# one step per epoch, showing the same penalty of other libraries.
|
|
41
|
+
STEPS_PER_EPOCH = 100
|
|
42
|
+
if K.backend() == "jax":
|
|
43
|
+
STEPS_PER_EPOCH = 1
|
|
44
|
+
|
|
35
45
|
# Some keys need to work for everyone
|
|
36
46
|
for k, v in optimizers.items():
|
|
37
47
|
v[1]["clipnorm"] = 1.0
|
|
@@ -98,7 +108,6 @@ class MetaModel(Model):
|
|
|
98
108
|
self.required_slots.add(k)
|
|
99
109
|
super().__init__(input_tensors, output_tensors, **kwargs)
|
|
100
110
|
|
|
101
|
-
self.x_in = x_in
|
|
102
111
|
self.input_tensors = input_tensors
|
|
103
112
|
self.single_replica_generator = None
|
|
104
113
|
|
|
@@ -106,6 +115,10 @@ class MetaModel(Model):
|
|
|
106
115
|
self.compute_losses_function = None
|
|
107
116
|
self._scaler = scaler
|
|
108
117
|
|
|
118
|
+
# Keras' __setattr__ would try to track the input dictionary as a TrackedDict
|
|
119
|
+
# which is incompatible with jax, to avoid this problem, set the attribute directly
|
|
120
|
+
object.__setattr__(self, "x_in", x_in)
|
|
121
|
+
|
|
109
122
|
def _parse_input(self, extra_input=None):
|
|
110
123
|
"""Returns the input data the model was compiled with.
|
|
111
124
|
Introduces the extra_input in the places asigned to the placeholders.
|
|
@@ -153,34 +166,22 @@ class MetaModel(Model):
|
|
|
153
166
|
if y is None:
|
|
154
167
|
y = self.target_tensors
|
|
155
168
|
|
|
156
|
-
#
|
|
157
|
-
|
|
169
|
+
# Running more than 1 step for every epoch eliminates some overhead of the backend libraries.
|
|
170
|
+
# In the special case in which epochs < STEPS_PER_EPOCH, set it to 1
|
|
171
|
+
if epochs < STEPS_PER_EPOCH:
|
|
172
|
+
steps_per_epoch = 1
|
|
173
|
+
else:
|
|
174
|
+
steps_per_epoch = STEPS_PER_EPOCH
|
|
158
175
|
|
|
159
176
|
for k, v in x_params.items():
|
|
160
177
|
x_params[k] = ops.repeat(v, steps_per_epoch, axis=0)
|
|
161
178
|
y = [ops.repeat(yi, steps_per_epoch, axis=0) for yi in y]
|
|
162
|
-
|
|
163
179
|
history = super().fit(
|
|
164
180
|
x=x_params, y=y, epochs=epochs // steps_per_epoch, batch_size=1, **kwargs
|
|
165
181
|
)
|
|
166
182
|
loss_dict = history.history
|
|
167
183
|
return loss_dict
|
|
168
184
|
|
|
169
|
-
def _determine_steps_per_epoch(self, epochs):
|
|
170
|
-
"""Determine how many step to run in every epoch.
|
|
171
|
-
When running a single replica (CPU) or when the number of epochs is < 100 default to 1.
|
|
172
|
-
Otherwise run 100 steps per epoch.
|
|
173
|
-
|
|
174
|
-
If the number of epochs requested is not divisible by 100 there will be a number
|
|
175
|
-
of extra training epochs being run equal to max_epochs % 100 in the worst case.
|
|
176
|
-
|
|
177
|
-
"""
|
|
178
|
-
num_replicas = self.output_shape[0]
|
|
179
|
-
if num_replicas == 1 or epochs < 100:
|
|
180
|
-
return 1
|
|
181
|
-
|
|
182
|
-
return 100
|
|
183
|
-
|
|
184
185
|
def predict(self, x=None, **kwargs):
|
|
185
186
|
"""Call super().predict with the right input arguments"""
|
|
186
187
|
x = self._parse_input(x)
|
|
@@ -408,7 +409,7 @@ class MetaModel(Model):
|
|
|
408
409
|
raise ValueError("Trying to generate single replica models with no generator set.")
|
|
409
410
|
replicas = []
|
|
410
411
|
for i_replica in range(self.num_replicas):
|
|
411
|
-
replica = self.single_replica_generator()
|
|
412
|
+
replica = self.single_replica_generator(i_replica)
|
|
412
413
|
replica.set_replica_weights(self.get_replica_weights(i_replica))
|
|
413
414
|
replicas.append(replica)
|
|
414
415
|
|
|
@@ -496,9 +497,9 @@ def get_layer_replica_weights(layer, i_replica: int):
|
|
|
496
497
|
"""
|
|
497
498
|
if is_stacked_single_replicas(layer):
|
|
498
499
|
weights_ref = layer.get_layer(f"{NN_PREFIX}_{i_replica}").weights
|
|
499
|
-
weights = [
|
|
500
|
+
weights = [ops.variable_to_numpy(w) for w in weights_ref]
|
|
500
501
|
else:
|
|
501
|
-
weights = [
|
|
502
|
+
weights = [ops.variable_to_numpy(w)[i_replica : i_replica + 1] for w in layer.weights]
|
|
502
503
|
|
|
503
504
|
return weights
|
|
504
505
|
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Callbacks to be used during training
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
The callbacks defined in this module can be passed to the ``callbacks`` argument
|
|
5
|
+
of the ``perform_fit`` method as a list.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
For the most typical usage: ``on_batch_end``,
|
|
8
|
+
they must take as input an epoch number and a log of the partial losses.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Note: the terminology used everywhere refers to a single training step as a single epoch.
|
|
11
|
+
It turns out that to avoid tensorflow overhead, it is beneficial to write a step as a
|
|
12
|
+
single batch instead. So callbacks must use ``on_batch_end``.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
import logging
|
|
16
16
|
from time import time
|
|
17
17
|
|
|
18
|
+
from keras import backend as K
|
|
18
19
|
from keras.callbacks import Callback, TensorBoard
|
|
19
20
|
import numpy as np
|
|
20
21
|
|
|
@@ -130,6 +131,13 @@ class StoppingCallback(CallbackStep):
|
|
|
130
131
|
print_stats = ((epoch + 1) % self.log_freq) == 0
|
|
131
132
|
# Note that the input logs correspond to the fit before the weights are updated
|
|
132
133
|
logs = self.correct_logs(logs)
|
|
134
|
+
|
|
135
|
+
# WARNING: this line seems to be necessary for jax
|
|
136
|
+
# otherwise the validation model itself cannot run compute_losses
|
|
137
|
+
# but it needs to be run every epoch, which makes no sense
|
|
138
|
+
if K.backend() == "jax":
|
|
139
|
+
_ = self.model.compute_losses()
|
|
140
|
+
|
|
133
141
|
self.stopping_object.monitor_chi2(logs, epoch, print_stats=print_stats)
|
|
134
142
|
if self.stopping_object.stop_here():
|
|
135
143
|
self.model.stop_training = True
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Library of functions that modify the internal state of Keras/Tensorflow
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
@@ -21,7 +21,8 @@ import numpy as np
|
|
|
21
21
|
log = logging.getLogger(__name__)
|
|
22
22
|
|
|
23
23
|
# Prepare Keras-backend dependent functions
|
|
24
|
-
if K.backend()
|
|
24
|
+
if (kback := K.backend()) == "torch":
|
|
25
|
+
|
|
25
26
|
import torch
|
|
26
27
|
|
|
27
28
|
def set_eager(flag=True):
|
|
@@ -56,6 +57,16 @@ elif K.backend() == "tensorflow":
|
|
|
56
57
|
"Could not set tensorflow parallelism settings from n3fit, maybe tensorflow is already initialized by a third program"
|
|
57
58
|
)
|
|
58
59
|
|
|
60
|
+
elif K.backend() == "jax":
|
|
61
|
+
|
|
62
|
+
import jax
|
|
63
|
+
|
|
64
|
+
def set_eager(flag=True):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def set_threading(threads, core):
|
|
68
|
+
pass
|
|
69
|
+
|
|
59
70
|
else:
|
|
60
71
|
# Keras should've failed by now, if it doesn't it could be a new backend that works ootb?
|
|
61
72
|
log.warning(f"Backend {K.backend()} not recognized. You are entering uncharted territory")
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
2
|
+
This module contains the list of operations that can be used within the
|
|
3
|
+
``call`` method of the ``n3fit`` layers as well as operations that can
|
|
4
|
+
act on layers.
|
|
5
|
+
|
|
6
|
+
This includes an implementation of the NNPDF operations on fktable in the keras
|
|
7
|
+
language (with the mapping ``c_to_py_fun``) into Keras ``Lambda`` layers.
|
|
8
|
+
|
|
9
|
+
The rest of the operations in this module are divided into four categories:
|
|
10
|
+
numpy to tensor:
|
|
11
|
+
Operations that take a numpy array and return a tensorflow tensor
|
|
12
|
+
layer to layer:
|
|
13
|
+
Operations that take a layer and return another layer
|
|
14
|
+
tensor to tensor:
|
|
15
|
+
Operations that take a tensor and return a tensor
|
|
16
|
+
layer generation:
|
|
17
|
+
Instanciate a layer to be applied by the calling function
|
|
18
|
+
|
|
19
|
+
Most of the operations in this module are just aliases to the backend
|
|
20
|
+
(Keras in this case) so that, when implementing new backends, it is clear
|
|
21
|
+
which operations may need to be overwritten.
|
|
22
|
+
For a few selected operations, a more complicated wrapper to e.g., make
|
|
23
|
+
them into layers or apply some default, is included.
|
|
24
|
+
|
|
25
|
+
Note that tensor operations can also be applied to layers as the output of a layer is a tensor
|
|
26
|
+
equally operations are automatically converted to layers when used as such.
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
from keras import backend as K
|
|
@@ -70,12 +70,12 @@ elif K.backend() == "jax":
|
|
|
70
70
|
decorator_compiler = lambda f: f
|
|
71
71
|
elif K.backend() == "tensorflow":
|
|
72
72
|
tensor_to_numpy_or_python = lambda x: x.numpy()
|
|
73
|
-
lambda ret: {k: i.numpy() for k, i in ret.items()}
|
|
74
73
|
import tensorflow as tf
|
|
75
74
|
|
|
76
75
|
decorator_compiler = tf.function
|
|
77
76
|
|
|
78
77
|
dict_to_numpy_or_python = lambda ret: {k: tensor_to_numpy_or_python(i) for k, i in ret.items()}
|
|
78
|
+
variable_to_numpy = lambda x: x.numpy()
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
def as_layer(operation, op_args=None, op_kwargs=None, **kwargs):
|
|
@@ -17,10 +17,10 @@ import copy
|
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
19
|
|
|
20
|
-
import hyperopt
|
|
21
20
|
from hyperopt.pyll.base import scope
|
|
22
21
|
import numpy as np
|
|
23
22
|
|
|
23
|
+
import hyperopt
|
|
24
24
|
from n3fit.backends import MetaLayer, MetaModel
|
|
25
25
|
from n3fit.hyper_optimization.filetrials import FileTrials
|
|
26
26
|
|
|
@@ -125,11 +125,6 @@ def hyper_scan_wrapper(replica_path_set, model_trainer, hyperscanner, max_evals=
|
|
|
125
125
|
a ``HyperScanner`` object defining the scan
|
|
126
126
|
max_evals: int
|
|
127
127
|
Number of trials to run
|
|
128
|
-
|
|
129
|
-
Returns
|
|
130
|
-
-------
|
|
131
|
-
dict
|
|
132
|
-
parameters of the best trial as found by ``hyperopt``
|
|
133
128
|
"""
|
|
134
129
|
# Tell the trainer we are doing hpyeropt
|
|
135
130
|
model_trainer.set_hyperopt(True, keys=hyperscanner.hyper_keys)
|
|
@@ -181,14 +176,13 @@ def hyper_scan_wrapper(replica_path_set, model_trainer, hyperscanner, max_evals=
|
|
|
181
176
|
)
|
|
182
177
|
if hyperscanner.parallel_hyperopt:
|
|
183
178
|
trials.start_mongo_workers()
|
|
184
|
-
|
|
179
|
+
hyperopt.fmin(**fmin_args, show_progressbar=True, max_queue_len=trials.num_workers)
|
|
185
180
|
trials.stop_mongo_workers()
|
|
186
181
|
# stop mongod command and compress database
|
|
187
182
|
hyperscanner.mongod_runner.stop(mongod)
|
|
188
183
|
trials.compress_mongodb_database()
|
|
189
184
|
else:
|
|
190
|
-
|
|
191
|
-
return hyperscanner.space_eval(best)
|
|
185
|
+
hyperopt.fmin(**fmin_args, show_progressbar=False, trials_save_file=trials.pkl_file)
|
|
192
186
|
|
|
193
187
|
|
|
194
188
|
class ActivationStr:
|
|
@@ -18,6 +18,7 @@ And return a float to be added to the hyperscan loss.
|
|
|
18
18
|
New penalties can be added directly in this module.
|
|
19
19
|
The name in the runcard must match the name used in this module.
|
|
20
20
|
"""
|
|
21
|
+
|
|
21
22
|
import numpy as np
|
|
22
23
|
|
|
23
24
|
from n3fit.vpinterface import N3PDF, integrability_numbers
|
|
@@ -48,11 +49,12 @@ def saturation(pdf_model=None, n=100, min_x=1e-6, max_x=1e-4, flavors=None, **_k
|
|
|
48
49
|
Example
|
|
49
50
|
-------
|
|
50
51
|
>>> from n3fit.hyper_optimization.penalties import saturation
|
|
51
|
-
>>> from n3fit.model_gen import
|
|
52
|
+
>>> from n3fit.model_gen import generate_pdf_model, ReplicaSettings
|
|
52
53
|
>>> fake_fl = [{'fl' : i, 'largex' : [0,1], 'smallx': [1,2]} for i in ['u', 'ubar', 'd', 'dbar', 'c', 'g', 's', 'sbar']]
|
|
53
|
-
>>>
|
|
54
|
-
>>>
|
|
55
|
-
|
|
54
|
+
>>> rp = [ReplicaSettings(nodes = [8], activations=["linear"], seed=0)]
|
|
55
|
+
>>> pdf_model = generate_pdf_model(rp, flav_info=fake_fl, fitbasis="FLAVOUR")
|
|
56
|
+
>>> saturation(pdf_model, 5)
|
|
57
|
+
array([0.00014878])
|
|
56
58
|
|
|
57
59
|
"""
|
|
58
60
|
if flavors is None:
|
|
@@ -128,11 +130,12 @@ def integrability(pdf_model=None, **_kwargs):
|
|
|
128
130
|
Example
|
|
129
131
|
-------
|
|
130
132
|
>>> from n3fit.hyper_optimization.penalties import integrability
|
|
131
|
-
>>> from n3fit.model_gen import
|
|
133
|
+
>>> from n3fit.model_gen import generate_pdf_model, ReplicaSettings
|
|
132
134
|
>>> fake_fl = [{'fl' : i, 'largex' : [0,1], 'smallx': [1,2]} for i in ['u', 'ubar', 'd', 'dbar', 'c', 'g', 's', 'sbar']]
|
|
133
|
-
>>>
|
|
134
|
-
>>>
|
|
135
|
-
|
|
135
|
+
>>> rp = [ReplicaSettings(nodes = [8], activations=["linear"], seed=0)]
|
|
136
|
+
>>> pdf_model = generate_pdf_model(rp, flav_info=fake_fl, fitbasis="FLAVOUR")
|
|
137
|
+
>>> integrability(pdf_model)
|
|
138
|
+
5.184705528587072e+21
|
|
136
139
|
|
|
137
140
|
"""
|
|
138
141
|
pdf_instance = N3PDF(pdf_model.split_replicas())
|
|
@@ -36,7 +36,7 @@ from typing import Callable
|
|
|
36
36
|
|
|
37
37
|
import numpy as np
|
|
38
38
|
|
|
39
|
-
from n3fit.vpinterface import N3PDF,
|
|
39
|
+
from n3fit.vpinterface import N3PDF, HyperoptMetrics, compute_hyperopt_metrics
|
|
40
40
|
from validphys.core import DataGroupSpec
|
|
41
41
|
from validphys.pdfgrids import distance_grids, xplotting_grid
|
|
42
42
|
|
|
@@ -103,7 +103,7 @@ IMPLEMENTED_STATS = {
|
|
|
103
103
|
"best_worst": _best_worst,
|
|
104
104
|
"std": _std,
|
|
105
105
|
}
|
|
106
|
-
IMPLEMENTED_LOSSES = ["chi2", "phi2"]
|
|
106
|
+
IMPLEMENTED_LOSSES = ["chi2", "phi2", "logp", "chi2p"]
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
def _pdfs_to_n3pdfs(pdfs_per_fold):
|
|
@@ -156,8 +156,10 @@ class HyperLoss:
|
|
|
156
156
|
|
|
157
157
|
self.loss_type = self._parse_loss(loss_type)
|
|
158
158
|
|
|
159
|
-
self.
|
|
160
|
-
self.
|
|
159
|
+
self.hyper_chi2_vector = []
|
|
160
|
+
self.hyper_phi2_vector = []
|
|
161
|
+
self.hyper_logp_vector = []
|
|
162
|
+
self.exp_chi2_matrix = []
|
|
161
163
|
self.penalties = {}
|
|
162
164
|
|
|
163
165
|
self.reduce_over_replicas = self._parse_statistic(replica_statistic, "replica")
|
|
@@ -167,7 +169,7 @@ class HyperLoss:
|
|
|
167
169
|
self,
|
|
168
170
|
penalties: dict[str, np.ndarray],
|
|
169
171
|
validation_loss: np.ndarray,
|
|
170
|
-
|
|
172
|
+
experimental_loss: np.ndarray,
|
|
171
173
|
pdf_object: N3PDF,
|
|
172
174
|
experimental_data: list[DataGroupSpec],
|
|
173
175
|
fold_idx: int = 0,
|
|
@@ -192,8 +194,6 @@ class HyperLoss:
|
|
|
192
194
|
List of tuples containing `validphys.core.DataGroupSpec` instances for each group data set
|
|
193
195
|
fold_idx: int
|
|
194
196
|
k-fold index. Defaults to 0.
|
|
195
|
-
include_penalties: float
|
|
196
|
-
Whether to include the penalties in the returned loss value
|
|
197
197
|
|
|
198
198
|
Returns
|
|
199
199
|
-------
|
|
@@ -213,7 +213,7 @@ class HyperLoss:
|
|
|
213
213
|
>>> ds = Loader().check_dataset("NMC_NC_NOTFIXED_P_EM-SIGMARED", variant="legacy", theoryid=399, cuts="internal")
|
|
214
214
|
>>> experimental_data = [Loader().check_experiment("My DataGroupSpec", [ds])]
|
|
215
215
|
>>> fake_fl = [{'fl' : i, 'largex' : [0,1], 'smallx': [1,2]} for i in ['u', 'ubar', 'd', 'dbar', 'c', 'g', 's', 'sbar']]
|
|
216
|
-
>>> pdf_model = generate_pdf_model(nodes=[8], activations=['linear'], seed=0,
|
|
216
|
+
>>> pdf_model = generate_pdf_model(nodes=[8], activations=['linear'], seed=[0,2], flav_info=fake_fl, fitbasis="FLAVOUR")
|
|
217
217
|
>>> pdf = N3PDF(pdf_model.split_replicas())
|
|
218
218
|
>>> loss = hyper.compute_loss(penalties, experimental_loss, pdf, experimental_data)
|
|
219
219
|
"""
|
|
@@ -225,21 +225,38 @@ class HyperLoss:
|
|
|
225
225
|
best_indexes = np.argsort(validation_loss, axis=0)[:num_best]
|
|
226
226
|
best_validation_losses = validation_loss[best_indexes]
|
|
227
227
|
|
|
228
|
-
#
|
|
228
|
+
# Select the `N3PDF` models to be used to compute the hyperopt metrics. The models
|
|
229
|
+
# are selected based on the validation losses using `self._proportion`.
|
|
229
230
|
pdf_object_reduced = pdf_object.select_models(best_indexes)
|
|
230
|
-
phi2_per_fold = compute_phi(pdf_object_reduced, experimental_data) ** 2
|
|
231
231
|
|
|
232
|
-
#
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
# Compute the different hyperopt metrics
|
|
233
|
+
hypermetics: HyperoptMetrics = compute_hyperopt_metrics(
|
|
234
|
+
n3pdf=pdf_object_reduced, experimental_data=experimental_data
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Extract & save the values of the hyperopt metrics
|
|
238
|
+
hyper_chi2_per_fold = hypermetics.chi2 # computed with PDF covmat
|
|
239
|
+
hyper_phi2_per_fold = hypermetics.phi2 # computed without PDF covmat
|
|
240
|
+
hyper_logp_per_fold = hypermetics.logp # computed with PDF covmat
|
|
241
|
+
|
|
242
|
+
# Update hyperopt metrics history
|
|
243
|
+
self._save_hyperopt_metrics(
|
|
244
|
+
hyper_chi2_per_fold,
|
|
245
|
+
hyper_phi2_per_fold,
|
|
246
|
+
hyper_logp_per_fold,
|
|
247
|
+
experimental_loss,
|
|
248
|
+
penalties,
|
|
249
|
+
fold_idx,
|
|
250
|
+
)
|
|
235
251
|
|
|
236
252
|
# Prepare the output loss, including penalties if necessary
|
|
237
253
|
if self._penalties_in_loss:
|
|
238
254
|
# include penalties to experimental loss
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
experimental_loss += sum(penalties.values())
|
|
256
|
+
# add penalties to `phi2` and `logp` in the form of a sum of per-replicas averages
|
|
257
|
+
sum_penalties = sum(np.mean(penalty) for penalty in penalties.values())
|
|
258
|
+
hyper_phi2_per_fold += sum_penalties
|
|
259
|
+
hyper_logp_per_fold += sum_penalties
|
|
243
260
|
|
|
244
261
|
# define loss for hyperopt according to the chosen loss_type
|
|
245
262
|
if self.loss_type == "chi2":
|
|
@@ -247,38 +264,48 @@ class HyperLoss:
|
|
|
247
264
|
|
|
248
265
|
# Construct the final loss as a sum of:
|
|
249
266
|
# 1. The validation chi2
|
|
250
|
-
# 2. The distance to 2 for the
|
|
267
|
+
# 2. The distance to 2 for the experimental chi2
|
|
251
268
|
# In the hyperopt paper we used 80% and 10% respectively, as a proxy for:
|
|
252
269
|
# "80% of the replicas should be good, but only a small % has to cover the folds"
|
|
253
270
|
# Currently take reduce_proportion for a) and 1.0 - reduce_proportion for b)
|
|
254
271
|
validation_loss_average = self.reduce_over_replicas(best_validation_losses)
|
|
255
272
|
|
|
256
|
-
nselect = int(np.ceil((1.0 - self._proportion) * len(
|
|
257
|
-
|
|
258
|
-
|
|
273
|
+
nselect = int(np.ceil((1.0 - self._proportion) * len(experimental_loss)))
|
|
274
|
+
best_exp_losses = np.sort(experimental_loss, axis=0)[:nselect]
|
|
275
|
+
exp_loss_average = self.reduce_over_replicas(best_exp_losses)
|
|
259
276
|
|
|
260
|
-
loss = validation_loss_average + (max(
|
|
277
|
+
loss = validation_loss_average + (max(exp_loss_average, 2.0) - 2.0)
|
|
261
278
|
elif self.loss_type == "phi2":
|
|
262
|
-
loss =
|
|
279
|
+
loss = hyper_phi2_per_fold
|
|
280
|
+
elif self.loss_type == "logp":
|
|
281
|
+
loss = hyper_logp_per_fold
|
|
282
|
+
elif self.loss_type == "chi2p":
|
|
283
|
+
loss = hyper_chi2_per_fold
|
|
263
284
|
|
|
264
285
|
return loss
|
|
265
286
|
|
|
266
287
|
def _save_hyperopt_metrics(
|
|
267
288
|
self,
|
|
268
|
-
|
|
269
|
-
|
|
289
|
+
hyper_chi2_per_fold: float,
|
|
290
|
+
hyper_phi2_per_fold: float,
|
|
291
|
+
hyper_logp_per_fold: float,
|
|
292
|
+
exp_chi2_per_fold: np.ndarray,
|
|
270
293
|
penalties: dict[str, np.ndarray],
|
|
271
294
|
fold_idx: int = 0,
|
|
272
295
|
) -> None:
|
|
273
296
|
"""
|
|
274
|
-
Save all
|
|
297
|
+
Save all the calculated metrics per replica and per fold, including penalties.
|
|
275
298
|
|
|
276
299
|
Parameters
|
|
277
300
|
----------
|
|
278
|
-
|
|
301
|
+
hyper_chi2_per_fold: float
|
|
302
|
+
Computed chi2 for a given k-fold
|
|
303
|
+
hyper_phi2_per_fold: float
|
|
279
304
|
Computed phi2 for a given k-fold
|
|
280
|
-
|
|
281
|
-
Computed
|
|
305
|
+
hyper_logp_per_fold: float
|
|
306
|
+
Computed logp for a given k-fold
|
|
307
|
+
exp_chi2_per_fold: np.ndarray
|
|
308
|
+
Computed experimental chi2 for all the replica for a given k-fold
|
|
282
309
|
penalties: Dict[str, np.ndarray]
|
|
283
310
|
dictionary of all penalties with their names
|
|
284
311
|
fold_idx: int
|
|
@@ -286,13 +313,17 @@ class HyperLoss:
|
|
|
286
313
|
"""
|
|
287
314
|
# reset chi2 and phi arrays for every trial
|
|
288
315
|
if fold_idx == 0:
|
|
289
|
-
self.
|
|
290
|
-
self.
|
|
316
|
+
self.hyper_chi2_vector = []
|
|
317
|
+
self.hyper_phi2_vector = []
|
|
318
|
+
self.hyper_logp_vector = []
|
|
319
|
+
self.exp_chi2_matrix = []
|
|
291
320
|
self.penalties = {}
|
|
292
321
|
|
|
293
322
|
# populate chi2 matrix and phi vector calculated for a given k-fold
|
|
294
|
-
self.
|
|
295
|
-
self.
|
|
323
|
+
self.hyper_chi2_vector.append(hyper_chi2_per_fold)
|
|
324
|
+
self.hyper_phi2_vector.append(hyper_phi2_per_fold)
|
|
325
|
+
self.hyper_logp_vector.append(hyper_logp_per_fold)
|
|
326
|
+
self.exp_chi2_matrix.append(exp_chi2_per_fold)
|
|
296
327
|
|
|
297
328
|
# save penalties per replica for a given k-fold
|
|
298
329
|
for name, values in penalties.items():
|
|
@@ -366,7 +397,7 @@ class HyperLoss:
|
|
|
366
397
|
|
|
367
398
|
selected_statistic = IMPLEMENTED_STATS[statistic]
|
|
368
399
|
|
|
369
|
-
if self.loss_type == "chi2":
|
|
400
|
+
if self.loss_type == "chi2" or self.loss_type == "logp" or self.loss_type == "chi2p":
|
|
370
401
|
return selected_statistic
|
|
371
402
|
elif self.loss_type == "phi2":
|
|
372
403
|
# In case of phi2, calculate the inverse of the applied statistics
|