evolutionary-policy-optimization 0.2.18__tar.gz → 0.2.20__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evolutionary-policy-optimization
3
- Version: 0.2.18
3
+ Version: 0.2.20
4
4
  Summary: EPO - Pytorch
5
5
  Project-URL: Homepage, https://pypi.org/project/evolutionary-policy-optimization/
6
6
  Project-URL: Repository, https://github.com/lucidrains/evolutionary-policy-optimization
@@ -45,9 +45,13 @@ Requires-Dist: torch>=2.2
45
45
  Requires-Dist: tqdm
46
46
  Requires-Dist: x-mlps-pytorch>=0.3.0
47
47
  Provides-Extra: examples
48
+ Requires-Dist: fire; extra == 'examples'
49
+ Requires-Dist: gymnasium[box2d]>=1.0.0; extra == 'examples'
50
+ Requires-Dist: moviepy; extra == 'examples'
48
51
  Requires-Dist: numpy; extra == 'examples'
49
- Requires-Dist: pufferlib>=2.0.6; extra == 'examples'
52
+ Requires-Dist: swig; extra == 'examples'
50
53
  Requires-Dist: tqdm; extra == 'examples'
54
+ Requires-Dist: wandb; extra == 'examples'
51
55
  Provides-Extra: experimental
52
56
  Requires-Dist: tensordict; extra == 'experimental'
53
57
  Requires-Dist: torchvision; extra == 'experimental'
@@ -149,6 +153,34 @@ agent.save('./agent.pt', overwrite = True)
149
153
  agent.load('./agent.pt')
150
154
  ```
151
155
 
156
+ ## Train Gym
157
+
158
+ An example training script for LunarLander-v3 is provided at `train_gym.py`
159
+
160
+ First install example dependencies
161
+
162
+ ```bash
163
+ $ pip install '.[examples]' # or `uv pip install '.[examples]'`
164
+ ```
165
+
166
+ Single process
167
+
168
+ ```bash
169
+ $ python train_gym.py --cpu
170
+ ```
171
+
172
+ Distributed with 8 processes (one latent per process)
173
+
174
+ ```bash
175
+ $ torchrun --nproc_per_node=8 train_gym.py --cpu
176
+ ```
177
+
178
+ With wandb logging
179
+
180
+ ```bash
181
+ $ torchrun --nproc_per_node=8 train_gym.py --cpu --use_wandb
182
+ ```
183
+
152
184
  ## Contributing
153
185
 
154
186
  At the project root, run
@@ -323,6 +355,30 @@ That's it
323
355
  }
324
356
  ```
325
357
 
358
+ ```bibtex
359
+ @article{Eysenbach2018DiversityIA,
360
+ title = {Diversity is All You Need: Learning Skills without a Reward Function},
361
+ author = {Benjamin Eysenbach and Abhishek Gupta and Julian Ibarz and Sergey Levine},
362
+ journal = {ArXiv},
363
+ year = {2018},
364
+ volume = {abs/1802.06070},
365
+ url = {https://arxiv.org/abs/1802.06070}
366
+ url = {https://arxiv.org/abs/2602.16863},
367
+ ```
368
+
369
+ ```bibtex
370
+ @article{Zhu2025Hybrid,
371
+ author = {Zhu, Zimo and Yu, Chuanqiang and Wang, Junti},
372
+ title = {A Hybrid Genetic Algorithm and Proximal Policy Optimization System for Efficient Multi-Agent Task Allocation},
373
+ journal = {Systems},
374
+ volume = {13},
375
+ year = {2025},
376
+ number = {6},
377
+ article-number = {453},
378
+ url = {https://www.mdpi.com/2079-8954/13/6/453},
379
+ issn = {2079-8954}
380
+ ```
381
+
326
382
  ```bibtex
327
383
  @misc{kedia2026simtoolrealobjectcentricpolicyzeroshot,
328
384
  title = {SimToolReal: An Object-Centric Policy for Zero-Shot Dexterous Tool Manipulation},
@@ -335,15 +391,4 @@ That's it
335
391
  }
336
392
  ```
337
393
 
