pyerualjetwork 4.1.6__py3-none-any.whl → 4.1.8__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.
- pyerualjetwork/__init__.py +2 -13
- pyerualjetwork/data_operations_cuda.py +21 -16
- pyerualjetwork/memory_operations.py +15 -20
- pyerualjetwork/plan.py +104 -136
- pyerualjetwork/plan_cuda.py +107 -118
- pyerualjetwork/planeat.py +28 -19
- pyerualjetwork/planeat_cuda.py +28 -20
- pyerualjetwork/visualizations.py +6 -4
- pyerualjetwork/visualizations_cuda.py +5 -2
- {pyerualjetwork-4.1.6.dist-info → pyerualjetwork-4.1.8.dist-info}/METADATA +1 -1
- pyerualjetwork-4.1.8.dist-info/RECORD +24 -0
- pyerualjetwork-4.1.6.dist-info/RECORD +0 -24
- {pyerualjetwork-4.1.6.dist-info → pyerualjetwork-4.1.8.dist-info}/WHEEL +0 -0
- {pyerualjetwork-4.1.6.dist-info → pyerualjetwork-4.1.8.dist-info}/top_level.txt +0 -0
pyerualjetwork/plan_cuda.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
"""
|
3
3
|
|
4
|
-
MAIN MODULE FOR
|
4
|
+
MAIN MODULE FOR PLAN_CUDA
|
5
5
|
|
6
|
-
PLAN document: https://github.com/HCB06/
|
7
|
-
|
6
|
+
PLAN document: https://github.com/HCB06/PyerualJetwork/blob/main/Welcome_to_PLAN/PLAN.pdf
|
7
|
+
PYERUALJETWORK document: https://github.com/HCB06/PyerualJetwork/blob/main/Welcome_to_PyerualJetwork/PYERUALJETWORK_USER_MANUEL_AND_LEGAL_INFORMATION(EN).pdf
|
8
8
|
|
9
9
|
@author: Hasan Can Beydili
|
10
10
|
@YouTube: https://www.youtube.com/@HasanCanBeydili
|
@@ -14,6 +14,7 @@ ANAPLAN document: https://github.com/HCB06/Anaplan/blob/main/Welcome_to_Anaplan/
|
|
14
14
|
"""
|
15
15
|
|
16
16
|
import cupy as cp
|
17
|
+
import numpy as np
|
17
18
|
from colorama import Fore
|
18
19
|
import math
|
19
20
|
|
@@ -24,6 +25,7 @@ from .loss_functions_cuda import binary_crossentropy, categorical_crossentropy
|
|
24
25
|
from .activation_functions_cuda import apply_activation, Softmax, all_activations
|
25
26
|
from .metrics_cuda import metrics
|
26
27
|
from .model_operations_cuda import get_acc, get_preds, get_preds_softmax
|
28
|
+
from .memory_operations import transfer_to_gpu, transfer_to_cpu, optimize_labels
|
27
29
|
from .visualizations_cuda import (
|
28
30
|
draw_neural_web,
|
29
31
|
update_neural_web_for_fit,
|
@@ -106,8 +108,6 @@ def fit(
|
|
106
108
|
numpyarray([num]): (Weight matrix).
|
107
109
|
"""
|
108
110
|
# Pre-checks
|
109
|
-
|
110
|
-
from memory_operations import transfer_to_gpu, transfer_to_cpu
|
111
111
|
|
112
112
|
if train_bar and val:
|
113
113
|
train_progress = initialize_loading_bar(total=len(x_train), ncols=71, desc='Fitting', bar_format=bar_format_normal)
|
@@ -188,45 +188,63 @@ def fit(
|
|
188
188
|
return normalization(LTPW, dtype=dtype)
|
189
189
|
|
190
190
|
|
191
|
-
def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', batch_size=1,
|
191
|
+
def learner(x_train, y_train, optimizer, x_test=None, y_test=None, strategy='accuracy', gen=None, batch_size=1,
|
192
192
|
neural_web_history=False, show_current_activations=False, auto_normalization=True,
|
193
|
-
neurons_history=False,
|
194
|
-
early_stop=False, loss='categorical_crossentropy', show_history=False,
|
193
|
+
neurons_history=False, early_stop=False, loss='categorical_crossentropy', show_history=False,
|
195
194
|
interval=33.33, target_acc=None, target_loss=None, except_this=None,
|
196
|
-
only_this=None,
|
195
|
+
only_this=None, start_this_act=None, start_this_W=None, target_fitness='max', dtype=cp.float32, memory='gpu'):
|
197
196
|
"""
|
198
197
|
Optimizes the activation functions for a neural network by leveraging train data to find
|
199
198
|
the most accurate combination of activation potentiation for the given dataset.
|
200
199
|
|
200
|
+
Why genetic optimization and not backpropagation?
|
201
|
+
Because PLAN is different from other neural network architectures. In PLAN, the learnable parameters are not the weights; instead, the learnable parameters are the activation functions.
|
202
|
+
Since activation functions are not differentiable, we cannot use gradient descent or backpropagation. However, I developed a more powerful genetic optimization algorithm: PLANEAT.
|
203
|
+
|
201
204
|
Args:
|
202
205
|
|
203
206
|
x_train (array-like): Training input data.
|
204
207
|
|
205
208
|
y_train (array-like): Labels for training data.
|
206
209
|
|
210
|
+
optimizer (function): PLAN optimization technique with hyperparameters. (PLAN using NEAT(PLANEAT) for optimization.) Please use this: from pyerualjetwork import planeat_cuda (and) optimizer = lambda *args, **kwargs: planeat_cuda.evolve(*args, 'here give your neat hyperparameters for example: activation_add_prob=0.85', **kwargs) Example:
|
211
|
+
```python
|
212
|
+
genetic_optimizer = lambda *args, **kwargs: planeat_cuda.evolve(*args,
|
213
|
+
activation_add_prob=0.85,
|
214
|
+
mutations=False,
|
215
|
+
strategy='cross_over',
|
216
|
+
**kwargs)
|
217
|
+
|
218
|
+
model = plan_cuda.learner(x_train,
|
219
|
+
y_train,
|
220
|
+
optimizer=genetic_optimizer,
|
221
|
+
strategy='accuracy',
|
222
|
+
show_history=True,
|
223
|
+
target_acc=0.94,
|
224
|
+
interval=16.67)
|
225
|
+
```
|
226
|
+
|
207
227
|
x_test (array-like, optional): Test input data (for improve next gen generilization). If test data is not given then train feedback learning active
|
208
228
|
|
209
229
|
y_test (array-like, optional): Test Labels (for improve next gen generilization). If test data is not given then train feedback learning active
|
210
230
|
|
211
|
-
strategy (str, optional): Learning strategy. (options: 'accuracy', '
|
231
|
+
strategy (str, optional): Learning strategy. (options: 'accuracy', 'f1', 'precision', 'recall'): 'accuracy', Maximizes train (or test if given) accuracy during learning. 'f1', Maximizes train (or test if given) f1 score during learning. 'precision', Maximizes train (or test if given) precision score during learning. 'recall', Maximizes train (or test if given) recall during learning. Default is 'accuracy'.
|
212
232
|
|
213
233
|
patience ((int, float), optional): patience value for adaptive strategies. For 'adaptive_accuracy' Default value: 5. For 'adaptive_loss' Default value: 0.150.
|
214
234
|
|
215
|
-
|
235
|
+
gen (int, optional): The generation count for genetic optimization.
|
216
236
|
|
217
237
|
batch_size (float, optional): Batch size is used in the prediction process to receive test feedback by dividing the test data into chunks and selecting activations based on randomly chosen partitions. This process reduces computational cost and time while still covering the entire test set due to random selection, so it doesn't significantly impact accuracy. For example, a batch size of 0.08 means each test batch represents 8% of the test set. Default is 1. (%100 of test)
|
218
238
|
|
219
239
|
auto_normalization (bool, optional): If auto normalization=False this makes more faster training times and much better accuracy performance for some datasets. Default is True.
|
220
240
|
|
221
|
-
|
222
|
-
|
223
|
-
early_stop (bool, optional): If True, implements early stopping during training.(If test accuracy not improves in two depth stops learning.) Default is False.
|
241
|
+
early_stop (bool, optional): If True, implements early stopping during training.(If test accuracy not improves in two gen stops learning.) Default is False.
|
224
242
|
|
225
243
|
show_current_activations (bool, optional): Should it display the activations selected according to the current strategies during learning, or not? (True or False) This can be very useful if you want to cancel the learning process and resume from where you left off later. After canceling, you will need to view the live training activations in order to choose the activations to be given to the 'start_this' parameter. Default is False
|
226
244
|
|
227
245
|
show_history (bool, optional): If True, displays the training history after optimization. Default is False.
|
228
246
|
|
229
|
-
loss (str, optional): For visualizing and monitoring. PLAN neural networks doesn't need any loss function in training
|
247
|
+
loss (str, optional): For visualizing and monitoring. PLAN neural networks doesn't need any loss function in training. options: ('categorical_crossentropy' or 'binary_crossentropy') Default is 'categorical_crossentropy'.
|
230
248
|
|
231
249
|
interval (int, optional): The interval at which evaluations are conducted during training. (33.33 = 30 FPS, 16.67 = 60 FPS) Default is 100.
|
232
250
|
|
@@ -238,8 +256,10 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
238
256
|
|
239
257
|
only_this (list, optional): A list of activations to focus on during optimization. Default is None. (For avaliable activation functions, run this code: plan.activations_list())
|
240
258
|
|
241
|
-
|
259
|
+
start_this_act (list, optional): To resume a previously canceled or interrupted training from where it left off, or to continue from that point with a different strategy, provide the list of activation functions selected up to the learned portion to this parameter. Default is None
|
242
260
|
|
261
|
+
start_this_W (cupy.array, optional): To resume a previously canceled or interrupted training from where it left off, or to continue from that point with a different strategy, provide the weight matrix of this genome. Default is None
|
262
|
+
|
243
263
|
neurons_history (bool, optional): Shows the history of changes that neurons undergo during the TFL (Test or Train Feedback Learning) stages. True or False. Default is False.
|
244
264
|
|
245
265
|
neural_web_history (bool, optional): Draws history of neural web. Default is False.
|
@@ -252,18 +272,20 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
252
272
|
tuple: A list for model parameters: [Weight matrix, Preds, Accuracy, [Activations functions]]. You can acces this parameters in model_operations module. For example: model_operations.get_weights() for Weight matrix.
|
253
273
|
|
254
274
|
"""
|
255
|
-
from memory_operations import transfer_to_gpu, transfer_to_cpu
|
256
275
|
|
257
|
-
print(Fore.WHITE + "\nRemember, optimization on large datasets can be very time-consuming and computationally expensive. Therefore, if you are working with such a dataset, our recommendation is to include activation function: ['circular'] in the 'except_this' parameter unless absolutely necessary, as they can significantly prolong the process. from: learner\n" + Fore.RESET)
|
276
|
+
print(Fore.WHITE + "\nRemember, optimization on large datasets can be very time-consuming and computationally expensive. Therefore, if you are working with such a dataset, our recommendation is to include activation function: ['circular', 'spiral'] in the 'except_this' parameter unless absolutely necessary, as they can significantly prolong the process. from: learner\n" + Fore.RESET)
|
258
277
|
|
259
278
|
activation_potentiation = all_activations()
|
260
279
|
|
280
|
+
y_train = optimize_labels(y_train, cuda=True)
|
281
|
+
|
261
282
|
if x_test is None and y_test is None:
|
262
283
|
x_test = x_train
|
263
284
|
y_test = y_train
|
264
285
|
data = 'Train'
|
265
286
|
else:
|
266
287
|
data = 'Test'
|
288
|
+
y_test = optimize_labels(y_test, cuda=True)
|
267
289
|
|
268
290
|
if memory == 'gpu':
|
269
291
|
x_train = transfer_to_gpu(x_train, dtype=dtype)
|
@@ -272,7 +294,7 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
272
294
|
x_test = transfer_to_gpu(x_test, dtype=dtype)
|
273
295
|
y_test = transfer_to_gpu(y_test, dtype=y_train.dtype)
|
274
296
|
|
275
|
-
from data_operations_cuda import batcher
|
297
|
+
from .data_operations_cuda import batcher
|
276
298
|
|
277
299
|
elif memory == 'cpu':
|
278
300
|
x_train = transfer_to_cpu(x_train, dtype=dtype)
|
@@ -281,57 +303,45 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
281
303
|
x_test = transfer_to_cpu(x_test, dtype=dtype)
|
282
304
|
y_test = transfer_to_cpu(y_test, dtype=y_train.dtype)
|
283
305
|
|
284
|
-
from data_operations import batcher
|
306
|
+
from .data_operations import batcher
|
285
307
|
|
286
308
|
else:
|
287
309
|
raise ValueError("memory parameter must be 'cpu' or 'gpu'.")
|
288
310
|
|
289
|
-
|
290
|
-
if early_shifting != False:
|
291
|
-
shift_patience = early_shifting
|
292
|
-
|
293
|
-
# Strategy initialization
|
294
|
-
if strategy == 'adaptive_accuracy':
|
295
|
-
strategy = 'accuracy'
|
296
|
-
adaptive = True
|
297
|
-
if patience == None:
|
298
|
-
patience = 5
|
299
|
-
elif strategy == 'adaptive_loss':
|
300
|
-
strategy = 'loss'
|
301
|
-
adaptive = True
|
302
|
-
if patience == None:
|
303
|
-
patience = 0.150
|
304
|
-
else:
|
305
|
-
adaptive = False
|
311
|
+
if strategy != 'accuracy' and strategy != 'f1' and strategy != 'recall' and strategy != 'precision': raise ValueError("Strategy parameter only be 'accuracy' or 'f1' or 'recall' or 'precision'.")
|
306
312
|
|
307
313
|
# Filter activation functions
|
308
|
-
if only_this
|
314
|
+
if only_this is not None:
|
309
315
|
activation_potentiation = only_this
|
310
|
-
if except_this
|
316
|
+
if except_this is not None:
|
311
317
|
activation_potentiation = [item for item in activation_potentiation if item not in except_this]
|
312
|
-
if
|
313
|
-
|
318
|
+
if gen is None:
|
319
|
+
gen = len(activation_potentiation)
|
314
320
|
|
321
|
+
if start_this_act is None and len(activation_potentiation) % 2 != 0: raise ValueError("Activation length must be even number. Please use 'except_this' parameter and except some activation. For example: except_this=['linear']")
|
322
|
+
if start_this_act is not None and len(activation_potentiation) + 1 % 2 != 0: raise ValueError("You are using start_this parameter, activation length still must be even number. Please use 'except_this' parameter and except some activation. For example: except_this=['linear']")
|
323
|
+
|
315
324
|
# Initialize visualization components
|
316
325
|
viz_objects = initialize_visualization_for_learner(show_history, neurons_history, neural_web_history, x_train, y_train)
|
317
326
|
|
318
327
|
# Initialize progress bar
|
319
328
|
if batch_size == 1:
|
320
|
-
ncols =
|
329
|
+
ncols = 86
|
321
330
|
else:
|
322
|
-
ncols =
|
323
|
-
progress = initialize_loading_bar(total=len(activation_potentiation), desc="", ncols=ncols, bar_format=bar_format_learner)
|
331
|
+
ncols = 99
|
324
332
|
|
325
333
|
# Initialize variables
|
326
|
-
|
327
|
-
|
328
|
-
|
334
|
+
act_pop = []
|
335
|
+
weight_pop = []
|
336
|
+
|
337
|
+
if start_this_act is None and start_this_W is None:
|
329
338
|
best_acc = 0
|
330
339
|
else:
|
331
|
-
|
340
|
+
act_pop.append(start_this_act)
|
341
|
+
weight_pop.append(start_this_W)
|
342
|
+
|
332
343
|
x_test_batch, y_test_batch = batcher(x_test, y_test, batch_size=batch_size)
|
333
|
-
|
334
|
-
model = evaluate(x_test_batch, y_test_batch, W=W, loading_bar_status=False, activation_potentiation=activations, dtype=dtype, memory=memory)
|
344
|
+
model = evaluate(x_test_batch, y_test_batch, W=start_this_W, loading_bar_status=False, activation_potentiation=act_pop, dtype=dtype, memory=memory)
|
335
345
|
|
336
346
|
if loss == 'categorical_crossentropy':
|
337
347
|
test_loss = categorical_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
@@ -341,12 +351,15 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
341
351
|
best_acc = model[get_acc()]
|
342
352
|
best_loss = test_loss
|
343
353
|
|
344
|
-
|
354
|
+
best_acc_per_gen_list = []
|
345
355
|
postfix_dict = {}
|
346
356
|
loss_list = []
|
347
|
-
|
348
|
-
|
349
|
-
|
357
|
+
target_pop = []
|
358
|
+
|
359
|
+
progress = initialize_loading_bar(total=len(activation_potentiation), desc="", ncols=ncols, bar_format=bar_format_learner)
|
360
|
+
|
361
|
+
for i in range(gen):
|
362
|
+
postfix_dict["Gen"] = str(i+1) + '/' + str(gen)
|
350
363
|
progress.set_postfix(postfix_dict)
|
351
364
|
|
352
365
|
progress.n = 0
|
@@ -354,79 +367,65 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
354
367
|
progress.update(0)
|
355
368
|
|
356
369
|
for j in range(len(activation_potentiation)):
|
357
|
-
for k in range(len(best_activations)):
|
358
|
-
activations.append(best_activations[k])
|
359
|
-
|
360
|
-
activations.append(activation_potentiation[j])
|
361
370
|
|
362
371
|
x_test_batch, y_test_batch = batcher(x_test, y_test, batch_size=batch_size)
|
363
|
-
|
364
|
-
|
372
|
+
|
373
|
+
if i == 0:
|
374
|
+
act_pop.append(activation_potentiation[j])
|
375
|
+
W = fit(x_train, y_train, activation_potentiation=act_pop[-1], train_bar=False, auto_normalization=auto_normalization, dtype=dtype)
|
376
|
+
weight_pop.append(W)
|
365
377
|
|
366
|
-
|
378
|
+
model = evaluate(x_test_batch, y_test_batch, W=weight_pop[j], loading_bar_status=False, activation_potentiation=act_pop[j], dtype=dtype, memory=memory)
|
367
379
|
|
368
|
-
|
369
|
-
|
370
|
-
test_loss = categorical_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
371
|
-
else:
|
372
|
-
test_loss = binary_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
380
|
+
acc = model[get_acc()]
|
381
|
+
if strategy == 'accuracy': target_pop.append(acc)
|
373
382
|
|
374
|
-
|
375
|
-
|
383
|
+
elif strategy == 'f1' or strategy == 'precision' or strategy == 'recall':
|
384
|
+
precision_score, recall_score, f1_score = metrics(y_test_batch, model[get_preds()])
|
376
385
|
|
377
|
-
|
378
|
-
|
386
|
+
if strategy == 'precision':
|
387
|
+
target_pop.append(precision_score)
|
379
388
|
|
380
|
-
if strategy == 'precision' or strategy == 'all':
|
381
389
|
if i == 0 and j == 0:
|
382
390
|
best_precision = precision_score
|
383
391
|
|
384
|
-
if strategy == 'recall'
|
392
|
+
if strategy == 'recall':
|
393
|
+
target_pop.append(recall_score)
|
394
|
+
|
385
395
|
if i == 0 and j == 0:
|
386
396
|
best_recall = recall_score
|
387
397
|
|
388
|
-
if strategy == 'f1'
|
398
|
+
if strategy == 'f1':
|
399
|
+
target_pop.append(f1_score)
|
400
|
+
|
389
401
|
if i == 0 and j == 0:
|
390
402
|
best_f1 = f1_score
|
391
403
|
|
392
|
-
if early_shifting != False:
|
393
|
-
if acc <= best_acc:
|
394
|
-
early_shifting -= 1
|
395
|
-
if early_shifting == 0:
|
396
|
-
early_shifting = shift_patience
|
397
|
-
break
|
398
|
-
|
399
404
|
if ((strategy == 'accuracy' and acc >= best_acc) or
|
400
|
-
(strategy == 'loss' and test_loss <= best_loss) or
|
401
405
|
(strategy == 'f1' and f1_score >= best_f1) or
|
402
406
|
(strategy == 'precision' and precision_score >= best_precision) or
|
403
|
-
(strategy == 'recall' and recall_score >= best_recall)
|
404
|
-
(strategy == 'all' and f1_score >= best_f1 and acc >= best_acc and
|
405
|
-
test_loss <= best_loss and precision_score >= best_precision and
|
406
|
-
recall_score >= best_recall)):
|
407
|
+
(strategy == 'recall' and recall_score >= best_recall)):
|
407
408
|
|
408
|
-
current_best_activation = activation_potentiation[j]
|
409
409
|
best_acc = acc
|
410
|
-
|
410
|
+
best_weights = weight_pop[j]
|
411
|
+
final_activations = act_pop[j]
|
412
|
+
best_model = model
|
413
|
+
|
414
|
+
final_activations = [final_activations[0]] if len(set(final_activations)) == 1 else final_activations # removing if all same
|
415
|
+
|
411
416
|
if batch_size == 1:
|
412
417
|
postfix_dict[f"{data} Accuracy"] = best_acc
|
413
418
|
else:
|
414
419
|
postfix_dict[f"{data} Batch Accuracy"] = acc
|
415
420
|
progress.set_postfix(postfix_dict)
|
416
|
-
|
417
|
-
final_activations = activations
|
418
421
|
|
419
422
|
if show_current_activations:
|
420
423
|
print(f", Current Activations={final_activations}", end='')
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
if loss == 'categorical_crossentropy':
|
427
|
-
test_loss = categorical_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
428
|
-
else:
|
429
|
-
test_loss = binary_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
424
|
+
|
425
|
+
if loss == 'categorical_crossentropy':
|
426
|
+
test_loss = categorical_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
427
|
+
else:
|
428
|
+
test_loss = binary_crossentropy(y_true_batch=transfer_to_gpu(y_test_batch, dtype=y_test_batch.dtype), y_pred_batch=model[get_preds_softmax()])
|
430
429
|
|
431
430
|
if batch_size == 1:
|
432
431
|
postfix_dict[f"{data} Loss"] = test_loss
|
@@ -438,9 +437,9 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
438
437
|
|
439
438
|
# Update visualizations during training
|
440
439
|
if show_history:
|
441
|
-
|
442
|
-
update_history_plots_for_learner(viz_objects,
|
443
|
-
|
440
|
+
gen_list = range(1, len(best_acc_per_gen_list) + 2)
|
441
|
+
update_history_plots_for_learner(viz_objects, gen_list, loss_list + [test_loss],
|
442
|
+
best_acc_per_gen_list + [best_acc], x_train, final_activations)
|
444
443
|
|
445
444
|
if neurons_history:
|
446
445
|
viz_objects['neurons']['artists'] = (
|
@@ -508,28 +507,19 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
508
507
|
return best_weights, best_model[get_preds()], best_acc, final_activations
|
509
508
|
|
510
509
|
progress.update(1)
|
511
|
-
activations = []
|
512
510
|
|
513
|
-
|
514
|
-
best_acc_per_depth_list.append(best_acc)
|
511
|
+
best_acc_per_gen_list.append(best_acc)
|
515
512
|
loss_list.append(best_loss)
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
check = best_acc_per_depth_list[-patience:]
|
520
|
-
if all(x == check[0] for x in check):
|
521
|
-
strategy = 'loss'
|
522
|
-
adaptive = False
|
523
|
-
elif adaptive == True and strategy == 'loss' and best_loss <= patience:
|
524
|
-
strategy = 'accuracy'
|
525
|
-
adaptive = False
|
513
|
+
|
514
|
+
weight_pop, act_pop = optimizer(cp.array(weight_pop, dtype=dtype), act_pop, i, cp.array(target_pop, dtype=dtype, copy=False), target_fitness=target_fitness, bar_status=False)
|
515
|
+
target_pop = []
|
526
516
|
|
527
517
|
# Early stopping check
|
528
518
|
if early_stop == True and i > 0:
|
529
|
-
if
|
519
|
+
if best_acc_per_gen_list[i] == best_acc_per_gen_list[i-1]:
|
530
520
|
progress.close()
|
531
521
|
train_model = evaluate(x_train, y_train, W=best_weights, loading_bar_status=False,
|
532
|
-
activation_potentiation=final_activations, dtype=dtype)
|
522
|
+
activation_potentiation=final_activations, dtype=dtype, memory=memory)
|
533
523
|
|
534
524
|
if loss == 'categorical_crossentropy':
|
535
525
|
train_loss = categorical_crossentropy(y_true_batch=y_train,
|
@@ -553,7 +543,7 @@ def learner(x_train, y_train, x_test=None, y_test=None, strategy='accuracy', bat
|
|
553
543
|
# Final evaluation
|
554
544
|
progress.close()
|
555
545
|
train_model = evaluate(x_train, y_train, W=best_weights, loading_bar_status=False,
|
556
|
-
activation_potentiation=final_activations, dtype=dtype)
|
546
|
+
activation_potentiation=final_activations, dtype=dtype, memory=memory)
|
557
547
|
|
558
548
|
if loss == 'categorical_crossentropy':
|
559
549
|
train_loss = categorical_crossentropy(y_true_batch=y_train, y_pred_batch=train_model[get_preds_softmax()])
|
@@ -652,7 +642,6 @@ def evaluate(
|
|
652
642
|
Returns:
|
653
643
|
tuple: Model (list).
|
654
644
|
"""
|
655
|
-
from memory_operations import transfer_to_cpu, transfer_to_gpu
|
656
645
|
|
657
646
|
if memory == 'gpu':
|
658
647
|
x_test = transfer_to_gpu(x_test, dtype=dtype)
|
pyerualjetwork/planeat.py
CHANGED
@@ -17,7 +17,7 @@ from tqdm import tqdm
|
|
17
17
|
### LIBRARY IMPORTS ###
|
18
18
|
from .plan import feed_forward
|
19
19
|
from .data_operations import normalization
|
20
|
-
from .ui import loading_bars
|
20
|
+
from .ui import loading_bars, initialize_loading_bar
|
21
21
|
from .activation_functions import apply_activation, all_activations
|
22
22
|
|
23
23
|
def define_genomes(input_shape, output_shape, population_size, dtype=np.float32):
|
@@ -66,10 +66,10 @@ def define_genomes(input_shape, output_shape, population_size, dtype=np.float32)
|
|
66
66
|
population_weights[i][j,:] = apply_activation(population_weights[i][j,:], population_activations[i])
|
67
67
|
population_weights[i][j,:] = normalization(population_weights[i][j,:], dtype=dtype)
|
68
68
|
|
69
|
-
return np.array(population_weights), population_activations
|
69
|
+
return np.array(population_weights, dtype=dtype), population_activations
|
70
70
|
|
71
71
|
|
72
|
-
def evolve(weights, activation_potentiations, what_gen,
|
72
|
+
def evolve(weights, activation_potentiations, what_gen, fitness, show_info=False, strategy='cross_over', bar_status=True, policy='normal_selective', target_fitness='max', mutations=True, bad_genoms_mutation_prob=None, activation_mutate_prob=0.5, save_best_genom=True, cross_over_mode='tpm', activation_add_prob=0.5, activation_delete_prob=0.5, activation_change_prob=0.5, weight_mutate_prob=1, weight_mutate_rate=32, activation_selection_add_prob=0.7, activation_selection_change_prob=0.5, activation_selection_rate=2, dtype=np.float32):
|
73
73
|
"""
|
74
74
|
Applies the evolving process of a population of genomes using selection, crossover, mutation, and activation function potentiation.
|
75
75
|
The function modifies the population's weights and activation functions based on a specified policy, mutation probabilities, and strategy.
|
@@ -83,8 +83,8 @@ Args:
|
|
83
83
|
|
84
84
|
what_gen (int): The current generation number, used for informational purposes or logging.
|
85
85
|
|
86
|
-
|
87
|
-
The array is used to rank the genomes based on their performance. PLANEAT maximizes
|
86
|
+
fitness (numpy.ndarray): A 1D array containing the fitness values of each genome.
|
87
|
+
The array is used to rank the genomes based on their performance. PLANEAT maximizes or minimizes this fitness for looking 'target' hyperparameter.
|
88
88
|
|
89
89
|
show_info (bool, optional): If True, prints information about the current generation and the
|
90
90
|
maximum reward obtained. Also shows the current configuration. Default is False.
|
@@ -96,12 +96,16 @@ Args:
|
|
96
96
|
(PLAN feature, similar to arithmetic crossover but different.)
|
97
97
|
Default is 'cross_over'.
|
98
98
|
|
99
|
+
bar_status (bool, optional): Loading bar status during evolving process of genomes. True or False. Default: True
|
100
|
+
|
99
101
|
policy (str, optional): The selection policy that governs how genomes are selected for reproduction. Options:
|
100
102
|
- 'normal_selective': Normal selection based on reward, where a portion of the bad genes are discarded.
|
101
103
|
- 'more_selective': A more selective policy, where fewer bad genes survive.
|
102
104
|
- 'less_selective': A less selective policy, where more bad genes survive.
|
103
105
|
Default is 'normal_selective'.
|
104
106
|
|
107
|
+
target_fitness (str, optional): Target fitness strategy for PLANEAT optimization. ('max' for machine learning, 'min' for machine unlearning.) Default: 'max'
|
108
|
+
|
105
109
|
mutations (bool, optional): If True, mutations are applied to the bad genomes and potentially
|
106
110
|
to the best genomes as well. Default is True.
|
107
111
|
|
@@ -139,7 +143,7 @@ Args:
|
|
139
143
|
WARNING: if you don't understand do NOT change this value. Default is 32.
|
140
144
|
|
141
145
|
activation_selection_add_prob (float, optional): The probability of adding an existing activation function for cross over.
|
142
|
-
from the genome. Must be in the range [0, 1]. Default is 0.
|
146
|
+
from the genome. Must be in the range [0, 1]. Default is 0.7. (WARNING! More higher values make models more complex. For fast training rise this value.)
|
143
147
|
|
144
148
|
activation_selection_change_prob (float, optional): The probability of changing an activation function in the genome for cross over.
|
145
149
|
Must be in the range [0, 1]. Default is 0.5.
|
@@ -163,7 +167,7 @@ Returns:
|
|
163
167
|
|
164
168
|
Notes:
|
165
169
|
- **Selection Process**:
|
166
|
-
- The genomes are sorted by their fitness (based on `
|
170
|
+
- The genomes are sorted by their fitness (based on `fitness`), and then split into "best" and "bad" halves.
|
167
171
|
- The best genomes are retained, and the bad genomes are modified based on the selected strategy.
|
168
172
|
|
169
173
|
- **Crossover and Potentiation Strategies**:
|
@@ -175,13 +179,13 @@ Notes:
|
|
175
179
|
- `bad_genoms_mutation_prob` determines the probability of applying mutations to the bad genomes.
|
176
180
|
- If `activation_mutate_prob` is provided, activation function mutations are applied to the genomes based on this probability.
|
177
181
|
|
178
|
-
- **Population Size**: The population size must be an even number to properly split the best and bad genomes. If `
|
182
|
+
- **Population Size**: The population size must be an even number to properly split the best and bad genomes. If `fitness` has an odd length, an error is raised.
|
179
183
|
|
180
184
|
- **Logging**: If `show_info=True`, the current generation and the maximum reward from the population are printed for tracking the learning progress.
|
181
185
|
|
182
186
|
Example:
|
183
187
|
```python
|
184
|
-
weights, activation_potentiations =
|
188
|
+
weights, activation_potentiations = planeat.evolve(weights, activation_potentiations, 1, fitness, show_info=True, strategy='cross_over', policy='normal_selective')
|
185
189
|
```
|
186
190
|
|
187
191
|
- The function returns the updated weights and activations after processing based on the chosen strategy, policy, and mutation parameters.
|
@@ -219,17 +223,19 @@ Example:
|
|
219
223
|
if not isinstance(activation_mutate_prob, float) or activation_mutate_prob < 0 or activation_mutate_prob > 1:
|
220
224
|
raise ValueError("activation_mutate_prob parameter must be float and 0-1 range")
|
221
225
|
|
222
|
-
if len(
|
223
|
-
slice_center = int(len(
|
226
|
+
if len(fitness) % 2 == 0:
|
227
|
+
slice_center = int(len(fitness) / 2)
|
224
228
|
|
225
229
|
else:
|
226
230
|
raise ValueError("genome population size must be even number. for example: not 99, make 100 or 98.")
|
227
231
|
|
228
|
-
|
232
|
+
|
233
|
+
### FITNESS IS SORTED IN ASCENDING (OR DESCENDING) ORDER, AND THE WEIGHT AND ACTIVATIONS OF EACH GENOME ARE SORTED ACCORDING TO THIS ORDER:
|
229
234
|
|
230
|
-
|
235
|
+
if target_fitness == 'max': sort_indices = np.argsort(fitness)
|
236
|
+
elif target_fitness == 'min': sort_indices = np.argsort(-fitness)
|
231
237
|
|
232
|
-
|
238
|
+
fitness = fitness[sort_indices]
|
233
239
|
weights = weights[sort_indices]
|
234
240
|
|
235
241
|
activation_potentiations = [activation_potentiations[i] for i in sort_indices]
|
@@ -249,7 +255,9 @@ Example:
|
|
249
255
|
|
250
256
|
bar_format = loading_bars()[0]
|
251
257
|
|
252
|
-
|
258
|
+
if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50, ascii="▱▰")
|
259
|
+
|
260
|
+
for i in range(len(bad_weights)):
|
253
261
|
|
254
262
|
if policy == 'normal_selective':
|
255
263
|
|
@@ -313,7 +321,8 @@ Example:
|
|
313
321
|
|
314
322
|
elif mutation_prob < bad_genoms_mutation_prob:
|
315
323
|
bad_weights[i], bad_activations[i] = mutation(bad_weights[i], bad_activations[i], activation_mutate_prob=activation_mutate_prob, activation_add_prob=activation_add_prob, activation_delete_prob=activation_delete_prob, activation_change_prob=activation_change_prob, weight_mutate_prob=weight_mutate_prob, threshold=weight_mutate_rate, dtype=dtype)
|
316
|
-
|
324
|
+
|
325
|
+
if bar_status: progress.update(1)
|
317
326
|
|
318
327
|
weights = np.vstack((bad_weights, best_weights))
|
319
328
|
activation_potentiations = bad_activations + best_activations
|
@@ -344,9 +353,9 @@ Example:
|
|
344
353
|
print(" ACTIVATION SELECTION RATE (THRESHOLD VALUE FOR SINGLE CROSS OVER):", str(activation_selection_rate) + '\n')
|
345
354
|
|
346
355
|
print("*** Performance ***")
|
347
|
-
print(" MAX
|
348
|
-
print(" MEAN
|
349
|
-
print(" MIN
|
356
|
+
print(" MAX FITNESS: ", str(round(max(fitness), 2)))
|
357
|
+
print(" MEAN FITNESS: ", str(round(np.mean(fitness), 2)))
|
358
|
+
print(" MIN FITNESS: ", str(round(min(fitness), 2)) + '\n')
|
350
359
|
|
351
360
|
print(" BEST GENOME INDEX: ", str(len(weights)-1))
|
352
361
|
print(" NOTE: Genomes are always sorted from the least successful to the most successful according to their performance ranking. Therefore, the genome at the last index is the king of the previous generation. " + '\n')
|