pyerualjetwork 4.1.9b2__py3-none-any.whl → 4.2.0__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
@@ -12,7 +14,7 @@ ANAPLAN document: https://github.com/HCB06/Anaplan/blob/main/Welcome_to_Anaplan/
12
14
 
13
15
  import numpy as np
14
16
  import random
15
- from tqdm import tqdm
17
+ import math
16
18
 
17
19
  ### LIBRARY IMPORTS ###
18
20
  from .plan import feed_forward
@@ -69,155 +71,199 @@ 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 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):
74
+ def evolver(weights,
75
+ activation_potentiations,
76
+ what_gen,
77
+ fitness,
78
+ show_info=False,
79
+ policy='aggressive',
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_genoms_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_genoms_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_genoms_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
+ - 'aggressive': 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: 'aggressive'.
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 ('aggressive', '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='aggressive')
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_genoms_mutation_prob == None:
198
- bad_genoms_mutation_prob = 0.7
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_genoms_mutation_prob == None:
202
- bad_genoms_mutation_prob = 0.85
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_genoms_mutation_prob == None:
206
- bad_genoms_mutation_prob = 0.6
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
- if cross_over_mode != 'tpm' and cross_over_mode != 'plantic':
216
- raise ValueError("cross_over_mode parameter must be 'tpm' or 'plantic'")
217
-
218
- if bad_genoms_mutation_prob is not None:
219
- if not isinstance(bad_genoms_mutation_prob, float) or bad_genoms_mutation_prob < 0 or bad_genoms_mutation_prob > 1:
220
- raise ValueError("bad_genoms_mutation_prob parameter must be float and 0-1 range")
264
+ if bad_genomes_mutation_prob is not None:
265
+ if not isinstance(bad_genomes_mutation_prob, float) or bad_genomes_mutation_prob < 0 or bad_genomes_mutation_prob > 1:
266
+ raise ValueError("bad_genomes_mutation_prob parameter must be float and 0-1 range")
221
267
 
222
268
  if activation_mutate_prob is not None:
223
269
  if not isinstance(activation_mutate_prob, float) or activation_mutate_prob < 0 or activation_mutate_prob > 1:
@@ -242,90 +288,90 @@ Example:
242
288
 
243
289
  ### GENOMES ARE DIVIDED INTO TWO GROUPS: GOOD GENOMES AND BAD GENOMES:
244
290
 
245
- best_weights = weights[slice_center:]
291
+ good_weights = weights[slice_center:]
246
292
  bad_weights = weights[:slice_center]
247
- best_weight = best_weights[len(best_weights)-1]
293
+ best_weight = good_weights[-1]
248
294
 
249
- best_activations = list(activation_potentiations[slice_center:])
295
+ good_activations = list(activation_potentiations[slice_center:])
250
296
  bad_activations = list(activation_potentiations[:slice_center])
251
- best_activation = best_activations[len(best_activations) - 1]
297
+ best_activations = good_activations[-1]
252
298
 
253
299
 
254
- ### NEAT IS APPLIED ACCORDING TO THE SPECIFIED POLICY, STRATEGY, AND PROBABILITY CONFIGURATION:
300
+ ### PLANEAT IS APPLIED ACCORDING TO THE SPECIFIED POLICY, STRATEGY, AND PROBABILITY CONFIGURATION:
255
301
 
256
302
  bar_format = loading_bars()[0]
257
303
 
258
- if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50, ascii="▱▰")
304
+ if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50)
305
+ normalized_fitness = abs(normalization(fitness, dtype=dtype))
259
306
 
260
- for i in range(len(bad_weights)):
307
+ best_fitness = normalized_fitness[-1]
308
+ epsilon = np.finfo(float).eps
261
309
 
262
- if policy == 'normal_selective':
263
-
264
- if strategy == 'cross_over':
265
- bad_weights[i], bad_activations[i] = cross_over(best_weight, best_weights[i], best_activations=best_activation, good_activations=best_activations[i], cross_over_mode=cross_over_mode, activation_selection_add_prob=activation_selection_add_prob, activation_selection_change_prob=activation_selection_change_prob, activation_selection_rate=activation_selection_rate)
310
+ for i in range(len(bad_weights)):
311
+
312
+ if policy == 'aggressive':
313
+ first_parent_W = best_weight
314
+ first_parent_act = best_activations
266
315
 
