x-evolution 0.1.5__tar.gz → 0.1.7__tar.gz
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.
- {x_evolution-0.1.5 → x_evolution-0.1.7}/PKG-INFO +3 -3
- {x_evolution-0.1.5 → x_evolution-0.1.7}/README.md +1 -1
- {x_evolution-0.1.5 → x_evolution-0.1.7}/pyproject.toml +2 -2
- {x_evolution-0.1.5 → x_evolution-0.1.7}/tests/test_evolution.py +8 -2
- {x_evolution-0.1.5 → x_evolution-0.1.7}/train_lunar.py +23 -15
- {x_evolution-0.1.5 → x_evolution-0.1.7}/train_mnist.py +2 -2
- {x_evolution-0.1.5 → x_evolution-0.1.7}/train_xor.py +9 -3
- {x_evolution-0.1.5 → x_evolution-0.1.7}/x_evolution/x_evolution.py +112 -14
- {x_evolution-0.1.5 → x_evolution-0.1.7}/.github/workflows/python-publish.yml +0 -0
- {x_evolution-0.1.5 → x_evolution-0.1.7}/.github/workflows/test.yml +0 -0
- {x_evolution-0.1.5 → x_evolution-0.1.7}/.gitignore +0 -0
- {x_evolution-0.1.5 → x_evolution-0.1.7}/LICENSE +0 -0
- {x_evolution-0.1.5 → x_evolution-0.1.7}/x_evolution/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: x-evolution
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: x-evolution
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/x-evolution/
|
|
6
6
|
Project-URL: Repository, https://github.com/lucidrains/x-evolution
|
|
@@ -38,7 +38,7 @@ Requires-Dist: accelerate
|
|
|
38
38
|
Requires-Dist: beartype
|
|
39
39
|
Requires-Dist: einops>=0.8.0
|
|
40
40
|
Requires-Dist: torch>=2.4
|
|
41
|
-
Requires-Dist: x-mlps-pytorch>=0.1.
|
|
41
|
+
Requires-Dist: x-mlps-pytorch>=0.1.31
|
|
42
42
|
Requires-Dist: x-transformers>=2.11.23
|
|
43
43
|
Provides-Extra: examples
|
|
44
44
|
Requires-Dist: gymnasium[box2d]>=1.0.0; extra == 'examples'
|
|
@@ -78,7 +78,7 @@ evo_strat = EvoStrategy(
|
|
|
78
78
|
model,
|
|
79
79
|
environment = lambda model: torch.randint(0, 100, ()), # environment is just a function that takes in the individual model (with unique noise) and outputs a scalar (the fitness) the measure you are selecting for
|
|
80
80
|
noise_population_size = 30, # increase this for better gradient estimates
|
|
81
|
-
noise_scale = 1e-
|
|
81
|
+
noise_scale = 1e-2, # the scale of the perturbation noise, also the initial noise scale (sigma) if `learned_noise_scale` = True
|
|
82
82
|
num_generations = 100, # number of generations / training steps
|
|
83
83
|
learning_rate = 1e-3, # scale on update derived by fitness and perturb noises
|
|
84
84
|
params_to_optimize = None # defaults to all parameters, but can be [str {param name}] or [Parameter]
|
|
@@ -29,7 +29,7 @@ evo_strat = EvoStrategy(
|
|
|
29
29
|
model,
|
|
30
30
|
environment = lambda model: torch.randint(0, 100, ()), # environment is just a function that takes in the individual model (with unique noise) and outputs a scalar (the fitness) the measure you are selecting for
|
|
31
31
|
noise_population_size = 30, # increase this for better gradient estimates
|
|
32
|
-
noise_scale = 1e-
|
|
32
|
+
noise_scale = 1e-2, # the scale of the perturbation noise, also the initial noise scale (sigma) if `learned_noise_scale` = True
|
|
33
33
|
num_generations = 100, # number of generations / training steps
|
|
34
34
|
learning_rate = 1e-3, # scale on update derived by fitness and perturb noises
|
|
35
35
|
params_to_optimize = None # defaults to all parameters, but can be [str {param name}] or [Parameter]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "x-evolution"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.7"
|
|
4
4
|
description = "x-evolution"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Phil Wang", email = "lucidrains@gmail.com" }
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
"beartype",
|
|
28
28
|
"einops>=0.8.0",
|
|
29
29
|
"torch>=2.4",
|
|
30
|
-
"x-mlps-pytorch>=0.1.
|
|
30
|
+
"x-mlps-pytorch>=0.1.31",
|
|
31
31
|
"x-transformers>=2.11.23"
|
|
32
32
|
]
|
|
33
33
|
|
|
@@ -11,12 +11,16 @@ model = MLP(8, 16, 4)
|
|
|
11
11
|
@param('noise_low_rank', (None, 1))
|
|
12
12
|
@param('mirror_sampling', (False, True))
|
|
13
13
|
@param('multi_models', (False, True))
|
|
14
|
+
@param('learned_sigma', (False, True))
|
|
15
|
+
@param('use_sigma_optimizer', (False, True))
|
|
14
16
|
def test_evo_strat(
|
|
15
17
|
params_to_optimize,
|
|
16
18
|
use_optimizer,
|
|
17
19
|
noise_low_rank,
|
|
18
20
|
mirror_sampling,
|
|
19
|
-
multi_models
|
|
21
|
+
multi_models,
|
|
22
|
+
learned_sigma,
|
|
23
|
+
use_sigma_optimizer
|
|
20
24
|
):
|
|
21
25
|
from random import randrange
|
|
22
26
|
|
|
@@ -31,10 +35,12 @@ def test_evo_strat(
|
|
|
31
35
|
to_optim,
|
|
32
36
|
environment = lambda model: float(randrange(100)),
|
|
33
37
|
num_generations = 2,
|
|
38
|
+
learned_noise_scale = learned_sigma,
|
|
34
39
|
params_to_optimize = params_to_optimize,
|
|
35
40
|
use_optimizer = use_optimizer,
|
|
36
41
|
noise_low_rank = noise_low_rank,
|
|
37
|
-
mirror_sampling = mirror_sampling
|
|
42
|
+
mirror_sampling = mirror_sampling,
|
|
43
|
+
use_sigma_optimizer = use_sigma_optimizer
|
|
38
44
|
)
|
|
39
45
|
|
|
40
46
|
evo_strat('evolve', 1)
|
|
@@ -19,6 +19,7 @@ class LunarEnvironment(Module):
|
|
|
19
19
|
video_folder = './recordings',
|
|
20
20
|
render_every_eps = 500,
|
|
21
21
|
max_steps = 500,
|
|
22
|
+
repeats = 1
|
|
22
23
|
):
|
|
23
24
|
super().__init__()
|
|
24
25
|
|
|
@@ -36,36 +37,40 @@ class LunarEnvironment(Module):
|
|
|
36
37
|
|
|
37
38
|
self.env = env
|
|
38
39
|
self.max_steps = max_steps
|
|
40
|
+
self.repeats = repeats
|
|
39
41
|
|
|
40
42
|
def forward(self, model):
|
|
41
43
|
|
|
42
44
|
device = next(model.parameters()).device
|
|
43
45
|
|
|
44
46
|
seed = torch.randint(0, int(1e6), ())
|
|
45
|
-
state, _ = self.env.reset(seed = seed.item())
|
|
46
47
|
|
|
47
|
-
step = 0
|
|
48
48
|
cum_reward = 0.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
for _ in range(self.repeats):
|
|
51
|
+
state, _ = self.env.reset(seed = seed.item())
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
step = 0
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
while step < self.max_steps:
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
state = torch.from_numpy(state).to(device)
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
action_logits = model(state)
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
step += 1
|
|
61
|
+
action = F.gumbel_softmax(action_logits, hard = True).argmax(dim = -1)
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
next_state, reward, truncated, terminated, *_ = self.env.step(action.item())
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
cum_reward += float(reward)
|
|
66
|
+
step += 1
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
state = next_state
|
|
69
|
+
|
|
70
|
+
if truncated or terminated:
|
|
71
|
+
break
|
|
72
|
+
|
|
73
|
+
return cum_reward / self.repeats
|
|
69
74
|
|
|
70
75
|
# evo strategy
|
|
71
76
|
|
|
@@ -84,12 +89,15 @@ actor = ResidualNormedMLP(
|
|
|
84
89
|
|
|
85
90
|
evo_strat = EvoStrategy(
|
|
86
91
|
actor,
|
|
87
|
-
environment = LunarEnvironment(),
|
|
92
|
+
environment = LunarEnvironment(repeats = 2),
|
|
88
93
|
num_generations = 50_000,
|
|
89
94
|
noise_population_size = 60,
|
|
90
95
|
noise_low_rank = 2,
|
|
91
96
|
noise_scale = 1e-1,
|
|
92
|
-
|
|
97
|
+
learned_noise_scale = True,
|
|
98
|
+
use_sigma_optimizer = True,
|
|
99
|
+
learning_rate = 5e-2,
|
|
100
|
+
noise_scale_learning_rate = 1e-2
|
|
93
101
|
)
|
|
94
102
|
|
|
95
103
|
evo_strat()
|
|
@@ -20,7 +20,7 @@ model = nn.Sequential(
|
|
|
20
20
|
ResidualNormedMLP(dim_in = 784, dim = 512, depth = 8, residual_every = 2, dim_out = 10)
|
|
21
21
|
).half()
|
|
22
22
|
|
|
23
|
-
batch_size =
|
|
23
|
+
batch_size = 256
|
|
24
24
|
|
|
25
25
|
# data
|
|
26
26
|
|
|
@@ -54,7 +54,7 @@ evo_strat = EvoStrategy(
|
|
|
54
54
|
noise_scale = 1e-2,
|
|
55
55
|
noise_low_rank = 2,
|
|
56
56
|
num_generations = 10_000,
|
|
57
|
-
learning_rate = 1e-
|
|
57
|
+
learning_rate = 1e-3
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
evo_strat()
|
|
@@ -12,6 +12,8 @@ model = nn.Sequential(
|
|
|
12
12
|
nn.Linear(16, 2)
|
|
13
13
|
).half()
|
|
14
14
|
|
|
15
|
+
batch_size = 128
|
|
16
|
+
|
|
15
17
|
# fitness as inverse of loss
|
|
16
18
|
|
|
17
19
|
from x_evolution import EvoStrategy
|
|
@@ -19,7 +21,7 @@ from x_evolution import EvoStrategy
|
|
|
19
21
|
def loss_xor(model):
|
|
20
22
|
device = next(model.parameters()).device
|
|
21
23
|
|
|
22
|
-
data = torch.randint(0, 2, (
|
|
24
|
+
data = torch.randint(0, 2, (batch_size, 2))
|
|
23
25
|
labels = data[:, 0] ^ data[:, 1]
|
|
24
26
|
|
|
25
27
|
data, labels = tuple(t.to(device) for t in (data, labels))
|
|
@@ -36,10 +38,14 @@ evo_strat = EvoStrategy(
|
|
|
36
38
|
model,
|
|
37
39
|
environment = loss_xor,
|
|
38
40
|
noise_population_size = 100,
|
|
39
|
-
noise_scale = 1e-1,
|
|
40
41
|
noise_low_rank = 1,
|
|
41
42
|
num_generations = 100_000,
|
|
42
|
-
learning_rate = 1e-
|
|
43
|
+
learning_rate = 1e-2,
|
|
44
|
+
noise_scale = 1e-1,
|
|
45
|
+
learned_noise_scale = True,
|
|
46
|
+
noise_scale_learning_rate = 5e-3,
|
|
47
|
+
sigma_optimizer_klass = torch.optim.Adam,
|
|
48
|
+
sigma_optimizer_kwargs = dict(betas = (0.9, 0.99))
|
|
43
49
|
)
|
|
44
50
|
|
|
45
51
|
evo_strat()
|
|
@@ -7,7 +7,7 @@ from functools import partial
|
|
|
7
7
|
|
|
8
8
|
import torch
|
|
9
9
|
from torch import tensor, Tensor, is_tensor, arange, randint
|
|
10
|
-
from torch.nn import Module, ModuleList, Parameter
|
|
10
|
+
from torch.nn import Module, ModuleList, Parameter, ParameterList
|
|
11
11
|
from torch.optim import SGD
|
|
12
12
|
|
|
13
13
|
import torch.nn.functional as F
|
|
@@ -56,14 +56,20 @@ class EvoStrategy(Module):
|
|
|
56
56
|
num_generations,
|
|
57
57
|
noise_population_size = 30,
|
|
58
58
|
learning_rate = 1e-3,
|
|
59
|
-
noise_scale = 1e-3, # the noise scaling during rollouts with environment, todo - figure out right value and make sure it can also be customized per parameter name through a dict
|
|
60
59
|
mirror_sampling = True,
|
|
61
60
|
params_to_optimize: list[str] | Module | list[Module] | list[Parameter] | None = None,
|
|
62
61
|
noise_low_rank: int | None = None,
|
|
63
62
|
rollout_fixed_seed = True,
|
|
63
|
+
noise_scale = 1e-2, # the noise scaling during rollouts with environment, todo - figure out right value and make sure it can also be customized per parameter name through a dict
|
|
64
|
+
learned_noise_scale = False,
|
|
65
|
+
noise_scale_learning_rate = 5e-3,
|
|
66
|
+
noise_scale_clamp_range: tuple[float, float] | None = None,
|
|
64
67
|
use_optimizer = True,
|
|
65
68
|
optimizer_klass = partial(SGD, nesterov = True, momentum = 0.1, weight_decay = 1e-2),
|
|
66
69
|
optimizer_kwargs: dict = dict(),
|
|
70
|
+
use_sigma_optimizer = True,
|
|
71
|
+
sigma_optimizer_klass = partial(SGD, nesterov = True, momentum = 0.1),
|
|
72
|
+
sigma_optimizer_kwargs: dict = dict(),
|
|
67
73
|
transform_fitness: Callable = identity,
|
|
68
74
|
fitness_to_weighted_factor: Callable[[Tensor], Tensor] = normalize,
|
|
69
75
|
checkpoint_every = None, # saving every number of generations
|
|
@@ -141,9 +147,24 @@ class EvoStrategy(Module):
|
|
|
141
147
|
|
|
142
148
|
self.mirror_sampling = mirror_sampling # mirror / antithetical sampling - reducing variance by doing positive + negative of noise and subtracting
|
|
143
149
|
|
|
150
|
+
self.learning_rate = learning_rate
|
|
151
|
+
|
|
152
|
+
# noise scale, which can be fixed or learned
|
|
153
|
+
|
|
144
154
|
self.noise_scale = noise_scale
|
|
145
155
|
|
|
146
|
-
self.
|
|
156
|
+
self.learned_noise_scale = learned_noise_scale
|
|
157
|
+
|
|
158
|
+
if learned_noise_scale:
|
|
159
|
+
self.sigmas = ParameterList([Parameter(torch.ones(()) * noise_scale) for _ in range(len(named_parameters_dict))])
|
|
160
|
+
self.param_name_to_sigma_index = {name: i for i, name in enumerate(named_parameters_dict.keys())}
|
|
161
|
+
|
|
162
|
+
self.sigma_clamp_ = identity
|
|
163
|
+
|
|
164
|
+
if exists(noise_scale_clamp_range):
|
|
165
|
+
self.sigma_clamp_ = lambda t: t.clamp_(*noise_scale_clamp_range)
|
|
166
|
+
|
|
167
|
+
self.noise_scale_learning_rate = noise_scale_learning_rate
|
|
147
168
|
|
|
148
169
|
# rolling out with a fixed seed
|
|
149
170
|
|
|
@@ -157,6 +178,11 @@ class EvoStrategy(Module):
|
|
|
157
178
|
optim_params = [named_parameters_dict[name] for name in params_to_optimize]
|
|
158
179
|
self.optimizer = optimizer_klass(optim_params, lr = learning_rate, **optimizer_kwargs)
|
|
159
180
|
|
|
181
|
+
self.use_sigma_optimizer = use_sigma_optimizer
|
|
182
|
+
|
|
183
|
+
if learned_noise_scale and use_sigma_optimizer:
|
|
184
|
+
self.sigma_optimizer = sigma_optimizer_klass(self.sigmas, lr = noise_scale_learning_rate, **sigma_optimizer_kwargs)
|
|
185
|
+
|
|
160
186
|
# rejecting the fitnesses for a certain generation if this function is true
|
|
161
187
|
|
|
162
188
|
self.reject_generation_fitnesses_if = reject_generation_fitnesses_if
|
|
@@ -175,6 +201,13 @@ class EvoStrategy(Module):
|
|
|
175
201
|
def print(self, *args, **kwargs):
|
|
176
202
|
return self.accelerate.print(*args, **kwargs)
|
|
177
203
|
|
|
204
|
+
def _get_noise_scale(self, param_name):
|
|
205
|
+
if not self.learned_noise_scale:
|
|
206
|
+
return self.noise_scale
|
|
207
|
+
|
|
208
|
+
sigma_index = self.param_name_to_sigma_index[param_name]
|
|
209
|
+
return self.sigmas[sigma_index]
|
|
210
|
+
|
|
178
211
|
@torch.inference_mode()
|
|
179
212
|
def evolve_(
|
|
180
213
|
self,
|
|
@@ -208,21 +241,30 @@ class EvoStrategy(Module):
|
|
|
208
241
|
else:
|
|
209
242
|
weights = fitnesses
|
|
210
243
|
|
|
211
|
-
weights /= self.
|
|
244
|
+
weights /= self.noise_population_size * (2. if self.mirror_sampling else 1.)
|
|
212
245
|
|
|
213
246
|
if not use_optimizer:
|
|
214
247
|
weights *= self.learning_rate # some learning rate that subsumes another constant
|
|
215
248
|
|
|
249
|
+
# maybe learned sigma
|
|
250
|
+
|
|
251
|
+
if self.learned_noise_scale:
|
|
252
|
+
grad_sigmas = [torch.zeros_like(sigma) for sigma in self.sigmas]
|
|
253
|
+
|
|
216
254
|
# update one seed at a time for enabling evolutionary strategy for large models
|
|
217
255
|
|
|
218
256
|
for individual_seed, weight in zip(seeds_for_population.tolist(), weights.tolist()):
|
|
219
257
|
|
|
220
258
|
individual_param_seeds = with_seed(individual_seed)(torch.randint)(0, MAX_SEED_VALUE, (self.num_params,))
|
|
221
259
|
|
|
260
|
+
# setup noise config
|
|
261
|
+
|
|
222
262
|
noise_config = dict(zip(self.param_names_to_optimize, individual_param_seeds.tolist()))
|
|
223
263
|
|
|
224
264
|
noise_config_with_weight = dict()
|
|
225
265
|
|
|
266
|
+
# loop through each noise
|
|
267
|
+
|
|
226
268
|
for param_name, seed in noise_config.items():
|
|
227
269
|
|
|
228
270
|
shape = self.param_shapes[param_name]
|
|
@@ -231,12 +273,31 @@ class EvoStrategy(Module):
|
|
|
231
273
|
# reproduce the noise from the seed
|
|
232
274
|
|
|
233
275
|
noise = with_seed(seed)(model.create_noise_fn)(shape, dtype = dtype)
|
|
276
|
+
noise = noise.to(self.device)
|
|
277
|
+
# scale the weight
|
|
278
|
+
|
|
279
|
+
noise_scale = self._get_noise_scale(param_name)
|
|
280
|
+
|
|
281
|
+
scaled_weight = weight / noise_scale
|
|
234
282
|
|
|
235
283
|
# set the noise weight
|
|
236
284
|
|
|
237
|
-
noise_config_with_weight[param_name] = (noise,
|
|
285
|
+
noise_config_with_weight[param_name] = (noise, scaled_weight)
|
|
286
|
+
|
|
287
|
+
# maybe learned sigma
|
|
238
288
|
|
|
239
|
-
|
|
289
|
+
if self.learned_noise_scale:
|
|
290
|
+
one_grad_sigma = weight * ((noise ** 2 - 1) / noise_scale)
|
|
291
|
+
|
|
292
|
+
sigma_index = self.param_name_to_sigma_index[param_name]
|
|
293
|
+
sigma = self.sigmas[sigma_index]
|
|
294
|
+
|
|
295
|
+
if sigma.numel() == 1:
|
|
296
|
+
one_grad_sigma = one_grad_sigma.mean()
|
|
297
|
+
|
|
298
|
+
grad_sigmas[sigma_index].add_(one_grad_sigma)
|
|
299
|
+
|
|
300
|
+
# now update params for one seed
|
|
240
301
|
|
|
241
302
|
model.add_noise_(noise_config_with_weight, negate = use_optimizer, add_to_grad = use_optimizer)
|
|
242
303
|
|
|
@@ -244,6 +305,21 @@ class EvoStrategy(Module):
|
|
|
244
305
|
self.optimizer.step()
|
|
245
306
|
self.optimizer.zero_grad()
|
|
246
307
|
|
|
308
|
+
if self.learned_noise_scale:
|
|
309
|
+
|
|
310
|
+
if self.use_sigma_optimizer:
|
|
311
|
+
for sigma, grad_sigma in zip(self.sigmas, grad_sigmas):
|
|
312
|
+
sigma.grad = -grad_sigma
|
|
313
|
+
|
|
314
|
+
self.sigma_optimizer.step()
|
|
315
|
+
self.sigma_optimizer.zero_grad()
|
|
316
|
+
else:
|
|
317
|
+
for sigma, grad_sigma in zip(self.sigmas, grad_sigmas):
|
|
318
|
+
sigma.add_(grad_sigma * self.noise_scale_learning_rate)
|
|
319
|
+
|
|
320
|
+
for sigma in self.sigmas:
|
|
321
|
+
self.sigma_clamp_(sigma)
|
|
322
|
+
|
|
247
323
|
def checkpoint(self, filename = 'evolved.model'):
|
|
248
324
|
|
|
249
325
|
if self.accelerate.is_main_process:
|
|
@@ -262,6 +338,11 @@ class EvoStrategy(Module):
|
|
|
262
338
|
|
|
263
339
|
model = self.noisable_model.to(self.device)
|
|
264
340
|
|
|
341
|
+
# maybe sigmas
|
|
342
|
+
|
|
343
|
+
if self.learned_noise_scale:
|
|
344
|
+
self.sigmas = self.sigmas.to(self.device)
|
|
345
|
+
|
|
265
346
|
# get world size, rank, and determine if distributed
|
|
266
347
|
|
|
267
348
|
rank = self.accelerate.process_index
|
|
@@ -333,11 +414,20 @@ class EvoStrategy(Module):
|
|
|
333
414
|
individual_param_seeds = with_seed(individual_seed)(randint)(0, MAX_SEED_VALUE, (self.num_params,))
|
|
334
415
|
|
|
335
416
|
noise_config = dict(zip(self.param_names_to_optimize, individual_param_seeds.tolist()))
|
|
336
|
-
|
|
417
|
+
|
|
418
|
+
# determine noise scale, which can be fixed or learned
|
|
419
|
+
|
|
420
|
+
noise_config_with_scale = dict()
|
|
421
|
+
|
|
422
|
+
for param_name, seed in noise_config.items():
|
|
423
|
+
|
|
424
|
+
noise_scale = self._get_noise_scale(param_name)
|
|
425
|
+
|
|
426
|
+
noise_config_with_scale[param_name] = (seed, noise_scale)
|
|
337
427
|
|
|
338
428
|
# maybe roll out with a fixed seed
|
|
339
429
|
|
|
340
|
-
with model.temp_add_noise_(
|
|
430
|
+
with model.temp_add_noise_(noise_config_with_scale):
|
|
341
431
|
fitness = with_seed(maybe_rollout_seed)(rollout_for_fitness)()
|
|
342
432
|
|
|
343
433
|
if not self.mirror_sampling:
|
|
@@ -346,7 +436,7 @@ class EvoStrategy(Module):
|
|
|
346
436
|
|
|
347
437
|
# handle mirror sampling
|
|
348
438
|
|
|
349
|
-
with model.temp_add_noise_(
|
|
439
|
+
with model.temp_add_noise_(noise_config_with_scale, negate = True):
|
|
350
440
|
fitness_mirrored = with_seed(maybe_rollout_seed)(rollout_for_fitness)()
|
|
351
441
|
|
|
352
442
|
fitnesses.append([fitness, fitness_mirrored])
|
|
@@ -360,6 +450,11 @@ class EvoStrategy(Module):
|
|
|
360
450
|
if is_distributed:
|
|
361
451
|
fitnesses = self.accelerate.gather(fitnesses)
|
|
362
452
|
|
|
453
|
+
# remove padding
|
|
454
|
+
|
|
455
|
+
fitnesses = fitnesses[:pop_size]
|
|
456
|
+
seeds_for_population = seeds_for_population[:pop_size]
|
|
457
|
+
|
|
363
458
|
# validate fitnesses
|
|
364
459
|
|
|
365
460
|
if exists(self.reject_generation_fitnesses_if) and self.reject_generation_fitnesses_if(fitnesses):
|
|
@@ -368,14 +463,17 @@ class EvoStrategy(Module):
|
|
|
368
463
|
|
|
369
464
|
# pass fitnesses to evolve function
|
|
370
465
|
|
|
371
|
-
self.evolve_(
|
|
372
|
-
fitnesses[:pop_size],
|
|
373
|
-
seeds_for_population[:pop_size]
|
|
374
|
-
)
|
|
466
|
+
self.evolve_(fitnesses, seeds_for_population)
|
|
375
467
|
|
|
376
468
|
# log
|
|
377
469
|
|
|
378
|
-
|
|
470
|
+
msg = f'[{generation}] average fitness: {fitnesses.mean():.3f} | fitness std: {fitnesses.std():.3f}'
|
|
471
|
+
|
|
472
|
+
if self.learned_noise_scale:
|
|
473
|
+
avg_sigma = torch.stack(list(self.sigmas)).mean().item()
|
|
474
|
+
msg += f' | avg sigma: {avg_sigma:.3f}'
|
|
475
|
+
|
|
476
|
+
self.print(msg)
|
|
379
477
|
|
|
380
478
|
# maybe checkpoint
|
|
381
479
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|