ghubner's picture
Update app with improved UI and markdown formatting
386550d
raw
history blame
7.19 kB
import gradio as gr
from train import TrainingLoop
from scipy.special import softmax
import numpy as np
# Global variables for training and data storage
train = None
frames, attributions = None, None
# Lunar Lander environment state feature mapping
LUNAR_LANDER_FEATURES = {
0: "X-coordinate",
1: "Y-coordinate",
2: "Linear velocity in the X-axis",
3: "Linear velocity in the Y-axis",
4: "Angle",
5: "Angular velocity",
6: "Left leg touched the floor",
7: "Right leg touched the floor"
}
def create_training_loop(env_spec):
"""Initialize the training loop with the specified environment."""
global train
train = TrainingLoop(env_spec=env_spec)
train.create_agent()
return train.env.spec
def display_softmax(inputs):
"""Convert raw attribution values to softmax probabilities for visualization."""
inputs = np.array(inputs)
probabilities = softmax(inputs)
softmax_dict = {
name: float(prob)
for name, prob in zip(LUNAR_LANDER_FEATURES.values(), probabilities)
}
return softmax_dict
def generate_output(num_iterations, option):
"""Generate attribution explanations for the trained agent."""
global frames, attributions
frames, attributions = train.explain_trained(
num_iterations=num_iterations,
option=option
)
slider.maximum = len(frames)
def get_frame_and_attribution(slider_value):
"""Get frame and attribution data for the selected timestep."""
global frames, attributions
slider_value = min(slider_value, len(frames) - 1)
frame = frames[slider_value]
print(f"Frame shape: {frame.shape}")
attribution = display_softmax(attributions[slider_value])
return frame, attribution
with gr.Blocks(
title="Deep RL Explainability",
theme=gr.themes.Soft(),
css="""
.gradio-container {
max-width: 1200px !important;
}
.tab-nav {
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
}
"""
) as demo:
# Header section
gr.Markdown("""
# ๐Ÿš€ Deep Reinforcement Learning Explainability
**Exploring AI decision-making through Integrated Gradients in RL environments**
---
""")
# Introduction section
gr.Markdown("""
## ๐Ÿ“– How This Works
This application demonstrates the application of **[Integrated Gradients](https://captum.ai/docs/extension/integrated_gradients)**
to Deep Reinforcement Learning scenarios. We use PyTorch's Captum library for interpretability
and Gymnasium for the continuous Lunar Lander environment.
### ๐Ÿง  Training Algorithm: [DDPG](https://arxiv.org/abs/1509.02971)
The agent is trained using **Deep Deterministic Policy Gradients** and achieves an average reward
of **260.8** per episode (successful landings).
### ๐ŸŽฏ How to Use This Space
1. **Select Environment**: Choose the Lunar Lander environment
2. **Choose Baseline**: Select between zero tensor or running average baseline
3. **Generate Attributions**: Click "ATTRIBUTE" and wait ~20-25 seconds
4. **Explore Results**: Use the slider to examine attributions at different timesteps
The attributions are normalized using Softmax to provide interpretable probability distributions.
""")
# Main interface tab
with gr.Tab("๐Ÿ” Attribution Analysis", elem_id="attribution-tab"):
# Environment setup
gr.Markdown("### ๐ŸŒ™ Environment Setup")
env_spec = gr.Dropdown(
choices=["LunarLander-v2"],
type="value",
multiselect=False,
label="Environment Specification",
value="LunarLander-v2",
info="Select the RL environment to analyze"
)
env_interface = gr.Interface(
title="Initialize Environment",
allow_flagging="never",
inputs=env_spec,
fn=create_training_loop,
outputs=gr.JSON(label="Environment Spec"),
description="Click to initialize the training environment"
)
# Attribution controls
gr.Markdown("### โš™๏ธ Attribution Configuration")
with gr.Row():
with gr.Column(scale=1):
option = gr.Dropdown(
choices=["Torch Tensor of 0's", "Running Average"],
type="index",
label="Baseline Method",
info="Choose the baseline for Integrated Gradients"
)
with gr.Column(scale=1):
baselines = gr.Slider(
label="Number of Baseline Iterations",
interactive=True,
minimum=0,
maximum=100,
value=10,
step=5,
info="Number of baseline inputs to collect for averaging"
)
# Generate button
generate_btn = gr.Button(
"๐Ÿš€ GENERATE ATTRIBUTIONS",
variant="primary",
size="lg"
)
generate_btn.click(
fn=generate_output,
inputs=[baselines, option],
outputs=[]
)
# Results section
gr.Markdown("### ๐Ÿ“Š Results Visualization")
slider = gr.Slider(
label="๐ŸŽฌ Key Frame Selector",
minimum=0,
maximum=1000,
step=1,
value=0,
info="Navigate through different timesteps to see attributions"
)
results_interface = gr.Interface(
fn=get_frame_and_attribution,
inputs=slider,
live=True,
outputs=[
gr.Image(label="๐ŸŽฎ Environment State", type="numpy"),
gr.Label(label="๐Ÿ“ˆ Feature Attributions", num_top_classes=8)
],
title="Real-time Attribution Analysis"
)
gr.Markdown("""
---
## ๐Ÿ› ๏ธ Local Usage & Installation
### Required Packages
```bash
pip install torch gymnasium 'gymnasium[box2d]'
```
### Box2D Installation (macOS)
```bash
brew install swig
pip install box2d
```
## ๐ŸŽฏ Lunar Lander Environment Details
### Reward Structure
- **Position**: Increased/decreased based on distance to landing pad
- **Velocity**: Increased/decreased based on speed (slower is better)
- **Angle**: Decreased when lander is tilted (horizontal is ideal)
- **Landing**: +10 points for each leg touching ground
- **Fuel**: -0.03 points per frame for side engine, -0.3 for main engine
- **Episode End**: -100 for crash, +100 for safe landing
**Success Threshold**: 200+ points per episode
### Training Functions
- `load_trained()`: Loads pre-trained model (1000 episodes)
- `train()`: Trains from scratch
- Set `render_mode=False` for faster training
---
*Built with โค๏ธ using Gradio, PyTorch, and Captum*
""")
if __name__ == "__main__":
demo.launch()