drlab 0.2.1__tar.gz → 0.2.3__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.
Files changed (44) hide show
  1. {drlab-0.2.1/src/drlab.egg-info → drlab-0.2.3}/PKG-INFO +1 -1
  2. {drlab-0.2.1 → drlab-0.2.3}/pyproject.toml +1 -1
  3. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/__init__.py +3 -1
  4. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/controllers/__init__.py +4 -2
  5. drlab-0.2.3/src/drlab/controllers/warmup.py +42 -0
  6. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/experiments/off_policy_experiment.py +46 -19
  7. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/experiments/on_policy_experiment.py +1 -1
  8. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/off_policy/base.py +4 -4
  9. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/off_policy/dqn.py +6 -4
  10. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/off_policy/sac.py +15 -5
  11. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/actor_critic.py +8 -8
  12. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/base.py +5 -5
  13. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/ppo.py +4 -4
  14. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/reinforce.py +4 -4
  15. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/replay/replay_buffer.py +18 -8
  16. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/replay/transition_batch.py +6 -3
  17. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/runners/runner.py +29 -16
  18. {drlab-0.2.1 → drlab-0.2.3/src/drlab.egg-info}/PKG-INFO +1 -1
  19. {drlab-0.2.1 → drlab-0.2.3}/src/drlab.egg-info/SOURCES.txt +4 -2
  20. {drlab-0.2.1 → drlab-0.2.3}/tests/test_controllers.py +46 -0
  21. {drlab-0.2.1 → drlab-0.2.3}/tests/test_learners.py +56 -6
  22. drlab-0.2.3/tests/test_off_policy_experiment.py +155 -0
  23. {drlab-0.2.1 → drlab-0.2.3}/tests/test_public_api.py +2 -1
  24. {drlab-0.2.1 → drlab-0.2.3}/tests/test_replay.py +21 -9
  25. {drlab-0.2.1 → drlab-0.2.3}/tests/test_runner.py +23 -0
  26. {drlab-0.2.1 → drlab-0.2.3}/LICENSE +0 -0
  27. {drlab-0.2.1 → drlab-0.2.3}/README.md +0 -0
  28. {drlab-0.2.1 → drlab-0.2.3}/setup.cfg +0 -0
  29. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/controllers/base.py +0 -0
  30. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/controllers/e_greedy.py +0 -0
  31. /drlab-0.2.1/src/drlab/controllers/gaussian_controller.py → /drlab-0.2.3/src/drlab/controllers/gaussian.py +0 -0
  32. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/controllers/greedy.py +0 -0
  33. /drlab-0.2.1/src/drlab/controllers/stochastic_controller.py → /drlab-0.2.3/src/drlab/controllers/stochastic.py +0 -0
  34. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/experiments/__init__.py +0 -0
  35. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/__init__.py +0 -0
  36. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/off_policy/__init__.py +0 -0
  37. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/off_policy/configs.py +0 -0
  38. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/__init__.py +0 -0
  39. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/learners/on_policy/configs.py +0 -0
  40. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/replay/__init__.py +0 -0
  41. {drlab-0.2.1 → drlab-0.2.3}/src/drlab/runners/__init__.py +0 -0
  42. {drlab-0.2.1 → drlab-0.2.3}/src/drlab.egg-info/dependency_links.txt +0 -0
  43. {drlab-0.2.1 → drlab-0.2.3}/src/drlab.egg-info/requires.txt +0 -0
  44. {drlab-0.2.1 → drlab-0.2.3}/src/drlab.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drlab
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: Deep Reinforcement Learning kit for research.
5
5
  Author: Tomas Osarte
6
6
  Keywords: reinforcement-learning,deep-learning,pytorch,gymnasium
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "drlab"
7
- version = "0.2.1"
7
+ version = "0.2.3"
8
8
  description = "Deep Reinforcement Learning kit for research."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -6,6 +6,7 @@ from drlab.controllers import (
6
6
  GaussianController,
7
7
  GreedyController,
8
8
  StochasticController,
9
+ WarmupController,
9
10
  )
