drlab 0.2.4__tar.gz → 0.2.6__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.4/src/drlab.egg-info → drlab-0.2.6}/PKG-INFO +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/pyproject.toml +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/__init__.py +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/off_policy/base.py +29 -6
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/off_policy/dqn.py +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/off_policy/sac.py +25 -21
- {drlab-0.2.4 → drlab-0.2.6/src/drlab.egg-info}/PKG-INFO +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_learners.py +42 -4
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_public_api.py +1 -1
- {drlab-0.2.4 → drlab-0.2.6}/LICENSE +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/README.md +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/setup.cfg +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/base.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/e_greedy.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/gaussian.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/greedy.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/stochastic.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/controllers/warmup.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/experiments/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/experiments/off_policy_experiment.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/experiments/on_policy_experiment.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/off_policy/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/off_policy/configs.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/actor_critic.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/base.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/configs.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/ppo.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/learners/on_policy/reinforce.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/replay/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/replay/replay_buffer.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/replay/transition_batch.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/runners/__init__.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab/runners/runner.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab.egg-info/SOURCES.txt +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab.egg-info/dependency_links.txt +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab.egg-info/requires.txt +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/src/drlab.egg-info/top_level.txt +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_controllers.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_off_policy_experiment.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_replay.py +0 -0
- {drlab-0.2.4 → drlab-0.2.6}/tests/test_runner.py +0 -0
|
@@ -52,6 +52,26 @@ class OffPolicyLearner(ABC):
|
|
|
52
52
|
|
|
53
53
|
return target
|
|
54
54
|
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _validate_optimizer_parameters(
|
|
57
|
+
optimizer: th.optim.Optimizer,
|
|
58
|
+
expected_parameters: Iterable[th.nn.Parameter],
|
|
59
|
+
optimizer_name: str,
|
|
60
|
+
) -> None:
|
|
61
|
+
expected_parameter_ids = sorted(
|
|
62
|
+
id(parameter) for parameter in expected_parameters
|
|
63
|
+
)
|
|
64
|
+
optimizer_parameter_ids = sorted(
|
|
65
|
+
id(parameter)
|
|
66
|
+
for group in optimizer.param_groups
|
|
67
|
+
for parameter in group["params"]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if optimizer_parameter_ids != expected_parameter_ids:
|
|
71
|
+
raise ValueError(
|
|
72
|
+
f"{optimizer_name} must contain exactly its model parameters."
|
|
73
|
+
)
|
|
74
|
+
|
|
55
75
|
def _hard_update(self, target: th.nn.Module, source: th.nn.Module):
|
|
56
76
|
target.load_state_dict(source.state_dict())
|
|
57
77
|
target.eval()
|
|
@@ -133,18 +153,21 @@ class OffPolicyLearner(ABC):
|
|
|
133
153
|
self,
|
|
134
154
|
loss: th.Tensor,
|
|
135
155
|
optimizer: th.optim.Optimizer,
|
|
136
|
-
parameters: Iterable[th.nn.Parameter],
|
|
156
|
+
parameters: list[Iterable[th.nn.Parameter]],
|
|
137
157
|
clipnorm: float | None = None,
|
|
138
158
|
) -> None:
|
|
139
|
-
|
|
159
|
+
parameter_groups = [tuple(group) for group in parameters]
|
|
160
|
+
parameters = [
|
|
161
|
+
parameter
|
|
162
|
+
for group in parameter_groups
|
|
163
|
+
for parameter in group
|
|
164
|
+
]
|
|
140
165
|
optimizer.zero_grad(set_to_none=True)
|
|
141
166
|
loss.backward(inputs=parameters)
|
|
142
167
|
|
|
143
168
|
if clipnorm is not None:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
clipnorm,
|
|
147
|
-
)
|
|
169
|
+
for group in parameter_groups:
|
|
170
|
+
th.nn.utils.clip_grad_norm_(group, clipnorm)
|
|
148
171
|
|
|
149
172
|
optimizer.step()
|
|
150
173
|
|
|
@@ -15,8 +15,7 @@ class SACLearner(OffPolicyLearner):
|
|
|
15
15
|
critic1: th.nn.Module,
|
|
16
16
|
critic2: th.nn.Module,
|
|
17
17
|
actor_optimizer: th.optim.Optimizer,
|
|
18
|
-
|
|
19
|
-
critic2_optimizer: th.optim.Optimizer,
|
|
18
|
+
critic_optimizer: th.optim.Optimizer,
|
|
20
19
|
config: SACConfig,
|
|
21
20
|
):
|
|
22
21
|
super().__init__(config)
|
|
@@ -32,8 +31,21 @@ class SACLearner(OffPolicyLearner):
|
|
|
32
31
|
self.critic2_target = self.make_target_model(self.critic2)
|
|
33
32
|
|
|
34
33
|
self.actor_optimizer = actor_optimizer
|
|
35
|
-
self.
|
|
36
|
-
|
|
34
|
+
self.critic_optimizer = critic_optimizer
|
|
35
|
+
|
|
36
|
+
self._validate_optimizer_parameters(
|
|
37
|
+
self.actor_optimizer,
|
|
38
|
+
self.actor.parameters(),
|
|
39
|
+
"actor_optimizer",
|
|
40
|
+
)
|
|
41
|
+
self._validate_optimizer_parameters(
|
|
42
|
+
self.critic_optimizer,
|
|
43
|
+
[
|
|
44
|
+
*self.critic1.parameters(),
|
|
45
|
+
*self.critic2.parameters(),
|
|
46
|
+
],
|
|
47
|
+
"critic_optimizer",
|
|
48
|
+
)
|
|
37
49
|
|
|
38
50
|
self.criterion = config.criterion
|
|
39
51
|
|
|
@@ -127,23 +139,15 @@ class SACLearner(OffPolicyLearner):
|
|
|
127
139
|
critic1_loss = self.criterion(current_q1, targets)
|
|
128
140
|
critic2_loss = self.criterion(current_q2, targets)
|
|
129
141
|
critic_loss = critic1_loss + critic2_loss
|
|
130
|
-
self.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if self.clipnorm is not None:
|
|
135
|
-
# Clip each critic independently to preserve the previous behavior.
|
|
136
|
-
th.nn.utils.clip_grad_norm_(
|
|
142
|
+
self.optimize(
|
|
143
|
+
critic_loss,
|
|
144
|
+
optimizer=self.critic_optimizer,
|
|
145
|
+
parameters=[
|
|
137
146
|
self.critic1.parameters(),
|
|
138
|
-
self.clipnorm,
|
|
139
|
-
)
|
|
140
|
-
th.nn.utils.clip_grad_norm_(
|
|
141
147
|
self.critic2.parameters(),
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
self.critic1_optimizer.step()
|
|
146
|
-
self.critic2_optimizer.step()
|
|
148
|
+
],
|
|
149
|
+
clipnorm=self.clipnorm,
|
|
150
|
+
)
|
|
147
151
|
|
|
148
152
|
# --------------------------------------------------
|
|
149
153
|
# 2. Update actor
|
|
@@ -167,7 +171,7 @@ class SACLearner(OffPolicyLearner):
|
|
|
167
171
|
self.optimize(
|
|
168
172
|
actor_loss,
|
|
169
173
|
optimizer=self.actor_optimizer,
|
|
170
|
-
parameters=self.actor.parameters(),
|
|
174
|
+
parameters=[self.actor.parameters()],
|
|
171
175
|
clipnorm=self.clipnorm,
|
|
172
176
|
)
|
|
173
177
|
|
|
@@ -181,7 +185,7 @@ class SACLearner(OffPolicyLearner):
|
|
|
181
185
|
self.optimize(
|
|
182
186
|
alpha_loss,
|
|
183
187
|
optimizer=self.alpha_optimizer,
|
|
184
|
-
parameters=[self.log_alpha],
|
|
188
|
+
parameters=[[self.log_alpha]],
|
|
185
189
|
clipnorm=self.clipnorm,
|
|
186
190
|
)
|
|
187
191
|
|
|
@@ -143,8 +143,10 @@ class LearnerSmokeTest(unittest.TestCase):
|
|
|
143
143
|
critic1=critic1,
|
|
144
144
|
critic2=critic2,
|
|
145
145
|
actor_optimizer=th.optim.SGD(actor.parameters(), lr=0.05),
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
critic_optimizer=th.optim.SGD(
|
|
147
|
+
[*critic1.parameters(), *critic2.parameters()],
|
|
148
|
+
lr=0.05,
|
|
149
|
+
),
|
|
148
150
|
config=SACConfig(action_shape=(action_dim,), initial_alpha=0.2),
|
|
149
151
|
)
|
|
150
152
|
actor_before = [param.detach().clone() for param in actor.parameters()]
|
|
@@ -217,6 +219,40 @@ class LearnerSmokeTest(unittest.TestCase):
|
|
|
217
219
|
with self.assertRaisesRegex(ValueError, "initial_alpha must be > 0"):
|
|
218
220
|
SACConfig(initial_alpha=0.0)
|
|
219
221
|
|
|
222
|
+
def test_sac_validates_actor_and_critic_optimizer_parameters(self):
|
|
223
|
+
obs_dim = 4
|
|
224
|
+
action_dim = 2
|
|
225
|
+
actor = th.nn.Linear(obs_dim, 2 * action_dim)
|
|
226
|
+
critic1 = th.nn.Linear(obs_dim + action_dim, 1)
|
|
227
|
+
critic2 = th.nn.Linear(obs_dim + action_dim, 1)
|
|
228
|
+
critic_parameters = [*critic1.parameters(), *critic2.parameters()]
|
|
229
|
+
|
|
230
|
+
with self.assertRaisesRegex(
|
|
231
|
+
ValueError,
|
|
232
|
+
"actor_optimizer must contain exactly its model parameters",
|
|
233
|
+
):
|
|
234
|
+
SACLearner(
|
|
235
|
+
actor=actor,
|
|
236
|
+
critic1=critic1,
|
|
237
|
+
critic2=critic2,
|
|
238
|
+
actor_optimizer=th.optim.SGD(critic1.parameters(), lr=0.05),
|
|
239
|
+
critic_optimizer=th.optim.SGD(critic_parameters, lr=0.05),
|
|
240
|
+
config=SACConfig(action_shape=(action_dim,)),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
with self.assertRaisesRegex(
|
|
244
|
+
ValueError,
|
|
245
|
+
"critic_optimizer must contain exactly its model parameters",
|
|
246
|
+
):
|
|
247
|
+
SACLearner(
|
|
248
|
+
actor=actor,
|
|
249
|
+
critic1=critic1,
|
|
250
|
+
critic2=critic2,
|
|
251
|
+
actor_optimizer=th.optim.SGD(actor.parameters(), lr=0.05),
|
|
252
|
+
critic_optimizer=th.optim.SGD(critic1.parameters(), lr=0.05),
|
|
253
|
+
config=SACConfig(action_shape=(action_dim,)),
|
|
254
|
+
)
|
|
255
|
+
|
|
220
256
|
def test_sac_actor_regularizer_contributes_to_loss(self):
|
|
221
257
|
th.manual_seed(0)
|
|
222
258
|
obs_dim = 4
|
|
@@ -247,8 +283,10 @@ class LearnerSmokeTest(unittest.TestCase):
|
|
|
247
283
|
critic1=critic1,
|
|
248
284
|
critic2=critic2,
|
|
249
285
|
actor_optimizer=th.optim.SGD(actor.parameters(), lr=0.05),
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
critic_optimizer=th.optim.SGD(
|
|
287
|
+
[*critic1.parameters(), *critic2.parameters()],
|
|
288
|
+
lr=0.05,
|
|
289
|
+
),
|
|
252
290
|
config=SACConfig(
|
|
253
291
|
action_shape=(action_dim,),
|
|
254
292
|
regularizers=[actor_l2],
|
|
@@ -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.5")
|
|
41
41
|
self.assertTrue(expected.issubset(set(drlab.__all__)))
|
|
42
42
|
for name in expected:
|
|
43
43
|
self.assertTrue(hasattr(drlab, name), name)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|