pyerualjetwork 4.2.0b0__py3-none-any.whl → 4.2.0b2__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/planeat.py CHANGED
@@ -1,6 +1,8 @@
1
1
  """
2
2
  MAIN MODULE FOR PLANEAT
3
3
 
4
+ Examples: https://github.com/HCB06/PyerualJetwork/tree/main/Welcome_to_PyerualJetwork/ExampleCodes
5
+
4
6
  ANAPLAN document: https://github.com/HCB06/Anaplan/blob/main/Welcome_to_Anaplan/ANAPLAN_USER_MANUEL_AND_LEGAL_INFORMATION(EN).pdf
5
7
 
6
8
  @author: Hasan Can Beydili
@@ -69,148 +71,195 @@ def define_genomes(input_shape, output_shape, population_size, dtype=np.float32)
69
71
  return np.array(population_weights, dtype=dtype), population_activations
70
72
 
71
73
 
72
- def evolver(weights, activation_potentiations, what_gen, fitness, show_info=False, strategy='cross_over', bad_genomes_selection_prob=None, bar_status=True, policy='normal_selective', target_fitness='max', mutations=True, bad_genomes_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):
74
+ def evolver(weights,
75
+ activation_potentiations,
76
+ what_gen,
77
+ fitness,
78
+ show_info=False,
79
+ policy='aggresive',
80
+ bad_genomes_selection_prob=None,
81
+ bar_status=True,
82
+ strategy='normal_selective',
83
+ target_fitness='max',
84
+ mutations=True,
85
+ bad_genomes_mutation_prob=None,
86
+ activation_mutate_prob=0.5,
87
+ save_best_genom=True,
88
+ fitness_bias=None,
89
+ cross_over_mode='tpm',
90
+ activation_mutate_add_prob=0.5,
91
+ activation_mutate_delete_prob=0.5,
92
+ activation_mutate_change_prob=0.5,
93
+ weight_mutate_prob=1,
94
+ weight_mutate_rate=32,
95
+ activation_selection_add_prob=0.6,
96
+ activation_selection_change_prob=0.4,
97
+ activation_selection_rate=2,
98
+ dtype=np.float32):
73
99
  """
74
- Applies the evolving process of a population of genomes using selection, crossover, mutation, and activation function potentiation.
75
- The function modifies the population's weights and activation functions based on a specified policy, mutation probabilities, and strategy.
100
+ Applies the evolving process of a population of genomes using selection, crossover, mutation, and activation function potentiation.
101
+ The function modifies the population's weights and activation functions based on a specified policy, mutation probabilities, and strategy.
76
102
 
77
- Args:
78
- weights (numpy.ndarray): Array of weights for each genome.
79
- (first returned value of define_genomes function)
80
-
81
- activation_potentiations (list): A list of activation functions for each genome.
82
- (second returned value of define_genomes function)
83
-
84
- what_gen (int): The current generation number, used for informational purposes or logging.
85
-
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
-
89
- show_info (bool, optional): If True, prints information about the current generation and the
90
- maximum reward obtained. Also shows the current configuration. Default is False.
91
-
92
- strategy (str, optional): The strategy for combining the best and bad genomes. Options:
93
- - 'cross_over': Perform crossover between the best genomes and replace bad genomes.
94
- (Classic NEAT crossover)
95
- - 'potentiate': Cumulate the weight of the best genomes and replace bad genomes.
96
- (PLAN feature, similar to arithmetic crossover but different.)
97
- Default is 'cross_over'.
98
-
99
- bar_status (bool, optional): Loading bar status during evolving process of genomes. True or False. Default: True
103
+ 'selection' args effects cross-over.
104
+ 'mutate' args effects mutation.
100
105
 
