pyerualjetwork 4.1.9b2__py3-none-any.whl → 4.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,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
@@ -13,6 +15,7 @@ ANAPLAN document: https://github.com/HCB06/Anaplan/blob/main/Welcome_to_Anaplan/
13
15
  import cupy as cp
14
16
  import numpy as np
15
17
  import random
18
+ import math
16
19
 
17
20
 
18
21
  ### LIBRARY IMPORTS ###
@@ -70,155 +73,196 @@ def define_genomes(input_shape, output_shape, population_size, dtype=cp.float32)
70
73
  return cp.array(population_weights, dtype=dtype), population_activations
71
74
 
72
75
 
73
- 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=cp.float32):
76
+ def evolver(weights,
77
+ activation_potentiations,
78
+ what_gen,
79
+ fitness,
80
+ show_info=False,
81
+ policy='aggresive',
82
+ bad_genomes_selection_prob=None,
83
+ bar_status=True,
84
+ strategy='normal_selective',
85
+ target_fitness='max',
86
+ mutations=True,
87
+ bad_genomes_mutation_prob=None,
88
+ activation_mutate_prob=0.5,
89
+ save_best_genom=True,
90
+ fitness_bias=None,
91
+ cross_over_mode='tpm',
92
+ activation_mutate_add_prob=0.5,
93
+ activation_mutate_delete_prob=0.5,
94
+ activation_mutate_change_prob=0.5,
95
+ weight_mutate_prob=1,
96
+ weight_mutate_rate=32,
97
+ activation_selection_add_prob=0.6,
98
+ activation_selection_change_prob=0.4,
99
+ activation_selection_rate=2,
100
+ dtype=cp.float32):
74
101
  """
75
- Applies the evolving process of a population of genomes using selection, crossover, mutation, and activation function potentiation.
76
- The function modifies the population's weights and activation functions based on a specified policy, mutation probabilities, and strategy.
102
+ Applies the evolving process of a population of genomes using selection, crossover, mutation, and activation function potentiation.
103
+ The function modifies the population's weights and activation functions based on a specified policy, mutation probabilities, and strategy.
77
104
 
78
- Args:
79
- weights (cupy.ndarray): Array of weights for each genome.
80
- (first returned value of define_genomes function)
81
-
82
- activation_potentiations (list): A list of activation functions for each genome.
83
- (second returned value of define_genomes function)
84
-
85
- what_gen (int): The current generation number, used for informational purposes or logging.
86
-
87
- fitness (cupy.ndarray): A 1D array containing the fitness or reward values of each genome.
88
- The array is used to rank the genomes based on their performance. PLANEAT maximizes the reward.
89
-
90
- show_info (bool, optional): If True, prints information about the current generation and the
91
- maximum reward obtained. Also shows the current configuration. Default is False.
92
-
93
- strategy (str, optional): The strategy for combining the best and bad genomes. Options:
94
- - 'cross_over': Perform crossover between the best genomes and replace bad genomes.
95
- (Classic NEAT crossover)
96
- - 'potentiate': Cumulate the weight of the best genomes and replace bad genomes.
97
- (PLAN feature, similar to arithmetic crossover but different.)
98
- Default is 'cross_over'.
99
-
100
- bar_status (bool, optional): Loading bar status during evolving process of genomes. True or False. Default: True
105
+ 'selection' args effects cross-over.
106
+ 'mutate' args effects mutation.
101
107
 
102
- policy (str, optional): The selection policy that governs how genomes are selected for reproduction. Options:
103
- - 'normal_selective': Normal selection based on reward, where a portion of the bad genes are discarded.
104
- - 'more_selective': A more selective policy, where fewer bad genes survive.
105
- - 'less_selective': A less selective policy, where more bad genes survive.
106
- Default is 'normal_selective'.
107
-
108
- target_fitness (str, optional): Target fitness strategy for PLANEAT optimization. ('max' for machine learning, 'min' for machine unlearning.) Default: 'max'
108
+ Args:
109
+ weights (cupy.ndarray): Array of weights for each genome.
110
+ (first returned value of define_genomes function)
111
+
112
+ activation_potentiations (list): A list of activation functions for each genome.
113
+ (second returned value of define_genomes function)
114
+
115
+ what_gen (int): The current generation number, used for informational purposes or logging.
116
+
117
+ fitness (cupy.ndarray): A 1D array containing the fitness values of each genome.
118
+ The array is used to rank the genomes based on their performance. PLANEAT maximizes or minimizes this fitness based on the `target_fitness` parameter.
119
+
120
+ show_info (bool, optional): If True, prints information about the current generation and the
121
+ maximum reward obtained. Also shows the current configuration. Default is False.
122
+
123
+ strategy (str, optional): The strategy for combining the best and bad genomes. Options:
124
+ - 'normal_selective': Normal selection based on reward, where a portion of the bad genes are discarded.
125
+ - 'more_selective': A more selective strategy, where fewer bad genes survive.
126
+ - 'less_selective': A less selective strategy, where more bad genes survive.
127
+ Default is 'normal_selective'.
128
+
129
+ bar_status (bool, optional): Loading bar status during evolving process of genomes. True or False. Default: True
109
130
 
110
- mutations (bool, optional): If True, mutations are applied to the bad genomes and potentially
111
- to the best genomes as well. Default is True.
112
-
113
- bad_genoms_mutation_prob (float, optional): The probability of applying mutation to the bad genomes.
114
- Must be in the range [0, 1]. Also affects the mutation probability of the best genomes inversely.
115
- For example, a value of 0.7 for bad genomes implies 0.3 for best genomes. Default is None,
116
- which means it is determined by the `policy` argument.
117
-
118
- activation_mutate_prob (float, optional): The probability of applying mutation to the activation functions.
119
- Must be in the range [0, 1]. Default is 0.5 (50%).
120
-
121
- save_best_genom (bool, optional): If True, ensures that the best genomes are saved and not mutated
122
- or altered during reproduction. Default is True.
123
-
124
- cross_over_mode (str, optional): Specifies the crossover method to use. Options:
125
- - 'tpm': Two-Point Matrix Crossover
126
- - 'plantic': plantic Crossover
127
- Default is 'tpm'.
128
-
129
- activation_add_prob (float, optional): The probability of adding a new activation function to the genome for mutation.
130
- Must be in the range [0, 1]. Default is 0.5.
131
-
132
- activation_delete_prob (float, optional): The probability of deleting an existing activation function
133
- from the genome for mutation. Must be in the range [0, 1]. Default is 0.5.
134
-
135
- activation_change_prob (float, optional): The probability of changing an activation function in the genome for mutation.
136
- Must be in the range [0, 1]. Default is 0.5.
137
-
138
- weight_mutate_prob (float, optional): The probability of mutating a weight in the genome.
139
- Must be in the range [0, 1]. Default is 1.
140
-
141
- weight_mutate_rate (int, optional): If the value you enter here is equal to the result of input layer * output layer,
142
- only a single weight will be mutated during each mutation process. If the value you enter here is half
143
- of the result of input layer * output layer, two weights in the weight matrix will be mutated.
144
- WARNING: if you don't understand do NOT change this value. Default is 32.
131
+ policy (str, optional): The selection policy that governs how genomes are selected for reproduction. Options:
132
+
133
+ - 'aggresive': Aggressive policy using very aggressive selection policy.
134
+ Advantages: fast training.
135
+ Disadvantages: may lead to fitness stuck in a local maximum or minimum.
145
136
 
146
- activation_selection_add_prob (float, optional): The probability of adding an existing activation function for cross over.
147
- 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.)
148
-
149
- activation_selection_change_prob (float, optional): The probability of changing an activation function in the genome for cross over.
150
- Must be in the range [0, 1]. Default is 0.5.
151
-
152
- 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.
153
-
154
- dtype (cupy.dtype): Data type for the arrays. np.float32 by default. Example: cp.float64 or cp.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
155
-
156
- Raises:
157
- ValueError:
158
- - If `policy` is not one of the specified values ('normal_selective', 'more_selective', 'less_selective').
159
- - If `cross_over_mode` is not one of the specified values ('tpm', 'plantic').
160
- - If `bad_genoms_mutation_prob`, `activation_mutate_prob`, or other probability parameters are not in the range [0, 1].
161
- - If the population size is odd (ensuring an even number of genomes is required for proper selection).
162
-
163
- Returns:
164
- tuple: A tuple containing:
165
- - weights (numpy.ndarray): The updated weights for the population after selection, crossover, and mutation.
166
- The shape is (population_size, output_shape, input_shape).
167
- - activation_potentiations (list): The updated list of activation functions for the population.
168
-
169
- Notes:
170
- - **Selection Process**:
171
- - The genomes are sorted by their fitness (based on `fitness`), and then split into "best" and "bad" halves.
172
- - The best genomes are retained, and the bad genomes are modified based on the selected strategy.
173
-
174
- - **Crossover and Potentiation Strategies**:
175
- - 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.
176
- - The **'potentiate'** strategy strengthens the best genomes by potentiating their weights towards the other good genomes.
177
-
178
- - **Mutation**:
179
- - Mutation is applied to both the best and bad genomes, depending on the mutation probability and the `policy`.
180
- - `bad_genoms_mutation_prob` determines the probability of applying mutations to the bad genomes.
181
- - If `activation_mutate_prob` is provided, activation function mutations are applied to the genomes based on this probability.
182
-
183
- - **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.
184
-
185
- - **Logging**: If `show_info=True`, the current generation and the maximum reward from the population are printed for tracking the learning progress.
137
+ - 'explorer': Explorer policy increases population diversity.
138
+ Advantages: fitness does not get stuck at local maximum or minimum.
139
+ Disadvantages: slow training.
140
+
141
+ Suggestions: Use hybrid and dynamic policy. When fitness appears stuck, switch to the 'explorer' policy.
186
142
 
187
- Example:
188
- ```python
189
- weights, activation_potentiations = planeat.evolve(weights, activation_potentiations, 1, fitness, show_info=True, strategy='cross_over', policy='normal_selective')
190
- ```
143
+ Default: 'aggresive'.
144
+
145
+ target_fitness (str, optional): Target fitness strategy for PLANEAT optimization. ('max' maximizes fitness, 'min' minimizes fitness.) Default: 'max'.
146
+
147
+ 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`.
191
148
 
192
- - The function returns the updated weights and activations after processing based on the chosen strategy, policy, and mutation parameters.
149
+ mutations (bool, optional): If True, mutations are applied to the bad genomes and potentially
150
+ to the best genomes as well. Default is True.
151
+
152
+ bad_genomes_mutation_prob (float, optional): The probability of applying mutation to the bad genomes.
153
+ Must be in the range [0, 1]. Also affects the mutation probability of the best genomes inversely.
154
+ For example, a value of 0.7 for bad genomes implies 0.3 for best genomes. Default: Determined by `policy`.
155
+
156
+ activation_mutate_prob (float, optional): The probability of applying mutation to the activation functions.
157
+ Must be in the range [0, 1]. Default is 0.5 (50%).
158
+
159
+ save_best_genom (bool, optional): If True, ensures that the best genomes are saved and not mutated
160
+ or altered during reproduction. Default is True.
161
+
162
+ cross_over_mode (str, optional): Specifies the crossover method to use. Options:
163
+ - 'tpm': Two-Point Matrix Crossover.
164
+ Default is 'tpm'.
165
+
166
+ activation_mutate_add_prob (float, optional): The probability of adding a new activation function to the genome for mutation.
167
+ Must be in the range [0, 1]. Default is 0.5.
168
+
169
+ activation_mutate_delete_prob (float, optional): The probability of deleting an existing activation function
170
+ from the genome for mutation. Must be in the range [0, 1]. Default is 0.5.
171
+
172
+ activation_mutate_change_prob (float, optional): The probability of changing an activation function in the genome for mutation.
173
+ Must be in the range [0, 1]. Default is 0.5.
174
+
175
+ weight_mutate_prob (float, optional): The probability of mutating a weight in the genome.
176
+ Must be in the range [0, 1]. Default is 1.
177
+
178
+ weight_mutate_rate (int, optional): If the value entered here equals the result of input_layer * output_layer,
179
+ only a single weight will be mutated during each mutation process. If the value is half of the result,
180
+ two weights will be mutated. WARNING: If you don't understand, do NOT change this value. Default is 32.
181
+
182
+ activation_selection_add_prob (float, optional): The probability of adding an existing activation function for crossover.
183
+ Must be in the range [0, 1]. Default is 0.6. (WARNING! Higher values increase complexity. For faster training, increase this value.)
184
+
185
+ activation_selection_change_prob (float, optional): The probability of changing an activation function in the genome for crossover.
186
+ Must be in the range [0, 1]. Default is 0.4.
187
+
188
+ 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.
189
+
190
+ dtype (cupy.dtype): Data type for the arrays. Default: cp.float32.
191
+ Example: cp.float64 or cp.float16 [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not recommended!].
192
+
193
+ Raises:
194
+ ValueError:
195
+ - If `policy` is not one of the specified values ('aggresive', 'explorer').
196
+ - If 'strategy' is not one of the specified values ('less_selective', 'normal_selective', 'more_selective')
197
+ - If `cross_over_mode` is not one of the specified values ('tpm').
198
+ - If `bad_genomes_mutation_prob`, `activation_mutate_prob`, or other probability parameters are not in the range 0 and 1.
199
+ - If the population size is odd (ensuring an even number of genomes is required for proper selection).
200
+ - If 'fitness_bias' value is not in range 0 and 1.
201
+
202
+ Returns:
203
+ tuple: A tuple containing:
204
+ - weights (numpy.ndarray): The updated weights for the population after selection, crossover, and mutation.
205
+ The shape is (population_size, output_shape, input_shape).
206
+ - activation_potentiations (list): The updated list of activation functions for the population.
207
+
208
+ Notes:
209
+ - **Selection Process**:
210
+ - The genomes are sorted by their fitness (based on `fitness`), and then split into "best" and "bad" halves.
211
+ - The best genomes are retained, and the bad genomes are modified based on the selected strategy.
212
+
213
+ - **Crossover Strategies**:
214
+ - The **'cross_over'** strategy performs crossover, where parts of the best genomes' weights are combined with other good genomes to create new weight matrices.
215
+
216
+ - **Mutation**:
217
+ - Mutation is applied to both the best and bad genomes, depending on the mutation probability and the `policy`.
218
+ - `bad_genomes_mutation_prob` determines the probability of applying mutations to the bad genomes.
219
+ - If `activation_mutate_prob` is provided, activation function mutations are applied to the genomes based on this probability.
220
+
221
+ - **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.
222
+
223
+ - **Logging**: If `show_info=True`, the current generation and the maximum reward from the population are printed for tracking the learning progress.
224
+
225
+ Example:
226
+ ```python
227
+ weights, activation_potentiations = planeat.evolver(weights, activation_potentiations, 1, fitness, show_info=True, strategy='normal_selective', policy='aggresive')
228
+ ```
229
+
230
+ - The function returns the updated weights and activations after processing based on the chosen strategy, policy, and mutation parameters.
193
231
  """
