saferl-lite 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.
- saferl_lite-0.1.0/LICENSE +21 -0
- saferl_lite-0.1.0/MANIFEST.in +5 -0
- saferl_lite-0.1.0/PKG-INFO +139 -0
- saferl_lite-0.1.0/README.md +87 -0
- saferl_lite-0.1.0/agents/__init__.py +0 -0
- saferl_lite-0.1.0/agents/constrained_dqn.py +82 -0
- saferl_lite-0.1.0/agents/constraints.py +39 -0
- saferl_lite-0.1.0/docs/about.md +65 -0
- saferl_lite-0.1.0/docs/docs/index.md +34 -0
- saferl_lite-0.1.0/docs/evaluation/metrics.md +113 -0
- saferl_lite-0.1.0/docs/examples/cartpole.md +84 -0
- saferl_lite-0.1.0/docs/explainability/saliency.md +90 -0
- saferl_lite-0.1.0/docs/explainability/shap.md +85 -0
- saferl_lite-0.1.0/docs/mkdocs.yml +54 -0
- saferl_lite-0.1.0/docs/reference/agents.md +54 -0
- saferl_lite-0.1.0/docs/reference/constraints.md +57 -0
- saferl_lite-0.1.0/docs/reference/envs.md +66 -0
- saferl_lite-0.1.0/docs/reference.md +35 -0
- saferl_lite-0.1.0/docs/usage/installation.md +54 -0
- saferl_lite-0.1.0/docs/usage/quickstart.md +48 -0
- saferl_lite-0.1.0/envs/__init__.py +0 -0
- saferl_lite-0.1.0/envs/wrappers.py +58 -0
- saferl_lite-0.1.0/explainability/__init__.py +0 -0
- saferl_lite-0.1.0/explainability/saliency.py +23 -0
- saferl_lite-0.1.0/explainability/shap_explainer.py +31 -0
- saferl_lite-0.1.0/requirements.txt +23 -0
- saferl_lite-0.1.0/saferl_lite.egg-info/PKG-INFO +139 -0
- saferl_lite-0.1.0/saferl_lite.egg-info/SOURCES.txt +34 -0
- saferl_lite-0.1.0/saferl_lite.egg-info/dependency_links.txt +1 -0
- saferl_lite-0.1.0/saferl_lite.egg-info/requires.txt +22 -0
- saferl_lite-0.1.0/saferl_lite.egg-info/top_level.txt +3 -0
- saferl_lite-0.1.0/setup.cfg +4 -0
- saferl_lite-0.1.0/setup.py +28 -0
- saferl_lite-0.1.0/tests/test_constraints.py +17 -0
- saferl_lite-0.1.0/tests/test_metrics.py +18 -0
- saferl_lite-0.1.0/tests/test_safe_env.py +11 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Satyam Mishra
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,139 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: saferl-lite
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A lightweight, explainable, and constrained reinforcement learning toolkit.
|
5
|
+
Home-page: https://github.com/satyamcser/saferl-lite
|
6
|
+
Author: Satyam Mishra
|
7
|
+
Author-email: satyam@example.com
|
8
|
+
Project-URL: Documentation, https://satyamcser.github.io/saferl-lite/
|
9
|
+
Project-URL: Source, https://github.com/satyamcser/saferl-lite
|
10
|
+
Project-URL: Bug Tracker, https://github.com/satyamcser/saferl-lite/issues
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
13
|
+
Classifier: Operating System :: OS Independent
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
16
|
+
Requires-Python: >=3.8
|
17
|
+
Description-Content-Type: text/markdown
|
18
|
+
License-File: LICENSE
|
19
|
+
Requires-Dist: gym
|
20
|
+
Requires-Dist: gymnasium
|
21
|
+
Requires-Dist: numpy
|
22
|
+
Requires-Dist: torch
|
23
|
+
Requires-Dist: matplotlib
|
24
|
+
Requires-Dist: seaborn
|
25
|
+
Requires-Dist: pre-commit
|
26
|
+
Requires-Dist: flake8
|
27
|
+
Requires-Dist: pyyaml
|
28
|
+
Requires-Dist: shap
|
29
|
+
Requires-Dist: captum
|
30
|
+
Requires-Dist: typer
|
31
|
+
Requires-Dist: scikit-learn
|
32
|
+
Requires-Dist: pandas
|
33
|
+
Requires-Dist: pytest
|
34
|
+
Requires-Dist: pytest-cov
|
35
|
+
Requires-Dist: coverage
|
36
|
+
Requires-Dist: mkdocs
|
37
|
+
Requires-Dist: wandb
|
38
|
+
Requires-Dist: mkdocs>=1.5
|
39
|
+
Requires-Dist: mkdocs-material>=9.5
|
40
|
+
Requires-Dist: mkdocstrings[python]
|
41
|
+
Dynamic: author
|
42
|
+
Dynamic: author-email
|
43
|
+
Dynamic: classifier
|
44
|
+
Dynamic: description
|
45
|
+
Dynamic: description-content-type
|
46
|
+
Dynamic: home-page
|
47
|
+
Dynamic: license-file
|
48
|
+
Dynamic: project-url
|
49
|
+
Dynamic: requires-dist
|
50
|
+
Dynamic: requires-python
|
51
|
+
Dynamic: summary
|
52
|
+
|
53
|
+
# ๐ SafeRL-Lite
|
54
|
+
|
55
|
+
A **lightweight, explainable, and modular** Python library for **Constrained Reinforcement Learning (Safe RL)** with real-time **SHAP & saliency-based explainability**, custom metrics, and Gym-compatible wrappers.
|
56
|
+
|
57
|
+
<p align="center">
|
58
|
+
<img src="https://img.shields.io/github/license/satyamcser/saferl-lite?style=flat-square">
|
59
|
+
<img src="https://img.shields.io/github/stars/satyamcser/saferl-lite?style=flat-square">
|
60
|
+
<img src="https://img.shields.io/pypi/v/saferl-lite?style=flat-square">
|
61
|
+
<img src="https://img.shields.io/github/actions/workflow/status/satyamcser/saferl-lite/ci.yml?branch=main&style=flat-square">
|
62
|
+
</p>
|
63
|
+
|
64
|
+
---
|
65
|
+
|
66
|
+
## ๐ Overview
|
67
|
+
|
68
|
+
**SafeRL-Lite** empowers reinforcement learning agents to act under **safety constraints**, while remaining **interpretable** and **modular** for fast experimentation. It wraps standard Gym environments and DQN-based agents with:
|
69
|
+
|
70
|
+
- โ
Safety constraint logic
|
71
|
+
- ๐ Visual explainability (SHAP, saliency maps)
|
72
|
+
- ๐ Violation and reward tracking
|
73
|
+
- ๐งช Built-in testing and evaluations
|
74
|
+
|
75
|
+
---
|
76
|
+
|
77
|
+
## ๐ง Installation
|
78
|
+
|
79
|
+
> ๐ฆ PyPI (coming soon)
|
80
|
+
```bash
|
81
|
+
pip install saferl-lite
|
82
|
+
```
|
83
|
+
|
84
|
+
## ๐ ๏ธ From source:
|
85
|
+
|
86
|
+
```bash
|
87
|
+
git clone https://github.com/satyamcser/saferl-lite.git
|
88
|
+
cd saferl-lite
|
89
|
+
pip install -e .
|
90
|
+
```
|
91
|
+
|
92
|
+
## ๐ Quickstart
|
93
|
+
Train a constrained DQN agent with saliency-based explainability:
|
94
|
+
|
95
|
+
```bash
|
96
|
+
python train.py --env CartPole-v1 --constraint pole_angle --explain shap
|
97
|
+
```
|
98
|
+
|
99
|
+
๐น This:
|
100
|
+
|
101
|
+
- Adds a pole-angle constraint wrapper to the Gym env
|
102
|
+
|
103
|
+
- Logs violations
|
104
|
+
|
105
|
+
- Displays SHAP or saliency explanations for agent decisions
|
106
|
+
|
107
|
+
## ๐ง Features
|
108
|
+
#### โ
Constrained RL
|
109
|
+
- Add custom constraints via wrapper or logic class
|
110
|
+
|
111
|
+
- Violation logging and reward shaping
|
112
|
+
|
113
|
+
- Safe vs unsafe episode tracking
|
114
|
+
|
115
|
+
#### ๐ Explainability
|
116
|
+
- SaliencyExplainer โ gradient-based visual heatmaps
|
117
|
+
|
118
|
+
- SHAPExplainer โ feature contribution values per decision
|
119
|
+
|
120
|
+
- Compatible with any PyTorch-based agent
|
121
|
+
|
122
|
+
#### ๐ Metrics
|
123
|
+
- Constraint violation rate
|
124
|
+
|
125
|
+
- Episode reward
|
126
|
+
|
127
|
+
- Cumulative safe reward
|
128
|
+
|
129
|
+
- Action entropy & temporal behavior stats
|
130
|
+
|
131
|
+
#### ๐ Modularity
|
132
|
+
- Swap out agents, constraints, evaluators, or explainers
|
133
|
+
|
134
|
+
- Supports Gym environments
|
135
|
+
|
136
|
+
- Configurable training pipeline
|
137
|
+
|
138
|
+
## ๐ Citation
|
139
|
+
Coming soon after arXiv/preprint release.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# ๐ SafeRL-Lite
|
2
|
+
|
3
|
+
A **lightweight, explainable, and modular** Python library for **Constrained Reinforcement Learning (Safe RL)** with real-time **SHAP & saliency-based explainability**, custom metrics, and Gym-compatible wrappers.
|
4
|
+
|
5
|
+
<p align="center">
|
6
|
+
<img src="https://img.shields.io/github/license/satyamcser/saferl-lite?style=flat-square">
|
7
|
+
<img src="https://img.shields.io/github/stars/satyamcser/saferl-lite?style=flat-square">
|
8
|
+
<img src="https://img.shields.io/pypi/v/saferl-lite?style=flat-square">
|
9
|
+
<img src="https://img.shields.io/github/actions/workflow/status/satyamcser/saferl-lite/ci.yml?branch=main&style=flat-square">
|
10
|
+
</p>
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
## ๐ Overview
|
15
|
+
|
16
|
+
**SafeRL-Lite** empowers reinforcement learning agents to act under **safety constraints**, while remaining **interpretable** and **modular** for fast experimentation. It wraps standard Gym environments and DQN-based agents with:
|
17
|
+
|
18
|
+
- โ
Safety constraint logic
|
19
|
+
- ๐ Visual explainability (SHAP, saliency maps)
|
20
|
+
- ๐ Violation and reward tracking
|
21
|
+
- ๐งช Built-in testing and evaluations
|
22
|
+
|
23
|
+
---
|
24
|
+
|
25
|
+
## ๐ง Installation
|
26
|
+
|
27
|
+
> ๐ฆ PyPI (coming soon)
|
28
|
+
```bash
|
29
|
+
pip install saferl-lite
|
30
|
+
```
|
31
|
+
|
32
|
+
## ๐ ๏ธ From source:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
git clone https://github.com/satyamcser/saferl-lite.git
|
36
|
+
cd saferl-lite
|
37
|
+
pip install -e .
|
38
|
+
```
|
39
|
+
|
40
|
+
## ๐ Quickstart
|
41
|
+
Train a constrained DQN agent with saliency-based explainability:
|
42
|
+
|
43
|
+
```bash
|
44
|
+
python train.py --env CartPole-v1 --constraint pole_angle --explain shap
|
45
|
+
```
|
46
|
+
|
47
|
+
๐น This:
|
48
|
+
|
49
|
+
- Adds a pole-angle constraint wrapper to the Gym env
|
50
|
+
|
51
|
+
- Logs violations
|
52
|
+
|
53
|
+
- Displays SHAP or saliency explanations for agent decisions
|
54
|
+
|
55
|
+
## ๐ง Features
|
56
|
+
#### โ
Constrained RL
|
57
|
+
- Add custom constraints via wrapper or logic class
|
58
|
+
|
59
|
+
- Violation logging and reward shaping
|
60
|
+
|
61
|
+
- Safe vs unsafe episode tracking
|
62
|
+
|
63
|
+
#### ๐ Explainability
|
64
|
+
- SaliencyExplainer โ gradient-based visual heatmaps
|
65
|
+
|
66
|
+
- SHAPExplainer โ feature contribution values per decision
|
67
|
+
|
68
|
+
- Compatible with any PyTorch-based agent
|
69
|
+
|
70
|
+
#### ๐ Metrics
|
71
|
+
- Constraint violation rate
|
72
|
+
|
73
|
+
- Episode reward
|
74
|
+
|
75
|
+
- Cumulative safe reward
|
76
|
+
|
77
|
+
- Action entropy & temporal behavior stats
|
78
|
+
|
79
|
+
#### ๐ Modularity
|
80
|
+
- Swap out agents, constraints, evaluators, or explainers
|
81
|
+
|
82
|
+
- Supports Gym environments
|
83
|
+
|
84
|
+
- Configurable training pipeline
|
85
|
+
|
86
|
+
## ๐ Citation
|
87
|
+
Coming soon after arXiv/preprint release.
|
File without changes
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# agents/constrained_dqn.py
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
import random
|
5
|
+
import torch
|
6
|
+
import torch.nn as nn
|
7
|
+
import torch.optim as optim
|
8
|
+
from collections import deque
|
9
|
+
from agents.constraints import Constraint
|
10
|
+
|
11
|
+
|
12
|
+
class DQNetwork(nn.Module):
|
13
|
+
def __init__(self, input_dim, output_dim):
|
14
|
+
super().__init__()
|
15
|
+
self.net = nn.Sequential(
|
16
|
+
nn.Linear(input_dim, 128),
|
17
|
+
nn.ReLU(),
|
18
|
+
nn.Linear(128, 128),
|
19
|
+
nn.ReLU(),
|
20
|
+
nn.Linear(128, output_dim),
|
21
|
+
)
|
22
|
+
|
23
|
+
def forward(self, x):
|
24
|
+
return self.net(x)
|
25
|
+
|
26
|
+
|
27
|
+
class ConstrainedDQNAgent:
|
28
|
+
def __init__(self, state_dim, action_dim, constraint: Constraint = None):
|
29
|
+
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
30
|
+
self.q_net = DQNetwork(state_dim, action_dim).to(self.device)
|
31
|
+
self.target_net = DQNetwork(state_dim, action_dim).to(self.device)
|
32
|
+
self.target_net.load_state_dict(self.q_net.state_dict())
|
33
|
+
|
34
|
+
self.optimizer = optim.Adam(self.q_net.parameters(), lr=1e-3)
|
35
|
+
self.memory = deque(maxlen=10000)
|
36
|
+
self.gamma = 0.99
|
37
|
+
self.batch_size = 64
|
38
|
+
|
39
|
+
self.constraint = constraint
|
40
|
+
self.action_dim = action_dim
|
41
|
+
|
42
|
+
def select_action(self, state, epsilon):
|
43
|
+
if random.random() < epsilon:
|
44
|
+
return random.randint(0, self.action_dim - 1)
|
45
|
+
state = torch.tensor(state, dtype=torch.float32).to(self.device)
|
46
|
+
with torch.no_grad():
|
47
|
+
q_values = self.q_net(state)
|
48
|
+
return q_values.argmax().item()
|
49
|
+
|
50
|
+
def store_transition(self, s, a, r, s_next, done):
|
51
|
+
self.memory.append((s, a, r, s_next, done))
|
52
|
+
|
53
|
+
def update(self):
|
54
|
+
if len(self.memory) < self.batch_size:
|
55
|
+
return
|
56
|
+
batch = random.sample(self.memory, self.batch_size)
|
57
|
+
s, a, r, s_next, done = zip(*batch)
|
58
|
+
|
59
|
+
s = torch.tensor(s, dtype=torch.float32).to(self.device)
|
60
|
+
a = torch.tensor(a).to(self.device)
|
61
|
+
r = torch.tensor(r, dtype=torch.float32).to(self.device)
|
62
|
+
s_next = torch.tensor(s_next, dtype=torch.float32).to(self.device)
|
63
|
+
done = torch.tensor(done, dtype=torch.float32).to(self.device)
|
64
|
+
|
65
|
+
q_values = self.q_net(s).gather(1, a.unsqueeze(1)).squeeze()
|
66
|
+
with torch.no_grad():
|
67
|
+
target_q = r + self.gamma * self.target_net(s_next).max(1)[0] * (1 - done)
|
68
|
+
|
69
|
+
loss = nn.functional.mse_loss(q_values, target_q)
|
70
|
+
self.optimizer.zero_grad()
|
71
|
+
loss.backward()
|
72
|
+
self.optimizer.step()
|
73
|
+
|
74
|
+
def apply_constraint(self, state, action, reward):
|
75
|
+
if self.constraint:
|
76
|
+
penalty = self.constraint.compute_penalty(state, action, reward)
|
77
|
+
return reward - penalty, penalty
|
78
|
+
return reward, 0.0
|
79
|
+
|
80
|
+
def reset_constraints(self):
|
81
|
+
if self.constraint:
|
82
|
+
self.constraint.reset()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# agents/constraints.py
|
2
|
+
|
3
|
+
from abc import ABC, abstractmethod
|
4
|
+
|
5
|
+
|
6
|
+
class Constraint(ABC):
|
7
|
+
"""Abstract base class for constraints in SafeRL agents."""
|
8
|
+
|
9
|
+
@abstractmethod
|
10
|
+
def compute_penalty(self, state, action, reward) -> float:
|
11
|
+
"""Return penalty value for a given step."""
|
12
|
+
pass
|
13
|
+
|
14
|
+
def reset(self):
|
15
|
+
"""Optional: reset internal counters for new episode."""
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
class ActionBudgetConstraint(Constraint):
|
20
|
+
def __init__(self, max_actions: int):
|
21
|
+
self.max_actions = max_actions
|
22
|
+
self.counter = 0
|
23
|
+
|
24
|
+
def compute_penalty(self, state, action, reward) -> float:
|
25
|
+
self.counter += 1
|
26
|
+
return 1.0 if self.counter > self.max_actions else 0.0
|
27
|
+
|
28
|
+
def reset(self):
|
29
|
+
self.counter = 0
|
30
|
+
|
31
|
+
|
32
|
+
class EnergyPenaltyConstraint(Constraint):
|
33
|
+
def __init__(self, energy_fn, max_energy):
|
34
|
+
self.energy_fn = energy_fn
|
35
|
+
self.max_energy = max_energy
|
36
|
+
|
37
|
+
def compute_penalty(self, state, action, reward) -> float:
|
38
|
+
energy = self.energy_fn(state, action)
|
39
|
+
return max(0.0, energy - self.max_energy)
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# ๐ About SafeRL-Lite
|
2
|
+
|
3
|
+
**SafeRL-Lite** is a lightweight, explainable, and modular Python library for constrained reinforcement learning (Safe RL). It is designed for researchers, educators, and engineers who want to build safe, interpretable agents in Gym-compatible environments with minimal setup.
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## ๐ฏ Mission
|
8
|
+
|
9
|
+
SafeRL-Lite aims to:
|
10
|
+
- Enable **constrained RL** with built-in safety logic.
|
11
|
+
- Support **real-time explainability** using SHAP and saliency maps.
|
12
|
+
- Provide **modular components** for easy experimentation and extension.
|
13
|
+
- Be **minimal**, **readable**, and **production-friendly**.
|
14
|
+
|
15
|
+
---
|
16
|
+
|
17
|
+
## ๐งฑ Key Components
|
18
|
+
|
19
|
+
- **Constrained DQN agent** with runtime violation tracking.
|
20
|
+
- **Environment wrappers** for safety constraints and logging.
|
21
|
+
- **Evaluation module** to track rewards, constraint violations, and success metrics.
|
22
|
+
- **Explainability tools**:
|
23
|
+
- Gradient-based **saliency maps**
|
24
|
+
- **SHAP** values for input importance
|
25
|
+
|
26
|
+
---
|
27
|
+
|
28
|
+
## ๐ฉโ๐ฌ Who Should Use This?
|
29
|
+
|
30
|
+
SafeRL-Lite is ideal for:
|
31
|
+
- ๐ **Educators** teaching RL and safety concepts.
|
32
|
+
- ๐ฌ **Researchers** in safe RL, explainable AI (XAI), or constrained optimization.
|
33
|
+
- ๐งช **Experimenters** building proof-of-concepts for safety-critical environments (e.g., healthcare, robotics).
|
34
|
+
|
35
|
+
---
|
36
|
+
|
37
|
+
## ๐ ๏ธ Design Philosophy
|
38
|
+
|
39
|
+
- โ
Simplicity over complexity
|
40
|
+
- ๐งฉ Component reusability
|
41
|
+
- ๐ Built-in explainability
|
42
|
+
- ๐งช Test-driven development
|
43
|
+
- ๐ฆ PyPI-ready structure
|
44
|
+
|
45
|
+
---
|
46
|
+
|
47
|
+
## ๐ค Contributing
|
48
|
+
|
49
|
+
We welcome contributions from the community! Check out the [CONTRIBUTING.md](https://github.com/satyamcser/saferl-lite/blob/main/CONTRIBUTING.md) for guidelines.
|
50
|
+
|
51
|
+
---
|
52
|
+
|
53
|
+
## ๐ License
|
54
|
+
|
55
|
+
This project is licensed under the **MIT License**. See the [LICENSE](https://github.com/satyamcser/saferl-lite/blob/main/LICENSE) file for details.
|
56
|
+
|
57
|
+
---
|
58
|
+
|
59
|
+
## ๐ Links
|
60
|
+
|
61
|
+
- GitHub: [https://github.com/satyamcser/saferl-lite](https://github.com/satyamcser/saferl-lite)
|
62
|
+
- PyPI: *Coming soon*
|
63
|
+
- Docs: *This site*
|
64
|
+
|
65
|
+
---
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# SafeRL-Lite
|
2
|
+
|
3
|
+
Welcome to **SafeRL-Lite**, a lightweight, explainable, and constrained reinforcement learning library built in Python.
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## โจ Features
|
8
|
+
|
9
|
+
- โป๏ธ **Constrained Agents**: Supports safe training using budgeted penalties and constraint wrappers.
|
10
|
+
- ๐ **Explainability Tools**: Includes SHAP and saliency-based attribution methods.
|
11
|
+
- ๐ฎ **Custom Environments**: Easy wrappers for constraint-aware OpenAI Gym environments.
|
12
|
+
- ๐ **Evaluation Metrics**: Regret, safe episode rate, violation count.
|
13
|
+
- ๐งช **Tested and Documented**: Full unit test suite with CI + MkDocs support.
|
14
|
+
|
15
|
+
---
|
16
|
+
|
17
|
+
## ๐ง Repository Info
|
18
|
+
|
19
|
+
- **Author**: [Satyam Mishra](https://github.com/satyamcser)
|
20
|
+
- **GitHub**: [github.com/satyamcser/saferl-lite](https://github.com/satyamcser/saferl-lite)
|
21
|
+
|
22
|
+
---
|
23
|
+
|
24
|
+
## ๐ฆ Installation
|
25
|
+
|
26
|
+
See [Usage โ Installation](usage/installation.md) for details.
|
27
|
+
|
28
|
+
## ๐ Quickstart
|
29
|
+
|
30
|
+
See [Usage โ Quickstart](usage/quickstart.md) to get up and running in 60 seconds.
|
31
|
+
|
32
|
+
## ๐งช Example
|
33
|
+
|
34
|
+
- [CartPole with Constraints](examples/cartpole.md)
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# ๐ SafeRL-Lite Evaluation Metrics
|
2
|
+
|
3
|
+
SafeRL-Lite provides built-in evaluation metrics to assess both **performance** and **safety** of RL agents in constrained environments.
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## ๐ฏ 1. `evaluate_safety_violations`
|
8
|
+
|
9
|
+
```python
|
10
|
+
evaluate_safety_violations(violations: List[int]) -> float
|
11
|
+
```
|
12
|
+
|
13
|
+
#### Description:
|
14
|
+
Calculates the percentage of time steps where the agent violated a safety constraint.
|
15
|
+
|
16
|
+
#### Arguments:
|
17
|
+
|
18
|
+
- violations (List[int]): A binary list where 1 indicates a violation at that timestep.
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
|
22
|
+
- float: Fraction of violated steps (e.g. 0.12 means 12% violation rate).
|
23
|
+
|
24
|
+
### Usage Example:
|
25
|
+
|
26
|
+
```python
|
27
|
+
violations = [0, 1, 0, 1, 1]
|
28
|
+
violation_rate = evaluate_safety_violations(violations)
|
29
|
+
# Output: 0.6
|
30
|
+
```
|
31
|
+
---
|
32
|
+
|
33
|
+
## ๐ 2. evaluate_cumulative_reward
|
34
|
+
|
35
|
+
```python
|
36
|
+
evaluate_cumulative_reward(rewards: List[float]) -> float
|
37
|
+
|
38
|
+
```
|
39
|
+
|
40
|
+
#### Description:
|
41
|
+
Computes the total accumulated reward across an episode.
|
42
|
+
|
43
|
+
#### Arguments:
|
44
|
+
|
45
|
+
- rewards (List[float]): A list of numerical rewards at each timestep.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
|
49
|
+
- float: Total reward over the episode.
|
50
|
+
|
51
|
+
### Usage Example:
|
52
|
+
|
53
|
+
```python
|
54
|
+
rewards = [1.0, -0.2, 2.0, 0.5]
|
55
|
+
total_reward = evaluate_cumulative_reward(rewards)
|
56
|
+
# Output: 3.3
|
57
|
+
```
|
58
|
+
|
59
|
+
|
60
|
+
---
|
61
|
+
|
62
|
+
## โ๏ธ 3. evaluate_constraint_satisfaction_rate
|
63
|
+
|
64
|
+
```python
|
65
|
+
evaluate_constraint_satisfaction_rate(satisfied: List[bool]) -> float
|
66
|
+
```
|
67
|
+
|
68
|
+
#### Description:
|
69
|
+
Measures the fraction of time steps where all constraints were satisfied.
|
70
|
+
|
71
|
+
#### Arguments:
|
72
|
+
|
73
|
+
- satisfied (List[bool]): A list where True means constraints were satisfied at that step.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
|
77
|
+
- float: Constraint satisfaction rate (e.g. 0.9 means 90% of steps were constraint-safe).
|
78
|
+
|
79
|
+
### Usage Example:
|
80
|
+
|
81
|
+
```python
|
82
|
+
satisfied = [True, False, True, True]
|
83
|
+
rate = evaluate_constraint_satisfaction_rate(satisfied)
|
84
|
+
# Output: 0.75
|
85
|
+
|
86
|
+
```
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
---
|
91
|
+
|
92
|
+
## ๐ 4. Visualization Hooks (WIP)
|
93
|
+
|
94
|
+
Future versions will include utilities for:
|
95
|
+
|
96
|
+
- Violation trend plots
|
97
|
+
|
98
|
+
- Reward-violation scatter plots
|
99
|
+
|
100
|
+
- Safety-performance Pareto frontiers
|
101
|
+
|
102
|
+
#### ๐ง Pro Tip
|
103
|
+
These metrics are modular, you can log them live during training or compute them post hoc from rollout logs using:
|
104
|
+
|
105
|
+
```python
|
106
|
+
from evaluations.metrics import (
|
107
|
+
evaluate_safety_violations,
|
108
|
+
evaluate_cumulative_reward,
|
109
|
+
evaluate_constraint_satisfaction_rate,
|
110
|
+
)
|
111
|
+
|
112
|
+
```
|
113
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# ๐งช Example: Safe CartPole
|
2
|
+
|
3
|
+
This example demonstrates how to train a **constrained DQN agent** on the classic `CartPole-v1` task with constraint-aware wrappers, SHAP-based explainability, and safe policy evaluation.
|
4
|
+
|
5
|
+
---
|
6
|
+
|
7
|
+
## ๐ง Objective
|
8
|
+
|
9
|
+
Balance the pole while **minimizing unsafe actions**, defined by custom constraints (e.g., excessive cart velocity).
|
10
|
+
|
11
|
+
---
|
12
|
+
|
13
|
+
## ๐ฆ Setup
|
14
|
+
|
15
|
+
Make sure youโve followed the [Installation Guide](../usage/installation.md).
|
16
|
+
|
17
|
+
---
|
18
|
+
|
19
|
+
## ๐ง 1. Import Required Modules
|
20
|
+
|
21
|
+
```python
|
22
|
+
import gymnasium as gym
|
23
|
+
from agents.constrained_dqn import ConstrainedDQNAgent
|
24
|
+
from envs.wrappers import ConstraintWrapper
|
25
|
+
from evaluations.metrics import evaluate_agent
|
26
|
+
from explainability.shap_explainer import SHAPExplainer
|
27
|
+
```
|
28
|
+
|
29
|
+
---
|
30
|
+
|
31
|
+
## ๐๏ธ 2. Create a Safe Environment
|
32
|
+
|
33
|
+
```python
|
34
|
+
env = gym.make("CartPole-v1", render_mode=None)
|
35
|
+
safe_env = ConstraintWrapper(env, constraint_threshold=0.5)
|
36
|
+
|
37
|
+
```
|
38
|
+
|
39
|
+
---
|
40
|
+
|
41
|
+
## ๐ค 3. Train a Constrained Agent
|
42
|
+
|
43
|
+
```python
|
44
|
+
agent = ConstrainedDQNAgent(env=safe_env, budget=1.0)
|
45
|
+
agent.train(episodes=10)
|
46
|
+
|
47
|
+
|
48
|
+
```
|
49
|
+
|
50
|
+
---
|
51
|
+
|
52
|
+
## ๐ 4. Evaluate the Agent
|
53
|
+
|
54
|
+
```python
|
55
|
+
metrics = evaluate_agent(agent, safe_env, episodes=5)
|
56
|
+
|
57
|
+
print("=== Evaluation Metrics ===")
|
58
|
+
print("Safe episode rate:", metrics["safe_rate"])
|
59
|
+
print("Average violations:", metrics["avg_violations"])
|
60
|
+
print("Total regret:", metrics["regret"])
|
61
|
+
|
62
|
+
```
|
63
|
+
|
64
|
+
---
|
65
|
+
|
66
|
+
## ๐ 5. Explain a Sample Episode with SHAP
|
67
|
+
|
68
|
+
```python
|
69
|
+
explainer = SHAPExplainer(agent, safe_env)
|
70
|
+
explainer.explain_episode(max_steps=50)
|
71
|
+
```
|
72
|
+
|
73
|
+
---
|
74
|
+
|
75
|
+
## โ
Output Snapshot
|
76
|
+
|
77
|
+
```bash
|
78
|
+
Episode 3: reward=1.0, penalty=0.0, violations=0.0
|
79
|
+
SHAP: ['0.04', '0.01']
|
80
|
+
Saliency: ['0.19', '0.05']
|
81
|
+
|
82
|
+
```
|
83
|
+
|
84
|
+
---
|