10
11
  from drlab.experiments import (
11
12
  OnPolicyExperiment,
@@ -34,7 +35,7 @@ from drlab.learners import (
34
35
  from drlab.replay import ReplayBuffer, TransitionBatch
35
36
  from drlab.runners import Runner
36
37
 
37
- __version__ = "0.2.1"
38
+ __version__ = "0.2.3"
38
39
 
39
40
  __all__ = [
40
41
  "__version__",
@@ -68,4 +69,5 @@ __all__ = [
68
69
  "StochasticController",
69
70
  "TransitionBatch",
70
71
  "ValueTargets",
72
+ "WarmupController",
71
73
  ]
@@ -1,8 +1,9 @@
1
1
  from .base import ContinuousActionController, Controller, DiscreteActionController
2
2
  from .greedy import GreedyController
3
3
  from .e_greedy import EpsilonGreedyController
4
- from .stochastic_controller import StochasticController
5
- from .gaussian_controller import GaussianController
4
+ from .stochastic import StochasticController
5
+ from .gaussian import GaussianController
6
+ from .warmup import WarmupController
6
7
 
7
8
  __all__ = [
8
9
  "ContinuousActionController",
@@ -12,4 +13,5 @@ __all__ = [
12
13
  "GaussianController",
13
14
  "GreedyController",
14
15
  "StochasticController",
16
+ "WarmupController",
15
17
  ]
@@ -0,0 +1,42 @@
1
+ from typing import Any
2
+
3
+ import numpy as np
4
+ import torch as th
5
+
6
+ from .base import ContinuousActionController, Controller, DiscreteActionController
7
+
8
+
9
+ class WarmupController(ContinuousActionController, DiscreteActionController):
10
+ def __init__(self, controller: Controller, action_space: Any, warmup_steps: int):
11
+ self.controller = controller
12
+ self.action_space = action_space
13
+ self.warmup_steps = warmup_steps
14
+ self.steps = 0
15
+ self.model = controller.model
16
+
17
+ if hasattr(controller, "num_actions"):
18
+ self.num_actions = controller.num_actions
19
+ if hasattr(controller, "action_dim"):
20
+ self.action_dim = controller.action_dim
21
+
22
+ if warmup_steps < 0:
23
+ raise ValueError("warmup_steps must be >= 0.")
24
+
25
+ def choose(
26
+ self,
27
+ obs: th.Tensor,
28
+ **kwargs,
29
+ ) -> th.Tensor:
30
+ if self.steps >= self.warmup_steps:
31
+ return self.controller.choose(obs, **kwargs)
32
+
33
+ batch_size = obs.shape[0]
34
+ self.steps += batch_size
35
+ actions = [self.action_space.sample() for _ in range(batch_size)]
36
+ return th.as_tensor(np.asarray(actions), device=obs.device)
37
+
38
+ def probabilities(self, obs: th.Tensor, **kwargs) -> th.Tensor:
39
+ if self.steps >= self.warmup_steps:
40
+ return self.controller.probabilities(obs, **kwargs)
41
+
42
+ return th.ones((obs.shape[0], self.num_actions), device=obs.device) / self.num_actions
@@ -2,12 +2,12 @@ import numpy as np
2
2
  from tqdm import tqdm
3
3
  import gymnasium as gym
4
4
  from dataclasses import dataclass
5
- from typing import Callable, Tuple
5
+ from typing import Callable
6
6
  from torch.utils.tensorboard import SummaryWriter
7
7
 
8
8
  from drlab.learners import OffPolicyLearner, SACLearner
9
9
  from drlab.runners import Runner
10
- from drlab.controllers import Controller
10
+ from drlab.controllers import Controller, WarmupController
11
11
  from drlab.replay import TransitionBatch, ReplayBuffer
12
12
 
13
13
  @dataclass
@@ -24,6 +24,8 @@ class OffPolicyExperimentConfig:
24
24
  grad_repeats: int = 1
25
25
  step_callback: Callable[[int], None] | None = None
26
26
  step_callback_interval: int | None = None
27
+ learning_starts: int | None = None
28
+ warmup_steps: int = 0
27
29
 
28
30
 
29
31
  class OffPolicyExperiment:
@@ -44,9 +46,22 @@ class OffPolicyExperiment:
44
46
  self.run_steps = config.run_steps
45
47
  self.step_callback = config.step_callback
46
48
  self.step_callback_interval = config.step_callback_interval
49
+ self.steps = 0
50
+ self.learning_starts = (
51
+ config.batch_size if config.learning_starts is None else config.learning_starts
52
+ )
53
+ self.warmup_steps = config.warmup_steps
54
+
55
+ self._validate_config()
47
56
 
48
57
  # Init drl components
49
58
  continous_actions = isinstance(learner, SACLearner)
59
+ if self.warmup_steps > 0:
60
+ controller = WarmupController(
61
+ controller,
62
+ env.action_space,
63
+ warmup_steps=self.warmup_steps,
64
+ )
50
65
  self.runner = Runner(
51
66
  env,
52
67
  controller,
@@ -73,9 +88,17 @@ class OffPolicyExperiment:
73
88
  self.writer = SummaryWriter(log_dir=config.log_dir)
74
89
  self.experiment_name = config.experiment_name
75
90
 
91
+
92
+ def _validate_config(self):
76
93
  if self.step_callback is not None and self.step_callback_interval is None:
77
94
  raise ValueError("step_callback_interval must be set when step_callback is provided.")
78
95
 
96
+ if self.learning_starts < self.batch_size:
97
+ raise ValueError("learning_starts must be greater than or equal to batch_size.")
98
+
99
+ if self.warmup_steps < 0:
100
+ raise ValueError("warmup_steps must be greater than or equal to 0.")
101
+
79
102
  def _make_minibatch(self, batch: TransitionBatch, last_episode: TransitionBatch | None) -> TransitionBatch:
80
103
 
81
104
  # No replay buffer
@@ -97,17 +120,22 @@ class OffPolicyExperiment:
97
120
  rest = self.replay_buffer.sample(self.batch_size - ep_len)
98
121
  return rest.cat(episode)
99
122
 
100
- def _learn_from_batch(self, batch: TransitionBatch, last_episode: TransitionBatch | None) -> float:
123
+ def _learn_from_batch(
124
+ self,
125
+ batch: TransitionBatch,
126
+ last_episode: TransitionBatch | None,
127
+ ) -> float:
101
128
  # 1) Add batch to replay buffer
102
129
  self.replay_buffer.add(
103
130
  states=batch.states,
104
131
  actions=batch.actions,
105
132
  rewards=batch.rewards,
106
- dones=batch.dones,
133
+ terminated=batch.terminated,
134
+ truncated=batch.truncated,
107
135
  next_states=batch.next_states,
108
136
  returns=batch.returns,
109
137
  )
110
- if self.replay_buffer.size < self.batch_size:
138
+ if self.steps < self.learning_starts:
111
139
  return 0.0
112
140
 
113
141
  # 2) train repeats
@@ -115,19 +143,19 @@ class OffPolicyExperiment:
115
143
  for _ in range(self.grad_repeats):
116
144
  mb = self._make_minibatch(batch, last_episode)
117
145
  total_loss += self.learner.train(
118
- mb.rewards, mb.dones, mb.states, mb.actions, mb.next_states
146
+ mb.rewards, mb.terminated, mb.states, mb.actions, mb.next_states
119
147
  )
120
148
 
121
149
  return total_loss / self.grad_repeats
122
150
 
123
151
  def run(self):
124
-
125
- steps = 0
152
+
153
+ self.steps = 0
126
154
  if self.step_callback is not None:
127
- self.step_callback(steps)
155
+ self.step_callback(self.steps)
128
156
  next_callback_step = self.step_callback_interval
129
157
  pbar = tqdm(total=self.max_steps, desc=self.experiment_name, dynamic_ncols=True, mininterval=1.0)
130
- while steps < self.max_steps:
158
+ while self.steps < self.max_steps:
131
159
 
132
160
  # 1. Run batch of transitions
133
161
  batch, ep_returns, ep_lengths, last_episode = self.runner.run(
@@ -135,16 +163,20 @@ class OffPolicyExperiment:
135
163
  as_numpy=True,
136
164
  )
137
165
 
166
+ step_inc = batch.states.shape[0]
167
+ self.steps += step_inc
168
+ pbar.update(step_inc)
169
+
138
170
  # 2. Learn from batch
139
171
  loss = self._learn_from_batch(batch, last_episode)
140
172
 
141
173
  # 3. Log results
142
- self.writer.add_scalar("Loss", loss, steps)
174
+ self.writer.add_scalar("Loss", loss, self.steps)
143
175
  if ep_returns:
144
176
  mean_return = np.mean(ep_returns)
145
177
  mean_length = np.mean(ep_lengths)
146
- self.writer.add_scalar("Episode return", mean_return, steps)
147
- self.writer.add_scalar("Episode Length", mean_length, steps)
178
+ self.writer.add_scalar("Episode return", mean_return, self.steps)
179
+ self.writer.add_scalar("Episode Length", mean_length, self.steps)
148
180
 
149
181
  pbar.set_postfix({
150
182
  "loss": f"{loss:.3f}",
@@ -152,12 +184,7 @@ class OffPolicyExperiment:
152
184
  "len": f"{mean_length:.1f}",
153
185
  }, refresh=False)
154
186
 
155
- # 3. Update steps & progress bar
156
- step_inc = batch.states.shape[0]
157
- steps += step_inc
158
- pbar.update(step_inc)
159
-
160
- while self.step_callback is not None and steps >= next_callback_step:
187
+ while self.step_callback is not None and self.steps >= next_callback_step:
161
188
  self.step_callback(next_callback_step)
162
189
  next_callback_step += self.step_callback_interval
163
190
 
@@ -65,7 +65,7 @@ class OnPolicyExperiment:
65
65
  # 2. Learn from batch
66
66
  loss = self.learner.train(
67
67
  batch.rewards,
68
- batch.dones,
68
+ batch.terminated,
69
69
  batch.states,
70
70
  batch.actions,
71
71
  batch.next_states,
@@ -88,7 +88,7 @@ class OffPolicyLearner(ABC):
88
88
  self,
89
89
  model: th.nn.Module,
90
90
  rewards: th.Tensor,
91
- dones: th.Tensor,
91
+ terminated: th.Tensor,
92
92
  states: th.Tensor,
93
93
  actions: th.Tensor,
94
94
  next_states: th.Tensor,
@@ -102,7 +102,7 @@ class OffPolicyLearner(ABC):
102
102
  value = regularizer(
103
103
  model,
104
104
  rewards,
105
- dones,
105
+ terminated,
106
106
  states,
107
107
  actions,
108
108
  next_states,
@@ -139,9 +139,9 @@ class OffPolicyLearner(ABC):
139
139
  def train(
140
140
  self,
141
141
  rewards: th.Tensor,
142
- dones: th.Tensor,
142
+ terminated: th.Tensor,
143
143
  states: th.Tensor,
144
144
  actions: th.Tensor,
145
145
  next_states: th.Tensor,
146
146
  ) -> float:
147
- pass
147
+ pass
@@ -58,7 +58,7 @@ class DQNLearner(OffPolicyLearner):
58
58
  def train(
59
59
  self,
60
60
  rewards: th.Tensor, # float32, [B,1]
61
- dones: th.Tensor, # bool or float(0/1), [B,1]
61
+ terminated: th.Tensor, # bool or float(0/1), [B,1]
62
62
  states: th.Tensor, # float32, [B, obs_dim] or [B,C,H,W]
63
63
  actions: th.Tensor, # int64, [B,1]
64
64
  next_states: th.Tensor, # float32, same as states
@@ -66,8 +66,10 @@ class DQNLearner(OffPolicyLearner):
66
66
  self.model.train(True)
67
67
 
68
68
  # Compute targets
69
- not_done = 1.0 - dones.float()
70
- targets = rewards + self.gamma * (not_done * self.next_values(next_states))
69
+ not_terminated = 1.0 - terminated.float()
70
+ targets = rewards + self.gamma * (
71
+ not_terminated * self.next_values(next_states)
72
+ )
71
73
  pred = self.current_values(states, actions)
72
74
 
73
75
  # Compute loss
@@ -75,7 +77,7 @@ class DQNLearner(OffPolicyLearner):
75
77
  reg_loss = self.regularization_loss(
76
78
  self.model,
77
79
  rewards=rewards,
78
- dones=dones,
80
+ terminated=terminated,
79
81
  states=states,
80
82
  actions=actions,
81
83
  next_states=next_states,
@@ -90,7 +90,7 @@ class SACLearner(OffPolicyLearner):
90
90
  def train(
91
91
  self,
92
92
  rewards: th.Tensor, # float32, [B,1]
93
- dones: th.Tensor, # bool or float(0/1), [B,1]
93
+ terminated: th.Tensor, # bool or float(0/1), [B,1]
94
94
  states: th.Tensor, # float32, [B, obs_dim] or [B,C,H,W]
95
95
  actions: th.Tensor, # float32, [B, action_dim]
96
96
  next_states: th.Tensor, # float32, same as states
@@ -110,9 +110,9 @@ class SACLearner(OffPolicyLearner):
110
110
  target_q2 = self.critic2_target(next_action_states)
111
111
  target_q = th.min(target_q1, target_q2)
112
112
 
113
- not_done = 1.0 - dones.float()
113
+ not_terminated = 1.0 - terminated.float()
114
114
  targets = rewards + self.config.gamma * (
115
- not_done * (target_q - self.alpha.detach() * next_log_probs)
115
+ not_terminated * (target_q - self.alpha.detach() * next_log_probs)
116
116
  )
117
117
 
118
118
  action_states = th.cat([states, actions], dim=-1)
@@ -145,7 +145,16 @@ class SACLearner(OffPolicyLearner):
145
145
  new_q2 = self.critic2(new_action_states)
146
146
  new_q = th.min(new_q1, new_q2)
147
147
 
148
- actor_loss = (self.alpha.detach() * log_probs - new_q).mean()
148
+ policy_loss = (self.alpha.detach() * log_probs - new_q).mean()
149
+ reg_loss = self.regularization_loss(
150
+ self.actor,
151
+ rewards=rewards,
152
+ terminated=terminated,
153
+ states=states,
154
+ actions=actions,
155
+ next_states=next_states,
156
+ )
157
+ actor_loss = policy_loss + reg_loss
149
158
  self.optimize(
150
159
  actor_loss,
151
160
  optimizer=self.actor_optimizer,
@@ -176,9 +185,10 @@ class SACLearner(OffPolicyLearner):
176
185
 
177
186
  loss = actor_loss + critic_loss + alpha_loss
178
187
  self.last_losses = {
179
- "actor": float(actor_loss.item()),
188
+ "actor": float(policy_loss.item()),
180
189
  "critic": float(critic_loss.item()),
181
190
  "alpha": float(alpha_loss.item()),
191
+ "regularization": float(reg_loss.item()),
182
192
  "total": float(loss.item()),
183
193
  }
184
194
 
@@ -28,14 +28,14 @@ class ActorCriticLearner(OnPolicyLearner):
28
28
  self,
29
29
  returns: th.Tensor,
30
30
  rewards: th.Tensor,
31
- dones: th.Tensor,
31
+ terminated: th.Tensor,
32
32
  values: th.Tensor,
33
33
  next_values: th.Tensor,
34
34
  ) -> th.Tensor:
35
35
  if self.config.value_targets == ValueTargets.RETURNS:
36
36
  targets = returns
37
37
  elif self.config.value_targets == ValueTargets.TD:
38
- targets = rewards + self.config.gamma * (~dones * next_values)
38
+ targets = rewards + self.config.gamma * (~terminated * next_values)
39
39
  else:
40
40
  raise ValueError(f"Unknown value_targets: {self.config.value_targets}")
41
41
  return self.config.value_criterion(values, targets)
@@ -44,13 +44,13 @@ class ActorCriticLearner(OnPolicyLearner):
44
44
  self,
45
45
  returns: th.Tensor,
46
46
  rewards: th.Tensor,
47
- dones: th.Tensor,
47
+ terminated: th.Tensor,
48
48
  values: th.Tensor,
49
49
  next_values: th.Tensor
50
50
  ) -> th.Tensor:
51
51
  advantages = None
52
52
  if self.config.advantage_bootstrap:
53
- advantages = rewards + self.config.gamma * (~dones * next_values)
53
+ advantages = rewards + self.config.gamma * (~terminated * next_values)
54
54
  else:
55
55
  advantages = returns
56
56
  if self.config.use_bias:
@@ -74,7 +74,7 @@ class ActorCriticLearner(OnPolicyLearner):
74
74
  def train(
75
75
  self,
76
76
  rewards: th.Tensor,
77
- dones: th.Tensor,
77
+ terminated: th.Tensor,
78
78
  states: th.Tensor,
79
79
  actions: th.Tensor,
80
80
  next_states: th.Tensor,
@@ -106,7 +106,7 @@ class ActorCriticLearner(OnPolicyLearner):
106
106
  advantages = self._advantages(
107
107
  returns=returns,
108
108
  rewards=rewards,
109
- dones=dones,
109
+ terminated=terminated,
110
110
  values=values,
111
111
  next_values=next_values,
112
112
  )
@@ -119,7 +119,7 @@ class ActorCriticLearner(OnPolicyLearner):
119
119
  value_loss = self.config.value_lambda * self._value_loss(
120
120
  returns=returns,
121
121
  rewards=rewards,
122
- dones=dones,
122
+ terminated=terminated,
123
123
  values=values,
124
124
  next_values=next_values,
125
125
  )
@@ -128,7 +128,7 @@ class ActorCriticLearner(OnPolicyLearner):
128
128
 
129
129
  reg_loss = self._regularization_loss(
130
130
  rewards=rewards,
131
- dones=dones,
131
+ terminated=terminated,
132
132
  states=states,
133
133
  actions=actions,
134
134
  next_states=next_states,
@@ -50,7 +50,7 @@ class OnPolicyLearner:
50
50
  def _regularization_loss(
51
51
  self,
52
52
  rewards: th.Tensor,
53
- dones: th.Tensor,
53
+ terminated: th.Tensor,
54
54
  states: th.Tensor,
55
55
  actions: th.Tensor,
56
56
  next_states: th.Tensor,
@@ -59,7 +59,7 @@ class OnPolicyLearner:
59
59
  return 0.0
60
60
 
61
61
  return sum(
62
- lam * reg(self.actor, rewards, dones, states, actions, next_states)
62
+ lam * reg(self.actor, rewards, terminated, states, actions, next_states)
63
63
  for reg, lam in zip(self.config.regularizers, self.config.reg_lams)
64
64
  )
65
65
 
@@ -67,7 +67,7 @@ class OnPolicyLearner:
67
67
  self,
68
68
  returns: th.Tensor,
69
69
  rewards: th.Tensor,
70
- dones: th.Tensor,
70
+ terminated: th.Tensor,
71
71
  values: th.Tensor,
72
72
  next_values: th.Tensor,
73
73
  ) -> th.Tensor:
@@ -106,7 +106,7 @@ class OnPolicyLearner:
106
106
  self,
107
107
  returns: th.Tensor,
108
108
  rewards: th.Tensor,
109
- dones: th.Tensor,
109
+ terminated: th.Tensor,
110
110
  values: th.Tensor,
111
111
  next_values: th.Tensor
112
112
  ) -> th.Tensor:
@@ -115,7 +115,7 @@ class OnPolicyLearner:
115
115
  def train(
116
116
  self,
117
117
  rewards: th.Tensor, # float32, [B,1]
118
- dones: th.Tensor, # bool or float(0/1), [B,1]
118
+ terminated: th.Tensor, # bool or float(0/1), [B,1]
119
119
  states: th.Tensor, # float32, [B, obs_dim] or [B,C,H,W]
120
120
  actions: th.Tensor, # int64, [B,1]
121
121
  next_states: th.Tensor, # float32, same as states
@@ -38,7 +38,7 @@ class PPOLearner(ActorCriticLearner):
38
38
  def train(
39
39
  self,
40
40
  rewards: th.Tensor,
41
- dones: th.Tensor,
41
+ terminated: th.Tensor,
42
42
  states: th.Tensor,
43
43
  actions: th.Tensor,
44
44
  next_states: th.Tensor,
@@ -69,7 +69,7 @@ class PPOLearner(ActorCriticLearner):
69
69
  advantages = self._advantages(
70
70
  returns=returns,
71
71
  rewards=rewards,
72
- dones=dones,
72
+ terminated=terminated,
73
73
  values=old_values,
74
74
  next_values=next_values,
75
75
  )
@@ -96,7 +96,7 @@ class PPOLearner(ActorCriticLearner):
96
96
  value_loss = self.config.value_lambda * self._value_loss(
97
97
  returns=returns,
98
98
  rewards=rewards,
99
- dones=dones,
99
+ terminated=terminated,
100
100
  values=values,
101
101
  next_values=next_values,
102
102
  )
@@ -105,7 +105,7 @@ class PPOLearner(ActorCriticLearner):
105
105
 
106
106
  reg_loss = self._regularization_loss(
107
107
  rewards=rewards,
108
- dones=dones,
108
+ terminated=terminated,
109
109
  states=states,
110
110
  actions=actions,
111
111
  next_states=next_states,
@@ -18,7 +18,7 @@ class ReinforceLearner(OnPolicyLearner):
18
18
  self,
19
19
  returns: th.Tensor,
20
20
  rewards: th.Tensor,
21
- dones: th.Tensor,
21
+ terminated: th.Tensor,
22
22
  values: th.Tensor | None,
23
23
  next_values: th.Tensor | None,
24
24
  ) -> th.Tensor:
@@ -34,7 +34,7 @@ class ReinforceLearner(OnPolicyLearner):
34
34
  def train(
35
35
  self,
36
36
  rewards: th.Tensor,
37
- dones: th.Tensor,
37
+ terminated: th.Tensor,
38
38
  states: th.Tensor,
39
39
  actions: th.Tensor,
40
40
  next_states: th.Tensor,
@@ -50,7 +50,7 @@ class ReinforceLearner(OnPolicyLearner):
50
50
  advantages = self._advantages(
51
51
  returns=returns,
52
52
  rewards=rewards,
53
- dones=dones,
53
+ terminated=terminated,
54
54
  values=None,
55
55
  next_values=None,
56
56
  )
@@ -60,7 +60,7 @@ class ReinforceLearner(OnPolicyLearner):
60
60
  entropy_loss = self._entropy_loss(logits)
61
61
  reg_loss = self._regularization_loss(
62
62
  rewards=rewards,
63
- dones=dones,
63
+ terminated=terminated,
64
64
  states=states,
65
65
  actions=actions,
66
66
  next_states=next_states,
@@ -27,7 +27,8 @@ class ReplayBuffer:
27
27
  self.actions = np.zeros((capacity, *action_shape), dtype=action_dtype)
28
28
 
29
29
  self.rewards = np.zeros((capacity, 1), dtype=np.float32)
30
- self.dones = np.zeros((capacity, 1), dtype=np.bool_)
30
+ self.terminated = np.zeros((capacity, 1), dtype=np.bool_)
31
+ self.truncated = np.zeros((capacity, 1), dtype=np.bool_)
31
32
  self.returns = np.zeros((capacity, 1), dtype=np.float32)
32
33
 
33
34
  self.ptr = 0
@@ -41,7 +42,8 @@ class ReplayBuffer:
41
42
  states: np.ndarray, # [B, *obs_shape]
42
43
  actions: np.ndarray, # [B] or [B,1]
43
44
  rewards: np.ndarray, # [B] or [B,1]
44
- dones: np.ndarray, # [B] or [B,1] (bool)
45
+ terminated: np.ndarray, # [B] or [B,1] (bool)
46
+ truncated: np.ndarray, # [B] or [B,1] (bool)
45
47
  next_states: np.ndarray, # [B, *obs_shape]
46
48
  returns: np.ndarray # [B, 1]
47
49
 
@@ -56,7 +58,8 @@ class ReplayBuffer:
56
58
  else:
57
59
  actions = np.asarray(actions, dtype=np.int64).reshape(B, 1)
58
60
  rewards = np.asarray(rewards, dtype=np.float32).reshape(B, 1)
59
- dones = np.asarray(dones, dtype=np.bool_).reshape(B, 1)
61
+ terminated = np.asarray(terminated, dtype=np.bool_).reshape(B, 1)
62
+ truncated = np.asarray(truncated, dtype=np.bool_).reshape(B, 1)
60
63
  returns = np.asarray(returns, dtype=np.float32).reshape(B, 1)
61
64
 
62
65
  idx = (self.ptr + np.arange(B)) % self.capacity
@@ -65,7 +68,8 @@ class ReplayBuffer:
65
68
  self.next_states[idx] = next_states
66
69
  self.actions[idx] = actions
67
70
  self.rewards[idx] = rewards
68
- self.dones[idx] = dones
71
+ self.terminated[idx] = terminated
72
+ self.truncated[idx] = truncated
69
73
  self.returns[idx] = returns
70
74
 
71
75
  self.ptr = (self.ptr + B) % self.capacity
@@ -76,9 +80,12 @@ class ReplayBuffer:
76
80
  next_states = th.from_numpy(self.next_states[:self.size]).to(self.device)
77
81
  actions = th.from_numpy(self.actions[:self.size]).to(self.device)
78
82
  rewards = th.from_numpy(self.rewards[:self.size]).to(self.device)
79
- dones = th.from_numpy(self.dones[:self.size]).to(self.device)
83
+ terminated = th.from_numpy(self.terminated[:self.size]).to(self.device)
84
+ truncated = th.from_numpy(self.truncated[:self.size]).to(self.device)
80
85
  returns = th.from_numpy(self.returns[:self.size]).to(self.device)
81
- return TransitionBatch(states, actions, rewards, dones, next_states, returns)
86
+ return TransitionBatch(
87
+ states, actions, rewards, terminated, truncated, next_states, returns
88
+ )
82
89
 
83
90
  def sample(self, batch_size: int) -> TransitionBatch:
84
91
  if self.size == 0:
@@ -90,7 +97,10 @@ class ReplayBuffer:
90
97
  next_states = th.from_numpy(self.next_states[idx]).to(self.device)
91
98
  actions = th.from_numpy(self.actions[idx]).to(self.device) # long already
92
99
  rewards = th.from_numpy(self.rewards[idx]).to(self.device) # float32
93
- dones = th.from_numpy(self.dones[idx]).to(self.device) # bool
100
+ terminated = th.from_numpy(self.terminated[idx]).to(self.device) # bool
101
+ truncated = th.from_numpy(self.truncated[idx]).to(self.device) # bool
94
102
  returns = th.from_numpy(self.returns[idx]).to(self.device) # float32
95
103
 
96
- return TransitionBatch(states, actions, rewards, dones, next_states, returns)
104
+ return TransitionBatch(
105
+ states, actions, rewards, terminated, truncated, next_states, returns
106
+ )
@@ -8,7 +8,8 @@ class TransitionBatch:
8
8
  states: th.Tensor | np.ndarray # [B, obs_dim]
9
9
  actions: th.Tensor | np.ndarray # [B, 1] (int64/float32)
10
10
  rewards: th.Tensor | np.ndarray # [B, 1] (float)
11
- dones: th.Tensor | np.ndarray # [B, 1] (bool)
11
+ terminated: th.Tensor | np.ndarray # [B, 1] (bool), disables bootstrapping
12
+ truncated: th.Tensor | np.ndarray # [B, 1] (bool), ends an episode only
12
13
  next_states: th.Tensor | np.ndarray # [B, obs_dim]
13
14
  returns: th.Tensor | np.ndarray # [B, 1] (float)
14
15
 
@@ -24,7 +25,8 @@ class TransitionBatch:
24
25
  states=move(self.states),
25
26
  actions=move(self.actions),
26
27
  rewards=move(self.rewards),
27
- dones=move(self.dones),
28
+ terminated=move(self.terminated),
29
+ truncated=move(self.truncated),
28
30
  next_states=move(self.next_states),
29
31
  returns=move(self.returns),
30
32
  )
@@ -34,7 +36,8 @@ class TransitionBatch:
34
36
  states=th.cat([self.states, other.states], dim=0),
35
37
  actions=th.cat([self.actions, other.actions], dim=0),
36
38
  rewards=th.cat([self.rewards, other.rewards], dim=0),
37
- dones=th.cat([self.dones, other.dones], dim=0),
39
+ terminated=th.cat([self.terminated, other.terminated], dim=0),
40
+ truncated=th.cat([self.truncated, other.truncated], dim=0),
38
41
  next_states=th.cat([self.next_states, other.next_states], dim=0),
39
42
  returns=th.cat([self.returns, other.returns], dim=0),
40
43
  )