ghubner commited on
Commit
386550d
ยท
1 Parent(s): 9a220ac

Update app with improved UI and markdown formatting

Browse files
Files changed (8) hide show
  1. .gitignore +53 -1
  2. .python-version +1 -0
  3. README.md +1 -1
  4. __pycache__/ddpg.cpython-310.pyc +0 -0
  5. app.py +183 -53
  6. pyproject.toml +23 -0
  7. requirements_hf.txt +13 -0
  8. uv.lock +0 -0
.gitignore CHANGED
@@ -1 +1,53 @@
1
- .DS_Store
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .DS_Store
2
+
3
+ # Python
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ *.so
8
+ .Python
9
+ build/
10
+ develop-eggs/
11
+ dist/
12
+ downloads/
13
+ eggs/
14
+ .eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+
25
+ # Virtual environments
26
+ .venv/
27
+ venv/
28
+ ENV/
29
+ env/
30
+
31
+ # IDE
32
+ .vscode/
33
+ .idea/
34
+ *.swp
35
+ *.swo
36
+
37
+ # Jupyter Notebook
38
+ .ipynb_checkpoints
39
+
40
+ # Model files (if large)
41
+ *.pth
42
+ *.pt
43
+ *.h5
44
+ *.pkl
45
+ *.joblib
46
+
47
+ # Logs
48
+ *.log
49
+ logs/
50
+
51
+ # Temporary files
52
+ tmp/
53
+ temp/
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.10
README.md CHANGED
@@ -54,4 +54,4 @@ For each step, the reward:
54
 
55
  ## `train()` and `load_trained()`
56
 
57
- `load_trained()` function loads a pre-trained model that ran through 1000 episodes of training, while `train()` does training from scratch. You can edit which one of the functions is running from the bottom of the main.py file. If you set render_mode=False, the program will train a lot faster.
 
54
 
55
  ## `train()` and `load_trained()`
56
 
57
+ `load_trained()` function loads a pre-trained model that ran through 1000 episodes of training, while `train()` does training from scratch. You can edit which one of the functions is running from the bottom of the main.py file. If you set render_mode=False, the program will train a lot faster.
__pycache__/ddpg.cpython-310.pyc CHANGED
Binary files a/__pycache__/ddpg.cpython-310.pyc and b/__pycache__/ddpg.cpython-310.pyc differ
 
app.py CHANGED
@@ -3,14 +3,14 @@ from train import TrainingLoop
3
  from scipy.special import softmax
4
  import numpy as np
5
 
6
-
7
  train = None
8
-
9
  frames, attributions = None, None
10
 