338
- ```bibtex
339
- @article{Eysenbach2018DiversityIA,
340
- title = {Diversity is All You Need: Learning Skills without a Reward Function},
341
- author = {Benjamin Eysenbach and Abhishek Gupta and Julian Ibarz and Sergey Levine},
342
- journal = {ArXiv},
343
- year = {2018},
344
- volume = {abs/1802.06070},
345
- url = {https://arxiv.org/abs/1802.06070}
346
- }
347
- ```
348
-
349
394
  *Evolution is cleverer than you are.* - Leslie Orgel
@@ -91,6 +91,34 @@ agent.save('./agent.pt', overwrite = True)
91
91
  agent.load('./agent.pt')
92
92
  ```
93
93
 
94
+ ## Train Gym
95
+
96
+ An example training script for LunarLander-v3 is provided at `train_gym.py`
97
+
98
+ First install example dependencies
99
+
100
+ ```bash
101
+ $ pip install '.[examples]' # or `uv pip install '.[examples]'`
102
+ ```
103
+
104
+ Single process
105
+
106
+ ```bash
107
+ $ python train_gym.py --cpu
108
+ ```
109
+
110
+ Distributed with 8 processes (one latent per process)
111
+
112
+ ```bash
113
+ $ torchrun --nproc_per_node=8 train_gym.py --cpu
114
+ ```
115
+
116
+ With wandb logging
117
+
118
+ ```bash
119
+ $ torchrun --nproc_per_node=8 train_gym.py --cpu --use_wandb
120
+ ```
121
+
94
122
  ## Contributing
95
123
 
96
124
  At the project root, run
@@ -265,6 +293,30 @@ That's it
265
293
  }
266
294
  ```
267
295
 
296
+ ```bibtex
297
+ @article{Eysenbach2018DiversityIA,
298
+ title = {Diversity is All You Need: Learning Skills without a Reward Function},
299
+ author = {Benjamin Eysenbach and Abhishek Gupta and Julian Ibarz and Sergey Levine},
300
+ journal = {ArXiv},
301
+ year = {2018},
302
+ volume = {abs/1802.06070},
303
+ url = {https://arxiv.org/abs/1802.06070}
304
+ url = {https://arxiv.org/abs/2602.16863},
305
+ ```
306
+
307
+ ```bibtex
308
+ @article{Zhu2025Hybrid,
309
+ author = {Zhu, Zimo and Yu, Chuanqiang and Wang, Junti},
310
+ title = {A Hybrid Genetic Algorithm and Proximal Policy Optimization System for Efficient Multi-Agent Task Allocation},
311
+ journal = {Systems},
312
+ volume = {13},
313
+ year = {2025},
314
+ number = {6},
315
+ article-number = {453},
316
+ url = {https://www.mdpi.com/2079-8954/13/6/453},
317
+ issn = {2079-8954}
318
+ ```
319
+
268
320
  ```bibtex
269
321
  @misc{kedia2026simtoolrealobjectcentricpolicyzeroshot,
270
322
  title = {SimToolReal: An Object-Centric Policy for Zero-Shot Dexterous Tool Manipulation},
@@ -277,15 +329,4 @@ That's it
277
329
  }
278
330
  ```
279
331
 
280
- ```bibtex
281
- @article{Eysenbach2018DiversityIA,
282
- title = {Diversity is All You Need: Learning Skills without a Reward Function},
283
- author = {Benjamin Eysenbach and Abhishek Gupta and Julian Ibarz and Sergey Levine},
284
- journal = {ArXiv},
285
- year = {2018},
286
- volume = {abs/1802.06070},
287
- url = {https://arxiv.org/abs/1802.06070}
288
- }
289
- ```
290
-
291
332
  *Evolution is cleverer than you are.* - Leslie Orgel
@@ -86,3 +86,7 @@ def all_gather_variable_dim(t, dim = 0, sizes = None):
86
86
  gathered_tensors = gathered_tensors.index_select(dim, indices)
87
87
 
88
88
  return gathered_tensors, sizes
89
+
90
+ def all_gather(t, dim = 0):
91
+ gathered, _ = all_gather_variable_dim(t, dim = dim)
92
+ return gathered
@@ -28,7 +28,7 @@ from evolutionary_policy_optimization.distributed import (
28
28
  is_distributed,
29
29
  get_world_and_rank,
30
30
  maybe_sync_seed,
31
- all_gather_variable_dim,
31
+ all_gather,
32
32
  maybe_barrier
33
33
  )