194
232
 
195
233
  ### ERROR AND CONFIGURATION CHECKS:
196
-
197
- if policy == 'normal_selective':
198
- if bad_genoms_mutation_prob == None:
199
- bad_genoms_mutation_prob = 0.7
234
+ if strategy == 'normal_selective':
235
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.7 # EFFECTS MUTATION
236
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.25 # EFFECTS CROSS-OVER
237
+ if fitness_bias is None: fitness_bias = 0.5 # The pressure applied by FITNESS to the CROSS-OVER
200
238
 
201
- elif policy == 'more_selective':
202
- if bad_genoms_mutation_prob == None:
203
- bad_genoms_mutation_prob = 0.85
239
+ elif strategy == 'more_selective':
240
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.85 # EFFECTS MUTATION
241
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.1 # EFFECTS CROSS-OVER
242
+ if fitness_bias is None: fitness_bias = 0.7 # The pressure applied by FITNESS to the CROSS-OVER
204
243
 
205
- elif policy == 'less_selective':
206
- if bad_genoms_mutation_prob == None:
207
- bad_genoms_mutation_prob = 0.6
244
+ elif strategy == 'less_selective':
245
+ if bad_genomes_mutation_prob is None: bad_genomes_mutation_prob = 0.6 # EFFECTS MUTATION
246
+ if bad_genomes_selection_prob is None: bad_genomes_selection_prob = 0.5 # EFFECTS CROSS-OVER
247
+ if fitness_bias is None: fitness_bias = 0.3 # The pressure applied by FITNESS to the CROSS-OVER
208
248
 