316
+ elif policy == 'explorer':
317
+ first_parent_W = good_weights[i]
318
+ first_parent_act = good_activations[i]
267
319
 
268
- elif strategy == 'potentiate':
269
- bad_weights[i], bad_activations[i] = potentiate(best_weight, best_weights[i], best_activations=best_activation, good_activations=best_activations[i], dtype=dtype)
270
-
320
+ else: raise ValueError("policy parameter must be: 'aggressive' or 'explorer'")
271
321
 
272
- if mutations is True:
273
-
274
- mutation_prob = random.uniform(0, 1)
275
-
276
- if mutation_prob > bad_genoms_mutation_prob:
277
- if (save_best_genom == True and not np.array_equal(best_weights[i], best_weight)) or save_best_genom == False:
278
- best_weights[i], best_activations[i] = mutation(best_weights[i], best_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)
279
-
280
- elif mutation_prob < bad_genoms_mutation_prob:
281
- 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)
282
-
283
- if policy == 'more_selective':
284
-
285
- if strategy == 'cross_over':
286
- bad_weights[i], bad_activations[i] = cross_over(best_weight, best_weights[i], best_activations=best_activation, good_activations=best_activations[i], cross_over_mode=cross_over_mode, activation_selection_add_prob=activation_selection_add_prob, activation_selection_change_prob=activation_selection_change_prob, activation_selection_rate=activation_selection_rate)
287
-
288
- elif strategy == 'potentiate':
289
- bad_weights[i], bad_activations[i] = potentiate(best_weight, best_weights[i], best_activations=best_activation, good_activations=best_activations[i], dtype=dtype)
290
-
291
- if mutations is True:
292
-
293
- mutation_prob = random.uniform(0, 1)
294
-
295
- if mutation_prob > bad_genoms_mutation_prob:
296
- if (save_best_genom == True and not np.array_equal(best_weights[i], best_weight)) or save_best_genom == False:
297
- best_weights[i], best_activations[i] = mutation(best_weights[i], best_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)
298
-
299
- elif mutation_prob < bad_genoms_mutation_prob:
300
- 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)
301
-
302
-
303
-
304
- if policy == 'less_selective':
305
-
306
- random_index = int(random.uniform(0, len(best_weights) - 1))
322
+ second_parent_W, second_parent_act, s_i = second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob)
323
+
324
+ bad_weights[i], bad_activations[i] = cross_over(first_parent_W,
325
+ second_parent_W,
326
+ first_parent_act,
327
+ second_parent_act,
328
+ cross_over_mode=cross_over_mode,
329
+ activation_selection_add_prob=activation_selection_add_prob,
330
+ activation_selection_change_prob=activation_selection_change_prob,
331
+ activation_selection_rate=activation_selection_rate,
332
+ bad_genomes_selection_prob=bad_genomes_selection_prob,
333
+ first_parent_fitness=best_fitness,
334
+ fitness_bias=fitness_bias,
335
+ second_parent_fitness=normalized_fitness[s_i],
336
+ epsilon=epsilon
337
+ )
338
+
339
+
340
+ if mutations is True:
341
+ mutation_prob = random.uniform(0, 1)
342
+
343
+ if mutation_prob > bad_genomes_mutation_prob:
344
+ if (save_best_genom == True and not np.array_equal(good_weights[i], best_weight)) or save_best_genom == False:
345
+
346
+ good_weights[i], good_activations[i] = mutation(good_weights[i],
347
+ good_activations[i],
348
+ activation_mutate_prob=activation_mutate_prob,
349
+ activation_add_prob=activation_mutate_add_prob,
350
+ activation_delete_prob=activation_mutate_delete_prob,
351
+ activation_change_prob=activation_mutate_change_prob,
352
+ weight_mutate_prob=weight_mutate_prob,
353
+ threshold=weight_mutate_rate,
354
+ genome_fitness=normalized_fitness[i],
355
+ epsilon=epsilon
356
+ )
307
357
 
