evolutionary-policy-optimization 0.4.0__tar.gz → 0.4.2__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.
@@ -174,3 +174,15 @@ cython_debug/
174
174
 
175
175
  # PyPI configuration file
176
176
  .pypirc
177
+
178
+ # microduck runs / artifacts
179
+ checkpoints*/
180
+ experiments/
181
+ videos*/
182
+ recordings/
183
+ wandb/
184
+ scratch/
185
+ data/
186
+ *.pt
187
+ *.mp4
188
+ *.log
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: evolutionary-policy-optimization
3
- Version: 0.4.0
3
+ Version: 0.4.2
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
@@ -40,10 +40,11 @@ Requires-Dist: einops>=0.8.1
40
40
  Requires-Dist: einx>=0.3.0
41
41
  Requires-Dist: ema-pytorch>=0.7.7
42
42
  Requires-Dist: hl-gauss-pytorch>=0.2.8
43
- Requires-Dist: mean-conc-beta>=0.0.7
43
+ Requires-Dist: mean-conc-beta>=0.2.7
44
44
  Requires-Dist: torch>=2.2
45
45
  Requires-Dist: tqdm
46
46
  Requires-Dist: x-mlps-pytorch>=0.3.0
47
+ Requires-Dist: x-ppo>=0.0.16
47
48
  Provides-Extra: examples
48
49
  Requires-Dist: fire; extra == 'examples'
49
50
  Requires-Dist: gymnasium[box2d]>=1.0.0; extra == 'examples'
@@ -29,6 +29,7 @@ from torch.utils._pytree import tree_map
29
29
  from torch.utils.data import DataLoader, TensorDataset
30
30
  from tqdm import tqdm
31
31
  from x_mlps_pytorch import AttnResidualNormedMLP
32
+ from x_ppo import hpo_actor_loss, ppo_actor_loss, spo_actor_loss
32
33
 
33
34
  from evolutionary_policy_optimization.distributed import all_gather, get_world_and_rank, is_distributed, maybe_barrier, maybe_sync_seed
34
35
 
@@ -52,6 +53,20 @@ def divisible_by(num, den):
52
53
  def to_device(inp, device):
53
54
  return tree_map(lambda t: t.to(device) if is_tensor(t) else t, inp)
54
55
 
56
+ class ShuffledBatches:
57
+ # fresh permutation on every pass
58
+
59
+ def __init__(self, fields, batch_size):
60
+ self.fields = fields
61
+ self.batch_size = batch_size
62
+
63
+ def __iter__(self):
64
+ perm = torch.randperm(self.fields[0].shape[0])
65
+
66
+ for i in range(0, len(perm), self.batch_size):
67
+ b = perm[i:i + self.batch_size]
68
+ yield [field[b] for field in self.fields]
69
+
55
70
  def maybe(fn):
56
71
 
57
72
  @wraps(fn)
@@ -1234,6 +1249,7 @@ class Agent(Module):
1234
1249
  hidden_spr_ema_update = 0.99,
1235
1250
  get_fitness_scores: Callable[..., Tensor] = get_fitness_scores,
1236
1251
  wrap_with_accelerate: bool = True,
1252
+ use_dataloader = False,
1237
1253
  accelerate_kwargs: dict = dict(),
1238
1254
  accelerator = None,
1239
1255
  quiet: bool = False,
@@ -1245,6 +1261,7 @@ class Agent(Module):
1245
1261
  # hf accelerate
1246
1262
 
1247
1263
  self.wrap_with_accelerate = wrap_with_accelerate
1264
+ self.use_dataloader = use_dataloader
1248
1265
 
1249
1266
  if wrap_with_accelerate:
1250
1267
  self.accelerate = accelerator if exists(accelerator) else Accelerator(**accelerate_kwargs)
@@ -1592,13 +1609,12 @@ class Agent(Module):
1592
1609
  epochs = 2
1593
1610
 
1594
1611
  ):
1595
- memories_and_cumulative_rewards = to_device(memories_and_cumulative_rewards, self.device)
1596
-
1597
1612
  memories_list, rewards_per_latent_episode = memories_and_cumulative_rewards
1598
1613
 
1599
- # stack memories
1614
+ # stack, then move once per field
1600
1615
 
1601
- memories = map(stack, zip(*memories_list))
1616
+ memories = [t.to(self.device) for t in map(stack, zip(*memories_list))]
1617
+ rewards_per_latent_episode = rewards_per_latent_episode.to(self.device)
1602
1618
 
1603
1619
  memories_list.clear()
1604
1620
 
@@ -1640,12 +1656,15 @@ class Agent(Module):
1640
1656
 
1641
1657
  valid_episode = episode_ids >= 0
1642
1658
 
1643
- dataset = TensorDataset(*[t[valid_episode] for t in (advantages, states, next_states, latent_gene_ids, actions, log_probs, values, dones)])
1659
+ fields = tuple(t[valid_episode] for t in (advantages, states, next_states, latent_gene_ids, actions, log_probs, values, dones))
1644
1660
 
