drlab 0.1.1__tar.gz → 0.2.2__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.2/PKG-INFO +208 -0
- drlab-0.2.2/README.md +171 -0
- {drlab-0.1.1 → drlab-0.2.2}/pyproject.toml +2 -2
- drlab-0.2.2/src/drlab/__init__.py +73 -0
- drlab-0.2.2/src/drlab/controllers/__init__.py +17 -0
- drlab-0.2.2/src/drlab/controllers/base.py +28 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/controllers/e_greedy.py +16 -6
- drlab-0.2.2/src/drlab/controllers/gaussian.py +32 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/controllers/greedy.py +5 -5
- drlab-0.1.1/src/drlab/controllers/stochastic_controller.py → drlab-0.2.2/src/drlab/controllers/stochastic.py +5 -5
- drlab-0.2.2/src/drlab/controllers/warmup.py +42 -0
- drlab-0.2.2/src/drlab/experiments/__init__.py +9 -0
- drlab-0.1.1/src/drlab/experiments/dqn_experiment.py → drlab-0.2.2/src/drlab/experiments/off_policy_experiment.py +72 -32
- drlab-0.1.1/src/drlab/experiments/ac_experiment.py → drlab-0.2.2/src/drlab/experiments/on_policy_experiment.py +8 -12
- drlab-0.2.2/src/drlab/learners/__init__.py +33 -0
- drlab-0.2.2/src/drlab/learners/off_policy/__init__.py +9 -0
- drlab-0.2.2/src/drlab/learners/off_policy/base.py +147 -0
- drlab-0.2.2/src/drlab/learners/off_policy/configs.py +72 -0
- drlab-0.2.2/src/drlab/learners/off_policy/dqn.py +101 -0
- drlab-0.2.2/src/drlab/learners/off_policy/sac.py +195 -0
- drlab-0.2.2/src/drlab/learners/on_policy/__init__.py +23 -0
- drlab-0.2.2/src/drlab/learners/on_policy/actor_critic.py +143 -0
- drlab-0.2.2/src/drlab/learners/on_policy/base.py +124 -0
- drlab-0.2.2/src/drlab/learners/on_policy/configs.py +51 -0
- drlab-0.2.2/src/drlab/learners/on_policy/ppo.py +122 -0
- drlab-0.2.2/src/drlab/learners/on_policy/reinforce.py +75 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/replay/replay_buffer.py +15 -5
- drlab-0.2.2/src/drlab/replay/transition_batch.py +40 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/runners/runner.py +79 -21
- drlab-0.2.2/src/drlab.egg-info/PKG-INFO +208 -0
- drlab-0.2.2/src/drlab.egg-info/SOURCES.txt +42 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab.egg-info/requires.txt +1 -1
- drlab-0.2.2/tests/test_controllers.py +163 -0
- drlab-0.2.2/tests/test_learners.py +239 -0
- drlab-0.2.2/tests/test_off_policy_experiment.py +154 -0
- drlab-0.2.2/tests/test_public_api.py +43 -0
- {drlab-0.1.1 → drlab-0.2.2}/tests/test_replay.py +17 -0
- {drlab-0.1.1 → drlab-0.2.2}/tests/test_runner.py +21 -0
- drlab-0.1.1/PKG-INFO +0 -275
- drlab-0.1.1/README.md +0 -238
- drlab-0.1.1/src/drlab/__init__.py +0 -36
- drlab-0.1.1/src/drlab/controllers/__init__.py +0 -6
- drlab-0.1.1/src/drlab/controllers/base.py +0 -17
- drlab-0.1.1/src/drlab/experiments/__init__.py +0 -9
- drlab-0.1.1/src/drlab/learners/__init__.py +0 -4
- drlab-0.1.1/src/drlab/learners/actor_critic.py +0 -206
- drlab-0.1.1/src/drlab/learners/dqn.py +0 -149
- drlab-0.1.1/src/drlab/replay/transition_batch.py +0 -33
- drlab-0.1.1/src/drlab.egg-info/PKG-INFO +0 -275
- drlab-0.1.1/src/drlab.egg-info/SOURCES.txt +0 -30
- drlab-0.1.1/tests/test_controllers.py +0 -80
- drlab-0.1.1/tests/test_learners.py +0 -74
- drlab-0.1.1/tests/test_public_api.py +0 -29
- {drlab-0.1.1 → drlab-0.2.2}/LICENSE +0 -0
- {drlab-0.1.1 → drlab-0.2.2}/setup.cfg +0 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/replay/__init__.py +0 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab/runners/__init__.py +0 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab.egg-info/dependency_links.txt +0 -0
- {drlab-0.1.1 → drlab-0.2.2}/src/drlab.egg-info/top_level.txt +0 -0
drlab-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: drlab
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Deep Reinforcement Learning kit for research.
|
|
5
|
+
Author: Tomas Osarte
|
|
6
|
+
Keywords: reinforcement-learning,deep-learning,pytorch,gymnasium
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Science/Research
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: torch<3,>=2.0
|
|
18
|
+
Requires-Dist: numpy==2.4.2
|
|
19
|
+
Requires-Dist: gymnasium==1.2.3
|
|
20
|
+
Requires-Dist: tqdm>=4.66
|
|
21
|
+
Requires-Dist: tensorboard>=2.16
|
|
22
|
+
Provides-Extra: experiments
|
|
23
|
+
Requires-Dist: ale-py>=0.11; extra == "experiments"
|
|
24
|
+
Requires-Dist: gymnasium[box2d]==1.2.3; extra == "experiments"
|
|
25
|
+
Requires-Dist: matplotlib>=3.8; extra == "experiments"
|
|
26
|
+
Requires-Dist: minigrid>=3.0; extra == "experiments"
|
|
27
|
+
Requires-Dist: opencv-python>=4.10; extra == "experiments"
|
|
28
|
+
Requires-Dist: scipy>=1.11; extra == "experiments"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
31
|
+
Requires-Dist: ipykernel>=6.29; extra == "dev"
|
|
32
|
+
Requires-Dist: notebook>=7.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pip-tools>=7.4; extra == "dev"
|
|
34
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# drlab
|
|
39
|
+
|
|
40
|
+
`drlab` is a small deep reinforcement learning library for training neural
|
|
41
|
+
network agents in Gymnasium environments. Its purpose is to provide simple,
|
|
42
|
+
research-friendly building blocks for reinforcement learning experiments,
|
|
43
|
+
especially when the environment or training setup is still being explored.
|
|
44
|
+
|
|
45
|
+
The library is built around PyTorch models, Gymnasium environments, reusable
|
|
46
|
+
controllers, replay buffers, runners, learners, and lightweight experiment
|
|
47
|
+
loops. It is intended for research code and prototypes, not as a large
|
|
48
|
+
production RL framework.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
The intended development setup uses [`uv`](https://docs.astral.sh/uv/). From the
|
|
53
|
+
repository root:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv sync --extra experiments --extra dev
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run commands through the managed environment:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run python -m pytest
|
|
63
|
+
uv run python examples/dqn_cartpole.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
You can also activate the local virtual environment created by `uv`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
source .venv/bin/activate
|
|
70
|
+
python -m pytest
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If you prefer a normal `venv` and `pip` workflow:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m venv .venv
|
|
77
|
+
source .venv/bin/activate
|
|
78
|
+
python -m pip install --upgrade pip
|
|
79
|
+
python -m pip install -e .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For experiment and development dependencies:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
python -m pip install -e ".[experiments,dev]"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`drlab` depends on PyTorch, NumPy, Gymnasium, tqdm, and TensorBoard. If you need
|
|
89
|
+
a specific CUDA build of PyTorch, install the matching PyTorch wheel before
|
|
90
|
+
installing the package dependencies.
|
|
91
|
+
|
|
92
|
+
## Library Overview
|
|
93
|
+
|
|
94
|
+
Most public classes can be imported directly from `drlab`:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from drlab import DQNConfig, DQNLearner, OffPolicyExperiment
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Off-Policy Learning
|
|
101
|
+
|
|
102
|
+
Off-policy learners train from transition batches that may come from a replay
|
|
103
|
+
buffer instead of only the most recent rollout. `OffPolicyExperiment` collects
|
|
104
|
+
environment transitions with a `Runner`, stores them in a `ReplayBuffer`, samples
|
|
105
|
+
minibatches, and calls the learner update.
|
|
106
|
+
|
|
107
|
+
Implemented off-policy learners:
|
|
108
|
+
|
|
109
|
+
- `DQNLearner`: value-based learning for discrete action spaces. It supports
|
|
110
|
+
replay-buffer training, target networks, Double DQN, hard or soft target
|
|
111
|
+
updates, gradient clipping, and custom regularizers.
|
|
112
|
+
- `SACLearner`: Soft Actor-Critic style learning for continuous action spaces.
|
|
113
|
+
It uses an actor, two critics, target critics, entropy tuning, and replay
|
|
114
|
+
buffer training.
|
|
115
|
+
|
|
116
|
+
### On-Policy Learning
|
|
117
|
+
|
|
118
|
+
On-policy learners train from the data collected by the current policy.
|
|
119
|
+
`OnPolicyExperiment` collects rollouts, computes returns when needed, and trains
|
|
120
|
+
the learner directly on the fresh batch.
|
|
121
|
+
|
|
122
|
+
Implemented on-policy learners:
|
|
123
|
+
|
|
124
|
+
- `ReinforceLearner`: policy-gradient learning from discounted returns.
|
|
125
|
+
- `ActorCriticLearner`: policy and value learning from shared model outputs.
|
|
126
|
+
- `PPOLearner`: clipped policy optimization over rollout batches.
|
|
127
|
+
|
|
128
|
+
### Supporting Components
|
|
129
|
+
|
|
130
|
+
Controllers turn model outputs into environment actions:
|
|
131
|
+
|
|
132
|
+
- `GreedyController`, `EpsilonGreedyController`, and `StochasticController`
|
|
133
|
+
support discrete action spaces.
|
|
134
|
+
- `GaussianController` supports continuous action spaces by sampling bounded
|
|
135
|
+
actions from model-predicted Gaussian parameters.
|
|
136
|
+
|
|
137
|
+
`Runner` interacts with Gymnasium environments and returns transition batches,
|
|
138
|
+
episode returns, episode lengths, and optionally the last completed episode.
|
|
139
|
+
|
|
140
|
+
`ReplayBuffer` stores transitions for off-policy learning. It supports both
|
|
141
|
+
discrete and continuous action spaces through the configured action shape and
|
|
142
|
+
action type.
|
|
143
|
+
|
|
144
|
+
`TransitionBatch` is the tensor container passed between runners, replay
|
|
145
|
+
buffers, experiments, and learners.
|
|
146
|
+
|
|
147
|
+
## Simple Usage
|
|
148
|
+
|
|
149
|
+
This example trains a DQN agent on `CartPole-v1`:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
import gymnasium as gym
|
|
153
|
+
import torch as th
|
|
154
|
+
|
|
155
|
+
from drlab import (
|
|
156
|
+
DQNConfig,
|
|
157
|
+
DQNLearner,
|
|
158
|
+
EpsilonGreedyController,
|
|
159
|
+
GreedyController,
|
|
160
|
+
OffPolicyExperiment,
|
|
161
|
+
OffPolicyExperimentConfig,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
env = gym.make("CartPole-v1")
|
|
165
|
+
|
|
166
|
+
obs_dim = env.observation_space.shape[0]
|
|
167
|
+
num_actions = env.action_space.n
|
|
168
|
+
|
|
169
|
+
model = th.nn.Sequential(
|
|
170
|
+
th.nn.Linear(obs_dim, 64),
|
|
171
|
+
th.nn.ReLU(),
|
|
172
|
+
th.nn.Linear(64, num_actions),
|
|
173
|
+
)
|
|
174
|
+
optimizer = th.optim.Adam(model.parameters(), lr=1e-3)
|
|
175
|
+
|
|
176
|
+
learner = DQNLearner(
|
|
177
|
+
model,
|
|
178
|
+
optimizer,
|
|
179
|
+
DQNConfig(num_actions=num_actions),
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
controller = EpsilonGreedyController(
|
|
183
|
+
GreedyController(model, num_actions=num_actions),
|
|
184
|
+
num_actions=num_actions,
|
|
185
|
+
max_eps=1.0,
|
|
186
|
+
min_eps=0.05,
|
|
187
|
+
anneal_steps=10_000,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
experiment = OffPolicyExperiment(
|
|
191
|
+
env,
|
|
192
|
+
controller,
|
|
193
|
+
learner,
|
|
194
|
+
OffPolicyExperimentConfig(
|
|
195
|
+
max_steps=10_000,
|
|
196
|
+
run_steps=1,
|
|
197
|
+
batch_size=64,
|
|
198
|
+
log_dir="runs/examples/dqn_cartpole",
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
experiment.run()
|
|
203
|
+
env.close()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
More complete scripts are available in the [`examples/`](examples/) folder,
|
|
207
|
+
including DQN, REINFORCE, actor-critic, PPO, SAC, and a comparison with
|
|
208
|
+
Stable-Baselines3.
|
drlab-0.2.2/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# drlab
|
|
2
|
+
|
|
3
|
+
`drlab` is a small deep reinforcement learning library for training neural
|
|
4
|
+
network agents in Gymnasium environments. Its purpose is to provide simple,
|
|
5
|
+
research-friendly building blocks for reinforcement learning experiments,
|
|
6
|
+
especially when the environment or training setup is still being explored.
|
|
7
|
+
|
|
8
|
+
The library is built around PyTorch models, Gymnasium environments, reusable
|
|
9
|
+
controllers, replay buffers, runners, learners, and lightweight experiment
|
|
10
|
+
loops. It is intended for research code and prototypes, not as a large
|
|
11
|
+
production RL framework.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
The intended development setup uses [`uv`](https://docs.astral.sh/uv/). From the
|
|
16
|
+
repository root:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv sync --extra experiments --extra dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Run commands through the managed environment:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv run python -m pytest
|
|
26
|
+
uv run python examples/dqn_cartpole.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
You can also activate the local virtual environment created by `uv`:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
source .venv/bin/activate
|
|
33
|
+
python -m pytest
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If you prefer a normal `venv` and `pip` workflow:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m venv .venv
|
|
40
|
+
source .venv/bin/activate
|
|
41
|
+
python -m pip install --upgrade pip
|
|
42
|
+
python -m pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For experiment and development dependencies:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m pip install -e ".[experiments,dev]"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`drlab` depends on PyTorch, NumPy, Gymnasium, tqdm, and TensorBoard. If you need
|
|
52
|
+
a specific CUDA build of PyTorch, install the matching PyTorch wheel before
|
|
53
|
+
installing the package dependencies.
|
|
54
|
+
|
|
55
|
+
## Library Overview
|
|
56
|
+
|
|
57
|
+
Most public classes can be imported directly from `drlab`:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from drlab import DQNConfig, DQNLearner, OffPolicyExperiment
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Off-Policy Learning
|
|
64
|
+
|
|
65
|
+
Off-policy learners train from transition batches that may come from a replay
|
|
66
|
+
buffer instead of only the most recent rollout. `OffPolicyExperiment` collects
|
|
67
|
+
environment transitions with a `Runner`, stores them in a `ReplayBuffer`, samples
|
|
68
|
+
minibatches, and calls the learner update.
|
|
69
|
+
|
|
70
|
+
Implemented off-policy learners:
|
|
71
|
+
|
|
72
|
+
- `DQNLearner`: value-based learning for discrete action spaces. It supports
|
|
73
|
+
replay-buffer training, target networks, Double DQN, hard or soft target
|
|
74
|
+
updates, gradient clipping, and custom regularizers.
|
|
75
|
+
- `SACLearner`: Soft Actor-Critic style learning for continuous action spaces.
|
|
76
|
+
It uses an actor, two critics, target critics, entropy tuning, and replay
|
|
77
|
+
buffer training.
|
|
78
|
+
|
|
79
|
+
### On-Policy Learning
|
|
80
|
+
|
|
81
|
+
On-policy learners train from the data collected by the current policy.
|
|
82
|
+
`OnPolicyExperiment` collects rollouts, computes returns when needed, and trains
|
|
83
|
+
the learner directly on the fresh batch.
|
|
84
|
+
|
|
85
|
+
Implemented on-policy learners:
|
|
86
|
+
|
|
87
|
+
- `ReinforceLearner`: policy-gradient learning from discounted returns.
|
|
88
|
+
- `ActorCriticLearner`: policy and value learning from shared model outputs.
|
|
89
|
+
- `PPOLearner`: clipped policy optimization over rollout batches.
|
|
90
|
+
|
|
91
|
+
### Supporting Components
|
|
92
|
+
|
|
93
|
+
Controllers turn model outputs into environment actions:
|
|
94
|
+
|
|
95
|
+
- `GreedyController`, `EpsilonGreedyController`, and `StochasticController`
|
|
96
|
+
support discrete action spaces.
|
|
97
|
+
- `GaussianController` supports continuous action spaces by sampling bounded
|
|
98
|
+
actions from model-predicted Gaussian parameters.
|
|
99
|
+
|
|
100
|
+
`Runner` interacts with Gymnasium environments and returns transition batches,
|
|
101
|
+
episode returns, episode lengths, and optionally the last completed episode.
|
|
102
|
+
|
|
103
|
+
`ReplayBuffer` stores transitions for off-policy learning. It supports both
|
|
104
|
+
discrete and continuous action spaces through the configured action shape and
|
|
105
|
+
action type.
|
|
106
|
+
|
|
107
|
+
`TransitionBatch` is the tensor container passed between runners, replay
|
|
108
|
+
buffers, experiments, and learners.
|
|
109
|
+
|
|
110
|
+
## Simple Usage
|
|
111
|
+
|
|
112
|
+
This example trains a DQN agent on `CartPole-v1`:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import gymnasium as gym
|
|
116
|
+
import torch as th
|
|
117
|
+
|
|
118
|
+
from drlab import (
|
|
119
|
+
DQNConfig,
|
|
120
|
+
DQNLearner,
|
|
121
|
+
EpsilonGreedyController,
|
|
122
|
+
GreedyController,
|
|
123
|
+
OffPolicyExperiment,
|
|
124
|
+
OffPolicyExperimentConfig,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
env = gym.make("CartPole-v1")
|
|
128
|
+
|
|
129
|
+
obs_dim = env.observation_space.shape[0]
|
|
130
|
+
num_actions = env.action_space.n
|
|
131
|
+
|
|
132
|
+
model = th.nn.Sequential(
|
|
133
|
+
th.nn.Linear(obs_dim, 64),
|
|
134
|
+
th.nn.ReLU(),
|
|
135
|
+
th.nn.Linear(64, num_actions),
|
|
136
|
+
)
|
|
137
|
+
optimizer = th.optim.Adam(model.parameters(), lr=1e-3)
|
|
138
|
+
|
|
139
|
+
learner = DQNLearner(
|
|
140
|
+
model,
|
|
141
|
+
optimizer,
|
|
142
|
+
DQNConfig(num_actions=num_actions),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
controller = EpsilonGreedyController(
|
|
146
|
+
GreedyController(model, num_actions=num_actions),
|
|
147
|
+
num_actions=num_actions,
|
|
148
|
+
max_eps=1.0,
|
|
149
|
+
min_eps=0.05,
|
|
150
|
+
anneal_steps=10_000,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
experiment = OffPolicyExperiment(
|
|
154
|
+
env,
|
|
155
|
+
controller,
|
|
156
|
+
learner,
|
|
157
|
+
OffPolicyExperimentConfig(
|
|
158
|
+
max_steps=10_000,
|
|
159
|
+
run_steps=1,
|
|
160
|
+
batch_size=64,
|
|
161
|
+
log_dir="runs/examples/dqn_cartpole",
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
experiment.run()
|
|
166
|
+
env.close()
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
More complete scripts are available in the [`examples/`](examples/) folder,
|
|
170
|
+
including DQN, REINFORCE, actor-critic, PPO, SAC, and a comparison with
|
|
171
|
+
Stable-Baselines3.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "drlab"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Deep Reinforcement Learning kit for research."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
21
21
|
]
|
|
22
22
|
dependencies = [
|
|
23
|
-
"torch
|
|
23
|
+
"torch>=2.0,<3",
|
|
24
24
|
"numpy==2.4.2",
|
|
25
25
|
"gymnasium==1.2.3",
|
|
26
26
|
"tqdm>=4.66",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from drlab.controllers import (
|
|
2
|
+
ContinuousActionController,
|
|
3
|
+
Controller,
|
|
4
|
+
DiscreteActionController,
|
|
5
|
+
EpsilonGreedyController,
|
|
6
|
+
GaussianController,
|
|
7
|
+
GreedyController,
|
|
8
|
+
StochasticController,
|
|
9
|
+
WarmupController,
|
|
10
|
+
)
|
|
11
|
+
from drlab.experiments import (
|
|
12
|
+
OnPolicyExperiment,
|
|
13
|
+
OnPolicyExperimentConfig,
|
|
14
|
+
OffPolicyExperiment,
|
|
15
|
+
OffPolicyExperimentConfig,
|
|
16
|
+
)
|
|
17
|
+
from drlab.learners import (
|
|
18
|
+
ActorCriticConfig,
|
|
19
|
+
ActorCriticLearner,
|
|
20
|
+
DQNConfig,
|
|
21
|
+
DQNLearner,
|
|
22
|
+
SACConfig,
|
|
23
|
+
SACLearner,
|
|
24
|
+
OnPolicyConfig,
|
|
25
|
+
OnPolicyLearner,
|
|
26
|
+
OffPolicyConfig,
|
|
27
|
+
OffPolicyLearner,
|
|
28
|
+
PPOConfig,
|
|
29
|
+
PPOLearner,
|
|
30
|
+
ReinforceConfig,
|
|
31
|
+
ReinforceLearner,
|
|
32
|
+
TargetUpdate,
|
|
33
|
+
ValueTargets,
|
|
34
|
+
)
|
|
35
|
+
from drlab.replay import ReplayBuffer, TransitionBatch
|
|
36
|
+
from drlab.runners import Runner
|
|
37
|
+
|
|
38
|
+
__version__ = "0.2.2"
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"__version__",
|
|
42
|
+
"ActorCriticConfig",
|
|
43
|
+
"ActorCriticLearner",
|
|
44
|
+
"OnPolicyExperiment",
|
|
45
|
+
"OnPolicyExperimentConfig",
|
|
46
|
+
"ContinuousActionController",
|
|
47
|
+
"Controller",
|
|
48
|
+
"DiscreteActionController",
|
|
49
|
+
"DQNConfig",
|
|
50
|
+
"DQNLearner",
|
|
51
|
+
"SACConfig",
|
|
52
|
+
"SACLearner",
|
|
53
|
+
"OnPolicyConfig",
|
|
54
|
+
"OnPolicyLearner",
|
|
55
|
+
"OffPolicyConfig",
|
|
56
|
+
"OffPolicyLearner",
|
|
57
|
+
"OffPolicyExperiment",
|
|
58
|
+
"OffPolicyExperimentConfig",
|
|
59
|
+
"PPOConfig",
|
|
60
|
+
"PPOLearner",
|
|
61
|
+
"ReinforceConfig",
|
|
62
|
+
"ReinforceLearner",
|
|
63
|
+
"TargetUpdate",
|
|
64
|
+
"EpsilonGreedyController",
|
|
65
|
+
"GaussianController",
|
|
66
|
+
"GreedyController",
|
|
67
|
+
"ReplayBuffer",
|
|
68
|
+
"Runner",
|
|
69
|
+
"StochasticController",
|
|
70
|
+
"TransitionBatch",
|
|
71
|
+
"ValueTargets",
|
|
72
|
+
"WarmupController",
|
|
73
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .base import ContinuousActionController, Controller, DiscreteActionController
|
|
2
|
+
from .greedy import GreedyController
|
|
3
|
+
from .e_greedy import EpsilonGreedyController
|
|
4
|
+
from .stochastic import StochasticController
|
|
5
|
+
from .gaussian import GaussianController
|
|
6
|
+
from .warmup import WarmupController
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"ContinuousActionController",
|
|
10
|
+
"Controller",
|
|
11
|
+
"DiscreteActionController",
|
|
12
|
+
"EpsilonGreedyController",
|
|
13
|
+
"GaussianController",
|
|
14
|
+
"GreedyController",
|
|
15
|
+
"StochasticController",
|
|
16
|
+
"WarmupController",
|
|
17
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import torch as th
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Controller(ABC):
|
|
8
|
+
"""Base controller interface for all action spaces."""
|
|
9
|
+
|
|
10
|
+
model: th.nn.Module
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def choose(self, obs: th.Tensor, **kwargs) -> th.Tensor: ...
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DiscreteActionController(Controller):
|
|
17
|
+
"""Controller interface for discrete action spaces."""
|
|
18
|
+
|
|
19
|
+
num_actions: int
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def probabilities(self, obs: th.Tensor, **kwargs) -> th.Tensor: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ContinuousActionController(Controller):
|
|
26
|
+
"""Controller interface for continuous action spaces."""
|
|
27
|
+
|
|
28
|
+
action_dim: int
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import torch as th
|
|
3
|
-
from .base import
|
|
3
|
+
from .base import DiscreteActionController
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
class EpsilonGreedyController(DiscreteActionController):
|
|
6
7
|
|
|
7
8
|
def __init__(
|
|
8
9
|
self,
|
|
9
|
-
controller:
|
|
10
|
+
controller: DiscreteActionController,
|
|
10
11
|
num_actions: int,
|
|
11
12
|
max_eps: float = 1.0,
|
|
12
13
|
min_eps: float = 0.1,
|
|
@@ -27,7 +28,12 @@ class EpsilonGreedyController(Controller):
|
|
|
27
28
|
frac = max(1 - self.num_decisions / (self.anneal_steps - 1), 0.0)
|
|
28
29
|
return frac * (self.max_eps - self.min_eps) + self.min_eps
|
|
29
30
|
|
|
30
|
-
def choose(
|
|
31
|
+
def choose(
|
|
32
|
+
self,
|
|
33
|
+
obs: th.Tensor,
|
|
34
|
+
increase_counter: bool = True,
|
|
35
|
+
**kwargs,
|
|
36
|
+
) -> th.Tensor:
|
|
31
37
|
eps = self.epsilon()
|
|
32
38
|
if increase_counter:
|
|
33
39
|
self.num_decisions += 1
|
|
@@ -40,7 +46,11 @@ class EpsilonGreedyController(Controller):
|
|
|
40
46
|
|
|
41
47
|
def probabilities(self, obs: th.Tensor, **kwargs) -> th.Tensor:
|
|
42
48
|
eps = self.epsilon()
|
|
43
|
-
greedy = self.controller.probabilities(obs, **kwargs)
|
|
49
|
+
greedy = self.controller.probabilities(obs, **kwargs)
|
|
44
50
|
B = greedy.shape[0]
|
|
45
|
-
uniform = th.full(
|
|
51
|
+
uniform = th.full(
|
|
52
|
+
(B, self.num_actions),
|
|
53
|
+
eps / self.num_actions,
|
|
54
|
+
device=greedy.device,
|
|
55
|
+
)
|
|
46
56
|
return uniform + (1 - eps) * greedy
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import torch as th
|
|
2
|
+
from .base import ContinuousActionController
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class GaussianController(ContinuousActionController):
|
|
6
|
+
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
model: th.nn.Module,
|
|
10
|
+
action_dim: int,
|
|
11
|
+
deterministic: bool = False,
|
|
12
|
+
):
|
|
13
|
+
self.model = model
|
|
14
|
+
self.action_dim = action_dim
|
|
15
|
+
self.num_actions = action_dim
|
|
16
|
+
self.deterministic = deterministic
|
|
17
|
+
|
|
18
|
+
def choose(self, obs: th.Tensor, **kwargs) -> th.Tensor:
|
|
19
|
+
output = self.model(obs)
|
|
20
|
+
|
|
21
|
+
mean = output[:, :self.action_dim]
|
|
22
|
+
log_std = output[:, self.action_dim: 2 * self.action_dim]
|
|
23
|
+
log_std = th.clamp(log_std, -20, 2)
|
|
24
|
+
|
|
25
|
+
if self.deterministic:
|
|
26
|
+
u = mean
|
|
27
|
+
else:
|
|
28
|
+
std = log_std.exp()
|
|
29
|
+
eps = th.randn_like(mean)
|
|
30
|
+
u = mean + std * eps
|
|
31
|
+
|
|
32
|
+
return th.tanh(u)
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import torch as th
|
|
2
|
-
from .base import
|
|
2
|
+
from .base import DiscreteActionController
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
class GreedyController(DiscreteActionController):
|
|
5
6
|
|
|
6
7
|
def __init__(self, model: th.nn.Module, num_actions: int):
|
|
7
|
-
|
|
8
8
|
self.num_actions = num_actions
|
|
9
9
|
self.model = model
|
|
10
10
|
|
|
11
11
|
def choose(self, obs: th.Tensor):
|
|
12
12
|
output: th.Tensor = self.model(obs)[:, :self.num_actions]
|
|
13
13
|
return th.argmax(output, dim=-1)
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def probabilities(self, obs: th.Tensor):
|
|
16
16
|
output: th.Tensor = self.model(obs)[:, :self.num_actions]
|
|
17
|
-
idx = output.argmax(dim=-1, keepdim=True)
|
|
17
|
+
idx = output.argmax(dim=-1, keepdim=True)
|
|
18
18
|
probs = th.zeros(output.shape[0], self.num_actions, device=output.device)
|
|
19
19
|
probs.scatter_(dim=-1, index=idx, value=1.0)
|
|
20
20
|
return probs
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import torch as th
|
|
2
|
-
from .base import
|
|
2
|
+
from .base import DiscreteActionController
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
class StochasticController(DiscreteActionController):
|
|
5
6
|
|
|
6
7
|
def __init__(self, model: th.nn.Module, num_actions: int):
|
|
7
|
-
|
|
8
8
|
self.num_actions = num_actions
|
|
9
9
|
self.model = model
|
|
10
10
|
|
|
11
11
|
def choose(self, obs: th.Tensor) -> th.Tensor:
|
|
12
12
|
probs = self.probabilities(obs)
|
|
13
13
|
return th.distributions.Categorical(probs=probs).sample()
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
def probabilities(self, obs: th.Tensor) -> th.Tensor:
|
|
16
16
|
output = self.model(obs)[:, :self.num_actions]
|
|
17
|
-
return th.nn.functional.softmax(output, dim=-1)
|
|
17
|
+
return th.nn.functional.softmax(output, dim=-1)
|
|
@@ -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
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .off_policy_experiment import OffPolicyExperiment, OffPolicyExperimentConfig
|
|
2
|
+
from .on_policy_experiment import OnPolicyExperiment, OnPolicyExperimentConfig
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"OffPolicyExperiment",
|
|
6
|
+
"OnPolicyExperiment",
|
|
7
|
+
"OffPolicyExperimentConfig",
|
|
8
|
+
"OnPolicyExperimentConfig",
|
|
9
|
+
]
|