308
- if strategy == 'cross_over':
309
- bad_weights[i], bad_activations[i] = cross_over(best_weights[random_index], best_weights[i], best_activations=best_activations[random_index], good_activations=best_activations[i], cross_over_mode=cross_over_mode, activation_selection_add_prob=activation_selection_add_prob, activation_selection_change_prob=activation_selection_change_prob, activation_selection_rate=activation_selection_rate)
358
+ elif mutation_prob < bad_genomes_mutation_prob:
359
+ bad_weights[i], bad_activations[i] = mutation(bad_weights[i],
360
+ bad_activations[i],
361
+ activation_mutate_prob=activation_mutate_prob,
362
+ activation_add_prob=activation_mutate_add_prob,
363
+ activation_delete_prob=activation_mutate_delete_prob,
364
+ activation_change_prob=activation_mutate_change_prob,
365
+ weight_mutate_prob=weight_mutate_prob,
366
+ threshold=weight_mutate_rate,
367
+ genome_fitness=normalized_fitness[i],
368
+ epsilon=epsilon
369
+ )
310
370
 
311
- elif strategy == 'potentiate':
312
- bad_weights[i], bad_activations[i] = potentiate(best_weights[random_index], best_weights[i], best_activations=best_activations[random_index], good_activations=best_activations[i])
313
-
314
- if mutations is True:
315
-
316
- mutation_prob = random.uniform(0, 1)
317
-
318
- if mutation_prob > bad_genoms_mutation_prob:
319
- if (save_best_genom == True and not np.array_equal(best_weights[i], best_weight)) or save_best_genom == False:
320
- best_weights[i], best_activations[i] = mutation(best_weights[i], best_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)
321
-
322
- elif mutation_prob < bad_genoms_mutation_prob:
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)
324
-
325
371
  if bar_status: progress.update(1)
326
372
 
327
- weights = np.vstack((bad_weights, best_weights))
328
- activation_potentiations = bad_activations + best_activations
373
+ weights = np.vstack((bad_weights, good_weights))
374
+ activation_potentiations = bad_activations + good_activations
329
375
 
330
376
  ### INFO PRINTING CONSOLE
331
377
 
@@ -334,22 +380,21 @@ Example:
334
380
  print("*** Configuration Settings ***")
335
381
  print(" POPULATION SIZE: ", str(len(weights)))
336
382
  print(" STRATEGY: ", strategy)
337
-
338
- if strategy == 'cross_over':
339
- print(" CROSS OVER MODE: ", cross_over_mode)
340
-
383
+ print(" CROSS OVER MODE: ", cross_over_mode)
341
384
  print(" POLICY: ", policy)
342
385
  print(" MUTATIONS: ", str(mutations))
343
- print(" BAD GENOMES MUTATION PROB: ", str(bad_genoms_mutation_prob))
344
- print(" GOOD GENOMES MUTATION PROB: ", str(round(1 - bad_genoms_mutation_prob, 2)))
386
+ print(" BAD GENOMES MUTATION PROB: ", str(bad_genomes_mutation_prob))
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))
345
389
  print(" WEIGHT MUTATE PROB: ", str(weight_mutate_prob))
346
390
  print(" WEIGHT MUTATE RATE (THRESHOLD VALUE FOR SINGLE MUTATION): ", str(weight_mutate_rate))
347
391
  print(" ACTIVATION MUTATE PROB: ", str(activation_mutate_prob))
348
- print(" ACTIVATION ADD PROB: ", str(activation_add_prob))
349
- print(" ACTIVATION DELETE PROB: ", str(activation_delete_prob))
350
- 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))
351
395
  print(" ACTIVATION SELECTION ADD PROB: ", str(activation_selection_add_prob))
352
396
  print(" ACTIVATION SELECTION CHANGE PROB: ", str(activation_selection_change_prob))
397
+ print(" FITNESS BIAS: ", str(fitness_bias))
353
398
  print(" ACTIVATION SELECTION RATE (THRESHOLD VALUE FOR SINGLE CROSS OVER):", str(activation_selection_rate) + '\n')
354
399
 
355
400
  print("*** Performance ***")
@@ -377,7 +422,7 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
377
422
  activation_potentiations (list or str): A list where each entry represents an activation function
378
423
  or a potentiation strategy applied to each genome. If only one
379
424
  activation function is used, this can be a single string.
380
- 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.)
381
426
  Default is False.
382
427
 
383
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)
@@ -402,7 +447,7 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
402
447
  outputs = evaluate(x_population, weights, activation_potentiations, rl_mode=False)