101
- policy (str, optional): The selection policy that governs how genomes are selected for reproduction. Options:
102
- - 'normal_selective': Normal selection based on reward, where a portion of the bad genes are discarded.
103
- - 'more_selective': A more selective policy, where fewer bad genes survive.
104
- - 'less_selective': A less selective policy, where more bad genes survive.
105
- Default is 'normal_selective'.
106
-
107
- target_fitness (str, optional): Target fitness strategy for PLANEAT optimization. ('max' for machine learning, 'min' for machine unlearning.) Default: 'max'
108
-
109
- mutations (bool, optional): If True, mutations are applied to the bad genomes and potentially
110
- to the best genomes as well. Default is True.
111
-
112
- bad_genomes_mutation_prob (float, optional): The probability of applying mutation to the bad genomes.
113
- Must be in the range [0, 1]. Also affects the mutation probability of the best genomes inversely.
114
- For example, a value of 0.7 for bad genomes implies 0.3 for best genomes. Default is None,
115
- which means it is determined by the `policy` argument.
116
-
117
- activation_mutate_prob (float, optional): The probability of applying mutation to the activation functions.
118
- Must be in the range [0, 1]. Default is 0.5 (50%).
119
-
120
- save_best_genom (bool, optional): If True, ensures that the best genomes are saved and not mutated
121
- or altered during reproduction. Default is True.
122
-
123
- cross_over_mode (str, optional): Specifies the crossover method to use. Options:
124
- - 'tpm': Two-Point Matrix Crossover
125
- - 'plantic': plantic Crossover
126
- Default is 'tpm'.
127
-
128
- activation_add_prob (float, optional): The probability of adding a new activation function to the genome for mutation.
129
- Must be in the range [0, 1]. Default is 0.5.
130
-
131
- activation_delete_prob (float, optional): The probability of deleting an existing activation function
132
- from the genome for mutation. Must be in the range [0, 1]. Default is 0.5.
133
-
134
- activation_change_prob (float, optional): The probability of changing an activation function in the genome for mutation.
135
- Must be in the range [0, 1]. Default is 0.5.
136
-
137
- weight_mutate_prob (float, optional): The probability of mutating a weight in the genome.
138
- Must be in the range [0, 1]. Default is 1.
139
-
140
- weight_mutate_rate (int, optional): If the value you enter here is equal to the result of input layer * output layer,
141
- only a single weight will be mutated during each mutation process. If the value you enter here is half
142
- of the result of input layer * output layer, two weights in the weight matrix will be mutated.
143
- WARNING: if you don't understand do NOT change this value. Default is 32.
106
+ Args:
107
+ weights (numpy.ndarray): Array of weights for each genome.
108
+ (first returned value of define_genomes function)
109
+
110
+ activation_potentiations (list): A list of activation functions for each genome.
111
+ (second returned value of define_genomes function)
112
+
113
+ what_gen (int): The current generation number, used for informational purposes or logging.
114
+
115
+ fitness (numpy.ndarray): A 1D array containing the fitness values of each genome.
116
+ The array is used to rank the genomes based on their performance. PLANEAT maximizes or minimizes this fitness based on the `target_fitness` parameter.
117
+
118
+ show_info (bool, optional): If True, prints information about the current generation and the
119
+ maximum reward obtained. Also shows the current configuration. Default is False.
120
+
121
+ strategy (str, optional): The strategy for combining the best and bad genomes. Options:
122
+ - 'normal_selective': Normal selection based on reward, where a portion of the bad genes are discarded.
123
+ - 'more_selective': A more selective strategy, where fewer bad genes survive.
124
+ - 'less_selective': A less selective strategy, where more bad genes survive.
125
+ Default is 'normal_selective'.
126
+
127
+ bar_status (bool, optional): Loading bar status during evolving process of genomes. True or False. Default: True
144
128
 
145
- activation_selection_add_prob (float, optional): The probability of adding an existing activation function for cross over.
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.)
147
-
148
- activation_selection_change_prob (float, optional): The probability of changing an activation function in the genome for cross over.
149
- Must be in the range [0, 1]. Default is 0.5.
150
-
151
- activation_selection_rate (int, optional): If the activation list of a good genome is smaller than the value entered here, only one activation will undergo a crossover operation. In other words, this parameter controls the model complexity. Default is 2.
152
-
153
- dtype (numpy.dtype): Data type for the arrays. np.float32 by default. Example: np.float64 or np.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
154
-
155
- Raises:
156
- ValueError:
157
- - If `policy` is not one of the specified values ('normal_selective', 'more_selective', 'less_selective').
158
- - If `cross_over_mode` is not one of the specified values ('tpm', 'plantic').
159
- - If `bad_genomes_mutation_prob`, `activation_mutate_prob`, or other probability parameters are not in the range [0, 1].
160
- - If the population size is odd (ensuring an even number of genomes is required for proper selection).
161
-
162
- Returns:
163
- tuple: A tuple containing:
164
- - weights (numpy.ndarray): The updated weights for the population after selection, crossover, and mutation.
165
- The shape is (population_size, output_shape, input_shape).
166
- - activation_potentiations (list): The updated list of activation functions for the population.
167
-
168
- Notes:
169
- - **Selection Process**:
170
- - The genomes are sorted by their fitness (based on `fitness`), and then split into "best" and "bad" halves.
171
- - The best genomes are retained, and the bad genomes are modified based on the selected strategy.
172
-
173
- - **Crossover and Potentiation Strategies**:
174
- - The **'cross_over'** strategy performs crossover, where parts of the best genomes' weights are combined with the other good genomes to create new weight matrices.
175
- - The **'potentiate'** strategy strengthens the best genomes by potentiating their weights towards the other good genomes.
176
-
177
- - **Mutation**:
178
- - Mutation is applied to both the best and bad genomes, depending on the mutation probability and the `policy`.
179
- - `bad_genomes_mutation_prob` determines the probability of applying mutations to the bad genomes.
180
- - If `activation_mutate_prob` is provided, activation function mutations are applied to the genomes based on this probability.
181
-
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.
183
-
184
- - **Logging**: If `show_info=True`, the current generation and the maximum reward from the population are printed for tracking the learning progress.
129
+ policy (str, optional): The selection policy that governs how genomes are selected for reproduction. Options:
130
+
131
+ - 'aggresive': Aggressive policy using very aggressive selection policy.
132
+ Advantages: fast training.
133
+ Disadvantages: may lead to fitness stuck in a local maximum or minimum.
185
134
 
