rl-template 0.1.0__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.
@@ -0,0 +1,11 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .opencode
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,82 @@
1
+ # AGENTS.md
2
+
3
+ ## Project
4
+
5
+ RL training template built on PyTorch + Gymnasium. Provides abstract base classes (`BaseAgent`, `BaseEnv`, `BaseTrain`) and a concrete PPO (Proximal Policy Optimization) implementation. Includes a full test suite (107 tests, all passing).
6
+
7
+ ## Package management
8
+
9
+ - Managed with **uv** (lockfile: `uv.lock`, Python version: `.python-version` → 3.11)
10
+ - Dependencies are pinned in `requirements.txt`, not declared in `pyproject.toml`
11
+
12
+ ## Lint / typecheck
13
+
14
+ ```
15
+ ruff check rl_template/ # linter (Pyflakes only, ruff.toml)
16
+ mypy rl_template/ # strict: disallow_untyped_defs, warn_unreachable (mypy.ini)
17
+ ```
18
+
19
+ No pre-commit hooks, no CI, no formatter config beyond ruff defaults.
20
+
21
+ ## Import style gotcha
22
+
23
+ - `train.py` uses **relative imports** (`from .env import BaseEnv`) — requires package-level import
24
+ - `ppo.py` uses **relative imports** (`from ...common import Buffer`) — assumes package-level import
25
+ - `algorithms/__init__.py` and `algorithms/ppo/__init__.py` exist (empty) — required for relative imports in `ppo.py` to resolve
26
+
27
+ ## Structure
28
+
29
+ ```
30
+ rl_template/
31
+ __init__.py # empty package marker
32
+ agent.py # BaseAgent (ABC, nn.Module) — abstract agent interface
33
+ env.py # BaseEnv (ABC) — Gymnasium v1 API wrapper interface
34
+ train.py # BaseTrain (ABC) — rollout/update/save training loop
35
+ common.py # Buffer — pre-allocated numpy rollout buffer with size property
36
+ config.py # PPOConfig (frozen), TrainConfig, WandbConfig dataclasses
37
+ errors.py # EmptyBufferError with detailed __str__
38
+ algorithms/
39
+ __init__.py # package marker (empty)
40
+ ppo/
41
+ __init__.py # package marker (empty)
42
+ ppo.py # PPOTrainer — GAE, clipped surrogate loss, linear LR decay
43
+ tests/
44
+ __init__.py
45
+ test_common.py # Buffer unit tests (21 tests)
46
+ test_config.py # Config dataclass tests (13 tests)
47
+ test_errors.py # EmptyBufferError tests (7 tests)
48
+ test_ppo.py # PPOTrainer tests (12 tests)
49
+ test_buffer_integration.py # Buffer integration tests (10 tests)
50
+ test_agent.py # BaseAgent abstract interface tests (12 tests)
51
+ test_env.py # BaseEnv abstract interface tests (11 tests)
52
+ test_train.py # BaseTrain tests: init, save_model, update_weights (6 tests)
53
+ ```
54
+
55
+ ## Conventions
56
+
57
+ - Abstract base classes use `@abstractmethod` with concrete bodies (template method pattern) — subclasses override and optionally call `super()`
58
+ - `PPOConfig` is `frozen=True` (immutable); `TrainConfig` uses `__post_init__` for computed fields
59
+ - `Buffer` pre-allocates numpy arrays and uses a slice pointer with a `size` property and bounds checking in `insert()`
60
+ - GPU detection is automatic in `TrainConfig.device`
61
+ - Tests use pytest, import rl_template as a package (`from rl_template.common import Buffer`)
62
+
63
+ ## Testing
64
+
65
+ ```
66
+ python -m pytest tests/ -v # run all 107 tests
67
+ ```
68
+
69
+ ## Fixes applied
70
+
71
+ - Created `algorithms/__init__.py` and `algorithms/ppo/__init__.py` for package resolution
72
+ - Added `size` property to `Buffer` class (returns current element count)
73
+ - Added bounds checking in `Buffer.insert()` — raises `ValueError` when buffer is full
74
+ - Fixed `save_model()` to use `os.makedirs(os.path.dirname(...), exist_ok=True)` instead of creating a `.pt` directory
75
+ - Fixed PPO `update()` loss tracking — `index_loss` now increments correctly, final mean excludes trailing zeros
76
+ - Fixed typo `BaseAgnt` → `BaseAgent` in `agent.py`
77
+ - Fixed `ruff.toml` `target-version` from `"py313"` to `"py311"` to match `.python-version`
78
+ - Removed `print()` side effects from `TrainConfig.__post_init__`
79
+ - Fixed `Buffer.get_all()` actions dtype from `torch.long` to `torch.float32` (continuous actions were silently truncated to integers)
80
+ - Fixed `Distributions` → `Distribution` import typo in `agent.py` (pre-existing bug, class is singular in PyTorch)
81
+ - Changed `train.py` from bare imports to relative imports for package-level compatibility
82
+ - Rewrote all docstrings and comments across source and test files for consistency
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: rl-template
3
+ Version: 0.1.0
4
+ Summary: A type-safe, algorithm-agnostic Reinforcement Learning framework
5
+ Author-email: Mohamed Tine <mohamedtine17@gmail.com>
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: numpy>=1.24.0
11
+ Requires-Dist: torch>=2.0.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # RL Template
15
+
16
+ A modular reinforcement learning training framework built on PyTorch and Gymnasium, providing abstract base classes and a concrete PPO implementation.
17
+
18
+ ## Features
19
+
20
+ - **Abstract base classes** — `BaseAgent`, `BaseEnv`, `BaseTrain` with template method pattern for easy extension
21
+ - **PPO implementation** — Clipped surrogate loss, GAE, linear LR decay, entropy bonus, gradient clipping
22
+ - **Pre-allocated buffer** — Zero-allocation rollout storage with bounds checking, supports discrete and continuous actions
23
+ - **Frozen configs** — Immutable `PPOConfig` and computed `TrainConfig` dataclasses
24
+ - **Auto GPU detection** — Automatic CUDA/CPU device selection
25
+ - **107 tests** — Full test suite covering all components
26
+
27
+ ## Project Structure
28
+
29
+ ```
30
+ rl_template/
31
+ __init__.py
32
+ agent.py # BaseAgent — abstract policy/value interface
33
+ env.py # BaseEnv — Gymnasium v1 API wrapper
34
+ train.py # BaseTrain — rollout/update training loop
35
+ common.py # Buffer — pre-allocated numpy rollout buffer
36
+ config.py # PPOConfig, TrainConfig, WandbConfig
37
+ errors.py # EmptyBufferError
38
+ algorithms/
39
+ ppo/
40
+ ppo.py # PPOTrainer — GAE + clipped surrogate loss
41
+ tests/
42
+ test_agent.py # BaseAgent tests (12)
43
+ test_env.py # BaseEnv tests (11)
44
+ test_train.py # BaseTrain tests (6)
45
+ test_common.py # Buffer tests (21)
46
+ test_config.py # Config tests (13)
47
+ test_errors.py # Error tests (7)
48
+ test_ppo.py # PPOTrainer tests (15)
49
+ test_buffer_integration.py # Buffer integration tests (6)
50
+ test_continuous_actions.py # Continuous action tests (16)
51
+ ```
52
+
53
+ ## Installation
54
+
55
+ Requires Python 3.11+.
56
+
57
+ ```bash
58
+ # With uv (recommended)
59
+ uv sync
60
+
61
+ # With pip
62
+ pip install -r requirements.txt
63
+ ```
64
+
65
+ ## Usage
66
+
67
+ ```python
68
+ import numpy as np
69
+ from rl_template.agent import BaseAgent
70
+ from rl_template.env import BaseEnv
71
+ from rl_template.train import BaseTrain
72
+ from rl_template.common import Buffer
73
+ from rl_template.config import TrainConfig, PPOConfig
74
+ from rl_template.algorithms.ppo.ppo import PPOTrainer
75
+
76
+
77
+ # 1. Implement your agent
78
+ class MyAgent(BaseAgent):
79
+ # Implement forward(), get_distribution()
80
+ ...
81
+
82
+ # 2. Implement your environment
83
+ class MyEnv(BaseEnv):
84
+ # Implement reset(), step(), close()
85
+ ...
86
+
87
+ # 3. Configure training
88
+ config = TrainConfig(model_name="my_agent", model_saved_path="./checkpoints")
89
+ ppo_config = PPOConfig(lr=3e-4, gamma=0.99, clip_eps=0.2)
90
+
91
+ # 4. Wire everything together
92
+ agent = MyAgent()
93
+ env = MyEnv()
94
+ buffer = Buffer(step=config.rollout_steps, state_shape=(4,))
95
+ ppo_trainer = PPOTrainer(agent, lr=ppo_config.lr, gamma=ppo_config.gamma)
96
+
97
+ # 5. Create trainer and run
98
+ class MyTrain(BaseTrain):
99
+ def rollout_phase(self, state): super().rollout_phase(state)
100
+ def update_weights(self, step): super().update_weights(step)
101
+ def save_model(self): super().save_model()
102
+
103
+ trainer = MyTrain(agent, env, buffer, config, ppo_trainer)
104
+ state, _ = env.reset()
105
+
106
+ for step in range(config.num_update):
107
+ trainer.rollout_phase(state)
108
+ trainer.update_weights(step)
109
+ trainer.save_model()
110
+ ```
111
+
112
+ ## Key Classes
113
+
114
+ | Class | Description |
115
+ |-------|-------------|
116
+ | `BaseAgent` | Abstract agent combining ABC and nn.Module. Subclasses implement `forward()` and `get_distribution()`. The `get_action()` template method handles sampling and log-probability computation. |
117
+ | `BaseEnv` | Abstract Gymnasium v1 environment wrapper. Subclasses implement `reset()`, `step()`, and `close()`. |
118
+ | `BaseTrain` | Abstract training loop orchestrating rollout collection, GAE computation, and PPO updates. |
119
+ | `Buffer` | Pre-allocated numpy buffer for rollout data. Supports discrete and continuous actions with automatic dtype handling. |
120
+ | `PPOTrainer` | PPO algorithm implementation with GAE, clipped surrogate loss, value loss, entropy bonus, and linear LR decay. |
121
+ | `PPOConfig` | Frozen (immutable) PPO hyperparameters. |
122
+ | `TrainConfig` | Training configuration with auto-computed `model_path` and `num_update`. |
123
+
124
+ ## PPO Algorithm
125
+
126
+ The PPO trainer implements:
127
+
128
+ - **Generalized Advantage Estimation (GAE)** — Blended n-step returns for low-variance advantage estimates
129
+ - **Clipped surrogate loss** — Prevents destructive policy updates
130
+ - **Value function loss** — MSE loss for the critic network
131
+ - **Entropy bonus** — Encourages exploration
132
+ - **Linear LR decay** — Learning rate anneals to zero over training
133
+ - **Gradient clipping** — Max norm of 1.0 for stability
134
+
135
+ ## Testing
136
+
137
+ ```bash
138
+ python -m pytest tests/ -v
139
+ ```
140
+
141
+ All 107 tests cover unit tests for each component, integration tests for buffer workflows, and continuous action space validation.
142
+
143
+ ## License
144
+
145
+ MIT
@@ -0,0 +1,132 @@
1
+ # RL Template
2
+
3
+ A modular reinforcement learning training framework built on PyTorch and Gymnasium, providing abstract base classes and a concrete PPO implementation.
4
+
5
+ ## Features
6
+
7
+ - **Abstract base classes** — `BaseAgent`, `BaseEnv`, `BaseTrain` with template method pattern for easy extension
8
+ - **PPO implementation** — Clipped surrogate loss, GAE, linear LR decay, entropy bonus, gradient clipping
9
+ - **Pre-allocated buffer** — Zero-allocation rollout storage with bounds checking, supports discrete and continuous actions
10
+ - **Frozen configs** — Immutable `PPOConfig` and computed `TrainConfig` dataclasses
11
+ - **Auto GPU detection** — Automatic CUDA/CPU device selection
12
+ - **107 tests** — Full test suite covering all components
13
+
14
+ ## Project Structure
15
+
16
+ ```
17
+ rl_template/
18
+ __init__.py
19
+ agent.py # BaseAgent — abstract policy/value interface
20
+ env.py # BaseEnv — Gymnasium v1 API wrapper
21
+ train.py # BaseTrain — rollout/update training loop
22
+ common.py # Buffer — pre-allocated numpy rollout buffer
23
+ config.py # PPOConfig, TrainConfig, WandbConfig
24
+ errors.py # EmptyBufferError
25
+ algorithms/
26
+ ppo/
27
+ ppo.py # PPOTrainer — GAE + clipped surrogate loss
28
+ tests/
29
+ test_agent.py # BaseAgent tests (12)
30
+ test_env.py # BaseEnv tests (11)
31
+ test_train.py # BaseTrain tests (6)
32
+ test_common.py # Buffer tests (21)
33
+ test_config.py # Config tests (13)
34
+ test_errors.py # Error tests (7)
35
+ test_ppo.py # PPOTrainer tests (15)
36
+ test_buffer_integration.py # Buffer integration tests (6)
37
+ test_continuous_actions.py # Continuous action tests (16)
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ Requires Python 3.11+.
43
+
44
+ ```bash
45
+ # With uv (recommended)
46
+ uv sync
47
+
48
+ # With pip
49
+ pip install -r requirements.txt
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ ```python
55
+ import numpy as np
56
+ from rl_template.agent import BaseAgent
57
+ from rl_template.env import BaseEnv
58
+ from rl_template.train import BaseTrain
59
+ from rl_template.common import Buffer
60
+ from rl_template.config import TrainConfig, PPOConfig
61
+ from rl_template.algorithms.ppo.ppo import PPOTrainer
62
+
63
+
64
+ # 1. Implement your agent
65
+ class MyAgent(BaseAgent):
66
+ # Implement forward(), get_distribution()
67
+ ...
68
+
69
+ # 2. Implement your environment
70
+ class MyEnv(BaseEnv):
71
+ # Implement reset(), step(), close()
72
+ ...
73
+
74
+ # 3. Configure training
75
+ config = TrainConfig(model_name="my_agent", model_saved_path="./checkpoints")
76
+ ppo_config = PPOConfig(lr=3e-4, gamma=0.99, clip_eps=0.2)
77
+
78
+ # 4. Wire everything together
79
+ agent = MyAgent()
80
+ env = MyEnv()
81
+ buffer = Buffer(step=config.rollout_steps, state_shape=(4,))
82
+ ppo_trainer = PPOTrainer(agent, lr=ppo_config.lr, gamma=ppo_config.gamma)
83
+
84
+ # 5. Create trainer and run
85
+ class MyTrain(BaseTrain):
86
+ def rollout_phase(self, state): super().rollout_phase(state)
87
+ def update_weights(self, step): super().update_weights(step)
88
+ def save_model(self): super().save_model()
89
+
90
+ trainer = MyTrain(agent, env, buffer, config, ppo_trainer)
91
+ state, _ = env.reset()
92
+
93
+ for step in range(config.num_update):
94
+ trainer.rollout_phase(state)
95
+ trainer.update_weights(step)
96
+ trainer.save_model()
97
+ ```
98
+
99
+ ## Key Classes
100
+
101
+ | Class | Description |
102
+ |-------|-------------|
103
+ | `BaseAgent` | Abstract agent combining ABC and nn.Module. Subclasses implement `forward()` and `get_distribution()`. The `get_action()` template method handles sampling and log-probability computation. |
104
+ | `BaseEnv` | Abstract Gymnasium v1 environment wrapper. Subclasses implement `reset()`, `step()`, and `close()`. |
105
+ | `BaseTrain` | Abstract training loop orchestrating rollout collection, GAE computation, and PPO updates. |
106
+ | `Buffer` | Pre-allocated numpy buffer for rollout data. Supports discrete and continuous actions with automatic dtype handling. |
107
+ | `PPOTrainer` | PPO algorithm implementation with GAE, clipped surrogate loss, value loss, entropy bonus, and linear LR decay. |
108
+ | `PPOConfig` | Frozen (immutable) PPO hyperparameters. |
109
+ | `TrainConfig` | Training configuration with auto-computed `model_path` and `num_update`. |
110
+
111
+ ## PPO Algorithm
112
+
113
+ The PPO trainer implements:
114
+
115
+ - **Generalized Advantage Estimation (GAE)** — Blended n-step returns for low-variance advantage estimates
116
+ - **Clipped surrogate loss** — Prevents destructive policy updates
117
+ - **Value function loss** — MSE loss for the critic network
118
+ - **Entropy bonus** — Encourages exploration
119
+ - **Linear LR decay** — Learning rate anneals to zero over training
120
+ - **Gradient clipping** — Max norm of 1.0 for stability
121
+
122
+ ## Testing
123
+
124
+ ```bash
125
+ python -m pytest tests/ -v
126
+ ```
127
+
128
+ All 107 tests cover unit tests for each component, integration tests for buffer workflows, and continuous action space validation.
129
+
130
+ ## License
131
+
132
+ MIT
@@ -0,0 +1,4 @@
1
+ [mypy]
2
+ files = rl_template
3
+ disallow_untyped_defs = True
4
+ warn_unreachable = True
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "rl-template"
3
+ version = "0.1.0"
4
+ description = "A type-safe, algorithm-agnostic Reinforcement Learning framework"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ authors = [
8
+ { name = "Mohamed Tine", email = "mohamedtine17@gmail.com" }
9
+ ]
10
+ classifiers = [
11
+ "Programming Language :: Python :: 3.11",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Topic :: Scientific/Engineering :: Artificial Intelligence"
14
+ ]
15
+ dependencies = [
16
+ "torch>=2.0.0",
17
+ "numpy>=1.24.0"
18
+ ]
19
+
20
+ [build-system]
21
+ requires = ["hatchling"]
22
+ build-backend = "hatchling.build"
@@ -0,0 +1,79 @@
1
+ alembic==1.18.5
2
+ annotated-types==0.7.0
3
+ bottle==0.13.4
4
+ certifi==2026.6.17
5
+ charset-normalizer==3.4.9
6
+ click==8.4.2
7
+ cloudpickle==3.1.2
8
+ colorlog==6.10.1
9
+ contourpy==1.3.3
10
+ cuda-bindings==13.3.1
11
+ cuda-pathfinder==1.5.6
12
+ cuda-toolkit==13.0.3.0
13
+ cycler==0.12.1
14
+ farama-notifications==0.0.6
15
+ filelock==3.29.7
16
+ fonttools==4.63.0
17
+ fsspec==2026.6.0
18
+ gitdb==4.0.12
19
+ gitpython==3.1.50
20
+ greenlet==3.5.3
21
+ gymnasium==1.3.0
22
+ idna==3.18
23
+ jinja2==3.1.6
24
+ joblib==1.5.3
25
+ kiwisolver==1.5.0
26
+ mako==1.3.12
27
+ markupsafe==3.0.3
28
+ matplotlib==3.11.0
29
+ mpmath==1.3.0
30
+ narwhals==2.23.0
31
+ networkx==3.6.1
32
+ numpy==2.4.6
33
+ nvidia-cublas==13.1.1.3
34
+ nvidia-cuda-cupti==13.0.85
35
+ nvidia-cuda-nvrtc==13.0.88
36
+ nvidia-cuda-runtime==13.0.96
37
+ nvidia-cudnn-cu13==9.20.0.48
38
+ nvidia-cufft==12.0.0.61
39
+ nvidia-cufile==1.15.1.6
40
+ nvidia-curand==10.4.0.35
41
+ nvidia-cusolver==12.0.4.66
42
+ nvidia-cusparse==12.6.3.3
43
+ nvidia-cusparselt-cu13==0.8.1
44
+ nvidia-nccl-cu13==2.29.7
45
+ nvidia-nvjitlink==13.3.33
46
+ nvidia-nvshmem-cu13==3.4.5
47
+ nvidia-nvtx==13.0.85
48
+ optuna==4.9.0
49
+ optuna-dashboard==0.20.0
50
+ packaging==26.2
51
+ pandas==3.0.3
52
+ pillow==12.3.0
53
+ platformdirs==4.10.0
54
+ plotly==6.8.0
55
+ protobuf==7.35.1
56
+ pydantic==2.13.4
57
+ pydantic-core==2.46.4
58
+ pyparsing==3.3.2
59
+ python-dateutil==2.9.0.post0
60
+ pyyaml==6.0.3
61
+ requests==2.34.2
62
+ ruff==0.15.20
63
+ scikit-learn==1.9.0
64
+ scipy==1.17.1
65
+ seaborn==0.13.2
66
+ sentry-sdk==2.64.0
67
+ setuptools==83.0.0
68
+ six==1.17.0
69
+ smmap==5.0.3
70
+ sqlalchemy==2.0.51
71
+ sympy==1.14.0
72
+ threadpoolctl==3.6.0
73
+ torch==2.13.0
74
+ tqdm==4.68.4
75
+ triton==3.7.1
76
+ typing-extensions==4.16.0
77
+ typing-inspection==0.4.2
78
+ urllib3==2.7.0
79
+ wandb==0.28.0
File without changes
@@ -0,0 +1,69 @@
1
+ """Abstract base agent interface for reinforcement learning.
2
+
3
+ Provides BaseAgent, an ABC + nn.Module hybrid that enforces a consistent
4
+ policy/value interface for all RL agent implementations.
5
+ """
6
+
7
+ import numpy as np
8
+ import torch.nn as nn
9
+ from torch.distributions import Distribution
10
+ from torch import Tensor
11
+ from abc import ABC, abstractmethod
12
+
13
+
14
+ class BaseAgent(ABC, nn.Module):
15
+ """Abstract base class for all RL agents.
16
+
17
+ Subclasses must implement forward() and get_distribution(). The
18
+ get_action() template method composes those two to sample actions,
19
+ compute log probabilities, and return critic values.
20
+ """
21
+
22
+ def __init__(self):
23
+ super().__init__()
24
+
25
+ @abstractmethod
26
+ def forward(self, state: np.ndarray) -> tuple[Tensor, Tensor]:
27
+ """Compute raw policy logits and value estimate.
28
+
29
+ Args:
30
+ state: Environment observation.
31
+
32
+ Returns:
33
+ Tuple of (policy_logits, value) tensors.
34
+ """
35
+ pass
36
+
37
+ @abstractmethod
38
+ def get_distribution(self, state: np.ndarray) -> tuple[Distribution, Tensor]:
39
+ """Build a distribution over actions for the given state.
40
+
41
+ Args:
42
+ state: Environment observation.
43
+
44
+ Returns:
45
+ Tuple of (distribution, value) where distribution is a
46
+ torch.distributions.Distribution instance.
47
+ """
48
+ pass
49
+
50
+ def get_action(self, state: np.ndarray, action: int | None = None) -> tuple[Tensor, Tensor, Tensor, Tensor]:
51
+ """Sample or evaluate an action under the current policy.
52
+
53
+ Template method: calls get_distribution(), then samples if no
54
+ action is provided.
55
+
56
+ Args:
57
+ state: Environment observation.
58
+ action: Optional pre-selected action. When None, samples from
59
+ the policy distribution.
60
+
61
+ Returns:
62
+ Tuple of (action, log_prob, entropy, value).
63
+ """
64
+ dist, value = self.get_distribution(state)
65
+ if action is None:
66
+ action = dist.sample()
67
+ log_prob = dist.log_prob(action)
68
+ dist_entropy = dist.entropy()
69
+ return (action, log_prob, dist_entropy, value)
File without changes