403
448
  ```
404
449
 
405
- - 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
406
451
  the output for each genome in `x_population`.
407
452
  """
408
453
 
@@ -435,39 +480,82 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
435
480
  return outputs
436
481
 
437
482
 
438
- def cross_over(best_weight, good_weight, best_activations, good_activations, cross_over_mode, activation_selection_add_prob, activation_selection_change_prob, activation_selection_rate):
483
+ def cross_over(first_parent_W,
484
+ second_parent_W,
485
+ first_parent_act,
486
+ second_parent_act,
487
+ cross_over_mode,
488
+ activation_selection_add_prob,
489
+ activation_selection_change_prob,
490
+ activation_selection_rate,
491
+ bad_genomes_selection_prob,
492
+ first_parent_fitness,
493
+ second_parent_fitness,
494
+ fitness_bias,
495
+ epsilon):
439
496
  """
440
- Performs a selected Crossover operation on two sets of weights and activation functions.
497
+ Performs a crossover operation on two sets of weights and activation functions.
441
498
  This function combines two individuals (represented by their weights and activation functions)
442
499
  to create a new individual by exchanging parts of their weight matrices and activation functions.
443
500
 
444
501
  Args:
445
- best_weight (numpy.ndarray): The weight matrix of the first individual (parent).
446
- good_weight (numpy.ndarray): The weight matrix of the second individual (parent).
447
- best_activations (str or list): The activation function(s) of the first individual.
448
- good_activations (str or list): The activation function(s) of the second individual.
502
+ first_parent_W (numpy.ndarray): The weight matrix of the first individual (parent).
503
+
504
+ second_parent_W (numpy.ndarray): The weight matrix of the second individual (parent).
505
+
506
+ first_parent_act (str or list): The activation function(s) of the first individual.
507
+
508
+ second_parent_act (str or list): The activation function(s) of the second individual.
509
+
449
510
  cross_over_mode (str): Determines the crossover method to be used. Options:
450
- - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights
451
- are swapped between parents.
452
- - 'plan': Output Connections Crossover, where specific connections
453
- in the weight matrix are crossed over. Default is 'tpm'.
511
+ - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights are swapped between parents.
512
+
513
+ activation_selection_add_prob (float): Probability of adding new activation functions
514
+ from the second parent to the child genome.
515
+
516
+ activation_selection_change_prob (float): Probability of replacing an activation function in the child genome
517
+ with one from the second parent.
518
+
519
+ activation_selection_rate (float): Determines how quickly activation functions are added or replaced
520
+ during the crossover process.
521
+
522
+ bad_genomes_selection_prob (float): Probability of selecting a "bad" genome for replacement with the offspring.
523
+
524
+ first_parent_fitness (float): Fitness score of the first parent.
525
+
526
+ second_parent_fitness (float): Fitness score of the second parent.
527
+
528
+ fitness_bias (float): A bias factor used to favor fitter parents during crossover operations.
529
+
530
+ epsilon (float): Small epsilon constant
454
531
 
455
532
  Returns:
456
533
  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.
534
+ - child_W (numpy.ndarray): The weight matrix of the new individual created by crossover.
535
+ - child_act (list): The list of activation functions of the new individual created by crossover.
459
536
 
460
537
  Notes:
461
538
  - 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
- - In 'plantic', specific connections in the weight matrix are swapped between parents.
464
- - The crossover operation combines the activation functions of both parents:
465
- - If the activation functions are passed as strings, they are converted to lists for uniform handling.
466
- - The resulting activation functions depend on the crossover method and the parent's configuration.
539
+ - In 'tpm' mode, random sub-matrices from the parent weight matrices are swapped.
540
+ - Activation functions from both parents are combined using the probabilities and rates provided.
467
541
 
468
542
  Example:
469
543
  ```python
