drlab 0.2.7__tar.gz → 0.2.9__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.
- {drlab-0.2.7/src/drlab.egg-info → drlab-0.2.9}/PKG-INFO +6 -2
- {drlab-0.2.7 → drlab-0.2.9}/README.md +5 -1
- {drlab-0.2.7 → drlab-0.2.9}/pyproject.toml +1 -1
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/__init__.py +1 -1
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/off_policy/base.py +4 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/off_policy/dqn.py +4 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/off_policy/sac.py +9 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/base.py +4 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/replay/replay_buffer.py +5 -0
- {drlab-0.2.7 → drlab-0.2.9/src/drlab.egg-info}/PKG-INFO +6 -2
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_learners.py +81 -0
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_off_policy_experiment.py +5 -0
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_public_api.py +1 -1
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_replay.py +34 -0
- {drlab-0.2.7 → drlab-0.2.9}/LICENSE +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/setup.cfg +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/base.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/e_greedy.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/gaussian.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/greedy.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/stochastic.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/controllers/warmup.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/experiments/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/experiments/off_policy_experiment.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/experiments/on_policy_experiment.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/off_policy/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/off_policy/configs.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/actor_critic.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/configs.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/ppo.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/learners/on_policy/reinforce.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/replay/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/replay/transition_batch.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/runners/__init__.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab/runners/runner.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab.egg-info/SOURCES.txt +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab.egg-info/dependency_links.txt +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab.egg-info/requires.txt +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/src/drlab.egg-info/top_level.txt +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_controllers.py +0 -0
- {drlab-0.2.7 → drlab-0.2.9}/tests/test_runner.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drlab
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Deep Reinforcement Learning kit for research.
|
|
5
5
|
Author: Tomas Osarte
|
|
6
6
|
Keywords: reinforcement-learning,deep-learning,pytorch,gymnasium
|
|
@@ -139,11 +139,15 @@ episode returns, episode lengths, and optionally the last completed episode.
|
|
|
139
139
|
|
|
140
140
|
`ReplayBuffer` stores transitions for off-policy learning. It supports both
|
|
141
141
|
discrete and continuous action spaces through the configured action shape and
|
|
142
|
-
action type.
|
|
142
|
+
action type. Call `reset()` to remove all stored transitions and reuse the
|
|
143
|
+
buffer.
|
|
143
144
|
|
|
144
145
|
`TransitionBatch` is the tensor container passed between runners, replay
|
|
145
146
|
buffers, experiments, and learners.
|
|
146
147
|
|
|
148
|
+
All learners provide `reset_optimizers()` to clear optimizer state without
|
|
149
|
+
changing gradients, optimizer settings, or model parameters.
|
|
150
|
+
|
|
147
151
|
## Simple Usage
|
|
148
152
|
|
|
149
153
|
This example trains a DQN agent on `CartPole-v1`:
|
|
@@ -102,11 +102,15 @@ episode returns, episode lengths, and optionally the last completed episode.
|
|
|
102
102
|
|
|
103
103
|
`ReplayBuffer` stores transitions for off-policy learning. It supports both
|
|
104
104
|
discrete and continuous action spaces through the configured action shape and
|
|
105
|
-
action type.
|
|
105
|
+
action type. Call `reset()` to remove all stored transitions and reuse the
|
|
106
|
+
buffer.
|
|
106
107
|
|
|
107
108
|
`TransitionBatch` is the tensor container passed between runners, replay
|
|
108
109
|
buffers, experiments, and learners.
|
|
109
110
|
|
|
111
|
+
All learners provide `reset_optimizers()` to clear optimizer state without
|
|
112
|
+
changing gradients, optimizer settings, or model parameters.
|
|
113
|
+
|
|
110
114
|
## Simple Usage
|
|
111
115
|
|
|
112
116
|
This example trains a DQN agent on `CartPole-v1`:
|
|
@@ -28,6 +28,10 @@ class OffPolicyLearner(ABC):
|
|
|
28
28
|
|
|
29
29
|
self._validate_config()
|
|
30
30
|
|
|
31
|
+
def reset_optimizers(self) -> None:
|
|
32
|
+
"""Reset optimizer state owned by the learner, if any."""
|
|
33
|
+
pass
|
|
34
|
+
|
|
31
35
|
def _validate_config(self) -> None:
|
|
32
36
|
if len(self.regularizers) != len(self.reg_lams):
|
|
33
37
|
raise ValueError("regularizers and reg_lams must have same length.")
|
|
@@ -28,6 +28,10 @@ class DQNLearner(OffPolicyLearner):
|
|
|
28
28
|
if self.use_target_model:
|
|
29
29
|
self.target_model = self.make_target_model(self.model)
|
|
30
30
|
|
|
31
|
+
def reset_optimizers(self) -> None:
|
|
32
|
+
"""Clear the optimizer state."""
|
|
33
|
+
self.optimizer.state.clear()
|
|
34
|
+
|
|
31
35
|
def _validate_dqn_config(self) -> None:
|
|
32
36
|
if self.double_q and not self.use_target_model:
|
|
33
37
|
raise ValueError("double_q=True requires use_target_model=True.")
|
|
@@ -63,6 +63,15 @@ class SACLearner(OffPolicyLearner):
|
|
|
63
63
|
lr=config.alpha_lr,
|
|
64
64
|
)
|
|
65
65
|
|
|
66
|
+
def reset_optimizers(self) -> None:
|
|
67
|
+
"""Clear the state of every optimizer owned by the learner."""
|
|
68
|
+
for optimizer in (
|
|
69
|
+
self.actor_optimizer,
|
|
70
|
+
self.critic_optimizer,
|
|
71
|
+
self.alpha_optimizer,
|
|
72
|
+
):
|
|
73
|
+
optimizer.state.clear()
|
|
74
|
+
|
|
66
75
|
@property
|
|
67
76
|
def alpha(self) -> th.Tensor:
|
|
68
77
|
return self.log_alpha.exp()
|
|
@@ -20,6 +20,10 @@ class OnPolicyLearner:
|
|
|
20
20
|
|
|
21
21
|
self._validate_config()
|
|
22
22
|
|
|
23
|
+
def reset_optimizers(self) -> None:
|
|
24
|
+
"""Clear the optimizer state."""
|
|
25
|
+
self.optimizer.state.clear()
|
|
26
|
+
|
|
23
27
|
def _validate_config(self):
|
|
24
28
|
if len(self.config.regularizers) != len(self.config.reg_lams):
|
|
25
29
|
raise ValueError("regularizers and reg_lams must have same length.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drlab
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: Deep Reinforcement Learning kit for research.
|
|
5
5
|
Author: Tomas Osarte
|
|
6
6
|
Keywords: reinforcement-learning,deep-learning,pytorch,gymnasium
|
|
@@ -139,11 +139,15 @@ episode returns, episode lengths, and optionally the last completed episode.
|
|
|
139
139
|
|
|
140
140
|
`ReplayBuffer` stores transitions for off-policy learning. It supports both
|
|
141
141
|
discrete and continuous action spaces through the configured action shape and
|
|
142
|
-
action type.
|
|
142
|
+
action type. Call `reset()` to remove all stored transitions and reuse the
|
|
143
|
+
buffer.
|
|
143
144
|
|
|
144
145
|
`TransitionBatch` is the tensor container passed between runners, replay
|
|
145
146
|
buffers, experiments, and learners.
|
|
146
147
|
|
|
148
|
+
All learners provide `reset_optimizers()` to clear optimizer state without
|
|
149
|
+
changing gradients, optimizer settings, or model parameters.
|
|
150
|
+
|
|
147
151
|
## Simple Usage
|
|
148
152
|
|
|
149
153
|
This example trains a DQN agent on `CartPole-v1`:
|
|
@@ -25,7 +25,88 @@ def parameters_changed(model, before):
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def populate_optimizer_state(optimizer):
|
|
29
|
+
optimizer.zero_grad(set_to_none=True)
|
|
30
|
+
loss = sum(
|
|
31
|
+
parameter.square().sum()
|
|
32
|
+
for group in optimizer.param_groups
|
|
33
|
+
for parameter in group["params"]
|
|
34
|
+
)
|
|
35
|
+
loss.backward()
|
|
36
|
+
optimizer.step()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def assert_optimizer_state_reset(test_case, optimizer):
|
|
40
|
+
test_case.assertEqual(len(optimizer.state), 0)
|
|
41
|
+
for group in optimizer.param_groups:
|
|
42
|
+
for parameter in group["params"]:
|
|
43
|
+
test_case.assertIsNotNone(parameter.grad)
|
|
44
|
+
|
|
45
|
+
|
|
28
46
|
class LearnerSmokeTest(unittest.TestCase):
|
|
47
|
+
def test_all_on_policy_learners_reset_their_optimizer(self):
|
|
48
|
+
cases = (
|
|
49
|
+
(ReinforceLearner, ReinforceConfig(num_actions=2), 2),
|
|
50
|
+
(ActorCriticLearner, ActorCriticConfig(num_actions=2), 3),
|
|
51
|
+
(PPOLearner, PPOConfig(num_actions=2), 3),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
for learner_type, config, output_size in cases:
|
|
55
|
+
with self.subTest(learner=learner_type.__name__):
|
|
56
|
+
actor = th.nn.Linear(4, output_size)
|
|
57
|
+
optimizer = th.optim.Adam(actor.parameters())
|
|
58
|
+
learner = learner_type(actor, optimizer, config)
|
|
59
|
+
populate_optimizer_state(optimizer)
|
|
60
|
+
|
|
61
|
+
learner.reset_optimizers()
|
|
62
|
+
|
|
63
|
+
assert_optimizer_state_reset(self, optimizer)
|
|
64
|
+
|
|
65
|
+
def test_dqn_resets_its_optimizer(self):
|
|
66
|
+
model = th.nn.Linear(4, 2)
|
|
67
|
+
optimizer = th.optim.Adam(model.parameters())
|
|
68
|
+
learner = DQNLearner(
|
|
69
|
+
model,
|
|
70
|
+
optimizer,
|
|
71
|
+
DQNConfig(num_actions=2),
|
|
72
|
+
)
|
|
73
|
+
populate_optimizer_state(optimizer)
|
|
74
|
+
|
|
75
|
+
learner.reset_optimizers()
|
|
76
|
+
|
|
77
|
+
assert_optimizer_state_reset(self, optimizer)
|
|
78
|
+
|
|
79
|
+
def test_sac_resets_all_three_optimizers(self):
|
|
80
|
+
obs_dim = 4
|
|
81
|
+
action_dim = 2
|
|
82
|
+
actor = th.nn.Linear(obs_dim, 2 * action_dim)
|
|
83
|
+
critic1 = th.nn.Linear(obs_dim + action_dim, 1)
|
|
84
|
+
critic2 = th.nn.Linear(obs_dim + action_dim, 1)
|
|
85
|
+
actor_optimizer = th.optim.Adam(actor.parameters())
|
|
86
|
+
critic_optimizer = th.optim.Adam(
|
|
87
|
+
[*critic1.parameters(), *critic2.parameters()]
|
|
88
|
+
)
|
|
89
|
+
learner = SACLearner(
|
|
90
|
+
actor=actor,
|
|
91
|
+
critic1=critic1,
|
|
92
|
+
critic2=critic2,
|
|
93
|
+
actor_optimizer=actor_optimizer,
|
|
94
|
+
critic_optimizer=critic_optimizer,
|
|
95
|
+
config=SACConfig(action_shape=(action_dim,)),
|
|
96
|
+
)
|
|
97
|
+
optimizers = (
|
|
98
|
+
actor_optimizer,
|
|
99
|
+
critic_optimizer,
|
|
100
|
+
learner.alpha_optimizer,
|
|
101
|
+
)
|
|
102
|
+
for optimizer in optimizers:
|
|
103
|
+
populate_optimizer_state(optimizer)
|
|
104
|
+
|
|
105
|
+
learner.reset_optimizers()
|
|
106
|
+
|
|
107
|
+
for optimizer in optimizers:
|
|
108
|
+
assert_optimizer_state_reset(self, optimizer)
|
|
109
|
+
|
|
29
110
|
def test_soft_target_update_matches_original_arithmetic_exactly(self):
|
|
30
111
|
source1 = th.nn.Linear(4, 3)
|
|
31
112
|
source2 = th.nn.Linear(3, 2)
|
|
@@ -71,6 +71,11 @@ def one_transition() -> TransitionBatch:
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
class OffPolicyExperimentTest(unittest.TestCase):
|
|
74
|
+
def test_base_learner_optimizer_reset_is_a_noop(self):
|
|
75
|
+
learner = CountingLearner()
|
|
76
|
+
|
|
77
|
+
self.assertIsNone(learner.reset_optimizers())
|
|
78
|
+
|
|
74
79
|
def make_experiment(self, config: OffPolicyExperimentConfig) -> OffPolicyExperiment:
|
|
75
80
|
env = OneStepEnv()
|
|
76
81
|
learner = CountingLearner()
|
|
@@ -37,7 +37,7 @@ class PublicAPITest(unittest.TestCase):
|
|
|
37
37
|
"WarmupController",
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
self.assertEqual(drlab.__version__, "0.2.
|
|
40
|
+
self.assertEqual(drlab.__version__, "0.2.9")
|
|
41
41
|
self.assertTrue(expected.issubset(set(drlab.__all__)))
|
|
42
42
|
for name in expected:
|
|
43
43
|
self.assertTrue(hasattr(drlab, name), name)
|
|
@@ -134,3 +134,37 @@ class ReplayBufferTest(unittest.TestCase):
|
|
|
134
134
|
|
|
135
135
|
with self.assertRaisesRegex(ValueError, "empty buffer"):
|
|
136
136
|
buffer.sample(1)
|
|
137
|
+
|
|
138
|
+
def test_reset_empties_buffer_and_allows_reuse(self):
|
|
139
|
+
buffer = ReplayBuffer(capacity=3, obs_shape=(1,), device="cpu")
|
|
140
|
+
buffer.add(
|
|
141
|
+
states=np.asarray([[0], [1]], dtype=np.float32),
|
|
142
|
+
actions=np.asarray([0, 1]),
|
|
143
|
+
rewards=np.asarray([1.0, 2.0]),
|
|
144
|
+
terminated=np.asarray([False, True]),
|
|
145
|
+
truncated=np.asarray([False, False]),
|
|
146
|
+
next_states=np.asarray([[1], [2]], dtype=np.float32),
|
|
147
|
+
returns=np.asarray([3.0, 2.0]),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
buffer.reset()
|
|
151
|
+
|
|
152
|
+
self.assertEqual(len(buffer), 0)
|
|
153
|
+
self.assertEqual(buffer.ptr, 0)
|
|
154
|
+
self.assertEqual(buffer.get_all().states.shape, (0, 1))
|
|
155
|
+
with self.assertRaisesRegex(ValueError, "empty buffer"):
|
|
156
|
+
buffer.sample(1)
|
|
157
|
+
|
|
158
|
+
buffer.add(
|
|
159
|
+
states=np.asarray([[4]], dtype=np.float32),
|
|
160
|
+
actions=np.asarray([1]),
|
|
161
|
+
rewards=np.asarray([5.0]),
|
|
162
|
+
terminated=np.asarray([False]),
|
|
163
|
+
truncated=np.asarray([True]),
|
|
164
|
+
next_states=np.asarray([[5]], dtype=np.float32),
|
|
165
|
+
returns=np.asarray([5.0]),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
self.assertEqual(len(buffer), 1)
|
|
169
|
+
self.assertEqual(buffer.ptr, 1)
|
|
170
|
+
self.assertEqual(buffer.get_all().states.item(), 4.0)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|