209
249
  else:
210
- raise ValueError("policy parameter must be: 'normal_selective' or 'more_selective' or 'less_selective'")
211
-
212
-
213
- 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):
250
+ raise ValueError("strategy parameter must be: 'normal_selective' or 'more_selective' or 'less_selective'")
251
+
252
+ if ((activation_mutate_add_prob < 0 or activation_mutate_add_prob > 1) or
253
+ (activation_mutate_change_prob < 0 or activation_mutate_change_prob > 1) or
254
+ (activation_mutate_delete_prob < 0 or activation_mutate_delete_prob > 1) or
255
+ (weight_mutate_prob < 0 or weight_mutate_prob > 1) or
256
+ (activation_selection_add_prob < 0 or activation_selection_add_prob > 1) or (
257
+ activation_selection_change_prob < 0 or activation_selection_change_prob > 1)):
258
+
214
259
  raise ValueError("All hyperparameters ending with 'prob' must be a number between 0 and 1.")
215
260
 
216
- if cross_over_mode != 'tpm' and cross_over_mode != 'plantic':
217
- raise ValueError("cross_over_mode parameter must be 'tpm' or 'plantic'")
261
+ if fitness_bias < 0 or fitness_bias > 1: raise ValueError("fitness_bias value must be a number between 0 and 1.")
218
262
 