11
- lunar_lander_spec_conversion = {
 
12
  0: "X-coordinate",
13
- 1: "Y-coordinate",
14
  2: "Linear velocity in the X-axis",
15
  3: "Linear velocity in the Y-axis",
16
  4: "Angle",
@@ -20,76 +20,206 @@ lunar_lander_spec_conversion = {
20
  }
21
 
22
  def create_training_loop(env_spec):
 
23
  global train
24
  train = TrainingLoop(env_spec=env_spec)
25
  train.create_agent()
26
-
27
  return train.env.spec
28
 
29
  def display_softmax(inputs):
 
30
  inputs = np.array(inputs)
31
  probabilities = softmax(inputs)
32
-
33
- softmax_dict = {name: float(prob) for name, prob in zip(lunar_lander_spec_conversion.values(), probabilities)}
34
-
 
 
35
  return softmax_dict
36
 
37
  def generate_output(num_iterations, option):
 
38
  global frames, attributions
39
- frames, attributions = train.explain_trained(num_iterations=num_iterations, option=option)
 
 
 
40
  slider.maximum = len(frames)
41
 
42
  def get_frame_and_attribution(slider_value):
 
43
  global frames, attributions
44
  slider_value = min(slider_value, len(frames) - 1)
45
  frame = frames[slider_value]
46
-
47
- print(f"{frame.shape=}")
48
-
49
  attribution = display_softmax(attributions[slider_value])
50
-
51
  return frame, attribution
52
 
53
- with gr.Blocks() as demo:
54
- gr.Markdown("# Introspection in Deep Reinforcement Learning")
55
- gr.Markdown(r"""
56
- \#\# How this space works:
57
- This space was created for trying to apply [Integrated Gradients](https://captum.ai/docs/extension/integrated_gradients\#:~:text=Integrated%20gradients%20is%20a%20simple,and%20feature%20or%20rule%20extraction.) \
58
- into Deep Reinforcement Learning Scenarions. It uses PyTorch's captum library for interpretability, and Gymnasium for the emulator of the continuous lunar lander.
59
- \#\#\# Training algorithm: [DDPG](https://arxiv.org/abs/1509.02971)
60
- This agent was trained with Deep Deterministic Policy Gradients, and outputs an average reward of 260.8 per episode (successful)
61
- \#\#\# Using this space:
62
- - First, select the environment (futurely there will be more environments available)
63
- - Then, select if you want the baseline (see IG paper for more detail) to be \
64
- a torch `tensor` of zeroes, or a running average of the initial frames of a few episodes (selected on the right) \
65
- - Click attribute and wait a few seconds (usually 20-25s) for the attributions to be computed with the trained agent over 10 episodes
66
- - Finally, use the slider to get a key frame that tells the attributions of the agent. They're under a Softmax to fit the component's requirements for a probability distribution.
 
 
 
 
 
 
67
  """)
68
- with gr.Tab(label="Attribute"):
69
- env_spec = gr.Dropdown(choices=["LunarLander-v2"],type="value",multiselect=False, label="Environment Specification (e.g.: LunarLander-v2)")
70
- env = gr.Interface(title="Create the Environment", allow_flagging="never", inputs=env_spec, fn=create_training_loop, outputs=gr.JSON())
71
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  with gr.Row():
73
- option = gr.Dropdown(choices=["Torch Tensor of 0's", "Running Average"], type="index")
74
- baselines = gr.Slider(label="Number of Baseline Iterations", interactive=True, minimum=0, maximum=100, value=10, step=5, info="Baseline inputs to collect for the average", render=True)
75
- gr.Button("ATTRIBUTE").click(fn=generate_output, inputs=[baselines, option])
76
- slider = gr.Slider(label="Key Frame", minimum=0, maximum=1000, step=1, value=0)
77
-
78
- gr.Interface(fn=get_frame_and_attribution, inputs=slider, live=True, outputs=[gr.Image(label="Timestep"),gr.Label(label="Attributions")])
79
- gr.Markdown(r"""\#\# Local Usage and Packages \
80
- `pip install torch gymnasium 'gymnasium[box2d]'` \
81
- You might need to install Box2D Separately, which requires a swig package to compile code from Python into C/C++, which is the language that Box2d was built in: \
82
- `brew install swig` \
83
- `pip install box2d \n \#\# Average Score: 164.38 (significant improvement from discrete action spaces) \
84
- For each step, the reward: \
85
- - is increased/decreased the closer/further the lander is to the landing pad. \
86
- - is increased/decreased the slower/faster the lander is moving.\
87
- - is decreased the more the lander is tilted (angle not horizontal). \
88
- - is increased by 10 points for each leg that is in contact with the ground. \
89
- - is decreased by 0.03 points each frame a side engine is firing.\
90
- - is decreased by 0.3 points each frame the main engine is firing. \
91
- The episode receives an additional reward of -100 or +100 points for crashing or landing safely respectively. An episode is considered a solution if it scores at least 200 points.\*\* \
92
- \#\# `train()` and `load_trained()` \
93
- `load_trained()` function loads a pre-trained model that ran through 1000 episodes of training, while `train()` does training from scratch. You can edit which one of the functions is running from the bottom of the main.py file. If you set render_mode=False, the program will train a lot faster.)\n demo.launch()""")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
95
- demo.launch()
 
 
3
  from scipy.special import softmax
4
  import numpy as np
5
 
6
+ # Global variables for training and data storage
7
  train = None
 
8
  frames, attributions = None, None
9
 
10
+ # Lunar Lander environment state feature mapping
11
+ LUNAR_LANDER_FEATURES = {
12
  0: "X-coordinate",
13
+ 1: "Y-coordinate",
14
  2: "Linear velocity in the X-axis",
15
  3: "Linear velocity in the Y-axis",
16
  4: "Angle",
 
20
  }
21
 
22
  def create_training_loop(env_spec):
23
+ """Initialize the training loop with the specified environment."""
24
  global train
25
  train = TrainingLoop(env_spec=env_spec)
26
  train.create_agent()
 
27
  return train.env.spec
28
 
29
  def display_softmax(inputs):
30
+ """Convert raw attribution values to softmax probabilities for visualization."""
31
  inputs = np.array(inputs)
32
  probabilities = softmax(inputs)
33
+
34
+ softmax_dict = {
35
+ name: float(prob)
36
+ for name, prob in zip(LUNAR_LANDER_FEATURES.values(), probabilities)
37
+ }
38
  return softmax_dict
39
 
40
  def generate_output(num_iterations, option):
41
+ """Generate attribution explanations for the trained agent."""
42
  global frames, attributions
43
+ frames, attributions = train.explain_trained(
44
+ num_iterations=num_iterations,
45
+ option=option
46
+ )
47
  slider.maximum = len(frames)
48
 
49
  def get_frame_and_attribution(slider_value):
50
+ """Get frame and attribution data for the selected timestep."""
51
  global frames, attributions
52
  slider_value = min(slider_value, len(frames) - 1)
53
  frame = frames[slider_value]
54
+
55
+ print(f"Frame shape: {frame.shape}")
56
+
57
  attribution = display_softmax(attributions[slider_value])
 
58
  return frame, attribution
59
 
60
+ with gr.Blocks(
61
+ title="Deep RL Explainability",
62
+ theme=gr.themes.Soft(),
63
+ css="""
64
+ .gradio-container {
65
+ max-width: 1200px !important;
66
+ }
67
+ .tab-nav {
68
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
69
+ }
70
+ """
71
+ ) as demo:
72
+
73
+ # Header section
74
+ gr.Markdown("""
75
+ # ๐Ÿš€ Deep Reinforcement Learning Explainability
76
+
77
+ **Exploring AI decision-making through Integrated Gradients in RL environments**
78
+
79
+ ---
80
  """)
81
+
82
+ # Introduction section
83
+ gr.Markdown("""
84
+ ## ๐Ÿ“– How This Works
85
+
86
+ This application demonstrates the application of **[Integrated Gradients](https://captum.ai/docs/extension/integrated_gradients)**
87
+ to Deep Reinforcement Learning scenarios. We use PyTorch's Captum library for interpretability
88
+ and Gymnasium for the continuous Lunar Lander environment.
89
+
90
+ ### ๐Ÿง  Training Algorithm: [DDPG](https://arxiv.org/abs/1509.02971)
91
+
92
+ The agent is trained using **Deep Deterministic Policy Gradients** and achieves an average reward
93
+ of **260.8** per episode (successful landings).
94
+
95
+ ### ๐ŸŽฏ How to Use This Space
96
+
97
+ 1. **Select Environment**: Choose the Lunar Lander environment
98
+ 2. **Choose Baseline**: Select between zero tensor or running average baseline
99
+ 3. **Generate Attributions**: Click "ATTRIBUTE" and wait ~20-25 seconds
100
+ 4. **Explore Results**: Use the slider to examine attributions at different timesteps
101
+
102
+ The attributions are normalized using Softmax to provide interpretable probability distributions.
103
+ """)
104
+
105
+ # Main interface tab
106
+ with gr.Tab("๐Ÿ” Attribution Analysis", elem_id="attribution-tab"):
107
+
108
+ # Environment setup
109
+ gr.Markdown("### ๐ŸŒ™ Environment Setup")
110
+ env_spec = gr.Dropdown(
111
+ choices=["LunarLander-v2"],
112
+ type="value",
113
+ multiselect=False,
114
+ label="Environment Specification",
115
+ value="LunarLander-v2",
116
+ info="Select the RL environment to analyze"
117
+ )
118
+
119
+ env_interface = gr.Interface(
120
+ title="Initialize Environment",
121
+ allow_flagging="never",
122
+ inputs=env_spec,
123
+ fn=create_training_loop,
124
+ outputs=gr.JSON(label="Environment Spec"),
125
+ description="Click to initialize the training environment"
126
+ )
127
+
128
+ # Attribution controls
129
+ gr.Markdown("### โš™๏ธ Attribution Configuration")
130
+
131
  with gr.Row():
132
+ with gr.Column(scale=1):
133
+ option = gr.Dropdown(
134
+ choices=["Torch Tensor of 0's", "Running Average"],
135
+ type="index",
136
+ label="Baseline Method",
137
+ info="Choose the baseline for Integrated Gradients"
138
+ )
139
+
140
+ with gr.Column(scale=1):
141
+ baselines = gr.Slider(
142
+ label="Number of Baseline Iterations",
143
+ interactive=True,
144
+ minimum=0,
145
+ maximum=100,
146
+ value=10,
147
+ step=5,
148
+ info="Number of baseline inputs to collect for averaging"
149
+ )
150
+
151
+ # Generate button
152
+ generate_btn = gr.Button(
153
+ "๐Ÿš€ GENERATE ATTRIBUTIONS",
154
+ variant="primary",
155
+ size="lg"
156
+ )
157
+ generate_btn.click(
158
+ fn=generate_output,
159
+ inputs=[baselines, option],
160
+ outputs=[]
161
+ )
162
+
163
+ # Results section
164
+ gr.Markdown("### ๐Ÿ“Š Results Visualization")
165
+
166
+ slider = gr.Slider(
167
+ label="๐ŸŽฌ Key Frame Selector",
168
+ minimum=0,
169
+ maximum=1000,
170
+ step=1,
171
+ value=0,
172
+ info="Navigate through different timesteps to see attributions"
173
+ )
174
+
175
+ results_interface = gr.Interface(
176
+ fn=get_frame_and_attribution,
177
+ inputs=slider,
178
+ live=True,
179
+ outputs=[
180
+ gr.Image(label="๐ŸŽฎ Environment State", type="numpy"),
181
+ gr.Label(label="๐Ÿ“ˆ Feature Attributions", num_top_classes=8)
182
+ ],
183
+ title="Real-time Attribution Analysis"
184
+ )
185
+
186
+ gr.Markdown("""
187
+ ---
188
+
189
+ ## ๐Ÿ› ๏ธ Local Usage & Installation
190
+
191
+ ### Required Packages
192
+ ```bash
193
+ pip install torch gymnasium 'gymnasium[box2d]'
194
+ ```
195
+
196
+ ### Box2D Installation (macOS)
197
+ ```bash
198
+ brew install swig
199
+ pip install box2d
200
+ ```
201
+
202
+ ## ๐ŸŽฏ Lunar Lander Environment Details
203
+
204
+ ### Reward Structure
205
+ - **Position**: Increased/decreased based on distance to landing pad
206
+ - **Velocity**: Increased/decreased based on speed (slower is better)
207
+ - **Angle**: Decreased when lander is tilted (horizontal is ideal)
208
+ - **Landing**: +10 points for each leg touching ground
209
+ - **Fuel**: -0.03 points per frame for side engine, -0.3 for main engine
210
+ - **Episode End**: -100 for crash, +100 for safe landing
211
+
212
+ **Success Threshold**: 200+ points per episode
213
+
214
+ ### Training Functions
215
+ - `load_trained()`: Loads pre-trained model (1000 episodes)
216
+ - `train()`: Trains from scratch
217
+ - Set `render_mode=False` for faster training
218
+
219
+ ---
220
+
221
+ *Built with โค๏ธ using Gradio, PyTorch, and Captum*
222
+ """)
223
 
224
+ if __name__ == "__main__":
225
+ demo.launch()
pyproject.toml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "deep-rl-explainability"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ requires-python = ">=3.10"
6
+ dependencies = [
7
+ "ale-py==0.8.1",
8
+ "autorom==0.4.2",
9
+ "autorom-accept-rom-license==0.6.1",
10
+ "captum==0.6.0",
11
+ "gradio>=5.44.1",
12
+ "gymnasium[box2d]==0.29.1",
13
+ "huggingface-hub>=0.34.4",
14
+ "imageio==2.31.5",
15
+ "imageio-ffmpeg==0.4.9",
16
+ "matplotlib==3.8.0",
17
+ "matplotlib-inline==0.1.6",
18
+ "moviepy==1.0.3",
19
+ "mujoco==2.3.7",
20
+ "numpy==1.26.0",
21
+ "scipy>=1.15.3",
22
+ "torch==2.1.0",
23
+ ]
requirements_hf.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch==2.1.0
2
+ gymnasium==0.29.1
3
+ gymnasium[box2d]
4
+ gradio==5.44.1
5
+ captum==0.6.0
6
+ numpy==1.26.0
7
+ scipy
8
+ matplotlib==3.8.0
9
+ moviepy==1.0.3
10
+ imageio==2.31.5
11
+ imageio-ffmpeg==0.4.9
12
+ box2d-py==2.3.5
13
+ swig==4.*
uv.lock ADDED
The diff for this file is too large to render. See raw diff