likelihood 1.5.1__py3-none-any.whl → 1.5.3__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.
@@ -1 +1,2 @@
1
1
  from .autoencoders import *
2
+ from .gan import *
@@ -0,0 +1,313 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import tensorflow as tf
4
+ from IPython.display import clear_output
5
+ from tensorflow.keras.regularizers import l2
6
+ from tqdm import tqdm
7
+
8
+ from likelihood.tools import get_metrics
9
+
10
+
11
+ @tf.keras.utils.register_keras_serializable(package="Custom", name="GANRegressor")
12
+ class GANRegressor(tf.keras.Model):
13
+ """
14
+ GANRegressor is a custom Keras model that combines a generator and a discriminator
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ input_shape_parm,
20
+ output_shape_parm,
21
+ num_neurons=128,
22
+ activation="linear",
23
+ depth=5,
24
+ dropout=0.2,
25
+ l2_reg=0.0,
26
+ **kwargs,
27
+ ):
28
+ super(GANRegressor, self).__init__()
29
+ self.input_shape_parm = input_shape_parm
30
+ self.output_shape_parm = output_shape_parm
31
+ self.num_neurons = num_neurons
32
+ self.activation = activation
33
+ self.depth = depth
34
+ self.dropout = dropout
35
+ self.l2_reg = l2_reg
36
+ self.optimizer = kwargs.get("optimizer", "adam")
37
+
38
+ self.generator = self._build_generator()
39
+ self.discriminator = self._build_discriminator()
40
+ dummy_input = tf.convert_to_tensor(tf.random.normal([1, self.input_shape_parm]))
41
+ self.build(dummy_input.shape)
42
+
43
+ def build(self, input_shape):
44
+ self.gan = tf.keras.models.Sequential([self.generator, self.discriminator])
45
+
46
+ self.generator.compile(
47
+ optimizer=self.optimizer,
48
+ loss=tf.keras.losses.MeanAbsolutePercentageError(),
49
+ metrics=[tf.keras.metrics.MeanAbsolutePercentageError()],
50
+ )
51
+
52
+ self.discriminator.compile(
53
+ optimizer=self.optimizer, loss="binary_crossentropy", metrics=["accuracy"]
54
+ )
55
+
56
+ self.gan.compile(optimizer=self.optimizer, loss="binary_crossentropy")
57
+ super(GANRegressor, self).build(input_shape)
58
+
59
+ def _build_generator(self):
60
+ generator = tf.keras.Sequential()
61
+ generator.add(
62
+ tf.keras.layers.Dense(
63
+ self.num_neurons,
64
+ activation="selu",
65
+ input_shape=[self.input_shape_parm],
66
+ kernel_regularizer=l2(self.l2_reg),
67
+ )
68
+ )
69
+ generator.add(tf.keras.layers.Dropout(self.dropout))
70
+ for _ in range(self.depth - 1):
71
+ generator.add(
72
+ tf.keras.layers.Dense(
73
+ self.num_neurons, activation="selu", kernel_regularizer=l2(self.l2_reg)
74
+ ),
75
+ )
76
+ generator.add(tf.keras.layers.Dropout(self.dropout))
77
+ generator.add(tf.keras.layers.Dense(2 * self.output_shape_parm, activation=self.activation))
78
+ return generator
79
+
80
+ def _build_discriminator(self):
81
+ discriminator = tf.keras.Sequential()
82
+ for _ in range(self.depth):
83
+ discriminator.add(
84
+ tf.keras.layers.Dense(
85
+ self.num_neurons, activation="selu", kernel_regularizer=l2(self.l2_reg)
86
+ ),
87
+ )
88
+ discriminator.add(tf.keras.layers.Dropout(self.dropout))
89
+ discriminator.add(tf.keras.layers.Dense(2, activation="softmax"))
90
+ return discriminator
91
+
92
+ def train_gan(
93
+ self,
94
+ X,
95
+ y,
96
+ batch_size,
97
+ n_epochs,
98
+ validation_split=0.2,
99
+ verbose=1,
100
+ ):
101
+ """
102
+ Train the GAN model.
103
+
104
+ Parameters
105
+ --------
106
+ X : array-like
107
+ Input data.
108
+ y : array-like
109
+ Target data.
110
+ batch_size : int
111
+ Number of samples in each batch.
112
+ n_epochs : int
113
+ Number of training epochs.
114
+ validation_split : float, optional
115
+ Fraction of the data to be used for validation.
116
+ verbose : int, optional
117
+ Verbosity level. Default is 1.
118
+
119
+ Returns
120
+ --------
121
+ history : pd.DataFrame
122
+ Training history.
123
+ """
124
+ loss_history = []
125
+ for epoch in tqdm(range(n_epochs)):
126
+ batch_starts = np.arange(0, len(X), batch_size)
127
+ for start in batch_starts:
128
+ np.random.shuffle(batch_starts)
129
+ end = start + batch_size
130
+ X_batch = X[start:end]
131
+ y_batch = y[start:end].reshape(-1, self.output_shape_parm)
132
+ y_batch = np.concatenate((y_batch, y_batch**2), axis=1)
133
+ X_batch = tf.cast(X_batch, "float32")
134
+ noise = tf.random.normal(
135
+ shape=X_batch.shape, stddev=tf.math.reduce_std(X_batch, keepdims=False)
136
+ )
137
+
138
+ # Phase 1 - training the generator
139
+ self.generator.train_on_batch(X_batch, y_batch)
140
+
141
+ # Phase 2 - training the discriminator
142
+ generated_y_fake = self.generator(noise)
143
+ generated_y_real = self.generator(X_batch)
144
+ fake_and_real = tf.concat([generated_y_fake, generated_y_real], axis=0)
145
+ X_fake_and_real = tf.concat([noise, X_batch], axis=0)
146
+ batch_size = int(fake_and_real.shape[0] / 2)
147
+ indices_ = tf.constant([[0.0]] * batch_size + [[1.0]] * batch_size)[:, 0]
148
+ indices_ = tf.cast(indices_, "int32")
149
+ y1 = tf.one_hot(indices_, 2)
150
+ self.gan.train_on_batch(X_fake_and_real, y1)
151
+
152
+ loss = self._cal_loss(generated_y_real, y_batch)
153
+ loss_history.append([epoch, loss])
154
+
155
+ if verbose:
156
+ X_batch, y_batch, X_batch_val, y_batch_val = self._train_and_val(
157
+ X_batch, y_batch, validation_split=validation_split
158
+ )
159
+ generated_y = self.generator(X_batch)
160
+ generated_y_val = self.generator(X_batch_val)
161
+ y_pred = self.discriminator.predict(fake_and_real, verbose=0)
162
+ y_pred = list(np.argmax(y_pred, axis=1))
163
+
164
+ metrics = get_metrics(self._get_frame(indices_.numpy().tolist(), y_pred), "y", "y_pred")
165
+ loss = self._cal_loss(generated_y, y_batch)
166
+ loss_val = self._cal_loss(generated_y_val, y_batch_val)
167
+ clear_output(wait=True)
168
+ metrics_list = [
169
+ ("Epoch", f"{epoch}"),
170
+ ("Loss", f"{loss:.2f} / {loss_val:.2f}"),
171
+ ("Accuracy", f"{metrics['accuracy']:.2f} / {metrics['accuracy']:.2f}"),
172
+ ("Precision", f"{metrics['precision']:.2f} / {metrics['precision']:.2f}"),
173
+ ("Recall", f"{metrics['recall']:.2f} / {metrics['recall']:.2f}"),
174
+ ("F1 Score", f"{metrics['f1_score']:.2f} / {metrics['f1_score']:.2f}"),
175
+ ("Kappa", f"{metrics['kappa']:.2f} / {metrics['kappa']:.2f}"),
176
+ ]
177
+
178
+ metric_width = 15
179
+ value_width = 30
180
+
181
+ header = f"| {'Metric':<{metric_width}} | {'Value':<{value_width}} |"
182
+ separator = "+" + "-" * (len(header) - 2) + "+"
183
+
184
+ print(separator)
185
+ print(header)
186
+ print(separator)
187
+
188
+ for metric_name, metric_values in metrics_list:
189
+ data_row = f"| {metric_name:<{metric_width}} | {metric_values:<{value_width}} |"
190
+ print(data_row)
191
+
192
+ print(separator)
193
+
194
+ return pd.DataFrame(loss_history, columns=["epoch", "loss"])
195
+
196
+ def _get_frame(self, y, y_pred):
197
+ df = pd.DataFrame()
198
+ df["y"] = y
199
+ df["y_pred"] = y_pred
200
+ return df
201
+
202
+ def _train_and_val(self, X, y, validation_split):
203
+ split = int((1 - validation_split) * len(X))
204
+
205
+ if len(X) > split and split > 0:
206
+ X_train = X[:split]
207
+ y_train = y[:split]
208
+ X_val = X[split:]
209
+ y_val = y[split:]
210
+ else:
211
+ X_train = X
212
+ y_train = y
213
+ X_val = X
214
+ y_val = y
215
+
216
+ X_train = tf.cast(X_train, "float32")
217
+ X_val = tf.cast(X_val, "float32")
218
+
219
+ return X_train, y_train, X_val, y_val
220
+
221
+ def _cal_loss(self, generated, y):
222
+ return tf.math.reduce_mean(100 * abs((y - generated) / y), keepdims=False).numpy()
223
+
224
+ def train_gen(
225
+ self,
226
+ X_train,
227
+ y_train,
228
+ batch_size,
229
+ n_epochs,
230
+ validation_split=0.2,
231
+ patience=3,
232
+ ):
233
+ """
234
+ Train the generator model.
235
+
236
+ Parameters
237
+ --------
238
+ X_train : array-like
239
+ Training data.
240
+ y_train : array-like
241
+ Training target data.
242
+ batch_size : int
243
+ Batch size for training.
244
+ n_epochs : int
245
+ Number of epochs for training.
246
+ validation_split : float, optional
247
+ Fraction of data to use for validation. Default is 0.2.
248
+ patience : int, optional
249
+ Number of epochs to wait before early stopping. Default is 3.
250
+
251
+ Returns
252
+ --------
253
+ history : pd.DataFrame
254
+ Training history.
255
+ """
256
+ callback = tf.keras.callbacks.EarlyStopping(monitor="val_loss", patience=patience)
257
+ # Prepare the target by extending it with its square
258
+ self.discriminator.trainable = False
259
+ y_train_extended = np.concatenate(
260
+ (
261
+ y_train.reshape(-1, self.output_shape_parm),
262
+ y_train.reshape(-1, self.output_shape_parm) ** 2,
263
+ ),
264
+ axis=1,
265
+ )
266
+
267
+ history = self.generator.fit(
268
+ X_train,
269
+ y_train_extended,
270
+ epochs=n_epochs,
271
+ batch_size=batch_size,
272
+ verbose=0,
273
+ validation_split=validation_split,
274
+ callbacks=[callback],
275
+ )
276
+
277
+ return pd.DataFrame(history.history)
278
+
279
+ def call(self, inputs):
280
+ return self.generator(inputs)[:, 0]
281
+
282
+ def get_config(self):
283
+ config = {
284
+ "input_shape_parm": self.input_shape_parm,
285
+ "output_shape_parm": self.output_shape_parm,
286
+ "num_neurons": self.num_neurons,
287
+ "activation": self.activation,
288
+ "depth": self.depth,
289
+ "dropout": self.dropout,
290
+ "generator": self.generator,
291
+ "discriminator": self.discriminator,
292
+ "gan": self.gan,
293
+ "l2_reg": self.l2_reg,
294
+ "optimizer": self.optimizer,
295
+ }
296
+ base_config = super(GANRegressor, self).get_config()
297
+ return dict(list(base_config.items()) + list(config.items()))
298
+
299
+ @classmethod
300
+ def from_config(cls, config):
301
+ return cls(
302
+ input_shape_parm=config["input_shape_parm"],
303
+ output_shape_parm=config["output_shape_parm"],
304
+ num_neurons=config["num_neurons"],
305
+ activation=config["activation"],
306
+ depth=config["depth"],
307
+ dropout=config["dropout"],
308
+ generator=config["generator"],
309
+ discriminator=config["discriminator"],
310
+ gan=config["gan"],
311
+ l2_reg=config["l2_reg"],
312
+ optimizer=config["optimizer"],
313
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: likelihood
3
- Version: 1.5.1
3
+ Version: 1.5.3
4
4
  Summary: A package that performs the maximum likelihood algorithm.
5
5
  Home-page: https://github.com/jzsmoreno/likelihood/
6
6
  Author: J. A. Moreno-Guerra
@@ -24,6 +24,7 @@ Requires-Dist: numpy<2.0.0
24
24
  Requires-Dist: pydot==2.0.0
25
25
  Requires-Dist: matplotlib
26
26
  Requires-Dist: graphviz
27
+ Requires-Dist: seaborn
27
28
  Requires-Dist: pyyaml
28
29
  Requires-Dist: pandas
29
30
  Requires-Dist: corner
@@ -56,7 +57,7 @@ Dynamic: summary
56
57
  <!-- Project description -->
57
58
  This repository contains the code to build the [likelihood package](./likelihood/) which contains tools for typical tasks in maintain machine learning models in production and the training of custom models, for more information review our [`documentation`](https://jzsmoreno.github.io/likelihood/).
58
59
 
59
- ## Prerequisities
60
+ ## Prerequisites
60
61
 
61
62
  Before you begin, ensure you have met the following requirements:
62
63
 
@@ -8,16 +8,17 @@ likelihood/models/hmm.py,sha256=0s0gFySH1u4NjRaZDxiZ8oeTaFhFrw1x0GJxwy3dFrA,6253
8
8
  likelihood/models/regression.py,sha256=9cakyGlJCEO6WfpoKLh3GxdXQeQp7cUvJIkQ5odT0TA,9404
9
9
  likelihood/models/simulation.py,sha256=IkYGA6-L1LvSnIlyrVWTzQQu-JnfXml5Tewt-GC05PY,8446
10
10
  likelihood/models/utils.py,sha256=dvigPi_hxcs5ntfHr7Y1JvP5ULtMW3kkN0nJpS4orE8,1319
11
- likelihood/models/deep/__init__.py,sha256=-KIPippVaMqgG8mEgYjNxYQdqOUcFhUuKhbVe8TTCfo,28
11
+ likelihood/models/deep/__init__.py,sha256=m607FtMP2gAfPtM0mssFXMKyKOqoeYskZ_xIC6dKhr4,47
12
12
  likelihood/models/deep/autoencoders.py,sha256=0EIZwDNlZ9NCfQbhQ_KdXkkRwIjUEU-jk0l0u-J1wmA,44212
13
+ likelihood/models/deep/gan.py,sha256=aoSaNO5LvCU62cjxA0AxvnQvE7NSFtrp1Ta4EDJchpo,10874
13
14
  likelihood/tools/__init__.py,sha256=N1IhMDzacsGQT2MIYBMBC0zTxes78vC_0gGrwkuPgmg,78
14
15
  likelihood/tools/figures.py,sha256=waF0NHIMrctCmaLhcuz5DMcXyRKynmn6aG0XITYCTLc,10940
15
16
  likelihood/tools/impute.py,sha256=BwBVFSQkG3uWsZEk1THTmqZc3YhHlDhMXgKIV3sx5Lg,9486
16
17
  likelihood/tools/models_tools.py,sha256=c3-vac-1MYSarYDtfR6XfVC7X_WY9auS7y2_3Z973IQ,8875
17
18
  likelihood/tools/numeric_tools.py,sha256=OelCF45QO-zhanX3GmfcdYMfUZxYt353oJ8_gPEdWss,11959
18
19
  likelihood/tools/tools.py,sha256=vlQ-peK_z5-MLVnStxlBdl-NfmF6ILxZ6LhBd4K77JI,42282
19
- likelihood-1.5.1.dist-info/licenses/LICENSE,sha256=XWHWt9egYEUHGPTnlcZfJKLPmysacOwdiLj_-J7Z9ew,1066
20
- likelihood-1.5.1.dist-info/METADATA,sha256=s__LhxtBZXbQHaU-WQtpRvOmfnP7zZ1nqhI6I9IRNFA,2844
21
- likelihood-1.5.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
22
- likelihood-1.5.1.dist-info/top_level.txt,sha256=KDiBLr870YTxqLFqObTOSrTK10uw8dFsITSNLlte3PA,11
23
- likelihood-1.5.1.dist-info/RECORD,,
20
+ likelihood-1.5.3.dist-info/licenses/LICENSE,sha256=XWHWt9egYEUHGPTnlcZfJKLPmysacOwdiLj_-J7Z9ew,1066
21
+ likelihood-1.5.3.dist-info/METADATA,sha256=K7CXRIaJbwKyvGzwouhojx8ARZinAgEpaZdMb912c_c,2866
22
+ likelihood-1.5.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
23
+ likelihood-1.5.3.dist-info/top_level.txt,sha256=KDiBLr870YTxqLFqObTOSrTK10uw8dFsITSNLlte3PA,11
24
+ likelihood-1.5.3.dist-info/RECORD,,