219
- if bad_genoms_mutation_prob is not None:
220
- if not isinstance(bad_genoms_mutation_prob, float) or bad_genoms_mutation_prob < 0 or bad_genoms_mutation_prob > 1:
221
- raise ValueError("bad_genoms_mutation_prob parameter must be float and 0-1 range")
263
+ if bad_genomes_mutation_prob is not None:
264
+ if not isinstance(bad_genomes_mutation_prob, float) or bad_genomes_mutation_prob < 0 or bad_genomes_mutation_prob > 1:
265
+ raise ValueError("bad_genomes_mutation_prob parameter must be float and 0-1 range")
222
266
 
223
267
  if activation_mutate_prob is not None:
224
268
  if not isinstance(activation_mutate_prob, float) or activation_mutate_prob < 0 or activation_mutate_prob > 1:
@@ -242,90 +286,93 @@ Example:
242
286
 
243
287
  ### GENOMES ARE DIVIDED INTO TWO GROUPS: GOOD GENOMES AND BAD GENOMES:
244
288
 
245
- best_weights = weights[slice_center:]
289
+ good_weights = weights[slice_center:]
246
290
  bad_weights = weights[:slice_center]
247
- best_weight = best_weights[len(best_weights)-1]
291
+ best_weights = good_weights[-1]
248
292
 
249
- best_activations = list(activation_potentiations[slice_center:])
293
+ good_activations = list(activation_potentiations[slice_center:])
250
294
  bad_activations = list(activation_potentiations[:slice_center])
251
- best_activation = best_activations[len(best_activations) - 1]
295
+ best_activations = good_activations[-1]
252
296
 
253
297
 
254
- ### NEAT IS APPLIED ACCORDING TO THE SPECIFIED POLICY, STRATEGY, AND PROBABILITY CONFIGURATION:
298
+ ### PLANEAT IS APPLIED ACCORDING TO THE SPECIFIED POLICY, STRATEGY, AND PROBABILITY CONFIGURATION:
255
299
 
256
300
  bar_format = loading_bars()[0]
257
301
 
258
- if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50, ascii="▱▰")
259
-
260
- for i in range(len(bad_weights)):
261
-
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)
266
-
267
-
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
-
271
-
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 cp.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 cp.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
+ if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50)
303
+ normalized_fitness = abs(normalization(fitness, dtype=dtype))
302
304
 
305
+ best_fitness = normalized_fitness[-1]
303
306
 
304
- if policy == 'less_selective':
307
+ child_W = cp.copy(bad_weights)
308
+ child_act = bad_activations.copy()
305
309
 
