pyerualjetwork 4.1.9b1__py3-none-any.whl → 4.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyerualjetwork/__init__.py +1 -1
- pyerualjetwork/data_operations.py +1 -1
- pyerualjetwork/plan.py +3 -11
- pyerualjetwork/plan_cuda.py +2 -1
- pyerualjetwork/planeat.py +417 -342
- pyerualjetwork/planeat_cuda.py +422 -341
- {pyerualjetwork-4.1.9b1.dist-info → pyerualjetwork-4.2.0.dist-info}/METADATA +1 -1
- {pyerualjetwork-4.1.9b1.dist-info → pyerualjetwork-4.2.0.dist-info}/RECORD +10 -10
- {pyerualjetwork-4.1.9b1.dist-info → pyerualjetwork-4.2.0.dist-info}/WHEEL +0 -0
- {pyerualjetwork-4.1.9b1.dist-info → pyerualjetwork-4.2.0.dist-info}/top_level.txt +0 -0
pyerualjetwork/planeat_cuda.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
|
@@ -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,198 @@ 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
|
76
|
+
def evolver(weights,
|
77
|
+
activation_potentiations,
|
78
|
+
what_gen,
|
79
|
+
fitness,
|
80
|
+
show_info=False,
|
81
|
+
policy='aggressive',
|
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
|
-
|
79
|
-
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
+
- 'aggressive': 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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
143
|
+
Default: 'aggressive'.
|
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
|
-
|
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 ('aggressive', '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='aggressive')
|
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
|
-
|
198
|
-
if
|
199
|
-
|
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
|
202
|
-
if
|
203
|
-
|
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
|
206
|
-
if
|
207
|
-
|
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("
|
211
|
-
|
212
|
-
|
213
|
-
|
250
|
+
raise ValueError("strategy parameter must be: 'normal_selective' or 'more_selective' or 'less_selective'")
|
251
|
+
|
252
|
+
if policy =='explorer': fitness_bias = 0
|
253
|
+
|
254
|
+
if ((activation_mutate_add_prob < 0 or activation_mutate_add_prob > 1) or
|
255
|
+
(activation_mutate_change_prob < 0 or activation_mutate_change_prob > 1) or
|
256
|
+
(activation_mutate_delete_prob < 0 or activation_mutate_delete_prob > 1) or
|
257
|
+
(weight_mutate_prob < 0 or weight_mutate_prob > 1) or
|
258
|
+
(activation_selection_add_prob < 0 or activation_selection_add_prob > 1) or (
|
259
|
+
activation_selection_change_prob < 0 or activation_selection_change_prob > 1)):
|
260
|
+
|
214
261
|
raise ValueError("All hyperparameters ending with 'prob' must be a number between 0 and 1.")
|
215
262
|
|
216
|
-
if
|
217
|
-
raise ValueError("cross_over_mode parameter must be 'tpm' or 'plantic'")
|
263
|
+
if fitness_bias < 0 or fitness_bias > 1: raise ValueError("fitness_bias value must be a number between 0 and 1.")
|
218
264
|
|
219
|
-
if
|
220
|
-
if not isinstance(
|
221
|
-
raise ValueError("
|
265
|
+
if bad_genomes_mutation_prob is not None:
|
266
|
+
if not isinstance(bad_genomes_mutation_prob, float) or bad_genomes_mutation_prob < 0 or bad_genomes_mutation_prob > 1:
|
267
|
+
raise ValueError("bad_genomes_mutation_prob parameter must be float and 0-1 range")
|
222
268
|
|
223
269
|
if activation_mutate_prob is not None:
|
224
270
|
if not isinstance(activation_mutate_prob, float) or activation_mutate_prob < 0 or activation_mutate_prob > 1:
|
@@ -242,90 +288,90 @@ Example:
|
|
242
288
|
|
243
289
|
### GENOMES ARE DIVIDED INTO TWO GROUPS: GOOD GENOMES AND BAD GENOMES:
|
244
290
|
|
245
|
-
|
291
|
+
good_weights = weights[slice_center:]
|
246
292
|
bad_weights = weights[:slice_center]
|
247
|
-
best_weight =
|
293
|
+
best_weight = good_weights[-1]
|
248
294
|
|
249
|
-
|
295
|
+
good_activations = list(activation_potentiations[slice_center:])
|
250
296
|
bad_activations = list(activation_potentiations[:slice_center])
|
251
|
-
|
297
|
+
best_activations = good_activations[-1]
|
252
298
|
|
253
299
|
|
254
|
-
###
|
300
|
+
### PLANEAT IS APPLIED ACCORDING TO THE SPECIFIED POLICY, STRATEGY, AND PROBABILITY CONFIGURATION:
|
255
301
|
|
256
302
|
bar_format = loading_bars()[0]
|
257
303
|
|
258
|
-
if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50
|
304
|
+
if bar_status: progress = initialize_loading_bar(len(bad_weights), desc="GENERATION: " + str(what_gen), bar_format=bar_format, ncols=50)
|
305
|
+
normalized_fitness = abs(normalization(fitness, dtype=dtype))
|
259
306
|
|
260
|
-
|
307
|
+
best_fitness = normalized_fitness[-1]
|
308
|
+
epsilon = cp.finfo(float).eps
|
261
309
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
310
|
+
for i in range(len(bad_weights)):
|
311
|
+
|
312
|
+
if policy == 'aggressive':
|
313
|
+
first_parent_W = best_weight
|
314
|
+
first_parent_act = best_activations
|
266
315
|
|
316
|
+
elif policy == 'explorer':
|
317
|
+
first_parent_W = good_weights[i]
|
318
|
+
first_parent_act = good_activations[i]
|
267
319
|
|
268
|
-
|
269
|
-
bad_weights[i], bad_activations[i] = potentiate(best_weight, best_weights[i], best_activations=best_activation, good_activations=best_activations[i], dtype=dtype)
|
270
|
-
|
320
|
+
else: raise ValueError("policy parameter must be: 'aggressive' or 'explorer'")
|
271
321
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
322
|
+
second_parent_W, second_parent_act, s_i = second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob)
|
323
|
+
|
324
|
+
bad_weights[i], bad_activations[i] = cross_over(first_parent_W,
|
325
|
+
second_parent_W,
|
326
|
+
first_parent_act,
|
327
|
+
second_parent_act,
|
328
|
+
cross_over_mode=cross_over_mode,
|
329
|
+
activation_selection_add_prob=activation_selection_add_prob,
|
330
|
+
activation_selection_change_prob=activation_selection_change_prob,
|
331
|
+
activation_selection_rate=activation_selection_rate,
|
332
|
+
bad_genomes_selection_prob=bad_genomes_selection_prob,
|
333
|
+
first_parent_fitness=best_fitness,
|
334
|
+
fitness_bias=fitness_bias,
|
335
|
+
second_parent_fitness=normalized_fitness[s_i],
|
336
|
+
epsilon=epsilon
|
337
|
+
)
|
338
|
+
|
339
|
+
|
340
|
+
if mutations is True:
|
341
|
+
mutation_prob = random.uniform(0, 1)
|
342
|
+
|
343
|
+
if mutation_prob > bad_genomes_mutation_prob:
|
344
|
+
if (save_best_genom == True and not np.array_equal(good_weights[i], best_weight)) or save_best_genom == False:
|
345
|
+
|
346
|
+
good_weights[i], good_activations[i] = mutation(good_weights[i],
|
347
|
+
good_activations[i],
|
348
|
+
activation_mutate_prob=activation_mutate_prob,
|
349
|
+
activation_add_prob=activation_mutate_add_prob,
|
350
|
+
activation_delete_prob=activation_mutate_delete_prob,
|
351
|
+
activation_change_prob=activation_mutate_change_prob,
|
352
|
+
weight_mutate_prob=weight_mutate_prob,
|
353
|
+
threshold=weight_mutate_rate,
|
354
|
+
genome_fitness=normalized_fitness[i],
|
355
|
+
epsilon=epsilon
|
356
|
+
)
|
290
357
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
if policy == 'less_selective':
|
305
|
-
|
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)
|
358
|
+
elif mutation_prob < bad_genomes_mutation_prob:
|
359
|
+
bad_weights[i], bad_activations[i] = mutation(bad_weights[i],
|
360
|
+
bad_activations[i],
|
361
|
+
activation_mutate_prob=activation_mutate_prob,
|
362
|
+
activation_add_prob=activation_mutate_add_prob,
|
363
|
+
activation_delete_prob=activation_mutate_delete_prob,
|
364
|
+
activation_change_prob=activation_mutate_change_prob,
|
365
|
+
weight_mutate_prob=weight_mutate_prob,
|
366
|
+
threshold=weight_mutate_rate,
|
367
|
+
genome_fitness=normalized_fitness[i],
|
368
|
+
epsilon=epsilon
|
369
|
+
)
|
310
370
|
|
311
|
-
elif strategy == 'potentiate':
|
312
|
-
bad_weights[i], bad_activations[i] = potentiate(best_weights[random_index], best_weights[i], best_activations=best_activations[random_index], good_activations=best_activations[i], dtype=dtype)
|
313
|
-
|
314
|
-
if mutations is True:
|
315
|
-
|
316
|
-
mutation_prob = random.uniform(0, 1)
|
317
|
-
|
318
|
-
if mutation_prob > bad_genoms_mutation_prob:
|
319
|
-
if (save_best_genom == True and not 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
371
|
if bar_status: progress.update(1)
|
326
372
|
|
327
|
-
weights = cp.vstack((bad_weights,
|
328
|
-
activation_potentiations = bad_activations +
|
373
|
+
weights = cp.vstack((bad_weights, good_weights))
|
374
|
+
activation_potentiations = bad_activations + good_activations
|
329
375
|
|
330
376
|
### INFO PRINTING CONSOLE
|
331
377
|
|
@@ -334,26 +380,24 @@ Example:
|
|
334
380
|
print("*** Configuration Settings ***")
|
335
381
|
print(" POPULATION SIZE: ", str(len(weights)))
|
336
382
|
print(" STRATEGY: ", strategy)
|
337
|
-
|
338
|
-
if strategy == 'cross_over':
|
339
|
-
print(" CROSS OVER MODE: ", cross_over_mode)
|
340
|
-
|
383
|
+
print(" CROSS OVER MODE: ", cross_over_mode)
|
341
384
|
print(" POLICY: ", policy)
|
342
385
|
print(" MUTATIONS: ", str(mutations))
|
343
|
-
print(" BAD GENOMES MUTATION PROB: ", str(
|
344
|
-
print(" GOOD GENOMES MUTATION PROB: ", str(round(1 -
|
386
|
+
print(" BAD GENOMES MUTATION PROB: ", str(bad_genomes_mutation_prob))
|
387
|
+
print(" GOOD GENOMES MUTATION PROB: ", str(round(1 - bad_genomes_mutation_prob, 2)))
|
345
388
|
print(" WEIGHT MUTATE PROB: ", str(weight_mutate_prob))
|
346
389
|
print(" WEIGHT MUTATE RATE (THRESHOLD VALUE FOR SINGLE MUTATION): ", str(weight_mutate_rate))
|
347
390
|
print(" ACTIVATION MUTATE PROB: ", str(activation_mutate_prob))
|
348
|
-
print(" ACTIVATION ADD PROB: ", str(
|
349
|
-
print(" ACTIVATION DELETE PROB: ", str(
|
350
|
-
print(" ACTIVATION CHANGE PROB: ", str(
|
391
|
+
print(" ACTIVATION MUTATE ADD PROB: ", str(activation_mutate_add_prob))
|
392
|
+
print(" ACTIVATION MUTATE DELETE PROB: ", str(activation_mutate_delete_prob))
|
393
|
+
print(" ACTIVATION MUTATE CHANGE PROB: ", str(activation_mutate_change_prob))
|
351
394
|
print(" ACTIVATION SELECTION ADD PROB: ", str(activation_selection_add_prob))
|
352
395
|
print(" ACTIVATION SELECTION CHANGE PROB: ", str(activation_selection_change_prob))
|
396
|
+
print(" FITNESS BIAS: ", str(fitness_bias))
|
353
397
|
print(" ACTIVATION SELECTION RATE (THRESHOLD VALUE FOR SINGLE CROSS OVER):", str(activation_selection_rate) + '\n')
|
354
|
-
|
398
|
+
|
355
399
|
print("*** Performance ***")
|
356
|
-
print("
|
400
|
+
print(" MAX REWARD: ", str(cp.round(max(fitness), 2)))
|
357
401
|
print(" MEAN REWARD: ", str(cp.round(cp.mean(fitness), 2)))
|
358
402
|
print(" MIN REWARD: ", str(cp.round(min(fitness), 2)) + '\n')
|
359
403
|
|
@@ -361,7 +405,7 @@ Example:
|
|
361
405
|
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
406
|
|
363
407
|
|
364
|
-
return
|
408
|
+
return weights, activation_potentiations
|
365
409
|
|
366
410
|
|
367
411
|
def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dtype=cp.float32):
|
@@ -370,14 +414,17 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
|
|
370
414
|
and weights depending on whether reinforcement learning mode is enabled or not.
|
371
415
|
|
372
416
|
Args:
|
373
|
-
x_population (list or
|
417
|
+
x_population (list or cupy.ndarray): A list or 2D numpy or cupy array where each element represents
|
374
418
|
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
|
-
|
419
|
+
|
420
|
+
weights (list or cupy.ndarray): A list or 2D numpy array of weights corresponding to each genome
|
376
421
|
in `x_population`. This determines the strength of connections.
|
422
|
+
|
377
423
|
activation_potentiations (list or str): A list where each entry represents an activation function
|
378
424
|
or a potentiation strategy applied to each genome. If only one
|
379
425
|
activation function is used, this can be a single string.
|
380
|
-
|
426
|
+
|
427
|
+
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
428
|
Default is False.
|
382
429
|
|
383
430
|
|
@@ -436,48 +483,112 @@ def evaluate(x_population, weights, activation_potentiations, rl_mode=False, dty
|
|
436
483
|
return outputs
|
437
484
|
|
438
485
|
|
439
|
-
def cross_over(
|
486
|
+
def cross_over(first_parent_W,
|
487
|
+
second_parent_W,
|
488
|
+
first_parent_act,
|
489
|
+
second_parent_act,
|
490
|
+
cross_over_mode,
|
491
|
+
activation_selection_add_prob,
|
492
|
+
activation_selection_change_prob,
|
493
|
+
activation_selection_rate,
|
494
|
+
bad_genomes_selection_prob,
|
495
|
+
first_parent_fitness,
|
496
|
+
second_parent_fitness,
|
497
|
+
fitness_bias,
|
498
|
+
epsilon):
|
440
499
|
"""
|
441
|
-
Performs a
|
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
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
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
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
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.
|
532
|
+
|
533
|
+
epsilon (float): Small epsilon constant
|
455
534
|
|
456
535
|
Returns:
|
457
536
|
tuple: A tuple containing:
|
458
|
-
-
|
459
|
-
-
|
537
|
+
- child_W (numpy.ndarray): The weight matrix of the new individual created by crossover.
|
538
|
+
- child_act (list): The list of activation functions of the new individual created by crossover.
|
460
539
|
|
461
540
|
Notes:
|
462
541
|
- The crossover is performed based on the selected `cross_over_mode`.
|
463
|
-
|
464
|
-
|
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.
|
542
|
+
- In 'tpm' mode, random sub-matrices from the parent weight matrices are swapped.
|
543
|
+
- Activation functions from both parents are combined using the probabilities and rates provided.
|
468
544
|
|
469
545
|
Example:
|
470
546
|
```python
|
471
|
-
new_weights, new_activations = cross_over(
|
547
|
+
new_weights, new_activations = cross_over(
|
548
|
+
first_parent_W=parent1_weights,
|
549
|
+
second_parent_W=parent2_weights,
|
550
|
+
first_parent_act=parent1_activations,
|
551
|
+
second_parent_act=parent2_activations,
|
552
|
+
cross_over_mode='tpm',
|
553
|
+
activation_selection_add_prob=0.8,
|
554
|
+
activation_selection_change_prob=0.5,
|
555
|
+
activation_selection_rate=0.1,
|
556
|
+
bad_genomes_selection_prob=0.7,
|
557
|
+
first_parent_fitness=0.9,
|
558
|
+
second_parent_fitness=0.85,
|
559
|
+
fitness_bias=0.6,
|
560
|
+
epsilon=cp.finfo.eps
|
561
|
+
)
|
472
562
|
```
|
473
563
|
"""
|
474
564
|
|
475
|
-
|
565
|
+
### 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
566
|
|
477
567
|
start = 0
|
568
|
+
|
569
|
+
row_end = first_parent_W.shape[0]
|
570
|
+
col_end = first_parent_W.shape[1]
|
571
|
+
|
572
|
+
total_gene = row_end * col_end
|
573
|
+
half_of_gene = int(total_gene / 2)
|
574
|
+
|
575
|
+
decision = dominant_parent_selection(bad_genomes_selection_prob)
|
576
|
+
|
577
|
+
if decision == 'first_parent':
|
578
|
+
dominant_parent_W = cp.copy(first_parent_W)
|
579
|
+
dominant_parent_act = first_parent_act
|
478
580
|
|
479
|
-
|
480
|
-
|
581
|
+
undominant_parent_W = cp.copy(second_parent_W)
|
582
|
+
undominant_parent_act = second_parent_act
|
583
|
+
succes = second_parent_fitness + epsilon
|
584
|
+
|
585
|
+
elif decision == 'second_parent':
|
586
|
+
dominant_parent_W = cp.copy(second_parent_W)
|
587
|
+
dominant_parent_act = second_parent_act
|
588
|
+
|
589
|
+
undominant_parent_W = cp.copy(first_parent_W)
|
590
|
+
undominant_parent_act = first_parent_act
|
591
|
+
succes = first_parent_fitness + epsilon
|
481
592
|
|
482
593
|
while True:
|
483
594
|
|
@@ -487,48 +598,47 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
|
|
487
598
|
row_cut_end = int(random.uniform(start, row_end))
|
488
599
|
col_cut_end = int(random.uniform(start, col_end))
|
489
600
|
|
490
|
-
if (row_cut_end > row_cut_start) and
|
601
|
+
if ((row_cut_end > row_cut_start) and
|
602
|
+
(col_cut_end > col_cut_start) and
|
603
|
+
(((row_cut_end + 1) - (row_cut_start + 1) * 2) + ((col_cut_end + 1) - (col_cut_start + 1) * 2) <= half_of_gene)):
|
491
604
|
break
|
605
|
+
|
606
|
+
selection_bias = random.uniform(0, 1)
|
492
607
|
|
493
|
-
|
494
|
-
|
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,:]
|
608
|
+
if fitness_bias > selection_bias:
|
609
|
+
row_cut_start = math.floor(row_cut_start * succes)
|
610
|
+
row_cut_end = math.ceil(row_cut_end * succes)
|
501
611
|
|
612
|
+
col_cut_start = math.floor(col_cut_start * succes)
|
613
|
+
col_cut_end = math.ceil(col_cut_end * succes)
|
502
614
|
|
503
|
-
|
504
|
-
best = [best_activations]
|
615
|
+
child_W = dominant_parent_W
|
505
616
|
|
506
|
-
if
|
507
|
-
|
617
|
+
if cross_over_mode == 'tpm':
|
618
|
+
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
619
|
|
509
|
-
if isinstance(best_activations, list):
|
510
|
-
best = best_activations
|
511
620
|
|
512
|
-
if isinstance(
|
513
|
-
|
621
|
+
if isinstance(dominant_parent_act, str): dominant_parent_act = [dominant_parent_act]
|
622
|
+
if isinstance(undominant_parent_act, str): undominant_parent_act = [undominant_parent_act]
|
514
623
|
|
515
|
-
|
624
|
+
child_act = list(np.copy(dominant_parent_act))
|
516
625
|
|
517
626
|
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
627
|
potential_activation_selection_add = random.uniform(0, 1)
|
519
628
|
|
520
629
|
if potential_activation_selection_add > activation_selection_add_prob:
|
521
630
|
|
631
|
+
activation_selection_rate = activation_selection_rate / succes
|
522
632
|
new_threshold = activation_selection_rate
|
523
633
|
|
524
634
|
while True:
|
525
635
|
|
526
|
-
|
527
|
-
|
636
|
+
random_index = int(random.uniform(0, len(undominant_parent_act)-1))
|
637
|
+
random_undominant_activation = undominant_parent_act[random_index]
|
528
638
|
|
529
|
-
|
639
|
+
child_act.append(random_undominant_activation)
|
530
640
|
|
531
|
-
if len(
|
641
|
+
if len(dominant_parent_act) > new_threshold:
|
532
642
|
new_threshold += activation_selection_rate
|
533
643
|
pass
|
534
644
|
|
@@ -539,85 +649,64 @@ def cross_over(best_weight, good_weight, best_activations, good_activations, cro
|
|
539
649
|
potential_activation_selection_change_prob = random.uniform(0, 1)
|
540
650
|
|
541
651
|
if potential_activation_selection_change_prob > activation_selection_change_prob:
|
542
|
-
|
652
|
+
|
653
|
+
activation_selection_rate = activation_selection_rate / succes
|
543
654
|
new_threshold = activation_selection_rate
|
544
655
|
|
545
656
|
while True:
|
546
657
|
|
547
|
-
|
548
|
-
|
549
|
-
|
658
|
+
random_index_undominant = int(random.uniform(0, len(undominant_parent_act)-1))
|
659
|
+
random_index_dominant = int(random.uniform(0, len(dominant_parent_act)-1))
|
660
|
+
random_undominant_activation = undominant_parent_act[random_index_undominant]
|
550
661
|
|
551
|
-
|
662
|
+
child_act[random_index_dominant] = random_undominant_activation
|
552
663
|
|
553
|
-
if len(
|
664
|
+
if len(dominant_parent_act) > new_threshold:
|
554
665
|
new_threshold += activation_selection_rate
|
555
666
|
pass
|
556
667
|
|
557
668
|
else:
|
558
669
|
break
|
559
670
|
|
560
|
-
return
|
671
|
+
return child_W, child_act
|
561
672
|
|
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
|
596
|
-
|
597
|
-
if isinstance(good_activations, list):
|
598
|
-
good = good_activations
|
599
|
-
|
600
|
-
new_activations = best + good
|
601
|
-
|
602
|
-
return new_weight, new_activations
|
603
673
|
|
604
|
-
def mutation(weight,
|
674
|
+
def mutation(weight,
|
675
|
+
activations,
|
676
|
+
activation_mutate_prob,
|
677
|
+
activation_add_prob,
|
678
|
+
activation_delete_prob,
|
679
|
+
activation_change_prob,
|
680
|
+
weight_mutate_prob,
|
681
|
+
threshold,
|
682
|
+
genome_fitness,
|
683
|
+
epsilon):
|
605
684
|
"""
|
606
685
|
Performs mutation on the given weight matrix and activation functions.
|
607
686
|
- The weight matrix is mutated by randomly changing its values based on the mutation probability.
|
608
687
|
- The activation functions are mutated by adding, removing, or replacing them with predefined probabilities.
|
609
688
|
|
610
689
|
Args:
|
611
|
-
weight (
|
690
|
+
weight (cupy.ndarray): The weight matrix to mutate.
|
691
|
+
|
612
692
|
activations (list): The list of activation functions to mutate.
|
693
|
+
|
613
694
|
activation_mutate_prob (float): The overall probability of mutating activation functions.
|
695
|
+
|
614
696
|
activation_add_prob (float): Probability of adding a new activation function.
|
697
|
+
|
615
698
|
activation_delete_prob (float): Probability of removing an existing activation function.
|
699
|
+
|
616
700
|
activation_change_prob (float): Probability of replacing an existing activation function with a new one.
|
701
|
+
|
617
702
|
weight_mutate_prob (float): The probability of mutating weight matrix.
|
703
|
+
|
618
704
|
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
705
|
|
706
|
+
genome_fitness (float): Fitness value of genome
|
707
|
+
|
708
|
+
epsilon (float): Small epsilon constant
|
709
|
+
|
621
710
|
Returns:
|
622
711
|
tuple: A tuple containing:
|
623
712
|
- mutated_weight (numpy.ndarray): The weight matrix after mutation.
|
@@ -635,8 +724,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
635
724
|
the optimization process.
|
636
725
|
"""
|
637
726
|
|
638
|
-
if isinstance(activations, str):
|
639
|
-
activations = [activations]
|
727
|
+
if isinstance(activations, str): activations = [activations]
|
640
728
|
|
641
729
|
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
730
|
potential_weight_mutation = random.uniform(0, 1)
|
@@ -646,6 +734,8 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
646
734
|
start = 0
|
647
735
|
row_end = weight.shape[0]
|
648
736
|
col_end = weight.shape[1]
|
737
|
+
|
738
|
+
threshold = threshold * (genome_fitness + epsilon)
|
649
739
|
new_threshold = threshold
|
650
740
|
|
651
741
|
while True:
|
@@ -662,7 +752,6 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
662
752
|
else:
|
663
753
|
break
|
664
754
|
|
665
|
-
|
666
755
|
activation_mutate_prob = 1 - activation_mutate_prob
|
667
756
|
potential_activation_mutation = random.uniform(0, 1)
|
668
757
|
|
@@ -685,13 +774,7 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
685
774
|
|
686
775
|
random_index_all_act = int(random.uniform(0, len(all_acts)-1))
|
687
776
|
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
777
|
|
693
|
-
weight = normalization(weight, dtype=dtype)
|
694
|
-
|
695
778
|
except:
|
696
779
|
|
697
780
|
activation = activations
|
@@ -700,26 +783,12 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
700
783
|
activations.append(activation)
|
701
784
|
activations.append(all_acts[int(random.uniform(0, len(all_acts)-1))])
|
702
785
|
|
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
786
|
if potential_activation_delete_prob > activation_delete_prob and len(activations) > 1:
|
710
787
|
|
711
788
|
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
789
|
activations.pop(random_index)
|
720
|
-
weight = normalization(weight, dtype=dtype)
|
721
790
|
|
722
|
-
|
791
|
+
|
723
792
|
if potential_activation_change_prob > activation_change_prob:
|
724
793
|
|
725
794
|
random_index_all_act = int(random.uniform(0, len(all_acts)-1))
|
@@ -727,18 +796,30 @@ def mutation(weight, activations, activation_mutate_prob, activation_add_prob, a
|
|
727
796
|
|
728
797
|
activations[random_index_genom_act] = all_acts[random_index_all_act]
|
729
798
|
|
730
|
-
|
731
|
-
|
799
|
+
return weight, activations
|
800
|
+
|
732
801
|
|
733
|
-
|
734
|
-
|
802
|
+
def second_parent_selection(good_weights, bad_weights, good_activations, bad_activations, bad_genomes_selection_prob):
|
803
|
+
|
804
|
+
selection_prob = random.uniform(0, 1)
|
805
|
+
random_index = int(random.uniform(0, len(good_weights) - 1))
|
806
|
+
|
807
|
+
if selection_prob > bad_genomes_selection_prob:
|
808
|
+
second_selected_W = good_weights[random_index]
|
809
|
+
second_selected_act = good_activations[random_index]
|
735
810
|
|
736
|
-
|
811
|
+
else:
|
812
|
+
second_selected_W = bad_weights[random_index]
|
813
|
+
second_selected_act = bad_activations[random_index]
|
814
|
+
|
815
|
+
return second_selected_W, second_selected_act, random_index
|
816
|
+
|
737
817
|
|
738
|
-
|
818
|
+
def dominant_parent_selection(bad_genomes_selection_prob):
|
739
819
|
|
740
|
-
|
820
|
+
selection_prob = random.uniform(0, 1)
|
741
821
|
|
742
|
-
|
822
|
+
if selection_prob > bad_genomes_selection_prob: decision = 'first_parent'
|
823
|
+
else: decision = 'second_parent'
|
743
824
|
|
744
|
-
return
|
825
|
+
return decision
|