34
34
 
@@ -1121,6 +1121,7 @@ class Agent(Module):
1121
1121
  get_fitness_scores: Callable[..., Tensor] = get_fitness_scores,
1122
1122
  wrap_with_accelerate: bool = True,
1123
1123
  accelerate_kwargs: dict = dict(),
1124
+ accelerator = None,
1124
1125
  ):
1125
1126
  super().__init__()
1126
1127
 
@@ -1129,8 +1130,7 @@ class Agent(Module):
1129
1130
  self.wrap_with_accelerate = wrap_with_accelerate
1130
1131
 
1131
1132
  if wrap_with_accelerate:
1132
- accelerate = Accelerator(**accelerate_kwargs)
1133
- self.accelerate = accelerate
1133
+ self.accelerate = accelerator if exists(accelerator) else Accelerator(**accelerate_kwargs)
1134
1134
 
1135
1135
  # state norm
1136
1136
 
@@ -1239,35 +1239,40 @@ class Agent(Module):
1239
1239
 
1240
1240
  if wrap_with_accelerate:
1241
1241
  self.clip_grad_norm_ = self.accelerate.clip_grad_norm_
1242
+ device = self.accelerate.device
1243
+
1244
+ # device placement for modules without gradient parameters
1245
+
1246
+ for m in (self.state_norm, self.latent_gene_pool):
1247
+ if exists(m):
1248
+ m.to(device)
1249
+
1250
+ # DDP wrap models with gradient parameters + prepare optimizers
1242
1251
 
1243
1252
  (
1244
- self.state_norm,
1245
1253
  self.actor,
1246
1254
  self.critic,
1247
- self.latent_gene_pool,
1248
- self.diversity_discr,
1249
1255
  self.actor_optim,
1250
1256
  self.critic_optim,
1251
- self.latent_optim,
1252
- self.diversity_discr_optim,
1253
- ) = tuple(
1254
- maybe(self.accelerate.prepare)(m) for m in (
1255
- self.state_norm,
1256
- self.actor,
1257
- self.critic,
1258
- self.latent_gene_pool,
1259
- self.diversity_discr,
1260
- self.actor_optim,
1261
- self.critic_optim,
1262
- self.latent_optim,
1263
- self.diversity_discr_optim,
1264
- )
1257
+ ) = self.accelerate.prepare(
1258
+ self.actor,
1259
+ self.critic,
1260
+ self.actor_optim,
1261
+ self.critic_optim,
1265
1262
  )
1266
1263
 
1264
+ if exists(self.diversity_discr):
1265
+ self.diversity_discr, self.diversity_discr_optim = self.accelerate.prepare(
1266
+ self.diversity_discr, self.diversity_discr_optim
1267
+ )
1268
+
1269
+ if exists(self.latent_optim):
1270
+ self.latent_optim = self.accelerate.prepare(self.latent_optim)
1271
+
1267
1272
  if exists(self.critic_ema):
1268
- self.critic_ema.to(self.accelerate.device)
1273
+ self.critic_ema.to(device)
1269
1274
 
1270
- step = step.to(self.accelerate.device)
1275
+ step = step.to(device)
1271
1276
 
1272
1277
  # device tracking
1273
1278
 
@@ -1418,9 +1423,8 @@ class Agent(Module):
1418
1423
  maybe_barrier()
1419
1424
 
1420
1425
  if is_distributed():
1421
- memories = map(partial(all_gather_variable_dim, dim = 0), memories)
1422
-
1423
- rewards_per_latent_episode = dist.all_reduce(rewards_per_latent_episode)
1426
+ memories = [all_gather(m) for m in memories]
1427
+ dist.all_reduce(rewards_per_latent_episode)
1424
1428
 
1425
1429
  # calculate fitness scores
1426
1430
 
@@ -1500,7 +1504,7 @@ class Agent(Module):
1500
1504
 
1501
1505
  # learn critic with maybe classification loss
1502
1506
 