186
- Example:
187
- ```python
188
- weights, activation_potentiations = planeat.evolve(weights, activation_potentiations, 1, fitness, show_info=True, strategy='cross_over', policy='normal_selective')
189
- ```
135
+ - 'explorer': Explorer policy increases population diversity.
136
+ Advantages: fitness does not get stuck at local maximum or minimum.
137
+ Disadvantages: slow training.
138
+
139
+ Suggestions: Use hybrid and dynamic policy. When fitness appears stuck, switch to the 'explorer' policy.
140
+
141
+ Default: 'aggresive'.
142
+
143
+ target_fitness (str, optional): Target fitness strategy for PLANEAT optimization. ('max' maximizes fitness, 'min' minimizes fitness.) Default: 'max'.
144
+
145
+ fitness_bias (float, optional): Fitness bias must be a probability value between 0 and 1 that determines the effect of fitness on the crossover process. Default: Determined by the `strategy`.
146
+
147
+ mutations (bool, optional): If True, mutations are applied to the bad genomes and potentially
148
+ to the best genomes as well. Default is True.
149
+
150
+ bad_genomes_mutation_prob (float, optional): The probability of applying mutation to the bad genomes.
151
+ Must be in the range [0, 1]. Also affects the mutation probability of the best genomes inversely.
152
+ For example, a value of 0.7 for bad genomes implies 0.3 for best genomes. Default: Determined by `policy`.
153
+
154
+ activation_mutate_prob (float, optional): The probability of applying mutation to the activation functions.
155
+ Must be in the range [0, 1]. Default is 0.5 (50%).
156
+
157
+ save_best_genom (bool, optional): If True, ensures that the best genomes are saved and not mutated
158
+ or altered during reproduction. Default is True.
159
+
160
+ cross_over_mode (str, optional): Specifies the crossover method to use. Options:
161
+ - 'tpm': Two-Point Matrix Crossover.
162
+ Default is 'tpm'.
163
+
164
+ activation_mutate_add_prob (float, optional): The probability of adding a new activation function to the genome for mutation.
165
+ Must be in the range [0, 1]. Default is 0.5.
166
+
167
+ activation_mutate_delete_prob (float, optional): The probability of deleting an existing activation function
168
+ from the genome for mutation. Must be in the range [0, 1]. Default is 0.5.
169
+
170
+ activation_mutate_change_prob (float, optional): The probability of changing an activation function in the genome for mutation.
171
+ Must be in the range [0, 1]. Default is 0.5.
172
+
173
+ weight_mutate_prob (float, optional): The probability of mutating a weight in the genome.
174
+ Must be in the range [0, 1]. Default is 1.
175
+
176
+ weight_mutate_rate (int, optional): If the value entered here equals the result of input_layer * output_layer,
177
+ only a single weight will be mutated during each mutation process. If the value is half of the result,
178
+ two weights will be mutated. WARNING: If you don't understand, do NOT change this value. Default is 32.
179
+
180
+ activation_selection_add_prob (float, optional): The probability of adding an existing activation function for crossover.
181
+ Must be in the range [0, 1]. Default is 0.6. (WARNING! Higher values increase complexity. For faster training, increase this value.)
182
+
183
+ activation_selection_change_prob (float, optional): The probability of changing an activation function in the genome for crossover.
184
+ Must be in the range [0, 1]. Default is 0.4.
185
+
186
+ activation_selection_rate (int, optional): If the activation list of a good genome is smaller than this value, only one activation will undergo crossover. This parameter controls model complexity. Default is 2.
187
+
188
+ dtype (numpy.dtype): Data type for the arrays. Default: np.float32.
189
+ Example: np.float64 or np.float16 [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not recommended!].
190
+
191
+ Raises:
192
+ ValueError:
193
+ - If `policy` is not one of the specified values ('aggresive', 'explorer').
194
+ - If 'strategy' is not one of the specified values ('less_selective', 'normal_selective', 'more_selective')
195
+ - If `cross_over_mode` is not one of the specified values ('tpm').
196
+ - If `bad_genomes_mutation_prob`, `activation_mutate_prob`, or other probability parameters are not in the range 0 and 1.
197
+ - If the population size is odd (ensuring an even number of genomes is required for proper selection).
198
+ - If 'fitness_bias' value is not in range 0 and 1.
199
+
200
+ Returns:
201
+ tuple: A tuple containing:
202
+ - weights (numpy.ndarray): The updated weights for the population after selection, crossover, and mutation.
203
+ The shape is (population_size, output_shape, input_shape).
204
+ - activation_potentiations (list): The updated list of activation functions for the population.
205
+
206
+ Notes:
207
+ - **Selection Process**:
208
+ - The genomes are sorted by their fitness (based on `fitness`), and then split into "best" and "bad" halves.
209
+ - The best genomes are retained, and the bad genomes are modified based on the selected strategy.
210
+
211
+ - **Crossover Strategies**:
212
+ - The **'cross_over'** strategy performs crossover, where parts of the best genomes' weights are combined with other good genomes to create new weight matrices.
213
+
214
+ - **Mutation**:
215
+ - Mutation is applied to both the best and bad genomes, depending on the mutation probability and the `policy`.
216
+ - `bad_genomes_mutation_prob` determines the probability of applying mutations to the bad genomes.
217
+ - If `activation_mutate_prob` is provided, activation function mutations are applied to the genomes based on this probability.
218
+
219
+ - **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.
220
+
221
+ - **Logging**: If `show_info=True`, the current generation and the maximum reward from the population are printed for tracking the learning progress.
222
+
223
+ Example:
224
+ ```python
225
+ weights, activation_potentiations = planeat.evolver(weights, activation_potentiations, 1, fitness, show_info=True, strategy='normal_selective', policy='aggresive')
226
+ ```
227
+
228
+ - The function returns the updated weights and activations after processing based on the chosen strategy, policy, and mutation parameters.
229
+ """
190
230
 
191
- - The function returns the updated weights and activations after processing based on the chosen strategy, policy, and mutation parameters.
192
- """
193
-
194
231
  ### ERROR AND CONFIGURATION CHECKS:
