Exemplo n.º 1
0
def launch_executable(file_name: str, args: List[str]) -> subprocess.Popen:
    """
    Launches a Unity executable and returns the process handle for it.
    :param file_name: the name of the executable
    :param args: List of string that will be passed as command line arguments
    when launching the executable.
    """
    launch_string = validate_environment_path(file_name)
    if launch_string is None:
        raise UnityEnvironmentException(
            f"Couldn't launch the {file_name} environment. Provided filename does not match any environments."
        )
    else:
        get_logger(__name__).debug(
            f"This is the launch string {launch_string}")
        # Launch Unity environment
        subprocess_args = [launch_string] + args
        try:
            return subprocess.Popen(
                subprocess_args,
                # start_new_session=True means that signals to the parent python process
                # (e.g. SIGINT from keyboard interrupt) will not be sent to the new process on POSIX platforms.
                # This is generally good since we want the environment to have a chance to shutdown,
                # but may be undesirable in come cases; if so, we'll add a command-line toggle.
                # Note that on Windows, the CTRL_C signal will still be sent.
                start_new_session=True,
            )
        except PermissionError as perm:
            # This is likely due to missing read or execute permissions on file.
            raise UnityEnvironmentException(
                f"Error when trying to launch environment - make sure "
                f"permissions are set correctly. For example "
                f'"chmod -R 755 {launch_string}"') from perm
Exemplo n.º 2
0
 def process_side_channel_message(self, data: bytes) -> None:
     """
     Separates the data received from Python into individual messages for each
     registered side channel and calls on_message_received on them.
     :param data: The packed message sent by Unity
     """
     offset = 0
     while offset < len(data):
         try:
             channel_id = uuid.UUID(bytes_le=bytes(data[offset:offset +
                                                        16]))
             offset += 16
             message_len, = struct.unpack_from("<i", data, offset)
             offset = offset + 4
             message_data = data[offset:offset + message_len]
             offset = offset + message_len
         except (struct.error, ValueError, IndexError):
             raise UnityEnvironmentException(
                 "There was a problem reading a message in a SideChannel. "
                 "Please make sure the version of MLAgents in Unity is "
                 "compatible with the Python version.")
         if len(message_data) != message_len:
             raise UnityEnvironmentException(
                 "The message received by the side channel {0} was "
                 "unexpectedly short. Make sure your Unity Environment "
                 "sending side channel data properly.".format(channel_id))
         if channel_id in self._side_channels_dict:
             incoming_message = IncomingMessage(message_data)
             self._side_channels_dict[channel_id].on_message_received(
                 incoming_message)
         else:
             get_logger(__name__).warning(
                 f"Unknown side channel data received. Channel type: {channel_id}."
             )
Exemplo n.º 3
0
def validate_environment_path(env_path: str) -> Optional[str]:
    """
    Strip out executable extensions of the env_path
    :param env_path: The path to the executable
    """
    env_path = (env_path.strip().replace(".app", "").replace(
        ".exe", "").replace(".x86_64", "").replace(".x86", ""))
    true_filename = os.path.basename(os.path.normpath(env_path))
    get_logger(__name__).debug(f"The true file name is {true_filename}")

    if not (glob.glob(env_path) or glob.glob(env_path + ".*")):
        return None

    cwd = os.getcwd()
    launch_string = None
    true_filename = os.path.basename(os.path.normpath(env_path))
    if get_platform() == "linux" or get_platform() == "linux2":
        candidates = glob.glob(os.path.join(cwd, env_path) + ".x86_64")
        if len(candidates) == 0:
            candidates = glob.glob(os.path.join(cwd, env_path) + ".x86")
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".x86_64")
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".x86")
        if len(candidates) > 0:
            launch_string = candidates[0]

    elif get_platform() == "darwin":
        candidates = glob.glob(
            os.path.join(cwd, env_path + ".app", "Contents", "MacOS",
                         true_filename))
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(env_path + ".app", "Contents", "MacOS",
                             true_filename))
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(cwd, env_path + ".app", "Contents", "MacOS", "*"))
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(env_path + ".app", "Contents", "MacOS", "*"))
        if len(candidates) > 0:
            launch_string = candidates[0]
    elif get_platform() == "win32":
        candidates = glob.glob(os.path.join(cwd, env_path + ".exe"))
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".exe")
        if len(candidates) == 0:
            # Look for e.g. 3DBall\UnityEnvironment.exe
            crash_handlers = set(
                glob.glob(os.path.join(cwd, env_path,
                                       "UnityCrashHandler*.exe")))
            candidates = [
                c for c in glob.glob(os.path.join(cwd, env_path, "*.exe"))
                if c not in crash_handlers
            ]
        if len(candidates) > 0:
            launch_string = candidates[0]
    return launch_string