306
- random_index = int(random.uniform(0, len(best_weights) - 1))
307
-
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)
310
+ for i in range(len(bad_weights)):
311
+ second_parent_W, second_parent_act, s_i = second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob)
312
+
313
+ if policy == 'aggresive':
314
+ child_W[i], child_act[i] = cross_over(best_weights,
315
+ second_parent_W,
316
+ best_activations,
317
+ second_parent_act,
318
+ cross_over_mode=cross_over_mode,
319
+ activation_selection_add_prob=activation_selection_add_prob,
320
+ activation_selection_change_prob=activation_selection_change_prob,
321
+ activation_selection_rate=activation_selection_rate,
322
+ bad_genomes_selection_prob=bad_genomes_selection_prob,
323
+ first_parent_fitness=best_fitness,
324
+ fitness_bias=fitness_bias,
325
+ second_parent_fitness=normalized_fitness[s_i]
326
+ )
327
+ elif policy == 'explorer':
328
+ child_W[i], child_act[i] = cross_over(good_weights[i],
329
+ second_parent_W,
330
+ good_activations[i],
331
+ second_parent_act,
332
+ cross_over_mode=cross_over_mode,
333
+ activation_selection_add_prob=activation_selection_add_prob,
334
+ activation_selection_change_prob=activation_selection_change_prob,
335
+ activation_selection_rate=activation_selection_rate,
336
+ bad_genomes_selection_prob=bad_genomes_selection_prob,
337
+ first_parent_fitness=normalized_fitness[i],
338
+ fitness_bias=fitness_bias,
339
+ second_parent_fitness=normalized_fitness[s_i]
340
+ )
341
+
342
+ else: raise ValueError("policy parameter must be: 'aggresive' or 'explorer'")
343
+
344
+ if mutations is True:
345
+ mutation_prob = random.uniform(0, 1)
346
+
347
+ if mutation_prob > bad_genomes_mutation_prob:
348
+ if (save_best_genom == True and not np.array_equal(good_weights[i], best_weights)) or save_best_genom == False:
349
+ good_weights[i], good_activations[i] = mutation(good_weights[i],
350
+ good_activations[i],
351
+ activation_mutate_prob=activation_mutate_prob,
352
+ activation_add_prob=activation_mutate_add_prob,
353
+ activation_delete_prob=activation_mutate_delete_prob,
354
+ activation_change_prob=activation_mutate_change_prob,
355
+ weight_mutate_prob=weight_mutate_prob,
356
+ threshold=weight_mutate_rate,
357
+ genome_fitness=normalized_fitness[i]
358
+ )
310
359
 
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], dtype=dtype)
360
+ elif mutation_prob < bad_genomes_mutation_prob:
361
+ bad_weights[i], bad_activations[i] = mutation(bad_weights[i],
362
+ bad_activations[i],
363
+ activation_mutate_prob=activation_mutate_prob,
364
+ activation_add_prob=activation_mutate_add_prob,
365
+ activation_delete_prob=activation_mutate_delete_prob,
366
+ activation_change_prob=activation_mutate_change_prob,
367
+ weight_mutate_prob=weight_mutate_prob,
368
+ threshold=weight_mutate_rate,
369
+ genome_fitness=normalized_fitness[i]
370
+ )
313
371
 
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 cp.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
372
  if bar_status: progress.update(1)
326
373
 
327
- weights = cp.vstack((bad_weights, best_weights))
328
- activation_potentiations = bad_activations + best_activations
374
+ weights = cp.vstack((child_W, good_weights))
375
+ activation_potentiations = child_act + good_activations
329
376
 
330
377
  ### INFO PRINTING CONSOLE
331
378
 
@@ -334,26 +381,24 @@ Example:
334
381
  print("*** Configuration Settings ***")
335
382
  print(" POPULATION SIZE: ", str(len(weights)))
336
383
  print(" STRATEGY: ", strategy)
337
-
338
- if strategy == 'cross_over':
339
- print(" CROSS OVER MODE: ", cross_over_mode)
340
-
384
+ print(" CROSS OVER MODE: ", cross_over_mode)
341
385
  print(" POLICY: ", policy)
342
386
  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)))
387
+ print(" BAD GENOMES MUTATION PROB: ", str(bad_genomes_mutation_prob))
388
+ print(" GOOD GENOMES MUTATION PROB: ", str(round(1 - bad_genomes_mutation_prob, 2)))
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 ***")
356
- print(" MAX REWARD: ", str(cp.round(max(fitness), 2)))
401
+ print(" MAX REWARD: ", str(cp.round(max(fitness), 2)))
357
402
  print(" MEAN REWARD: ", str(cp.round(cp.mean(fitness), 2)))
358
403
  print(" MIN REWARD: ", str(cp.round(min(fitness), 2)) + '\n')
359
404
 
@@ -361,7 +406,7 @@ Example:
361
406
  print(" NOTE: Genomes are always sorted from the least successful to the most successful according to their performance ranking. Therefore, the genome at the last index is the king of the previous generation. " + '\n')
362
407
 
363
408
 
364
- return cp.array(weights), activation_potentiations
409
+ return weights, activation_potentiations
365
410
 
366
411
 
367
412
  def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dtype=cp.float32):
@@ -370,14 +415,17 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
370
415
  and weights depending on whether reinforcement learning mode is enabled or not.
371
416
 
372
417
  Args:
373
- x_population (list or numpy.ndarray): A list or 2D numpy array where each element represents
418
+ x_population (list or cupy.ndarray): A list or 2D numpy or cupy array where each element represents
374
419
  a genome (A list of input features for each genome, or a single set of input features for one genome (only in rl_mode)).
375
- weights (list or numpy.ndarray): A list or 2D numpy array of weights corresponding to each genome
420
+
421
+ weights (list or cupy.ndarray): A list or 2D numpy array of weights corresponding to each genome
376
422
  in `x_population`. This determines the strength of connections.
423
+
377
424
  activation_potentiations (list or str): A list where each entry represents an activation function
378
425
  or a potentiation strategy applied to each genome. If only one
379
426
  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.)
427
+
428
+ 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
429
  Default is False.
382
430
 
383
431
 
@@ -436,48 +484,108 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
436
484
  return outputs
437
485
 
438
486
 