195
232
 
196
- if policy == 'normal_selective':
197
- if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.7
198
- if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.25
233
+ if strategy == 'normal_selective':
234
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.7 # EFFECTS MUTATION
235
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.25 # EFFECTS CROSS-OVER
236
+ if fitness_bias is None: fitness_bias = 0.5 # The pressure applied by FITNESS to the CROSS-OVER
199
237
 
200
- elif policy == 'more_selective':
201
- if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.85
202
- if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.1
238
+ elif strategy == 'more_selective':
239
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.85 # EFFECTS MUTATION
240
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.1 # EFFECTS CROSS-OVER
241
+ if fitness_bias is None: fitness_bias = 0.7 # The pressure applied by FITNESS to the CROSS-OVER
203
242
 
204
- elif policy == 'less_selective':
205
- if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.6
206
- if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.5
243
+ elif strategy == 'less_selective':
244
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.6 # EFFECTS MUTATION
245
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.5 # EFFECTS CROSS-OVER
246
+ if fitness_bias is None: fitness_bias = 0.3 # The pressure applied by FITNESS to the CROSS-OVER
207
247
 
208
248
  else:
209
- raise ValueError("policy parameter must be: 'normal_selective' or 'more_selective' or 'less_selective'")
210
-
249
+ raise ValueError("strategy parameter must be: 'normal_selective' or 'more_selective' or 'less_selective'")
211
250
 
212
- if (activation_add_prob < 0 or activation_add_prob > 1) or (activation_change_prob < 0 or activation_change_prob > 1) or (activation_delete_prob < 0 or activation_delete_prob > 1) or (weight_mutate_prob < 0 or weight_mutate_prob > 1) or (activation_selection_add_prob < 0 or activation_selection_add_prob > 1) or (activation_selection_change_prob < 0 or activation_selection_change_prob > 1):
251
+ if policy == 'explorer': fitness_bias = 0
252
+
253
+ if ((activation_mutate_add_prob < 0 or activation_mutate_add_prob > 1) or
254
+ (activation_mutate_change_prob < 0 or activation_mutate_change_prob > 1) or
255
+ (activation_mutate_delete_prob < 0 or activation_mutate_delete_prob > 1) or
256
+ (weight_mutate_prob < 0 or weight_mutate_prob > 1) or
257
+ (activation_selection_add_prob < 0 or activation_selection_add_prob > 1) or (
258
+ activation_selection_change_prob < 0 or activation_selection_change_prob > 1)):
259
+
213
260
  raise ValueError("All hyperparameters ending with 'prob' must be a number between 0 and 1.")
261
+
262
+ if fitness_bias < 0 or fitness_bias > 1: raise ValueError("fitness_bias value must be a number between 0 and 1.")
214
263
 
215
264
  if bad_genomes_mutation_prob is not None:
216
265
  if not isinstance(bad_genomes_mutation_prob, float) or bad_genomes_mutation_prob < 0 or bad_genomes_mutation_prob > 1:
@@ -253,42 +302,44 @@ Example:
253
302
  bar_format = loading_bars()[0]
