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