1503
- critic_loss = self.critic.forward_for_loss(
1507
+ critic_loss = self.unwrap_model(self.critic).forward_for_loss(
1504
1508
  states,
1505
1509
  latents,
1506
1510
  old_values = old_values,
@@ -1668,6 +1672,7 @@ def create_agent(
1668
1672
  critic_dim,
1669
1673
  critic_mlp_depth,
1670
1674
  use_critic_ema = True,
1675
+ use_state_norm = False,
1671
1676
  latent_gene_pool_kwargs: dict = dict(),
1672
1677
  actor_kwargs: dict = dict(),
1673
1678
  critic_kwargs: dict = dict(),
@@ -1685,7 +1690,7 @@ def create_agent(
1685
1690
  **latent_gene_pool_kwargs
1686
1691
  ) if has_latent_genes else None
1687
1692
 
1688
- state_norm = StateNorm(dim = dim_state)
1693
+ state_norm = StateNorm(dim = dim_state) if use_state_norm else None
1689
1694
 
1690
1695
  actor = Actor(
1691
1696
  num_actions = actor_num_actions,
@@ -7,6 +7,7 @@ import torch.nn.functional as F
7
7
  from torch.func import vmap, functional_call
8
8
  from torch.nn import Module, ParameterList
9
9
 
10
+ import einx
10
11
  from einops import rearrange, reduce, repeat
11
12
 
12
13
  def exists(v):
@@ -31,11 +32,12 @@ def shrink_and_perturb_(
31
32
 
32
33
  def crossover_weights(
33
34
  w1, w2,
35
+ alpha = 0.5,
34
36
  shrink_perturb = False,
35
37
  shrink_factor = 0.4,
36
38
  perturb_factor = 0.1
37
39
  ):
38
- assert w2.shape == w2.shape
40
+ assert w1.shape == w2.shape
39
41
 
40
42
  no_batch = w1.ndim == 2
41
43
 
@@ -58,12 +60,17 @@ def crossover_weights(
58
60
  u1, s1, v1 = torch.svd(w1)
59
61
  u2, s2, v2 = torch.svd(w2)
60
62
 
63
+ sign = einx.dot('b j d, b j d -> b d', v1, v2).sign()
64
+
65
+ u2 = einx.multiply('b i d, b d -> b i d', u2, sign)
66
+ v2 = einx.multiply('b j d, b d -> b j d', v2, sign)
67
+
61
68
  batch_randperm = torch.randn((batch, rank), device = w1.device).argsort(dim = -1)
62
- mask = batch_randperm < (rank // 2)
69
+ mask = batch_randperm < int(rank * alpha)
63
70
 
64
- u = torch.where(mask[:, None, :], u1, u2)
65
- s = torch.where(mask, s1, s2)
66
- v = torch.where(mask[:, :, None], v1, v2)
71
+ u = einx.where('b d, b i d, b i d -> b i d', mask, u1, u2)
72
+ s = einx.where('b d, b d, b d -> b d', mask, s1, s2)
73
+ v = einx.where('b d, b j d, b j d -> b j d', mask, v1, v2)
67
74
 
68
75
  out = u @ torch.diag_embed(s) @ v.mT
69
76
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "evolutionary-policy-optimization"
3
- version = "0.2.18"
3
+ version = "0.2.20"
4
4
  description = "EPO - Pytorch"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -14,7 +14,7 @@ keywords = [
14
14
  'reinforcement learning',
15
15
  'genetic algorithms',
16
16
  'robotics'
17
- ]
17
+ ]
18
18
  classifiers = [
19
19
  'Development Status :: 4 - Beta',
20
20
  'Intended Audience :: Developers',
@@ -42,9 +42,13 @@ Repository = "https://github.com/lucidrains/evolutionary-policy-optimization"
42
42
 
43
43
  [project.optional-dependencies]
44
44
  examples = [
45
+ "fire",
46
+ "gymnasium[box2d]>=1.0.0",
47
+ "moviepy",
45
48
  "numpy",
46
- "pufferlib>=2.0.6",
49
+ "swig",
47
50
  "tqdm",
51
+ "wandb",
48
52
  ]
49
53
 
50
54
  experimental = [