env-ssl-wrapper 0.5.6__tar.gz → 0.5.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.
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/.gitignore +3 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/PKG-INFO +27 -2
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/README.md +26 -1
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/__init__.py +2 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/sgs.py +132 -26
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/helpers.py +3 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/pyproject.toml +1 -1
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/LICENSE +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/action_chunk.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/evaluate.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/memory_trace.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/__init__.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/action_transform_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/adapters.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/auto_batched_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/done_tracker_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/episode_padding_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/flatten_obs_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/image_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/mocks.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/spaces.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/standardize_env_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/standardize_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/tensor_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/time_limit_wrapper.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/utils.py +0 -0
- {env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: env-ssl-wrapper
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.7
|
|
4
4
|
Summary: One torch-native interface for any MDP environment
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/env-ssl-wrapper/
|
|
6
6
|
Project-URL: Repository, https://codeberg.org/lucidrains/env-ssl-wrapper
|
|
@@ -198,7 +198,32 @@ obs, info = env.reset()
|
|
|
198
198
|
# info['sgs_config_id'] -> the config this episode started from (success rates update on episode end)
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
-
`reset_configs` holds reset states — or callables drawing one (`lambda rng: ...`) — passed through `options`, or built by a `reset_options_fn` / `state_transform`.
|
|
201
|
+
`reset_configs` holds reset states — or callables drawing one (`lambda rng: ...`) — passed through `options`, or built by a `reset_options_fn` / `state_transform`.
|
|
202
|
+
|
|
203
|
+
The score equation is swappable: the default beta shaped kernel around `target` (`sgs_score_fn`) is simply one rule of the bank's state. Whatever you pass as `score_fn` is handed, by name, the arguments it declares — `p` (per state success rates), `counts`, `history` (the raw episode outcomes), `step`, `window`, and the hparams `target`, `kappa`, `eps`, `unvisited_weight`.
|
|
204
|
+
|
|
205
|
+
The sampling distribution is swappable too: the default (`sgs_sample_fn`) draws from the beta shape the score produces, while a custom `sample_fn` is handed, by name, whatever it declares — `p`, `counts`, `history`, `configs`, `weights`, `probs`, `rng`, `size`, `step`, and the hparams — so any distribution of the bank can be plugged in.
|
|
206
|
+
|
|
207
|
+
The rest of the loop is hookable as well: target schedule, uniform floor (`uniform_prob`), env-native fallback (`default_prob`), success signal (`success_fn`).
|
|
208
|
+
|
|
209
|
+
Track the curriculum as it runs — one snapshot of the bank per credited episode, kept in memory and appended to a csv when `log_path` is set:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
env = SuccessGuidedSamplingWrapper(
|
|
213
|
+
StandardizeEnvWrapper(gym.make('CartPole-v1')),
|
|
214
|
+
reset_configs = reset_states,
|
|
215
|
+
log_every = 1, # snapshot every episode (None turns logging off)
|
|
216
|
+
log_path = 'sgs_progression.csv',
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
env.trace # [dict(step, success_rates, probs), ...]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
LunarLander is the worked example — a difficulty ladder of reset states, three arms (native spawns, uniform bank resets, SGS), paired evaluation and the speedup chart:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
uv run train_lunar_sgs.py --steps=200000 --seeds=0,1,2,3,4 # writes experiments/lunar_sgs/
|
|
226
|
+
```
|
|
202
227
|
|
|
203
228
|
## Wrappers
|
|
204
229
|
|
|
@@ -138,7 +138,32 @@ obs, info = env.reset()
|
|
|
138
138
|
# info['sgs_config_id'] -> the config this episode started from (success rates update on episode end)
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
`reset_configs` holds reset states — or callables drawing one (`lambda rng: ...`) — passed through `options`, or built by a `reset_options_fn` / `state_transform`.
|
|
141
|
+
`reset_configs` holds reset states — or callables drawing one (`lambda rng: ...`) — passed through `options`, or built by a `reset_options_fn` / `state_transform`.
|
|
142
|
+
|
|
143
|
+
The score equation is swappable: the default beta shaped kernel around `target` (`sgs_score_fn`) is simply one rule of the bank's state. Whatever you pass as `score_fn` is handed, by name, the arguments it declares — `p` (per state success rates), `counts`, `history` (the raw episode outcomes), `step`, `window`, and the hparams `target`, `kappa`, `eps`, `unvisited_weight`.
|
|
144
|
+
|
|
145
|
+
The sampling distribution is swappable too: the default (`sgs_sample_fn`) draws from the beta shape the score produces, while a custom `sample_fn` is handed, by name, whatever it declares — `p`, `counts`, `history`, `configs`, `weights`, `probs`, `rng`, `size`, `step`, and the hparams — so any distribution of the bank can be plugged in.
|
|
146
|
+
|
|
147
|
+
The rest of the loop is hookable as well: target schedule, uniform floor (`uniform_prob`), env-native fallback (`default_prob`), success signal (`success_fn`).
|
|
148
|
+
|
|
149
|
+
Track the curriculum as it runs — one snapshot of the bank per credited episode, kept in memory and appended to a csv when `log_path` is set:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
env = SuccessGuidedSamplingWrapper(
|
|
153
|
+
StandardizeEnvWrapper(gym.make('CartPole-v1')),
|
|
154
|
+
reset_configs = reset_states,
|
|
155
|
+
log_every = 1, # snapshot every episode (None turns logging off)
|
|
156
|
+
log_path = 'sgs_progression.csv',
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
env.trace # [dict(step, success_rates, probs), ...]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
LunarLander is the worked example — a difficulty ladder of reset states, three arms (native spawns, uniform bank resets, SGS), paired evaluation and the speedup chart:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uv run train_lunar_sgs.py --steps=200000 --seeds=0,1,2,3,4 # writes experiments/lunar_sgs/
|
|
166
|
+
```
|
|
142
167
|
|
|
143
168
|
## Wrappers
|
|
144
169
|
|
|
@@ -12,6 +12,7 @@ from .sgs import (
|
|
|
12
12
|
SGSWrapper,
|
|
13
13
|
SGSSampler,
|
|
14
14
|
sgs_score_fn,
|
|
15
|
+
sgs_sample_fn,
|
|
15
16
|
variance_score_fn,
|
|
16
17
|
uniform_score_fn,
|
|
17
18
|
)
|
|
@@ -50,6 +51,7 @@ __all__ = [
|
|
|
50
51
|
'SGSWrapper',
|
|
51
52
|
'SGSSampler',
|
|
52
53
|
'sgs_score_fn',
|
|
54
|
+
'sgs_sample_fn',
|
|
53
55
|
'variance_score_fn',
|
|
54
56
|
'uniform_score_fn',
|
|
55
57
|
'evaluate_actor',
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections import deque
|
|
4
4
|
import inspect
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
5
7
|
from typing import Callable, Sequence
|
|
6
8
|
|
|
7
9
|
import numpy as np
|
|
@@ -14,6 +16,7 @@ from .standardize.helpers import (
|
|
|
14
16
|
any_true,
|
|
15
17
|
copy_leaf,
|
|
16
18
|
default,
|
|
19
|
+
divisible_by,
|
|
17
20
|
dones_of,
|
|
18
21
|
env_autoresets,
|
|
19
22
|
env_num_envs,
|
|
@@ -48,6 +51,19 @@ def call_hook(fn: Callable, *args):
|
|
|
48
51
|
def resolve_schedule(val: float | Callable[[int], float], step: int) -> float:
|
|
49
52
|
return float(val(step)) if callable(val) else float(val)
|
|
50
53
|
|
|
54
|
+
def inject_args(fn: Callable, available: dict) -> dict:
|
|
55
|
+
# dependency injection - hand the callable exactly the arguments it declares
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
params = inspect.signature(fn).parameters
|
|
59
|
+
except (TypeError, ValueError):
|
|
60
|
+
return dict(available)
|
|
61
|
+
|
|
62
|
+
if any(param.kind == inspect.Parameter.VAR_KEYWORD for param in params.values()):
|
|
63
|
+
return dict(available)
|
|
64
|
+
|
|
65
|
+
return {name: value for name, value in available.items() if name in params}
|
|
66
|
+
|
|
51
67
|
def default_success_fn(obs, reward, terminated, truncated, info):
|
|
52
68
|
if isinstance(info, dict):
|
|
53
69
|
succ = first_existing(info, 'is_success', 'success')
|
|
@@ -144,12 +160,34 @@ def uniform_score_fn(
|
|
|
144
160
|
) -> torch.Tensor:
|
|
145
161
|
return torch.ones_like(p, dtype = torch.float32)
|
|
146
162
|
|
|
163
|
+
# default sampling function
|
|
164
|
+
|
|
165
|
+
def sgs_sample_fn(
|
|
166
|
+
probs: torch.Tensor,
|
|
167
|
+
rng: np.random.Generator,
|
|
168
|
+
size: int = 1
|
|
169
|
+
) -> np.ndarray:
|
|
170
|
+
# the paper's default - categorical draw over the beta shaped probs (see `sgs_score_fn`)
|
|
171
|
+
|
|
172
|
+
probs_np = to_numpy(probs).astype(np.float64)
|
|
173
|
+
|
|
174
|
+
return rng.choice(len(probs_np), size = size, p = probs_np / probs_np.sum())
|
|
175
|
+
|
|
147
176
|
# sampler
|
|
148
177
|
|
|
149
178
|
class SGSSampler:
|
|
150
179
|
"""
|
|
151
180
|
Success-Guided Sampling (SGS) curriculum sampler over a bank of reset configurations.
|
|
152
181
|
Proposed by Octi Zhang et al. in OmniReset (https://arxiv.org/abs/2603.15999).
|
|
182
|
+
|
|
183
|
+
The default sampling distribution is the beta kernel around `target` evaluated at the
|
|
184
|
+
success rates (`sgs_score_fn`), drawn by `sgs_sample_fn`. Swap either hook - `score_fn`
|
|
185
|
+
reshapes the scores, `sample_fn` picks the distribution - each is handed, by name,
|
|
186
|
+
whatever it declares of `p`, `counts`, `history`, `configs`, `weights`, `probs`, `rng`,
|
|
187
|
+
`size`, `step`, `window` and the hparams.
|
|
188
|
+
|
|
189
|
+
Set `log_every` to keep snapshots of the bank in `self.trace` as episodes are credited,
|
|
190
|
+
and `log_path` to also append them to a csv (step, success rates, sampling probs).
|
|
153
191
|
"""
|
|
154
192
|
|
|
155
193
|
def __init__(
|
|
@@ -163,13 +201,17 @@ class SGSSampler:
|
|
|
163
201
|
uniform_prob: float | Callable[[int], float] = 0.,
|
|
164
202
|
default_prob: float | Callable[[int], float] = 0.,
|
|
165
203
|
score_fn: Callable | None = None,
|
|
204
|
+
sample_fn: Callable | None = None,
|
|
166
205
|
state_transform: Callable | None = None,
|
|
206
|
+
log_every: int | None = None,
|
|
207
|
+
log_path: str | os.PathLike | None = None,
|
|
167
208
|
seed: int | None = None,
|
|
168
209
|
):
|
|
169
210
|
self.configs = [c for c in configs]
|
|
170
211
|
assert len(self.configs) > 0, 'configs must not be empty'
|
|
171
212
|
assert window >= 1, f'window must be at least 1, got {window}'
|
|
172
213
|
assert eps > 0., f'eps must be positive, got {eps}'
|
|
214
|
+
assert not exists(log_every) or log_every >= 1, f'log_every must be at least 1, got {log_every}'
|
|
173
215
|
|
|
174
216
|
self.target = target
|
|
175
217
|
self.kappa = kappa
|
|
@@ -180,8 +222,13 @@ class SGSSampler:
|
|
|
180
222
|
self.default_prob = default_prob
|
|
181
223
|
|
|
182
224
|
self.score_fn = score_fn
|
|
225
|
+
self.sample_fn = sample_fn
|
|
183
226
|
self.state_transform = state_transform
|
|
184
227
|
|
|
228
|
+
self.log_every = log_every
|
|
229
|
+
self.log_path = log_path
|
|
230
|
+
self.trace: list[dict] = [] # progression of the bank, one snapshot per log_every episodes
|
|
231
|
+
|
|
185
232
|
self.history: list[deque[float]] = [deque(maxlen = self.window) for _ in range(len(self.configs))]
|
|
186
233
|
self.counts = torch.zeros(len(self.configs), dtype = torch.long)
|
|
187
234
|
self.step_count = 0
|
|
@@ -196,27 +243,42 @@ class SGSSampler:
|
|
|
196
243
|
rates = [float(np.mean(h)) if len(h) else float('nan') for h in self.history]
|
|
197
244
|
return torch.tensor(rates, dtype = torch.float32)
|
|
198
245
|
|
|
246
|
+
def _bank_args(self, step: int) -> dict:
|
|
247
|
+
# the common bank state both hooks are handed - the score fn sees this, the sampler
|
|
248
|
+
# all of it
|
|
249
|
+
|
|
250
|
+
return dict(
|
|
251
|
+
p = self.success_rates,
|
|
252
|
+
counts = self.counts,
|
|
253
|
+
history = self.history,
|
|
254
|
+
step = step,
|
|
255
|
+
window = self.window,
|
|
256
|
+
target = resolve_schedule(self.target, step),
|
|
257
|
+
kappa = resolve_schedule(self.kappa, step),
|
|
258
|
+
eps = self.eps,
|
|
259
|
+
unvisited_weight = self.unvisited_weight,
|
|
260
|
+
)
|
|
261
|
+
|
|
199
262
|
@property
|
|
200
263
|
def weights(self) -> torch.Tensor:
|
|
201
|
-
|
|
264
|
+
# score_fn is swappable - handed, by name, whatever it declares (see `inject_args`),
|
|
265
|
+
# sgs_score_fn by default
|
|
202
266
|
|
|
203
|
-
if exists(self.score_fn)
|
|
204
|
-
return torch.as_tensor(call_hook(self.score_fn, p, self.counts, self.step_count), dtype = torch.float32).clamp(min = 0.)
|
|
267
|
+
score_fn = self.score_fn if exists(self.score_fn) else sgs_score_fn
|
|
205
268
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
target = resolve_schedule(self.target, self.step_count),
|
|
210
|
-
kappa = resolve_schedule(self.kappa, self.step_count),
|
|
211
|
-
eps = self.eps,
|
|
212
|
-
unvisited_weight = self.unvisited_weight
|
|
213
|
-
)
|
|
269
|
+
weights = score_fn(**inject_args(score_fn, self._bank_args(self.step_count)))
|
|
270
|
+
|
|
271
|
+
return torch.as_tensor(weights, dtype = torch.float32).clamp(min = 0.)
|
|
214
272
|
|
|
215
273
|
@property
|
|
216
274
|
def probs(self) -> torch.Tensor:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
275
|
+
return self._mixed_probs(self.weights)
|
|
276
|
+
|
|
277
|
+
def _mixed_probs(self, weights: torch.Tensor) -> torch.Tensor:
|
|
278
|
+
# normalize, then mix in the uniform floor - what the default sampler draws from
|
|
279
|
+
|
|
280
|
+
total = weights.sum()
|
|
281
|
+
probs = weights / total if total > 0. else torch.full_like(weights, 1. / len(weights))
|
|
220
282
|
|
|
221
283
|
uniform_prob = resolve_schedule(self.uniform_prob, self.step_count)
|
|
222
284
|
assert 0. <= uniform_prob <= 1., f'uniform_prob must be within [0, 1], got {uniform_prob}'
|
|
@@ -239,15 +301,30 @@ class SGSSampler:
|
|
|
239
301
|
|
|
240
302
|
def sample(self, batch_size: int | None = None):
|
|
241
303
|
size = 1 if not exists(batch_size) else int(batch_size)
|
|
304
|
+
step = self.step_count
|
|
305
|
+
|
|
306
|
+
# sample_fn is swappable, handed whatever it declares (see `inject_args`) - the
|
|
307
|
+
# default draws from the beta shaped `probs`, a custom one from any distribution
|
|
308
|
+
|
|
309
|
+
sample_fn = self.sample_fn if exists(self.sample_fn) else sgs_sample_fn
|
|
310
|
+
|
|
311
|
+
weights = self.weights
|
|
312
|
+
available = dict(
|
|
313
|
+
**self._bank_args(step),
|
|
314
|
+
configs = self.configs,
|
|
315
|
+
weights = weights,
|
|
316
|
+
probs = self._mixed_probs(weights),
|
|
317
|
+
rng = self.rng,
|
|
318
|
+
size = size,
|
|
319
|
+
uniform_prob = resolve_schedule(self.uniform_prob, step),
|
|
320
|
+
)
|
|
242
321
|
|
|
243
|
-
|
|
244
|
-
|
|
322
|
+
indices = to_numpy(sample_fn(**inject_args(sample_fn, available))).astype(int).reshape(-1)
|
|
323
|
+
assert len(indices) == size, f'sample_fn must return {size} indices, got {len(indices)}'
|
|
245
324
|
|
|
246
|
-
default_prob = resolve_schedule(self.default_prob,
|
|
325
|
+
default_prob = resolve_schedule(self.default_prob, step)
|
|
247
326
|
assert 0. <= default_prob <= 1., f'default_prob must be within [0, 1], got {default_prob}'
|
|
248
327
|
|
|
249
|
-
indices = self.rng.choice(len(self.configs), size = size, p = probs_np)
|
|
250
|
-
|
|
251
328
|
# a fraction of the draws can fall back to the environment's own reset distribution
|
|
252
329
|
|
|
253
330
|
if default_prob > 0.:
|
|
@@ -275,6 +352,31 @@ class SGSSampler:
|
|
|
275
352
|
self.counts[idx] += 1
|
|
276
353
|
self.step_count += 1
|
|
277
354
|
|
|
355
|
+
self.log()
|
|
356
|
+
|
|
357
|
+
def log(self):
|
|
358
|
+
# snapshot in memory, and append to the csv when log_path is set
|
|
359
|
+
|
|
360
|
+
if not exists(self.log_every) or not divisible_by(self.step_count, self.log_every):
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
snapshot = dict(step = self.step_count, success_rates = self.success_rates, probs = self.probs)
|
|
364
|
+
self.trace.append(snapshot)
|
|
365
|
+
|
|
366
|
+
if not exists(self.log_path):
|
|
367
|
+
return
|
|
368
|
+
|
|
369
|
+
path = Path(self.log_path)
|
|
370
|
+
path.parent.mkdir(parents = True, exist_ok = True)
|
|
371
|
+
|
|
372
|
+
with path.open('a') as log:
|
|
373
|
+
if log.tell() == 0: # empty file - write the header
|
|
374
|
+
columns = [f'success_rate_{i}' for i in range(len(self))] + [f'prob_{i}' for i in range(len(self))]
|
|
375
|
+
log.write(','.join(['step', *columns]) + '\n')
|
|
376
|
+
|
|
377
|
+
values = [snapshot['step'], *to_numpy(snapshot['success_rates']), *to_numpy(snapshot['probs'])]
|
|
378
|
+
log.write(','.join(f'{value:.4f}' for value in values) + '\n')
|
|
379
|
+
|
|
278
380
|
def add_config(self, config, init_p: float | None = None) -> int:
|
|
279
381
|
idx = len(self.configs)
|
|
280
382
|
self.configs.append(copy_leaf(config))
|
|
@@ -289,6 +391,7 @@ class SuccessGuidedSamplingWrapper(EnvWrapper):
|
|
|
289
391
|
Success-Guided Sampling (SGS) environment wrapper (Octi Zhang et al., https://arxiv.org/abs/2603.15999).
|
|
290
392
|
Wraps on top of StandardizeEnvWrapper (or any single / vectorized environment) to adaptively sample
|
|
291
393
|
initial reset states at the policy's frontier of competence and track per-config success rates.
|
|
394
|
+
Pass `log_every` / `log_path` to record the progression of the bank (see `SGSSampler`).
|
|
292
395
|
"""
|
|
293
396
|
|
|
294
397
|
priority = 110
|
|
@@ -305,12 +408,15 @@ class SuccessGuidedSamplingWrapper(EnvWrapper):
|
|
|
305
408
|
uniform_prob: float | Callable[[int], float] = 0.,
|
|
306
409
|
default_prob: float | Callable[[int], float] = 0.,
|
|
307
410
|
score_fn: Callable | None = None,
|
|
411
|
+
sample_fn: Callable | None = None,
|
|
308
412
|
state_transform: Callable | None = None,
|
|
309
413
|
success_fn: Callable | None = None,
|
|
310
414
|
harvest_fn: Callable | None = None,
|
|
311
415
|
reset_options_fn: Callable | None = None,
|
|
312
416
|
set_state_fn: Callable | None = None,
|
|
313
417
|
options_key: str = 'reset_to_state',
|
|
418
|
+
log_every: int | None = None,
|
|
419
|
+
log_path: str | os.PathLike | None = None,
|
|
314
420
|
enabled: bool = True,
|
|
315
421
|
seed: int | None = None,
|
|
316
422
|
):
|
|
@@ -329,7 +435,10 @@ class SuccessGuidedSamplingWrapper(EnvWrapper):
|
|
|
329
435
|
uniform_prob = uniform_prob,
|
|
330
436
|
default_prob = default_prob,
|
|
331
437
|
score_fn = score_fn,
|
|
438
|
+
sample_fn = sample_fn,
|
|
332
439
|
state_transform = state_transform,
|
|
440
|
+
log_every = log_every,
|
|
441
|
+
log_path = log_path,
|
|
333
442
|
seed = seed,
|
|
334
443
|
)
|
|
335
444
|
|
|
@@ -364,6 +473,10 @@ class SuccessGuidedSamplingWrapper(EnvWrapper):
|
|
|
364
473
|
def counts(self) -> torch.Tensor:
|
|
365
474
|
return self.sampler.counts
|
|
366
475
|
|
|
476
|
+
@property
|
|
477
|
+
def trace(self) -> list[dict]:
|
|
478
|
+
return self.sampler.trace
|
|
479
|
+
|
|
367
480
|
def _build_options(self, state, cfg_id) -> dict:
|
|
368
481
|
if exists(self.reset_options_fn):
|
|
369
482
|
return call_hook(self.reset_options_fn, state, cfg_id)
|
|
@@ -407,13 +520,6 @@ class SuccessGuidedSamplingWrapper(EnvWrapper):
|
|
|
407
520
|
|
|
408
521
|
return obs, info
|
|
409
522
|
|
|
410
|
-
self._done_since_reset = np.zeros(self.num_envs, dtype = bool)
|
|
411
|
-
|
|
412
|
-
info = dict(info) if isinstance(info, dict) else {}
|
|
413
|
-
info['sgs_config_id'] = self._format_config_id_info()
|
|
414
|
-
|
|
415
|
-
return obs, info
|
|
416
|
-
|
|
417
523
|
def step(self, action):
|
|
418
524
|
obs, reward, terminated, truncated, info = normalize_step_out(self.env.step(action))
|
|
419
525
|
info = dict(info) if isinstance(info, dict) else {}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/auto_batched_wrapper.py
RENAMED
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/done_tracker_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/flatten_obs_wrapper.py
RENAMED
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/image_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/standardize_wrapper.py
RENAMED
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/tensor_wrapper.py
RENAMED
|
File without changes
|
{env_ssl_wrapper-0.5.6 → env_ssl_wrapper-0.5.7}/env_ssl_wrapper/standardize/time_limit_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|