439
- 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):
487
+ def cross_over(first_parent_W,
488
+ second_parent_W,
489
+ first_parent_act,
490
+ second_parent_act,
491
+ cross_over_mode,
492
+ activation_selection_add_prob,
493
+ activation_selection_change_prob,
494
+ activation_selection_rate,
495
+ bad_genomes_selection_prob,
496
+ first_parent_fitness,
497
+ second_parent_fitness,
498
+ fitness_bias):
440
499
  """
441
- Performs a selected Crossover operation on two sets of weights and activation functions.
500
+ Performs a crossover operation on two sets of weights and activation functions.
442
501
  This function combines two individuals (represented by their weights and activation functions)
443
502
  to create a new individual by exchanging parts of their weight matrices and activation functions.
444
503
 
445
504
  Args:
446
- best_weight (numpy.ndarray): The weight matrix of the first individual (parent).
447
- good_weight (numpy.ndarray): The weight matrix of the second individual (parent).
448
- best_activations (str or list): The activation function(s) of the first individual.
449
- good_activations (str or list): The activation function(s) of the second individual.
505
+ first_parent_W (cupy.ndarray): The weight matrix of the first individual (parent).
506
+
507
+ second_parent_W (numpy.ndarray): The weight matrix of the second individual (parent).
508
+
509
+ first_parent_act (str or list): The activation function(s) of the first individual.
510
+
511
+ second_parent_act (str or list): The activation function(s) of the second individual.
512
+
450
513
  cross_over_mode (str): Determines the crossover method to be used. Options:
451
- - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights
452
- are swapped between parents.
453
- - 'plan': Output Connections Crossover, where specific connections
454
- in the weight matrix are crossed over. Default is 'tpm'.
514
+ - 'tpm': Two-Point Matrix Crossover, where sub-matrices of weights are swapped between parents.
515
+
516
+ activation_selection_add_prob (float): Probability of adding new activation functions
517
+ from the second parent to the child genome.
518
+
519
+ activation_selection_change_prob (float): Probability of replacing an activation function in the child genome
520
+ with one from the second parent.
521
+
522
+ activation_selection_rate (float): Determines how quickly activation functions are added or replaced
523
+ during the crossover process.
524
+
525
+ bad_genomes_selection_prob (float): Probability of selecting a "bad" genome for replacement with the offspring.
526
+
527
+ first_parent_fitness (float): Fitness score of the first parent.
528
+
529
+ second_parent_fitness (float): Fitness score of the second parent.
530
+
531
+ fitness_bias (float): A bias factor used to favor fitter parents during crossover operations.
455
532
 
456
533
  Returns:
457
534
  tuple: A tuple containing:
458
- - new_weight (numpy.ndarray): The weight matrix of the new individual created by crossover.
459
- - new_activations (list): The list of activation functions of the new individual created by crossover.
535
+ - child_W (numpy.ndarray): The weight matrix of the new individual created by crossover.
536
+ - child_act (list): The list of activation functions of the new individual created by crossover.
460
537
 
461
538
  Notes:
462
539
  - The crossover is performed based on the selected `cross_over_mode`.
463
- - In 'tpm', random sub-matrices from the parent weight matrices are swapped.
464
- - In 'plantic', specific connections in the weight matrix are swapped between parents.
465
- - The crossover operation combines the activation functions of both parents:
466
- - If the activation functions are passed as strings, they are converted to lists for uniform handling.
467
- - The resulting activation functions depend on the crossover method and the parent's configuration.
540
+ - In 'tpm' mode, random sub-matrices from the parent weight matrices are swapped.
541
+ - Activation functions from both parents are combined using the probabilities and rates provided.
468
542
 
469
543
  Example:
470
544
  ```python
471
- new_weights, new_activations = cross_over(best_weight, good_weight, best_activations, good_activations, cross_over_mode='tpm')
545
+ new_weights, new_activations = cross_over(
546
+ first_parent_W=parent1_weights,
547
+ second_parent_W=parent2_weights,
548
+ first_parent_act=parent1_activations,
549
+ second_parent_act=parent2_activations,
550
+ cross_over_mode='tpm',
551
+ activation_selection_add_prob=0.8,
552
+ activation_selection_change_prob=0.5,
553
+ activation_selection_rate=0.1,
554
+ bad_genomes_selection_prob=0.7,
555
+ first_parent_fitness=0.9,
556
+ second_parent_fitness=0.85,
557
+ fitness_bias=0.6
558
+ )
472
559
  ```
473
560
  """
474
561
 
475
- ### THE GIVEN GENOMES' WEIGHTS ARE RANDOMLY SELECTED AND COMBINED OVER A RANDOM RANGE. SIMILARLY, THEIR ACTIVATIONS ARE COMBINED. A NEW GENOME IS RETURNED WITH THE COMBINED WEIGHTS FIRST, FOLLOWED BY THE ACTIVATIONS:
562
+ ### THE GIVEN GENOMES' WEIGHTS ARE RANDOMLY SELECTED AND COMBINED OVER A RANDOM RANGE. SIMILARLY, THEIR ACTIVATIONS ARE COMBINED. A NEW GENOME IS RETURNED WITH THE COMBINED WEIGHTS FIRST, FOLLOWED BY THE ACTIVATIONS:
476
563
 
477
564
  start = 0
565
+
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)
478
573
 
479
- row_end = best_weight.shape[0]
480
- col_end = best_weight.shape[1]
574
+ if decision == 'first_parent':
575
+ dominant_parent_W = cp.copy(first_parent_W)
576
+ dominant_parent_act = first_parent_act
577
+
578
+ undominant_parent_W = cp.copy(second_parent_W)
579
+ undominant_parent_act = second_parent_act
580
+ succes = second_parent_fitness
581
+
582
+ elif decision == 'second_parent':
583
+ dominant_parent_W = cp.copy(second_parent_W)
584
+ dominant_parent_act = second_parent_act
585
+
586
+ undominant_parent_W = cp.copy(first_parent_W)
587
+ undominant_parent_act = first_parent_act
588
+ succes = first_parent_fitness
481
589
 
482
590
  while True:
483
591
 
@@ -487,48 +595,47 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
487
595
  row_cut_end = int(random.uniform(start, row_end))
488
596
  col_cut_end = int(random.uniform(start, col_end))