254
303
 
255
304
  if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50)
256
- normalized_fitness = normalization(fitness, dtype=dtype)
305
+ normalized_fitness = abs(normalization(fitness, dtype=dtype))
257
306
 
258
307
  best_fitness = normalized_fitness[-1]
259
308
 
260
309
  for i in range(len(bad_weights)):
261
310
  second_parent_W, second_parent_act, s_i = second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob)
262
311
 
263
- if policy == 'normal_selective' or policy == 'less_selective':
264
- if strategy == 'cross_over':
265
- bad_weights[i], bad_activations[i] = cross_over(good_weights[i],
266
- second_parent_W,
267
- good_activations[i],
268
- second_parent_act,
269
- cross_over_mode=cross_over_mode,
270
- activation_selection_add_prob=activation_selection_add_prob,
271
- activation_selection_change_prob=activation_selection_change_prob,
272
- activation_selection_rate=activation_selection_rate,
273
- first_parent_fitness=normalized_fitness[i],
274
- second_parent_fitness=normalized_fitness[s_i]
275
- )
276
-
277
-
278
- if policy == 'more_selective':
279
- if strategy == 'cross_over':
280
- bad_weights[i], bad_activations[i] = cross_over(best_weights,
281
- second_parent_W,
282
- best_activations,
283
- second_parent_act,
284
- cross_over_mode=cross_over_mode,
285
- activation_selection_add_prob=activation_selection_add_prob,
286
- activation_selection_change_prob=activation_selection_change_prob,
287
- activation_selection_rate=activation_selection_rate,
288
- first_parent_fitness=best_fitness,
289
- second_parent_fitness=normalized_fitness[s_i]
290
- )
312
+ if policy == 'aggresive':
313
+ bad_weights[i], bad_activations[i] = cross_over(best_weights,
314
+ second_parent_W,
315
+ best_activations,
316
+ second_parent_act,
317
+ cross_over_mode=cross_over_mode,
318
+ activation_selection_add_prob=activation_selection_add_prob,
319
+ activation_selection_change_prob=activation_selection_change_prob,
320
+ activation_selection_rate=activation_selection_rate,
321
+ bad_genomes_selection_prob=bad_genomes_selection_prob,
322
+ first_parent_fitness=best_fitness,
323
+ fitness_bias=fitness_bias,
324
+ second_parent_fitness=normalized_fitness[s_i]
325
+ )
326
+ elif policy == 'explorer':
327
+ bad_weights[i], bad_activations[i] = cross_over(good_weights[i],
328
+ second_parent_W,
329
+ good_activations[i],
330
+ second_parent_act,
331
+ cross_over_mode=cross_over_mode,
332
+ activation_selection_add_prob=activation_selection_add_prob,
333
+ activation_selection_change_prob=activation_selection_change_prob,
334
+ activation_selection_rate=activation_selection_rate,
335
+ bad_genomes_selection_prob=bad_genomes_selection_prob,
336
+ first_parent_fitness=normalized_fitness[i],
337
+ fitness_bias=fitness_bias,
338
+ second_parent_fitness=normalized_fitness[s_i]
339
+ )
291
340
 
341
+ else: raise ValueError("policy parameter must be: 'aggresive' or 'explorer'")
342
+
292
343
  if mutations is True:
293
344
  mutation_prob = random.uniform(0, 1)
294
345
 
@@ -297,23 +348,25 @@ Example:
297
348
  good_weights[i], good_activations[i] = mutation(good_weights[i],
298
349
  good_activations[i],
299
350
  activation_mutate_prob=activation_mutate_prob,
300
- activation_add_prob=activation_add_prob,
301
- activation_delete_prob=activation_delete_prob,
302
- activation_change_prob=activation_change_prob,
351
+ activation_add_prob=activation_mutate_add_prob,
352
+ activation_delete_prob=activation_mutate_delete_prob,
353
+ activation_change_prob=activation_mutate_change_prob,
303
354
  weight_mutate_prob=weight_mutate_prob,
304
- threshold=weight_mutate_rate,
305
- dtype=dtype)
355
+ threshold=weight_mutate_rate,
356
+ genome_fitness=normalized_fitness[i]
357
+ )
306
358
 
307
359
  elif mutation_prob < bad_genomes_mutation_prob:
308
360
  bad_weights[i], bad_activations[i] = mutation(bad_weights[i],
309
361
  bad_activations[i],
310
362
  activation_mutate_prob=activation_mutate_prob,
311
- activation_add_prob=activation_add_prob,
312
- activation_delete_prob=activation_delete_prob,
313
- activation_change_prob=activation_change_prob,
363
+ activation_add_prob=activation_mutate_add_prob,
364
+ activation_delete_prob=activation_mutate_delete_prob,
365
+ activation_change_prob=activation_mutate_change_prob,
314
366
  weight_mutate_prob=weight_mutate_prob,
315
367
  threshold=weight_mutate_rate,
316
- dtype=dtype)
368
+ genome_fitness=normalized_fitness[i]
369
+ )
317
370
 
