Skip to content

Commit 622cdfd

Browse files
feat(zero): add --profile support for num_workers=1
1 parent a902a8c commit 622cdfd

File tree

7 files changed

+75
-43
lines changed

7 files changed

+75
-43
lines changed

libraries/mathy_python/mathy/agents/zero/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ class SelfPlayConfig(BaseConfig):
99
self_play_problems: int = 64
1010
training_iterations: int = 100
1111
cpuct: float = 1.0
12+
13+
14+
# When profile is true and workers == 1 the main thread will output worker_0.profile on exit
15+
profile: bool = False

libraries/mathy_python/mathy/agents/zero/practice_runner.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import queue
23
import time
34
from multiprocessing import Array, Pool, Process, Queue, cpu_count
@@ -141,25 +142,44 @@ def execute_episodes(
141142
"""
142143
examples = []
143144
results: List[EpisodeSummary] = []
145+
if self.config.profile:
146+
import cProfile
144147

145-
game = self.get_game()
146-
predictor = self.get_predictor(game)
147-
for i, args in enumerate(episode_args_list):
148-
start = time.time()
149-
(episode_examples, episode_reward, is_win, problem,) = self.execute_episode(
150-
i, game, predictor, **args
151-
)
152-
duration = time.time() - start
153-
examples.append(episode_examples)
154-
episode_summary = EpisodeSummary(
155-
solved=bool(is_win),
156-
text=problem.text,
157-
complexity=problem.complexity,
158-
reward=episode_reward,
159-
duration=duration,
160-
)
161-
results.append(episode_summary)
162-
self.episode_complete(i, episode_summary)
148+
pr = cProfile.Profile()
149+
pr.enable()
150+
151+
try:
152+
game = self.get_game()
153+
predictor = self.get_predictor(game)
154+
for i, args in enumerate(episode_args_list):
155+
start = time.time()
156+
(
157+
episode_examples,
158+
episode_reward,
159+
is_win,
160+
problem,
161+
) = self.execute_episode(i, game, predictor, **args)
162+
duration = time.time() - start
163+
examples.append(episode_examples)
164+
episode_summary = EpisodeSummary(
165+
solved=bool(is_win),
166+
text=problem.text,
167+
complexity=problem.complexity,
168+
reward=episode_reward,
169+
duration=duration,
170+
)
171+
results.append(episode_summary)
172+
self.episode_complete(i, episode_summary)
173+
except KeyboardInterrupt:
174+
print("Interrupt received. Exiting.")
175+
176+
if self.config.profile:
177+
profile_name = f"worker_0.profile"
178+
profile_path = os.path.join(self.config.model_dir, profile_name)
179+
pr.disable()
180+
pr.dump_stats(profile_path)
181+
if self.config.verbose:
182+
print(f"PROFILER: saved {profile_path}")
163183
return examples, results
164184

165185
def execute_episode(
@@ -231,7 +251,7 @@ class ParallelPracticeRunner(PracticeRunner):
231251
def execute_episodes(
232252
self, episode_args_list
233253
) -> Tuple[List[EpisodeHistory], List[EpisodeSummary]]:
234-
def worker(work_queue, result_queue):
254+
def worker(work_queue: Queue, result_queue: Queue):
235255
"""Pull items out of the work queue and execute episodes until there are
236256
no items left"""
237257
game = self.get_game()

libraries/mathy_python/mathy/agents/zero/self_play_runner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def self_play_runner(config: SelfPlayConfig):
2020
BaseEpisodeRunner = (
2121
PracticeRunner if config.num_workers < 2 else ParallelPracticeRunner
2222
)
23+
if config.profile and config.num_workers > 1:
24+
raise NotImplementedError("zero agent does not support multiprocess profiling")
2325
lesson_name = "mathy-poly-easy-v0"
2426
if config.verbose:
2527
print(config.json(indent=2))

libraries/mathy_python/mathy/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def cli_train(
258258
instance = A3CAgent(args)
259259
instance.train()
260260
elif agent == "zero":
261-
setup_tf_env(use_mp=True)
261+
setup_tf_env(use_mp=workers > 1)
262262
from .agents.zero import SelfPlayConfig, self_play_runner
263263

264264
self_play_cfg = SelfPlayConfig(
@@ -275,6 +275,7 @@ def cli_train(
275275
training_iterations=training_iterations,
276276
self_play_problems=self_play_problems,
277277
print_training=show,
278+
profile=profile,
278279
)
279280
if episodes is not None:
280281
self_play_cfg.max_eps = episodes
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import pytest
2+
3+
from ..mathy.agents.zero import SelfPlayConfig, self_play_runner
4+
5+
6+
def test_self_play_runner_errors():
7+
"""Throws error for bad profiling configuration of zero agent.
8+
9+
This is only because it wasn't clear how to profile multiple processes that
10+
stop/start overtime during training/evaluation loops"""
11+
with pytest.raises(NotImplementedError):
12+
self_play_runner(SelfPlayConfig(profile=True, num_workers=2))

libraries/website/docs/ml/a3c.md

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,29 +93,7 @@ The CLI A3C agent accepts a `--profile` option, or a config option when the API
9393
{!./snippets/ml/a3c_profiling.py!}
9494
```
9595

96-
The output files can be visualized using **[Snakeviz](https://jiffyclub.github.io/snakeviz/){target=\_blank}**:
97-
98-
You can install Snakeviz if it's not already present:
99-
100-
```bash
101-
pip install snakeviz
102-
```
103-
104-
You can view the output from the previous run:
105-
106-
```bash
107-
snakeviz /the_folder_my_model_is_in/worker_0.profile
108-
```
109-
110-
Running the above command will launch a webpage on your local system.
111-
112-
The webpage has performance information about the training run that just finished.
113-
114-
Clicking on the various functions will expand them further.
115-
116-
You can use this "drilling in" to find spots of code that may be using lots of time when they should not be.
117-
118-
<img mathy-logo src="/img/snakeviz_profile.png" alt="View agent performance profile in Skakeviz">
96+
Learn about how to view output profiles on the [debugging page](/ml/debugging)
11997

12098
## Multiprocess A3C
12199

libraries/website/docs/ml/zero.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,18 @@ In this mode you can set breakpoints in the debugger to help diagnose errors.
2727
```python
2828
{!./snippets/ml/zero_debugging.py!}
2929
```
30+
31+
### Performance Profiling
32+
33+
The CLI Zero agent accepts `--profile` option along with `--num-workers=1` or the same config options when the API is used.
34+
35+
!!! warning "Limited to num_workers=1"
36+
37+
It wasn't immediately clear how to profile multiple processes that start and stop over time, so to profile zero you must
38+
specify a single worker process.
39+
40+
```python
41+
{!./snippets/ml/a3c_profiling.py!}
42+
```
43+
44+
Learn about how to view output profiles on the [debugging page](/ml/debugging)

0 commit comments

Comments
 (0)