1645
- dataloader = DataLoader(dataset, batch_size = self.batch_size, shuffle = True)
1661
+ if self.wrap_with_accelerate or self.use_dataloader:
1662
+ dataloader = DataLoader(TensorDataset(*fields), batch_size = self.batch_size, shuffle = True)
1646
1663
 
1647
- if self.wrap_with_accelerate:
1648
- dataloader = self.accelerate.prepare(dataloader)
1664
+ if self.wrap_with_accelerate:
1665
+ dataloader = self.accelerate.prepare(dataloader)
1666
+ else:
1667
+ dataloader = ShuffledBatches(fields, self.batch_size)
1649
1668
 
1650
1669
  # updating actor and critic
1651
1670
 
@@ -1845,39 +1864,31 @@ def actor_loss(
1845
1864
  advantages, # Float[b]
1846
1865
  eps_clip = 0.2,
1847
1866
  entropy_weight = .01,
1848
- eps = 1e-5,
1849
1867
  norm_advantages = True,
1850
- use_spo = False
1868
+ use_spo = False,
1869
+ use_hpo = False
1851
1870
  ):
1852
- batch = advantages.shape[0]
1853
-
1854
1871
  log_probs = sum_to_batch(distr.log_prob(actions))
1855
1872
  entropy = sum_to_batch(distr.entropy())
1856
1873
 
1857
- ratio = (log_probs - old_log_probs).exp()
1858
-
1859
- if norm_advantages:
1860
- advantages = F.layer_norm(advantages, (batch,), eps = eps)
1861
-
1862
- if use_spo:
1863
- # simple policy optimization - line 14 Algorithm 1 https://arxiv.org/abs/2401.16025v9
1864
-
1865
- actor_loss = - (
1866
- ratio * advantages -
1867
- advantages.abs() / (2 * eps_clip) * (ratio - 1.).square()
1868
- )
1874
+ if use_hpo:
1875
+ loss_fn = hpo_actor_loss
1876
+ elif use_spo:
1877
+ loss_fn = spo_actor_loss
1869
1878
  else:
1870
- # classic clipped surrogate loss from ppo
1871
-
1872
- clipped_ratio = ratio.clamp(min = 1. - eps_clip, max = 1. + eps_clip)
1873
-
1874
- actor_loss = -torch.min(clipped_ratio * advantages, ratio * advantages)
1875
-
1876
- # add entropy loss for exploration
1879
+ loss_fn = ppo_actor_loss
1880
+
1881
+ loss = loss_fn(
1882
+ log_probs,
1883
+ old_log_probs,
1884
+ advantages,
1885
+ eps_clip = eps_clip,
1886
+ normalize_advantages = norm_advantages,
1887
+ )
1877
1888
 
1878
- entropy_aux_loss = -entropy_weight * entropy
1889
+ # entropy bonus
1879
1890
 
1880
- return (actor_loss + entropy_aux_loss).mean()
1891
+ return (loss - entropy_weight * entropy).mean()
1881
1892
 
1882
1893
  # agent contains the actor, critic, and the latent genetic pool
1883
1894
 
@@ -2160,6 +2171,7 @@ class EPO(Module):
2160
2171
 
2161
2172
  next_obs, rewards, terminated, truncated = env.step_batch(actions.cpu().numpy(), worker_ids = active)[:4]
2162
2173
 
2174
+ next_states = from_numpy(np.ascontiguousarray(next_obs)).float().to(self.device)
2163
2175
  rewards = from_numpy(np.asarray(rewards)).float().to(self.device)
2164
2176
  terminated = from_numpy(np.asarray(terminated)).to(self.device)
2165
2177
  truncated = from_numpy(np.asarray(truncated)).to(self.device)
@@ -2169,7 +2181,7 @@ class EPO(Module):
2169
2181
 
2170
2182
  latent_id, episode_id, latent, state = slot.latent_id, slot.episode_id, slot.latent, slot.state
2171
2183
 
2172
- next_state = from_numpy(np.array(next_obs[k])).float().to(self.device)
2184
+ next_state = next_states[k]
2173
2185
 
2174
2186
  reward, terminated_at, truncated_at = rewards[k], terminated[k], truncated[k]
2175
2187
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "evolutionary-policy-optimization"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "EPO - Pytorch"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -30,10 +30,11 @@ dependencies = [
30
30
  'einops>=0.8.1',
31
31
  'ema-pytorch>=0.7.7',
32
32
  'hl-gauss-pytorch>=0.2.8',
33
- 'mean-conc-beta>=0.0.7',
33
+ 'mean-conc-beta>=0.2.7',
34
34
  'torch>=2.2',
35
35
  'tqdm',
36
36
  "x-mlps-pytorch>=0.3.0",
37
+ "x-ppo>=0.0.16",
37
38
  ]
38
39
 
39
40
  [project.urls]