489
597
 
490
- 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)):
491
601
  break
602
+
603
+ selection_bias = random.uniform(0, 1)
492
604
 
493
- new_weight = cp.copy(best_weight)
494
- best_w2 = cp.copy(good_weight)
495
-
496
- if cross_over_mode == 'tpm':
497
- 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]
498
-
499
- elif cross_over_mode == 'plantic':
500
- new_weight[row_cut_start:row_cut_end,:] = best_w2[row_cut_start:row_cut_end,:]
605
+ if fitness_bias > selection_bias:
606
+ row_cut_start = math.floor(row_cut_start * succes)
607
+ row_cut_end = math.ceil(row_cut_end * succes)
501
608
 
609
+ col_cut_start = math.floor(col_cut_start * succes)
610
+ col_cut_end = math.ceil(col_cut_end * succes)
502
611
 
503
- if isinstance(best_activations, str):
504
- best = [best_activations]
612
+ child_W = dominant_parent_W
505
613
 
506
- if isinstance(good_activations, str):
507
- good = [good_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]
508
616
 
509
- if isinstance(best_activations, list):
510
- best = best_activations
511
617
 
512
- if isinstance(good_activations, list):
513
- good = good_activations
618
+ if isinstance(dominant_parent_act, str): dominant_parent_act = [dominant_parent_act]
619
+ if isinstance(undominant_parent_act, str): undominant_parent_act = [undominant_parent_act]
514
620
 
515
- new_activations = list(np.copy(best))
621
+ child_act = list(np.copy(dominant_parent_act))
516
622
 
517
623
  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
518
624
  potential_activation_selection_add = random.uniform(0, 1)
519
625
 
520
626
  if potential_activation_selection_add > activation_selection_add_prob:
521
627
 
628
+ activation_selection_rate = activation_selection_rate / succes
522
629
  new_threshold = activation_selection_rate
523
630
 
524
631
  while True:
525
632
 
526
- random_index_good = int(random.uniform(0, len(good)-1))
527
- random_good_activation = good[random_index_good]
633
+ random_index = int(random.uniform(0, len(undominant_parent_act)-1))
634
+ random_undominant_activation = undominant_parent_act[random_index]
528
635
 
529
- new_activations.append(random_good_activation)
636
+ child_act.append(random_undominant_activation)
530
637
 
531
- if len(best) > new_threshold:
638
+ if len(dominant_parent_act) > new_threshold:
532
639
  new_threshold += activation_selection_rate
533
640
  pass
534
641
 
@@ -539,85 +646,61 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
539
646
  potential_activation_selection_change_prob = random.uniform(0, 1)
540
647
 
541
648
  if potential_activation_selection_change_prob > activation_selection_change_prob:
542
-
649
+
650
+ activation_selection_rate = activation_selection_rate / succes
543
651
  new_threshold = activation_selection_rate
544
652
 
545
653
  while True:
546
654
 
547
- random_index_good = int(random.uniform(0, len(good)-1))
548
- random_index_best = int(random.uniform(0, len(best)-1))
549
- random_good_activation = good[random_index_good]
655
+ random_index_undominant = int(random.uniform(0, len(undominant_parent_act)-1))
656
+ random_index_dominant = int(random.uniform(0, len(dominant_parent_act)-1))
657
+ random_undominant_activation = undominant_parent_act[random_index_undominant]
550
658
 
551
- new_activations[random_index_best] = good[random_index_good]
659
+ child_act[random_index_dominant] = random_undominant_activation
552
660
 
553
- if len(best) > new_threshold:
661
+ if len(dominant_parent_act) > new_threshold:
554
662
  new_threshold += activation_selection_rate
555
663
  pass
556
664
 
557
665
  else:
558
666
  break
559
667
 
560
- return new_weight, new_activations
561
-
562
- def potentiate(best_weight, good_weight, best_activations, good_activations, dtype=cp.float32):
563
- """
564
- Combines two sets of weights and activation functions by adding the weight matrices and
565
- concatenating the activation functions. The resulting weight matrix is normalized. (Max abs normalization.)
566
-
567
- Args:
568
- best_weight (numpy.ndarray): The weight matrix of the first individual (parent).
569
- good_weight (numpy.ndarray): The weight matrix of the second individual (parent).
570
- best_activations (str or list): The activation function(s) of the first individual.
571
- good_activations (str or list): The activation function(s) of the second individual.
572
- dtype (cupy.dtype): Data type for the arrays. np.float32 by default. Example: cp.float64 or cp.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
573
-
574
- Returns:
575
- tuple: A tuple containing:
576
- - new_weight (numpy.ndarray): The new weight matrix after potentiation and normalization. (Max abs normalization.)
577
- - new_activations (list): The new activation functions after concatenation.
578
-
579
- Notes:
580
- - The weight matrices are element-wise added and then normalized using the `normalization` function. (Max abs normalization.)
581
- - The activation functions from both parents are concatenated to form the new activation functions list.
582
- - If the activation functions are passed as strings, they are converted to lists for uniform handling.
583
- """
584
-
585
- new_weight = best_weight + good_weight
586
- new_weight = normalization(new_weight, dtype=dtype)
587
-
588
- if isinstance(best_activations, str):
589
- best = [best_activations]
590
-
591
- if isinstance(good_activations, str):
592
- good = [good_activations]
593
-
594
- if isinstance(best_activations, list):
595
- best = best_activations
668
+ return child_W, child_act
596
669
 
597
- if isinstance(good_activations, list):
598
- good = good_activations
599
-
600
- new_activations = best + good
601
-
602
- return new_weight, new_activations
603
670
 
