streaming-deep-rl 0.2.2__tar.gz → 0.2.5__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: streaming-deep-rl
3
- Version: 0.2.2
3
+ Version: 0.2.5
4
4
  Summary: Streaming Deep Reinforcement Learning
5
5
  Project-URL: Homepage, https://pypi.org/project/streaming-deep-rl/
6
6
  Project-URL: Repository, https://codeberg.org/lucidrains/streaming-deep-rl
@@ -36,6 +36,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
36
36
  Requires-Python: >=3.9
37
37
  Requires-Dist: discrete-continuous-embed-readout>=0.2.0
38
38
  Requires-Dist: einops>=0.8.1
39
+ Requires-Dist: einx>=0.3.0
39
40
  Requires-Dist: ema-pytorch
40
41
  Requires-Dist: hl-gauss-pytorch
41
42
  Requires-Dist: torch-einops-utils
@@ -228,3 +229,15 @@ $ uv run train_lunar.py
228
229
  url = {https://arxiv.org/abs/2602.09396},
229
230
  }
230
231
  ```
232
+
233
+ ```bibtex
234
+ @misc{maes2026leworldmodelstableendtoendjointembedding,
235
+ title = {LeWorldModel: Stable End-to-End Joint-Embedding Predictive Architecture from Pixels},
236
+ author = {Lucas Maes and Quentin Le Lidec and Damien Scieur and Yann LeCun and Randall Balestriero},
237
+ year = {2026},
238
+ eprint = {2603.19312},
239
+ archivePrefix = {arXiv},
240
+ primaryClass = {cs.LG},
241
+ url = {https://arxiv.org/abs/2603.19312},
242
+ }
243
+ ```
@@ -179,3 +179,15 @@ $ uv run train_lunar.py
179
179
  url = {https://arxiv.org/abs/2602.09396},
180
180
  }
181
181
  ```
182
+
183
+ ```bibtex
184
+ @misc{maes2026leworldmodelstableendtoendjointembedding,
185
+ title = {LeWorldModel: Stable End-to-End Joint-Embedding Predictive Architecture from Pixels},
186
+ author = {Lucas Maes and Quentin Le Lidec and Damien Scieur and Yann LeCun and Randall Balestriero},
187
+ year = {2026},
188
+ eprint = {2603.19312},
189
+ archivePrefix = {arXiv},
190
+ primaryClass = {cs.LG},
191
+ url = {https://arxiv.org/abs/2603.19312},
192
+ }
193
+ ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "streaming-deep-rl"
3
- version = "0.2.2"
3
+ version = "0.2.5"
4
4
  description = "Streaming Deep Reinforcement Learning"
5
5
  authors = [
6
6
  { name = "Phil Wang", email = "lucidrains@gmail.com" }
@@ -25,6 +25,7 @@ classifiers=[
25
25
 
26
26
  dependencies = [
27
27
  "discrete-continuous-embed-readout>=0.2.0",
28
+ "einx>=0.3.0",
28
29
  "einops>=0.8.1",
29
30
  "ema-pytorch",
30
31
  "hl-gauss-pytorch",
@@ -9,16 +9,19 @@ import torch.nn.functional as F
9
9
  from torch import nn, tensor, is_tensor, cat, stack
10
10
  from torch.nn import Module, Linear, Sequential
11
11
 
12
- from einops import reduce
12
+ import einx
13
+ from einops import rearrange, reduce
13
14
 
14
15
  from discrete_continuous_embed_readout import Readout, Embed
15
16
 
16
- from torch_einops_utils import tree_map_tensor, pack_with_inverse
17
+ from torch_einops_utils import tree_map_tensor, pack_with_inverse, masked_mean
17
18
 
18
19
  from ema_pytorch import EMA
19
20
 
20
21
  from hl_gauss_pytorch import HLGaussLayer
21
22
 
23
+ from x_mlps_pytorch import MLP
24
+
22
25
  from streaming_deep_rl.buffer_dict import BufferDict
23
26
 
24
27
  # helpers
@@ -115,12 +118,15 @@ class SelfPredictRepr(Module):
115
118
  num_discrete_actions = 0,
116
119
  num_continuous_actions = 0,
117
120
  dim_predict = None,
118
- target_embed_from_ema = True # whether the target embed is from an EMA, or from the model itself (traditional vs sigreg from lejepa)
121
+ target_embed_from_ema = True, # whether the target embed is from an EMA, or from the model itself (traditional vs sigreg from lejepa)
122
+ sigreg_weight = 0.,
123
+ dim_hidden_expand_factor = 4
119
124
  ):
120
125
  super().__init__()
121
126
  assert num_discrete_actions > 0 or num_continuous_actions > 0
122
127
 
123
128
  dim_predict = default(dim_predict, dim_embed)
129
+ dim_mlp_hidden = int(dim_embed * dim_hidden_expand_factor)
124
130
 
125
131
  self.to_action_embed = Embed(dim_embed, num_discrete = num_discrete_actions, num_continuous = num_continuous_actions)
126
132
 
@@ -128,12 +134,13 @@ class SelfPredictRepr(Module):
128
134
 
129
135
  self.to_projection = nn.Sequential(
130
136
  nn.RMSNorm(dim_embed),
131
- nn.Linear(dim_embed, dim_predict, bias = False)
137
+ MLP(dim_embed, dim_mlp_hidden, dim_predict)
132
138
  )
133
139
 
134
- self.to_prediction = nn.Sequential(
135
- nn.Linear(dim_predict + dim_embed, dim_predict, bias = False)
136
- )
140
+ self.to_prediction = MLP(dim_predict + dim_embed, dim_mlp_hidden, dim_predict)
141
+
142
+ self.apply_sigreg = sigreg_weight > 0.
143
+ self.sigreg_weight = sigreg_weight
137
144
 
138
145
  def forward(
139
146
  self,
@@ -155,7 +162,54 @@ class SelfPredictRepr(Module):
155
162
 
156
163
  # cosine sim loss
157
164
 
158
- return F.mse_loss(l2norm(predicted), l2norm(next_projected))
165
+ loss = F.mse_loss(l2norm(predicted), l2norm(next_projected))
166
+
167
+ if not self.apply_sigreg:
168
+ return loss
169
+
170
+ return loss + self.sigreg_weight * sigreg_loss(projected)
171
+
172
+ # sigreg from lejepa
173
+
174
+ def sigreg_loss(
175
+ x,
176
+ num_slices = 1024,
177
+ domain = (-5, 5),
178
+ num_knots = 17,
179
+ mask = None
180
+ ):
181
+ # Randall Balestriero - https://arxiv.org/abs/2511.08544
182
+
183
+ dim, device = x.shape[-1], x.device
184
+
185
+ # slice sampling
186
+
187
+ rand_projs = torch.randn((num_slices, dim), device = device)
188
+ rand_projs = l2norm(rand_projs)
189
+
190
+ # integration points
191
+
192
+ t = torch.linspace(*domain, num_knots, device = device)
193
+
194
+ # theoretical CF for N(0, 1) and Gauss. window
195
+
196
+ exp_f = (-0.5 * t.square()).exp()
197
+
198
+ # empirical CF
199
+
200
+ x_t = einx.dot('... d, m d -> (...) m', x, rand_projs)
201
+
202
+ x_t = einx.multiply('n m, t -> n m t', x_t, t)
203
+ ecf = (1j * x_t).exp()
204
+
205
+ mask_1d = rearrange(mask, '... -> (...)') if exists(mask) else None
206
+ ecf = masked_mean(ecf, mask_1d, dim = 0)
207
+
208
+ # weighted L2 distance
209
+
210
+ err = ecf.sub(exp_f).abs().square().mul(exp_f)
211
+
212
+ return torch.trapz(err, t, dim = -1).mean()
159
213
 
160
214
  # online normalization from Welford in 1962
161
215
 
@@ -332,6 +386,9 @@ class StreamingACLambda(Module):
332
386
  critic_ema_beta = 0.7,
333
387
  actor_self_predict_repr = False,
334
388
  critic_self_predict_repr = False,
389
+ spr_target_embed_from_ema = True,
390
+ spr_sigreg_weight = 0.,
391
+ spr_dim_hidden_expand_factor = 4,
335
392
  entropy_weight = 0.01,
336
393
  init_sparsity = 0.9,
337
394
  dim_critic = 128,
@@ -406,22 +463,30 @@ class StreamingACLambda(Module):
406
463
 
407
464
  if actor_self_predict_repr:
408
465
 
409
- actor_use_ema |= True
466
+ if spr_target_embed_from_ema:
467
+ actor_use_ema |= True
410
468
 
411
469
  self.actor_spr = SelfPredictRepr(
412
470
  dim_actor,
413
471
  num_discrete_actions = num_discrete_actions,
414
472
  num_continuous_actions = num_continuous_actions,
473
+ target_embed_from_ema = spr_target_embed_from_ema,
474
+ sigreg_weight = spr_sigreg_weight,
475
+ dim_hidden_expand_factor = spr_dim_hidden_expand_factor
415
476
  )
416
477
 
417
478
  if critic_self_predict_repr:
418
479
 
419
- use_critic_ema |= True
480
+ if spr_target_embed_from_ema:
481
+ use_critic_ema |= True
420
482
 
421
483
  self.critic_spr = SelfPredictRepr(
422
484
  dim_critic,
423
485
  num_discrete_actions = num_discrete_actions,
424
486
  num_continuous_actions = num_continuous_actions,
487
+ target_embed_from_ema = spr_target_embed_from_ema,
488
+ sigreg_weight = spr_sigreg_weight,
489
+ dim_hidden_expand_factor = spr_dim_hidden_expand_factor
425
490
  )
426
491
 
427
492
  # actor