470
- new_weights, new_activations = cross_over(best_weight, good_weight, best_activations, good_activations, cross_over_mode='tpm')
544
+ new_weights, new_activations = cross_over(
545
+ first_parent_W=parent1_weights,
546
+ second_parent_W=parent2_weights,
547
+ first_parent_act=parent1_activations,
548
+ second_parent_act=parent2_activations,
549
+ cross_over_mode='tpm',
550
+ activation_selection_add_prob=0.8,
551
+ activation_selection_change_prob=0.5,
552
+ activation_selection_rate=0.1,
553
+ bad_genomes_selection_prob=0.7,
554
+ first_parent_fitness=0.9,
555
+ second_parent_fitness=0.85,
556
+ fitness_bias=0.6,
557
+ epsilon=np.finfo.eps
558
+ )
471
559
  ```
472
560
  """
473
561
 
@@ -475,8 +563,29 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
475
563
 
476
564
  start = 0
477
565
 
478
- row_end = best_weight.shape[0]
479
- col_end = best_weight.shape[1]
566
+ row_end = first_parent_W.shape[0]
567
+ col_end = first_parent_W.shape[1]
568
+
569
+ total_gene = row_end * col_end
570
+ half_of_gene = int(total_gene / 2)
571
+
572
+ decision = dominant_parent_selection(bad_genomes_selection_prob)
573
+
574
+ if decision == 'first_parent':
575
+ dominant_parent_W = np.copy(first_parent_W)
576
+ dominant_parent_act = first_parent_act
577
+
578
+ undominant_parent_W = np.copy(second_parent_W)
579
+ undominant_parent_act = second_parent_act
580
+ succes = second_parent_fitness + epsilon
581
+
582
+ elif decision == 'second_parent':
583
+ dominant_parent_W = np.copy(second_parent_W)
584
+ dominant_parent_act = second_parent_act
585
+
586
+ undominant_parent_W = np.copy(first_parent_W)
587
+ undominant_parent_act = first_parent_act
588
+ succes = first_parent_fitness + epsilon
480
589
 
481
590
  while True:
482
591
 
@@ -486,48 +595,46 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
486
595
  row_cut_end = int(random.uniform(start, row_end))
487
596
  col_cut_end = int(random.uniform(start, col_end))
488
597
 
489
- if (row_cut_end > row_cut_start) and (col_cut_end > col_cut_start):
598
+ if ((row_cut_end > row_cut_start) and
599
+ (col_cut_end > col_cut_start) and
600
+ (((row_cut_end + 1) - (row_cut_start + 1) * 2) + ((col_cut_end + 1) - (col_cut_start + 1) * 2) <= half_of_gene)):
490
601
  break
602
+
603
+ selection_bias = random.uniform(0, 1)
491
604
 
492
- new_weight = np.copy(best_weight)
493
- best_w2 = np.copy(good_weight)
494
-
495
- if cross_over_mode == 'tpm':
496
- new_weight[row_cut_start:row_cut_end, col_cut_start:col_cut_end] = best_w2[row_cut_start:row_cut_end, col_cut_start:col_cut_end]
497
-
498
- elif cross_over_mode == 'plantic':
499
- new_weight[row_cut_start:row_cut_end,:] = best_w2[row_cut_start:row_cut_end,:]
500
-
605
+ if fitness_bias > selection_bias:
606
+ row_cut_start = math.floor(row_cut_start * (succes + epsilon))
607
+ row_cut_end = math.ceil(row_cut_end * (succes + epsilon))
501
608
 
502
- if isinstance(best_activations, str):
503
- best = [best_activations]
609
+ col_cut_start = math.floor(col_cut_start * (succes + epsilon))
610
+ col_cut_end = math.ceil(col_cut_end * (succes + epsilon))
504
611
 
505
- if isinstance(good_activations, str):
506
- good = [good_activations]
612
+ child_W = dominant_parent_W
507
613
 
508
- if isinstance(best_activations, list):
509
- best = best_activations
614
+ if cross_over_mode == 'tpm':
615
+ child_W[row_cut_start:row_cut_end, col_cut_start:col_cut_end] = undominant_parent_W[row_cut_start:row_cut_end, col_cut_start:col_cut_end]
510
616
 
511
- if isinstance(good_activations, list):
512
- good = good_activations
617
+ if isinstance(dominant_parent_act, str): dominant_parent_act = [dominant_parent_act]
618
+ if isinstance(undominant_parent_act, str): undominant_parent_act = [undominant_parent_act]
513
619
 
514
- new_activations = list(np.copy(best))
620
+ child_act = list(np.copy(dominant_parent_act))
515
621
 
516
622
  activation_selection_add_prob = 1 - activation_selection_add_prob # if prob 0.8 (%80) then 1 - 0.8. Because 0-1 random number probably greater than 0.2
517
623
  potential_activation_selection_add = random.uniform(0, 1)
518
624
 
519
625
  if potential_activation_selection_add > activation_selection_add_prob:
520
626
 
627
+ activation_selection_rate = activation_selection_rate / succes
521
628
  new_threshold = activation_selection_rate
522
629
 
523
630
  while True:
524
631
 
525
- random_index_good = int(random.uniform(0, len(good)-1))
526
- random_good_activation = good[random_index_good]
632
+ random_index = int(random.uniform(0, len(undominant_parent_act)-1))
633
+ random_undominant_activation = undominant_parent_act[random_index]
527
634
 
528
- new_activations.append(random_good_activation)
635
+ child_act.append(random_undominant_activation)
529
636
 
530
- if len(best) > new_threshold:
637
+ if len(dominant_parent_act) > new_threshold:
531
638
  new_threshold += activation_selection_rate
532
639
  pass
533
640
 
@@ -538,69 +645,37 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
538
645
  potential_activation_selection_change_prob = random.uniform(0, 1)
539
646
 
540
647
  if potential_activation_selection_change_prob > activation_selection_change_prob:
541
-
648
+
649
+ activation_selection_rate = activation_selection_rate / succes
542
650
  new_threshold = activation_selection_rate
543
651
 
544
652
  while True:
545
653
 
546
- random_index_good = int(random.uniform(0, len(good)-1))
547
- random_index_best = int(random.uniform(0, len(best)-1))
548
- random_good_activation = good[random_index_good]
654
+ random_index_undominant = int(random.uniform(0, len(undominant_parent_act)-1))
655
+ random_index_dominant = int(random.uniform(0, len(dominant_parent_act)-1))
656
+ random_undominant_activation = undominant_parent_act[random_index_undominant]
549
657
 
550
- new_activations[random_index_best] = good[random_index_good]
658
+ child_act[random_index_dominant] = random_undominant_activation
551
659
 
552
- if len(best) > new_threshold:
660
+ if len(dominant_parent_act) > new_threshold:
553
661
  new_threshold += activation_selection_rate
554
662
  pass
555
663
 
556
664
  else:
557
665
  break
558
666
 
559
- return new_weight, new_activations
560
-
561
- def potentiate(best_weight, good_weight, best_activations, good_activations, dtype=np.float32):
562
- """
563
- Combines two sets of weights and activation functions by adding the weight matrices and
564
- concatenating the activation functions. The resulting weight matrix is normalized. (Max abs normalization.)
565
-
566
- Args:
567
- best_weight (numpy.ndarray): The weight matrix of the first individual (parent).
568
- good_weight (numpy.ndarray): The weight matrix of the second individual (parent).
569
- best_activations (str or list): The activation function(s) of the first individual.
570
- good_activations (str or list): The activation function(s) of the second individual.
571
- 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)
572
-
573
- Returns:
574
- tuple: A tuple containing:
575
- - new_weight (numpy.ndarray): The new weight matrix after potentiation and normalization. (Max abs normalization.)
576
- - new_activations (list): The new activation functions after concatenation.
577
-
578
- Notes:
579
- - The weight matrices are element-wise added and then normalized using the `normalization` function. (Max abs normalization.)
580
- - The activation functions from both parents are concatenated to form the new activation functions list.
581
- - If the activation functions are passed as strings, they are converted to lists for uniform handling.
582
- """
583
-
584
- new_weight = best_weight + good_weight
585
- new_weight = normalization(new_weight, dtype=dtype)
586
-
587
- if isinstance(best_activations, str):
588
- best = [best_activations]
589
-
590
- if isinstance(good_activations, str):
591
- good = [good_activations]
592
-
593
- if isinstance(best_activations, list):
594
- best = best_activations
595
-
596
- if isinstance(good_activations, list):
597
- good = good_activations
598
-
599
- new_activations = best + good
600
-
601
- return new_weight, new_activations
602
-
603
- def mutation(weight, activations, activation_mutate_prob, activation_add_prob, activation_delete_prob, activation_change_prob, weight_mutate_prob, threshold, dtype=np.float32):
667
+ return child_W, child_act
668
+
669
+ def mutation(weight,
670
+ activations,
671
+ activation_mutate_prob,
672
+ activation_add_prob,
673
+ activation_delete_prob,
674
+ activation_change_prob,
675
+ weight_mutate_prob,
676
+ threshold,
677
+ genome_fitness,
678
+ epsilon):
604
679
  """
605
680
  Performs mutation on the given weight matrix and activation functions.
606
681
  - The weight matrix is mutated by randomly changing its values based on the mutation probability.
@@ -608,14 +683,24 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
608
683
 
609
684
  Args:
610
685
  weight (numpy.ndarray): The weight matrix to mutate.
686
+
611
687
  activations (list): The list of activation functions to mutate.
688
+
612
689
  activation_mutate_prob (float): The overall probability of mutating activation functions.
690
+
613
691
  activation_add_prob (float): Probability of adding a new activation function.
692
+
614
693
  activation_delete_prob (float): Probability of removing an existing activation function.
694
+
615
695
  activation_change_prob (float): Probability of replacing an existing activation function with a new one.
696
+
616
697
  weight_mutate_prob (float): The probability of mutating weight matrix.
698
+
617
699
  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.
618
- 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)
700
+
701
+ genome_fitness (float): Fitness value of genome
702
+
703
+ epsilon (float): Small epsilon constant
619
704
 
620
705
  Returns:
621
706
  tuple: A tuple containing:
@@ -634,8 +719,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
634
719
  the optimization process.
635
720
  """
636
721
 
637
- if isinstance(activations, str):
638
- activations = [activations]
722
+ if isinstance(activations, str): activations = [activations]
639
723
 
640
724
  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
641
725
  potential_weight_mutation = random.uniform(0, 1)
@@ -645,6 +729,8 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
645
729
  start = 0
646
730
  row_end = weight.shape[0]
647
731
  col_end = weight.shape[1]
732
+
733
+ threshold = threshold * (genome_fitness + epsilon)
648
734
  new_threshold = threshold
649
735
 
650
736
  while True:
@@ -659,8 +745,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
659
745
  pass
660
746
 
661
747
  else:
662
- break
663
-
748
+ break
664
749
 
665
750
  activation_mutate_prob = 1 - activation_mutate_prob
666
751
  potential_activation_mutation = random.uniform(0, 1)
@@ -684,13 +769,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
684
769
 
685
770
  random_index_all_act = int(random.uniform(0, len(all_acts)-1))
686
771
  activations.append(all_acts[random_index_all_act])
687
-
688
- for i in range(weight.shape[0]):
689
-
690
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
691
772
 
692
- weight = normalization(weight, dtype=dtype)
693
-
694
773
  except:
695
774
 
696
775
  activation = activations
@@ -699,26 +778,12 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
699
778
  activations.append(activation)
700
779
  activations.append(all_acts[int(random.uniform(0, len(all_acts)-1))])
701
780
 
702
- for i in range(weight.shape[0]):
703
-
704
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
705
-
706
- weight = normalization(weight, dtype=dtype)
707
-
708
781
  if potential_activation_delete_prob > activation_delete_prob and len(activations) > 1:
709
782
 
710
783
  random_index = random.randint(0, len(activations) - 1)
711
-
712
- wc = np.copy(weight)
713
- for i in range(weight.shape[0]):
714
-
715
- wc[i,:] = apply_activation(wc[i,:], activations[random_index])
716
- weight[i,:] -= wc[i,:]
717
-
718
784
  activations.pop(random_index)
719
- weight = normalization(weight, dtype=dtype)
720
785
 
721
-
786
+
722
787
  if potential_activation_change_prob > activation_change_prob:
723
788
 
724
789
  random_index_all_act = int(random.uniform(0, len(all_acts)-1))
@@ -726,18 +791,28 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
726
791
 
727
792
  activations[random_index_genom_act] = all_acts[random_index_all_act]
728
793
 
729
- wc = np.copy(weight)
730
- for i in range(weight.shape[0]):
794
+ return weight, activations
731
795
 
732
- wc[i,:] = apply_activation(wc[i,:], activations[random_index_genom_act])
733
- weight[i,:] -= wc[i,:]
796
+ def second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob):
797
+
798
+ selection_prob = random.uniform(0, 1)
799
+ random_index = int(random.uniform(0, len(good_weights) - 1))
734
800
 
735
- weight = normalization(weight, dtype=dtype)
801
+ if selection_prob > bad_genomes_selection_prob:
802
+ second_selected_W = good_weights[random_index]
803
+ second_selected_act = good_activations[random_index]
736
804
 
737
- for i in range(weight.shape[0]):
805
+ else:
806
+ second_selected_W = bad_weights[random_index]
807
+ second_selected_act = bad_activations[random_index]
808
+
809
+ return second_selected_W, second_selected_act, random_index
810
+
811
+ def dominant_parent_selection(bad_genomes_selection_prob):
738
812
 
739
- weight[i,:] = apply_activation(weight[i,:], activations[random_index_genom_act])
813
+ selection_prob = random.uniform(0, 1)
740
814
 
741
- weight = normalization(weight, dtype=dtype)
815
+ if selection_prob > bad_genomes_selection_prob: decision = 'first_parent'
816
+ else: decision = 'second_parent'
742
817
 
743
- return weight, activations
818
+ return decision