Exemplo n.º 4
0
def validate_environment_path(env_path: str) -> Optional[str]:
    """
    Strip out executable extensions of the env_path
    :param env_path: The path to the executable
    """
    env_path = (
        env_path.strip()
        .replace(".app", "")
        .replace(".exe", "")
        .replace(".x86_64", "")
        .replace(".x86", "")
    )
    true_filename = os.path.basename(os.path.normpath(env_path))
    get_logger(__name__).debug("The true file name is {}".format(true_filename))

    if not (glob.glob(env_path) or glob.glob(env_path + ".*")):
        return None

    cwd = os.getcwd()
    launch_string = None
    true_filename = os.path.basename(os.path.normpath(env_path))
    if platform == "linux" or platform == "linux2":
        candidates = glob.glob(os.path.join(cwd, env_path) + ".x86_64")
        if len(candidates) == 0:
            candidates = glob.glob(os.path.join(cwd, env_path) + ".x86")
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".x86_64")
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".x86")
        if len(candidates) > 0:
            launch_string = candidates[0]

    elif platform == "darwin":
        candidates = glob.glob(
            os.path.join(cwd, env_path + ".app", "Contents", "MacOS", true_filename)
        )
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(env_path + ".app", "Contents", "MacOS", true_filename)
            )
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(cwd, env_path + ".app", "Contents", "MacOS", "*")
            )
        if len(candidates) == 0:
            candidates = glob.glob(
                os.path.join(env_path + ".app", "Contents", "MacOS", "*")
            )
        if len(candidates) > 0:
            launch_string = candidates[0]
    elif platform == "win32":
        candidates = glob.glob(os.path.join(cwd, env_path + ".exe"))
        if len(candidates) == 0:
            candidates = glob.glob(env_path + ".exe")
        if len(candidates) > 0:
            launch_string = candidates[0]
    return launch_string
Exemplo n.º 5
0
    def __init__(
        self,
        trainer_factory: TrainerFactory,
        output_path: str,
        run_id: str,
        param_manager: EnvironmentParameterManager,
        train: bool,
        training_seed: int,
    ):
        """
        :param output_path: Path to save the model.
        :param summaries_dir: Folder to save training summaries.
        :param run_id: The sub-directory name for model and summary statistics
        :param param_manager: EnvironmentParameterManager object which stores information about all
        environment parameters.
        :param train: Whether to train model, or only run inference.
        :param training_seed: Seed to use for Numpy and Tensorflow random number generation.
        :param threaded: Whether or not to run trainers in a separate thread. Disable for testing/debugging.
        """
        self.trainers: Dict[str, Trainer] = {}
        self.brain_name_to_identifier: Dict[str, Set] = defaultdict(set)
        self.trainer_factory = trainer_factory
        self.output_path = output_path
        self.logger = get_logger(__name__)
        self.run_id = run_id
        self.train_model = train
        self.param_manager = param_manager
        self.ghost_controller = self.trainer_factory.ghost_controller
        self.registered_behavior_ids: Set[str] = set()

        self.trainer_threads: List[threading.Thread] = []
        self.kill_trainers = False
        np.random.seed(training_seed)
        tf.set_random_seed(training_seed)
    def __init__(self, trainer_factory: TrainerFactory, output_path: str,
                 run_id: str, meta_curriculum: Optional[MetaCurriculum],
                 train: bool, training_seed: int,
                 sampler_manager: SamplerManager,
                 resampling_interval: Optional[int]):
        """
        :param output_path: Path to save the model.
        :param summaries_dir: Folder to save training summaries.
        :param run_id: The sub-directory name for model and summary statistics
        :param meta_curriculum: MetaCurriculum object which stores information about all curricula.
        :param train: Whether to train model, or only run inference.
        :param training_seed: Seed to use for Numpy and Tensorflow random number generation.
        :param sampler_manager: SamplerManager object handles samplers for resampling the reset parameters.
        :param resampling_interval: Specifies number of simulation steps after which reset parameters are resampled.
        :param threaded: Whether or not to run trainers in a separate thread. Disable for testing/debugging.
        """
        self.trainers: Dict[str, Trainer] = {}
        self.brain_name_to_identifier: Dict[str, Set] = defaultdict(set)
        self.trainer_factory = trainer_factory
        self.output_path = output_path
        self.logger = get_logger(__name__)
        self.run_id = run_id
        self.train_model = train
        self.meta_curriculum = meta_curriculum
        self.sampler_manager = sampler_manager
        self.resampling_interval = resampling_interval
        self.ghost_controller = self.trainer_factory.ghost_controller

        self.trainer_threads: List[threading.Thread] = []
        self.kill_trainers = False
        np.random.seed(training_seed)
        tf.set_random_seed(training_seed)