318
371
  if bar_status: progress.update(1)
319
372
 
@@ -327,22 +380,21 @@ Example:
327
380
  print("*** Configuration Settings ***")
328
381
  print(" POPULATION SIZE: ", str(len(weights)))
329
382
  print(" STRATEGY: ", strategy)
330
-
331
- if strategy == 'cross_over':
332
- print(" CROSS OVER MODE: ", cross_over_mode)
333
-
383
+ print(" CROSS OVER MODE: ", cross_over_mode)
334
384
  print(" POLICY: ", policy)
335
385
  print(" MUTATIONS: ", str(mutations))
336
386
  print(" BAD GENOMES MUTATION PROB: ", str(bad_genomes_mutation_prob))
337
387
  print(" GOOD GENOMES MUTATION PROB: ", str(round(1 - bad_genomes_mutation_prob, 2)))
388
+ print(" BAD GENOMES SELECTION PROB: ", str(bad_genomes_selection_prob))
338
389
  print(" WEIGHT MUTATE PROB: ", str(weight_mutate_prob))
339
390
  print(" WEIGHT MUTATE RATE (THRESHOLD VALUE FOR SINGLE MUTATION): ", str(weight_mutate_rate))
340
391
  print(" ACTIVATION MUTATE PROB: ", str(activation_mutate_prob))
341
- print(" ACTIVATION ADD PROB: ", str(activation_add_prob))
342
- print(" ACTIVATION DELETE PROB: ", str(activation_delete_prob))
343
- print(" ACTIVATION CHANGE PROB: ", str(activation_change_prob))
392
+ print(" ACTIVATION MUTATE ADD PROB: ", str(activation_mutate_add_prob))
393
+ print(" ACTIVATION MUTATE DELETE PROB: ", str(activation_mutate_delete_prob))
394
+ print(" ACTIVATION MUTATE CHANGE PROB: ", str(activation_mutate_change_prob))
344
395
  print(" ACTIVATION SELECTION ADD PROB: ", str(activation_selection_add_prob))
345
396
  print(" ACTIVATION SELECTION CHANGE PROB: ", str(activation_selection_change_prob))
397
+ print(" FITNESS BIAS: ", str(fitness_bias))
346
398
  print(" ACTIVATION SELECTION RATE (THRESHOLD VALUE FOR SINGLE CROSS OVER):", str(activation_selection_rate) + '\n')
347
399
 
348
400
  print("*** Performance ***")
@@ -370,7 +422,7 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
370
422
  activation_potentiations (list or str): A list where each entry represents an activation function
371
423
  or a potentiation strategy applied to each genome. If only one
372
424
  activation function is used, this can be a single string.
373
- rl_mode (bool, optional): If True, reinforcement learning mode is activated, this accepts x_population is a single genom. (Also weights and activation_potentations a single genomes part.)
425
+ rl_mode (bool, optional): If True, reinforcement learning mode is activated, this accepts x_population is a single genome. (Also weights and activation_potentations a single genomes part.)
374
426
  Default is False.
375
427
 
376
428
  dtype (numpy.dtype): Data type for the arrays. np.float32 by default. Example: np.float64 or np.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
@@ -395,7 +447,7 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
395
447
  outputs = evaluate(x_population, weights, activation_potentiations, rl_mode=False)
