Skip to content

Commit 52c004b

Browse files
Ervin TJonathan Harper
authored andcommitted
Fix training not quitting when play button is unchecked (#2376)
This fixes an issue where stopping the game when training in the Editor won't end training, due to the new asynchronous SubprocessEnvManager changes. Another minor change was made to move the `env_manager.close()` in TrainerController to the end of `start_learning` so that we are more likely to save the model if something goes wrong during the environment shutdown (this occurs sometimes on Windows machines).
1 parent efda758 commit 52c004b

File tree

4 files changed

+27
-9
lines changed

4 files changed

+27
-9
lines changed

ml-agents-envs/mlagents/envs/environment.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .brain import AllBrainInfo, BrainInfo, BrainParameters
1212
from .exception import (
1313
UnityEnvironmentException,
14+
UnityCommunicationException,
1415
UnityActionException,
1516
UnityTimeOutException,
1617
)
@@ -343,7 +344,7 @@ def reset(
343344
self._generate_reset_input(train_mode, config, custom_reset_parameters)
344345
)
345346
if outputs is None:
346-
raise KeyboardInterrupt
347+
raise UnityCommunicationException("Communicator has stopped.")
347348
rl_output = outputs.rl_output
348349
s = self._get_state(rl_output)
349350
self._global_done = s[1]
@@ -570,7 +571,7 @@ def step(
570571
with hierarchical_timer("communicator.exchange"):
571572
outputs = self.communicator.exchange(step_input)
572573
if outputs is None:
573-
raise KeyboardInterrupt
574+
raise UnityCommunicationException("Communicator has stopped.")
574575
rl_output = outputs.rl_output
575576
state = self._get_state(rl_output)
576577
self._global_done = state[1]

ml-agents-envs/mlagents/envs/exception.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ class UnityEnvironmentException(UnityException):
1919
pass
2020

2121

22+
class UnityCommunicationException(UnityException):
23+
"""
24+
Related to errors with the communicator.
25+
"""
26+
27+
pass
28+
29+
2230
class UnityActionException(UnityException):
2331
"""
2432
Related to errors with sending actions.

ml-agents-envs/mlagents/envs/subprocess_env_manager.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import cloudpickle
33

44
from mlagents.envs import UnityEnvironment
5+
from mlagents.envs.exception import UnityCommunicationException
56
from multiprocessing import Process, Pipe, Queue
67
from multiprocessing.connection import Connection
78
from queue import Empty as EmptyQueueException
@@ -47,14 +48,14 @@ def send(self, name: str, payload=None):
4748
cmd = EnvironmentCommand(name, payload)
4849
self.conn.send(cmd)
4950
except (BrokenPipeError, EOFError):
50-
raise KeyboardInterrupt
51+
raise UnityCommunicationException("UnityEnvironment worker: send failed.")
5152

5253
def recv(self) -> EnvironmentResponse:
5354
try:
5455
response: EnvironmentResponse = self.conn.recv()
5556
return response
5657
except (BrokenPipeError, EOFError):
57-
raise KeyboardInterrupt
58+
raise UnityCommunicationException("UnityEnvironment worker: recv failed.")
5859

5960
def close(self):
6061
try:
@@ -115,8 +116,9 @@ def _send_response(cmd_name, payload):
115116
_send_response("global_done", env.global_done)
116117
elif cmd.name == "close":
117118
break
118-
except KeyboardInterrupt:
119-
print("UnityEnvironment worker: keyboard interrupt")
119+
except (KeyboardInterrupt, UnityCommunicationException):
120+
print("UnityEnvironment worker: environment stopping.")
121+
step_queue.put(EnvironmentResponse("env_close", worker_id, None))
120122
finally:
121123
step_queue.close()
122124
env.close()
@@ -171,6 +173,10 @@ def step(self) -> List[StepInfo]:
171173
try:
172174
while True:
173175
step = self.step_queue.get_nowait()
176+
if step.name == "env_close":
177+
raise UnityCommunicationException(
178+
"At least one of the environments has closed."
179+
)
174180
self.env_workers[step.worker_id].waiting = False
175181
if step.worker_id not in step_workers:
176182
worker_steps.append(step)

ml-agents/mlagents/trainers/trainer_controller.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
from mlagents.envs import BrainParameters
1515
from mlagents.envs.env_manager import StepInfo
1616
from mlagents.envs.env_manager import EnvManager
17-
from mlagents.envs.exception import UnityEnvironmentException
17+
from mlagents.envs.exception import (
18+
UnityEnvironmentException,
19+
UnityCommunicationException,
20+
)
1821
from mlagents.envs.sampler_class import SamplerManager
1922
from mlagents.envs.timers import hierarchical_timer, get_timer_tree, timed
2023
from mlagents.trainers import Trainer, TrainerMetrics
@@ -302,15 +305,15 @@ def start_learning(
302305
# Final save Tensorflow model
303306
if global_step != 0 and self.train_model:
304307
self._save_model()
305-
except KeyboardInterrupt:
308+
except (KeyboardInterrupt, UnityCommunicationException):
306309
if self.train_model:
307310
self._save_model_when_interrupted()
308311
pass
309-
env_manager.close()
310312
if self.train_model:
311313
self._write_training_metrics()
312314
self._export_graph()
313315
self._write_timing_tree()
316+
env_manager.close()
314317

315318
def end_trainer_episodes(
316319
self, env: BaseUnityEnvironment, lessons_incremented: Dict[str, bool]

0 commit comments

Comments
 (0)