604
- def mutation(weight, activations, activation_mutate_prob, activation_add_prob, activation_delete_prob, activation_change_prob, weight_mutate_prob, threshold, dtype=cp.float32):
671
+ def mutation(weight,
672
+ activations,
673
+ activation_mutate_prob,
674
+ activation_add_prob,
675
+ activation_delete_prob,
676
+ activation_change_prob,
677
+ weight_mutate_prob,
678
+ threshold,
679
+ genome_fitness):
605
680
  """
606
681
  Performs mutation on the given weight matrix and activation functions.
607
682
  - The weight matrix is mutated by randomly changing its values based on the mutation probability.
608
683
  - The activation functions are mutated by adding, removing, or replacing them with predefined probabilities.
609
684
 
610
685
  Args:
611
- weight (numpy.ndarray): The weight matrix to mutate.
686
+ weight (cupy.ndarray): The weight matrix to mutate.
687
+
612
688
  activations (list): The list of activation functions to mutate.
689
+
613
690
  activation_mutate_prob (float): The overall probability of mutating activation functions.
691
+
614
692
  activation_add_prob (float): Probability of adding a new activation function.
693
+
615
694
  activation_delete_prob (float): Probability of removing an existing activation function.
695
+
616
696
  activation_change_prob (float): Probability of replacing an existing activation function with a new one.
697
+
617
698
  weight_mutate_prob (float): The probability of mutating weight matrix.
699
+
618
700
  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.
619
- dtype (cupy.dtype): Data type for the arrays. np.float32 by default. Example: cp.float64 or cp.float16. [fp32 for balanced devices, fp64 for strong devices, fp16 for weak devices: not reccomended!] (optional)
620
701
 
702
+ genome_fitness (float): Fitness value of genome
703
+
621
704
  Returns:
622
705
  tuple: A tuple containing:
623
706
  - mutated_weight (numpy.ndarray): The weight matrix after mutation.
@@ -635,8 +718,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
635
718
  the optimization process.
636
719
  """
637
720
 
638
- if isinstance(activations, str):
639
- activations = [activations]
721
+ if isinstance(activations, str): activations = [activations]
640
722
 
641
723
  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
642
724
  potential_weight_mutation = random.uniform(0, 1)
@@ -646,6 +728,8 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
646
728
  start = 0
647
729
  row_end = weight.shape[0]
648
730
  col_end = weight.shape[1]
731
+
732
+ threshold = threshold * genome_fitness
649
733
  new_threshold = threshold
650
734
 
651
735
  while True:
@@ -662,7 +746,6 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
662
746
  else:
663
747
  break
664
748
 
665
-
666
749
  activation_mutate_prob = 1 - activation_mutate_prob
667
750
  potential_activation_mutation = random.uniform(0, 1)
668
751
 
@@ -685,13 +768,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
685
768
 
686
769
  random_index_all_act = int(random.uniform(0, len(all_acts)-1))
687
770
  activations.append(all_acts[random_index_all_act])
688
-
689
- for i in range(weight.shape[0]):
690
-
691
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
692
771
 
693
- weight = normalization(weight, dtype=dtype)
694
-
695
772
  except:
696
773
 
697
774
  activation = activations
@@ -700,26 +777,12 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
700
777
  activations.append(activation)
701
778
  activations.append(all_acts[int(random.uniform(0, len(all_acts)-1))])
702
779
 
703
- for i in range(weight.shape[0]):
704
-
705
- weight[i,:] = apply_activation(weight[i,:], activations[-1])
706
-
707
- weight = normalization(weight, dtype=dtype)
708
-
709
780
  if potential_activation_delete_prob > activation_delete_prob and len(activations) > 1:
710
781
 
711
782
  random_index = random.randint(0, len(activations) - 1)
712
-
713
- wc = cp.copy(weight)
714
- for i in range(weight.shape[0]):
715
-
716
- wc[i,:] = apply_activation(wc[i,:], activations[random_index])
717
- weight[i,:] -= wc[i,:]
718
-
719
783
  activations.pop(random_index)
720
- weight = normalization(weight, dtype=dtype)
721
784
 
722
-
785
+
723
786
  if potential_activation_change_prob > activation_change_prob:
724
787
 
725
788
  random_index_all_act = int(random.uniform(0, len(all_acts)-1))
@@ -727,18 +790,30 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
727
790
 
728
791
  activations[random_index_genom_act] = all_acts[random_index_all_act]
729
792
 
730
- wc = cp.copy(weight)
731
- for i in range(weight.shape[0]):
793
+ return weight, activations
794
+
732
795
 
733
- wc[i,:] = apply_activation(wc[i,:], activations[random_index_genom_act])
734
- 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))
800
+
801
+ if selection_prob > bad_genomes_selection_prob:
802
+ second_selected_W = good_weights[random_index]
803
+ second_selected_act = good_activations[random_index]
735
804
 
736
- weight = normalization(weight, dtype=dtype)
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
+
737
811
 
738
- for i in range(weight.shape[0]):
812
+ def dominant_parent_selection(bad_genomes_selection_prob):
739
813
 
740
- weight[i,:] = apply_activation(weight[i,:], activations[random_index_genom_act])
814
+ selection_prob = random.uniform(0, 1)
741
815
 
742
- weight = normalization(weight, dtype=dtype)
816
+ if selection_prob > bad_genomes_selection_prob: decision = 'first_parent'
817
+ else: decision = 'second_parent'
743
818
 
744
- return weight, activations
819
+ return decision