396
448
  ```
397
449
 
398
- - The function returns a list of outputs after processing the population, where each element corresponds to
450
+ - The function returns a list of outputs after processing the population, where each element corresponds to
399
451
  the output for each genome in `x_population`.
400
452
  """
401
453
 
@@ -438,9 +490,10 @@ def cross_over(first_parent_W,
438
490
  activation_selection_rate,
439
491
  bad_genomes_selection_prob,
440
492
  first_parent_fitness,
441
- second_parent_fitness):
493
+ second_parent_fitness,
494
+ fitness_bias):
442
495
  """
443
- Performs a selected Crossover operation on two sets of weights and activation functions.
496
+ Performs a crossover operation on two sets of weights and activation functions.
444
497
  This function combines two individuals (represented by their weights and activation functions)
445
498
  to create a new individual by exchanging parts of their weight matrices and activation functions.
446
499
 
@@ -450,23 +503,44 @@ def cross_over(first_parent_W,
450
503
  first_parent_act (str or list): The activation function(s) of the first individual.
451
504
  second_parent_act (str or list): The activation function(s) of the second individual.
452
505
  cross_over_mode (str): Determines the crossover method to be used. Options:
453
- - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights
454
- are swapped between parents.
506
+ - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights are swapped between parents.
507
+ activation_selection_add_prob (float): Probability of adding new activation functions
508
+ from the second parent to the child genome.
509
+ activation_selection_change_prob (float): Probability of replacing an activation function in the child genome
510
+ with one from the second parent.
511
+ activation_selection_rate (float): Determines how quickly activation functions are added or replaced
512
+ during the crossover process.
513
+ bad_genomes_selection_prob (float): Probability of selecting a "bad" genome for replacement with the offspring.
514
+ first_parent_fitness (float): Fitness score of the first parent.
515
+ second_parent_fitness (float): Fitness score of the second parent.
516
+ fitness_bias (float): A bias factor used to favor fitter parents during crossover operations.
517
+
455
518
  Returns:
456
519
  tuple: A tuple containing:
457
- - new_weight (numpy.ndarray): The weight matrix of the new individual created by crossover.
458
- - new_activations (list): The list of activation functions of the new individual created by crossover.
520
+ - child_W (numpy.ndarray): The weight matrix of the new individual created by crossover.
521
+ - child_act (list): The list of activation functions of the new individual created by crossover.
459
522
 
460
523
  Notes:
461
524
  - The crossover is performed based on the selected `cross_over_mode`.
462
- - In 'tpm', random sub-matrices from the parent weight matrices are swapped.
463
- - The crossover operation combines the activation functions of both parents:
464
- - If the activation functions are passed as strings, they are converted to lists for uniform handling.
465
- - The resulting activation functions depend on the crossover method and the parent's configuration.
525
+ - In 'tpm' mode, random sub-matrices from the parent weight matrices are swapped.
526
+ - Activation functions from both parents are combined using the probabilities and rates provided.
466
527
 
467
528
  Example:
468
529
  ```python