Exemplo n.º 7
0
 def __init__(
     self,
     trainer_factory: TrainerFactory,
     model_path: str,
     summaries_dir: str,
     run_id: str,
     save_freq: int,
     meta_curriculum: Optional[MetaCurriculum],
     train: bool,
     training_seed: int,
     sampler_manager: SamplerManager,
     resampling_interval: Optional[int],
 ):
     """
     :param model_path: Path to save the model.
     :param summaries_dir: Folder to save training summaries.
     :param run_id: The sub-directory name for model and summary statistics
     :param save_freq: Frequency at which to save model
     :param meta_curriculum: MetaCurriculum object which stores information about all curricula.
     :param train: Whether to train model, or only run inference.
     :param training_seed: Seed to use for Numpy and Tensorflow random number generation.
     :param sampler_manager: SamplerManager object handles samplers for resampling the reset parameters.
     :param resampling_interval: Specifies number of simulation steps after which reset parameters are resampled.
     """
     self.trainers: Dict[str, Trainer] = {}
     self.brain_name_to_identifier: Dict[str, Set] = defaultdict(set)
     self.trainer_factory = trainer_factory
     self.model_path = model_path
     self.summaries_dir = summaries_dir
     self.logger = get_logger(__name__)
     self.run_id = run_id
     self.save_freq = save_freq
     self.train_model = train
     self.meta_curriculum = meta_curriculum
     self.sampler_manager = sampler_manager
     self.resampling_interval = resampling_interval
     np.random.seed(training_seed)
     tf.set_random_seed(training_seed)
Exemplo n.º 8
0
from mlagents_envs.communicator_objects.unity_rl_input_pb2 import UnityRLInputProto
from mlagents_envs.communicator_objects.unity_rl_output_pb2 import UnityRLOutputProto
from mlagents_envs.communicator_objects.agent_action_pb2 import AgentActionProto
from mlagents_envs.communicator_objects.unity_output_pb2 import UnityOutputProto
from mlagents_envs.communicator_objects.capabilities_pb2 import UnityRLCapabilitiesProto
from mlagents_envs.communicator_objects.unity_rl_initialization_input_pb2 import (
    UnityRLInitializationInputProto,
)

from mlagents_envs.communicator_objects.unity_input_pb2 import UnityInputProto

from .rpc_communicator import RpcCommunicator
import signal

logger = get_logger(__name__)


class UnityEnvironment(BaseEnv):
    # Communication protocol version.
    # When connecting to C#, this must be compatible with Academy.k_ApiVersion.
    # We follow semantic versioning on the communication version, so existing
    # functionality will work as long the major versions match.
    # This should be changed whenever a change is made to the communication protocol.
    API_VERSION = "1.0.0"

    # Default port that the editor listens on. If an environment executable
    # isn't specified, this port will be used.
    DEFAULT_EDITOR_PORT = 5004

    # Default base port for environments. Each environment will be offset from this
Exemplo n.º 9
0
from typing import Set, Dict, Any, TextIO
import os
import yaml
from mlagents.trainers.exception import TrainerConfigError
from mlagents_envs.environment import UnityEnvironment
import argparse
from mlagents_envs import logging_util

logger = logging_util.get_logger(__name__)


class RaiseRemovedWarning(argparse.Action):
    """
    Internal custom Action to raise warning when argument is called.
    """
    def __init__(self, nargs=0, **kwargs):
        super().__init__(nargs=nargs, **kwargs)

    def __call__(self, arg_parser, namespace, values, option_string=None):
        logger.warning(
            f"The command line argument {option_string} was removed.")


class DetectDefault(argparse.Action):
    """
    Internal custom Action to help detect arguments that aren't default.
    """

    non_default_args: Set[str] = set()

    def __call__(self, arg_parser, namespace, values, option_string=None):
Exemplo n.º 10
0
def test_set_logging_level():
    for level in [INFO, ERROR, FATAL, CRITICAL, DEBUG]:
        set_log_level(level)
        assert get_logger("test").level == level