469
- new_weights, new_activations = cross_over(best_weight, good_weight, best_activations, good_activations, cross_over_mode='tpm')
530
+ new_weights, new_activations = cross_over(
531
+ first_parent_W=parent1_weights,
532
+ second_parent_W=parent2_weights,
533
+ first_parent_act=parent1_activations,
534
+ second_parent_act=parent2_activations,
535
+ cross_over_mode='tpm',
536
+ activation_selection_add_prob=0.8,
537
+ activation_selection_change_prob=0.5,
538
+ activation_selection_rate=0.1,
539
+ bad_genomes_selection_prob=0.7,
540
+ first_parent_fitness=0.9,
541
+ second_parent_fitness=0.85,
542
+ fitness_bias=0.6
543
+ )
470
544
  ```
471
545
  """
472
546
 
@@ -488,7 +562,7 @@ def cross_over(first_parent_W,
488
562
 
489
563
  undominant_parent_W = np.copy(second_parent_W)
490
564
  undominant_parent_act = second_parent_act
491
- succes = abs(second_parent_fitness)
565
+ succes = second_parent_fitness
492
566
 
493
567
  elif decision == 'second_parent':
494
568
  dominant_parent_W = np.copy(second_parent_W)
@@ -496,7 +570,7 @@ def cross_over(first_parent_W,
496
570
 
497
571
  undominant_parent_W = np.copy(first_parent_W)
498
572
  undominant_parent_act = first_parent_act
499
- succes = abs(first_parent_fitness)
573
+ succes = first_parent_fitness
500
574
 
501
575
  while True:
502
576
 
@@ -511,11 +585,14 @@ def cross_over(first_parent_W,
511
585
  (((row_cut_end + 1) - (row_cut_start + 1) * 2) + ((col_cut_end + 1) - (col_cut_start + 1) * 2) <= half_of_gene)):
512
586
  break
513
587
 
514
- row_cut_start = math.floor(row_cut_start * succes)
515
- row_cut_end = math.ceil(row_cut_end * succes)
588
+ selection_bias = random.uniform(0, 1)
589
+
590
+ if fitness_bias > selection_bias:
591
+ row_cut_start = math.floor(row_cut_start * succes)
592
+ row_cut_end = math.ceil(row_cut_end * succes)
516
593
 
517
- col_cut_start = math.floor(col_cut_start * succes)
518
- col_cut_end = math.ceil(col_cut_end * succes)
594
+ col_cut_start = math.floor(col_cut_start * succes)
595
+ col_cut_end = math.ceil(col_cut_end * succes)
519
596
 
520
597
  child_W = dominant_parent_W
521
598
 
@@ -575,7 +652,15 @@ def cross_over(first_parent_W,
575
652
 
576
653
  return child_W, child_act
577
654
 
578
- def mutation(weight, activations, activation_mutate_prob, activation_add_prob, activation_delete_prob, activation_change_prob, weight_mutate_prob, threshold, dtype=np.float32):
655
+ def mutation(weight,
656
+ activations,
657
+ activation_mutate_prob,
658
+ activation_add_prob,
659
+ activation_delete_prob,
660
+ activation_change_prob,
661
+ weight_mutate_prob,
662
+ threshold,
663
+ genome_fitness):
579
664
  """
580
665
  Performs mutation on the given weight matrix and activation functions.
581
666
  - The weight matrix is mutated by randomly changing its values based on the mutation probability.
@@ -590,8 +675,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
590
675
  activation_change_prob (float): Probability of replacing an existing activation function with a new one.
591
676
  weight_mutate_prob (float): The probability of mutating weight matrix.
592
677
  threshold (float): If the value you enter here is equal to the result of input layer * output layer, only a single weight will be mutated during each mutation process. If the value you enter here is half of the result of input layer * output layer, two weights in the weight matrix will be mutated.
593
- dtype (numpy.dtype): Data type for the arrays. np.float32 by default. Example: np.float64 or np.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
594
-
678
+ genome_fitness (float): Fitness value of genome
595
679
  Returns:
596
680
  tuple: A tuple containing:
597
681
  - mutated_weight (numpy.ndarray): The weight matrix after mutation.
@@ -609,8 +693,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
609
693
  the optimization process.
610
694
  """
611
695
 
612
- if isinstance(activations, str):
613
- activations = [activations]
696
+ if isinstance(activations, str): activations = [activations]
614
697
 
615
698
  weight_mutate_prob = 1 - weight_mutate_prob # if prob 0.8 (%80) then 1 - 0.8. Because 0-1 random number probably greater than 0.2
616
699
  potential_weight_mutation = random.uniform(0, 1)
@@ -620,6 +703,8 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
620
703
  start = 0
621
704
  row_end = weight.shape[0]
622
705
  col_end = weight.shape[1]
706
+
707
+ threshold = threshold * genome_fitness
623
708
  new_threshold = threshold
624
709
 
625
710
  while True:
@@ -658,13 +743,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
658
743
 
659
744
  random_index_all_act = int(random.uniform(0, len(all_acts)-1))
660
745
  activations.append(all_acts[random_index_all_act])
661
-
662
- for i in range(weight.shape[0]):
663
746
 
664
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
665
-
666
- weight = normalization(weight, dtype=dtype)
667
-
668
747
  except:
669
748
 
670
749
  activation = activations
@@ -673,24 +752,10 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
673
752
  activations.append(activation)
674
753
  activations.append(all_acts[int(random.uniform(0, len(all_acts)-1))])
675
754
 
676
- for i in range(weight.shape[0]):
677
-
678
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
679
-
680
- weight = normalization(weight, dtype=dtype)
681
-
682
755
  if potential_activation_delete_prob > activation_delete_prob and len(activations) > 1:
683
756
 
684
757
  random_index = random.randint(0, len(activations) - 1)
685
-
686
- wc = np.copy(weight)
687
- for i in range(weight.shape[0]):
688
-
689
- wc[i,:] = apply_activation(wc[i,:], activations[random_index])
690
- weight[i,:] -= wc[i,:]
691
-
692
758
  activations.pop(random_index)
693
- weight = normalization(weight, dtype=dtype)
694
759
 
695
760
 
696
761
  if potential_activation_change_prob > activation_change_prob:
@@ -700,36 +765,22 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
700
765
 
701
766
  activations[random_index_genom_act] = all_acts[random_index_all_act]
702
767
 
703
- wc = np.copy(weight)
704
- for i in range(weight.shape[0]):
705
-
706
- wc[i,:] = apply_activation(wc[i,:], activations[random_index_genom_act])
707
- weight[i,:] -= wc[i,:]
708
-
709
- weight = normalization(weight, dtype=dtype)
710
-
711
- for i in range(weight.shape[0]):
712
-
713
- weight[i,:] = apply_activation(weight[i,:], activations[random_index_genom_act])
714
-
715
- weight = normalization(weight, dtype=dtype)
716
-
717
768
  return weight, activations
718
769
 
719
- def second_parent_selection(best_weights, bad_weights, best_activations, bad_activations, bad_genomes_selection_prob):
770
+ def second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob):
720
771
 
721
772
  selection_prob = random.uniform(0, 1)
722
- random_index = int(random.uniform(0, len(best_weights) - 1))
773
+ random_index = int(random.uniform(0, len(good_weights) - 1))
723
774
 
724
775
  if selection_prob > bad_genomes_selection_prob:
725
- second_selected_W = best_weights[random_index]
726
- second_selected_act = best_activations[random_index]
776
+ second_selected_W = good_weights[random_index]
777
+ second_selected_act = good_activations[random_index]
727
778
 
728
779
  else:
729
780
  second_selected_W = bad_weights[random_index]
730
781
  second_selected_act = bad_activations[random_index]
731
782
 
732
- return second_selected_W, second_selected_act, random_index
783
+ return second_selected_W, second_selected_act, random_index
733
784
 
734
785
  def dominant_parent_selection(bad_genomes_selection_prob):
735
786