Beispiel #1
0
def test_engine_configuration():
    sender = EngineConfigurationChannel()
    # We use a raw bytes channel to interpred the data
    receiver = RawBytesChannel(sender.channel_id)

    config = EngineConfig.default_config()
    sender.set_configuration(config)
    data = SideChannelManager([sender]).generate_side_channel_messages()
    SideChannelManager([receiver]).process_side_channel_message(data)

    received_data = receiver.get_and_clear_received_messages()
    assert len(received_data) == 5  # 5 different messages one for each setting

    sent_time_scale = 4.5
    sender.set_configuration_parameters(time_scale=sent_time_scale)

    data = SideChannelManager([sender]).generate_side_channel_messages()
    SideChannelManager([receiver]).process_side_channel_message(data)

    message = IncomingMessage(receiver.get_and_clear_received_messages()[0])
    message.read_int32()
    time_scale = message.read_float32()
    assert time_scale == sent_time_scale

    with pytest.raises(UnitySideChannelException):
        sender.set_configuration_parameters(width=None, height=42)

    with pytest.raises(UnityCommunicationException):
        # try to send data to the EngineConfigurationChannel
        sender.set_configuration_parameters(time_scale=sent_time_scale)
        data = SideChannelManager([sender]).generate_side_channel_messages()
        SideChannelManager([sender]).process_side_channel_message(data)
Beispiel #2
0
 def _create_engine_channel(self):
     engine_channel = EngineConfigurationChannel()
     engine_config = EngineConfig(80, 80, 1, 4.0, 30 *
                                  4) if self.train_mode else EngineConfig(
                                      1280, 720, 1, 1.0, 60)
     engine_channel.set_configuration(engine_config)
     return engine_channel
Beispiel #3
0
def _make_unity_env(
        env_path: Optional[str] = None,
        port: int = UnityEnvironment.BASE_ENVIRONMENT_PORT,
        seed: int = -1,
        env_args: Optional[List[str]] = None,
        engine_config: Optional[EngineConfig] = None,
        side_channels: Optional[List[SideChannel]] = None) -> UnityEnvironment:
    """
    Create a UnityEnvironment.
    """
    # Use Unity Editor if env file is not provided.
    if env_path is None:
        port = UnityEnvironment.DEFAULT_EDITOR_PORT
    else:
        launch_string = UnityEnvironment.validate_environment_path(env_path)
        if launch_string is None:
            raise UnityEnvironmentException(
                f"Couldn't launch the {env_path} environment. Provided filename does not match any environments."
            )
        logger.info(f"Starting environment from {env_path}.")

    # Configure Unity Engine.
    if engine_config is None:
        engine_config = EngineConfig.default_config()

    engine_configuration_channel = EngineConfigurationChannel()
    engine_configuration_channel.set_configuration(engine_config)

    if side_channels is None:
        side_channels = [engine_configuration_channel]
    else:
        side_channels.append(engine_configuration_channel)

    # Find an available port to connect to Unity environment.
    while True:
        try:
            env = UnityEnvironment(
                file_name=env_path,
                seed=seed,
                base_port=port,
                args=env_args,
                side_channels=side_channels,
            )
        except UnityWorkerInUseException:
            logger.debug(f"port {port} in use.")
            port += 1
        else:
            logger.info(f"Connected to environment using port {port}.")
            break

    return env
    def create_engine_config_side_channel(self) -> EngineConfigurationChannel:

        if self.play or self.inference:
            engine_configuration = EngineConfig(
                width=self.WINDOW_WIDTH.play,
                height=self.WINDOW_HEIGHT.play,
                quality_level=self.QUALITY_LEVEL.play,
                time_scale=self.TIMESCALE.play,
                target_frame_rate=self.TARGET_FRAME_RATE.play,
            )
        else:
            engine_configuration = EngineConfig(
                width=self.WINDOW_WIDTH.train,
                height=self.WINDOW_HEIGHT.train,
                quality_level=self.QUALITY_LEVEL.train,
                time_scale=self.TIMESCALE.train,
                target_frame_rate=self.TARGET_FRAME_RATE.train,
            )
        engine_configuration_channel = EngineConfigurationChannel()
        engine_configuration_channel.set_configuration(engine_configuration)
        return engine_configuration_channel
def worker(
    parent_conn: Connection,
    step_queue: Queue,
    pickled_env_factory: str,
    worker_id: int,
    engine_configuration: EngineConfig,
) -> None:
    env_factory: Callable[[int, List[SideChannel]],
                          UnityEnvironment] = cloudpickle.loads(
                              pickled_env_factory)
    shared_float_properties = FloatPropertiesChannel()
    engine_configuration_channel = EngineConfigurationChannel()
    engine_configuration_channel.set_configuration(engine_configuration)
    stats_channel = StatsSideChannel()
    env: BaseEnv = env_factory(
        worker_id,
        [shared_float_properties, engine_configuration_channel, stats_channel],
    )

    def _send_response(cmd_name, payload):
        parent_conn.send(EnvironmentResponse(cmd_name, worker_id, payload))

    def _generate_all_results() -> AllStepResult:
        all_step_result: AllStepResult = {}
        for brain_name in env.get_agent_groups():
            all_step_result[brain_name] = env.get_step_result(brain_name)
        return all_step_result

    def external_brains():
        result = {}
        for brain_name in env.get_agent_groups():
            result[brain_name] = group_spec_to_brain_parameters(
                brain_name, env.get_agent_group_spec(brain_name))
        return result

    try:
        while True:
            cmd: EnvironmentCommand = parent_conn.recv()
            if cmd.name == "step":
                all_action_info = cmd.payload
                for brain_name, action_info in all_action_info.items():
                    if len(action_info.action) != 0:
                        env.set_actions(brain_name, action_info.action)
                env.step()
                all_step_result = _generate_all_results()
                # The timers in this process are independent from all the processes and the "main" process
                # So after we send back the root timer, we can safely clear them.
                # Note that we could randomly return timers a fraction of the time if we wanted to reduce
                # the data transferred.
                # TODO get gauges from the workers and merge them in the main process too.
                env_stats = stats_channel.get_and_reset_stats()
                step_response = StepResponse(all_step_result, get_timer_root(),
                                             env_stats)
                step_queue.put(
                    EnvironmentResponse("step", worker_id, step_response))
                reset_timers()
            elif cmd.name == "external_brains":
                _send_response("external_brains", external_brains())
            elif cmd.name == "get_properties":
                reset_params = shared_float_properties.get_property_dict_copy()
                _send_response("get_properties", reset_params)
            elif cmd.name == "reset":
                for k, v in cmd.payload.items():
                    shared_float_properties.set_property(k, v)
                env.reset()
                all_step_result = _generate_all_results()
                _send_response("reset", all_step_result)
            elif cmd.name == "close":
                break
    except (KeyboardInterrupt, UnityCommunicationException,
            UnityTimeOutException):
        logger.info(
            f"UnityEnvironment worker {worker_id}: environment stopping.")
        step_queue.put(EnvironmentResponse("env_close", worker_id, None))
    finally:
        # If this worker has put an item in the step queue that hasn't been processed by the EnvManager, the process
        # will hang until the item is processed. We avoid this behavior by using Queue.cancel_join_thread()
        # See https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue.cancel_join_thread for
        # more info.
        logger.debug(f"UnityEnvironment worker {worker_id} closing.")
        step_queue.cancel_join_thread()
        step_queue.close()
        env.close()
        logger.debug(f"UnityEnvironment worker {worker_id} done.")
def worker(
    parent_conn: Connection,
    step_queue: Queue,
    pickled_env_factory: str,
    worker_id: int,
    engine_configuration: EngineConfig,
    log_level: int = logging_util.INFO,
) -> None:
    env_factory: Callable[
        [int, List[SideChannel]], UnityEnvironment
    ] = cloudpickle.loads(pickled_env_factory)
    env_parameters = EnvironmentParametersChannel()
    engine_configuration_channel = EngineConfigurationChannel()
    engine_configuration_channel.set_configuration(engine_configuration)
    stats_channel = StatsSideChannel()
    env: BaseEnv = None
    # Set log level. On some platforms, the logger isn't common with the
    # main process, so we need to set it again.
    logging_util.set_log_level(log_level)

    def _send_response(cmd_name: EnvironmentCommand, payload: Any) -> None:
        parent_conn.send(EnvironmentResponse(cmd_name, worker_id, payload))

    def _generate_all_results() -> AllStepResult:
        all_step_result: AllStepResult = {}
        for brain_name in env.behavior_specs:
            all_step_result[brain_name] = env.get_steps(brain_name)
        return all_step_result

    try:
        env = env_factory(
            worker_id, [env_parameters, engine_configuration_channel, stats_channel]
        )
        while True:
            req: EnvironmentRequest = parent_conn.recv()
            if req.cmd == EnvironmentCommand.STEP:
                all_action_info = req.payload
                for brain_name, action_info in all_action_info.items():
                    if len(action_info.action) != 0:
                        env.set_actions(brain_name, action_info.action)
                env.step()
                all_step_result = _generate_all_results()
                # The timers in this process are independent from all the processes and the "main" process
                # So after we send back the root timer, we can safely clear them.
                # Note that we could randomly return timers a fraction of the time if we wanted to reduce
                # the data transferred.
                # TODO get gauges from the workers and merge them in the main process too.
                env_stats = stats_channel.get_and_reset_stats()
                step_response = StepResponse(
                    all_step_result, get_timer_root(), env_stats
                )
                step_queue.put(
                    EnvironmentResponse(
                        EnvironmentCommand.STEP, worker_id, step_response
                    )
                )
                reset_timers()
            elif req.cmd == EnvironmentCommand.BEHAVIOR_SPECS:
                _send_response(EnvironmentCommand.BEHAVIOR_SPECS, env.behavior_specs)
            elif req.cmd == EnvironmentCommand.ENVIRONMENT_PARAMETERS:
                for k, v in req.payload.items():
                    if isinstance(v, ParameterRandomizationSettings):
                        v.apply(k, env_parameters)
            elif req.cmd == EnvironmentCommand.RESET:
                env.reset()
                all_step_result = _generate_all_results()
                _send_response(EnvironmentCommand.RESET, all_step_result)
            elif req.cmd == EnvironmentCommand.CLOSE:
                break
    except (
        KeyboardInterrupt,
        UnityCommunicationException,
        UnityTimeOutException,
        UnityEnvironmentException,
        UnityCommunicatorStoppedException,
    ) as ex:
        logger.info(f"UnityEnvironment worker {worker_id}: environment stopping.")
        step_queue.put(
            EnvironmentResponse(EnvironmentCommand.ENV_EXITED, worker_id, ex)
        )
        _send_response(EnvironmentCommand.ENV_EXITED, ex)
    finally:
        # If this worker has put an item in the step queue that hasn't been processed by the EnvManager, the process
        # will hang until the item is processed. We avoid this behavior by using Queue.cancel_join_thread()
        # See https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue.cancel_join_thread for
        # more info.
        logger.debug(f"UnityEnvironment worker {worker_id} closing.")
        step_queue.cancel_join_thread()
        step_queue.close()
        if env is not None:
            env.close()
        logger.debug(f"UnityEnvironment worker {worker_id} done.")
Beispiel #7
0
def worker(
    parent_conn: Connection,
    step_queue: Queue,
    pickled_env_factory: str,
    worker_id: int,
    run_options: RunOptions,
    log_level: int = logging_util.INFO,
) -> None:
    env_factory: Callable[
        [int, List[SideChannel]], UnityEnvironment
    ] = cloudpickle.loads(restricted_loads(pickled_env_factory))
    env_parameters = EnvironmentParametersChannel()

    engine_config = EngineConfig(
        width=run_options.engine_settings.width,
        height=run_options.engine_settings.height,
        quality_level=run_options.engine_settings.quality_level,
        time_scale=run_options.engine_settings.time_scale,
        target_frame_rate=run_options.engine_settings.target_frame_rate,
        capture_frame_rate=run_options.engine_settings.capture_frame_rate,
    )
    engine_configuration_channel = EngineConfigurationChannel()
    engine_configuration_channel.set_configuration(engine_config)

    stats_channel = StatsSideChannel()
    training_analytics_channel: Optional[TrainingAnalyticsSideChannel] = None
    if worker_id == 0:
        training_analytics_channel = TrainingAnalyticsSideChannel()
    env: UnityEnvironment = None
    # Set log level. On some platforms, the logger isn't common with the
    # main process, so we need to set it again.
    logging_util.set_log_level(log_level)

    def _send_response(cmd_name: EnvironmentCommand, payload: Any) -> None:
        parent_conn.send(EnvironmentResponse(cmd_name, worker_id, payload))

    def _generate_all_results() -> AllStepResult:
        all_step_result: AllStepResult = {}
        for brain_name in env.behavior_specs:
            all_step_result[brain_name] = env.get_steps(brain_name)
        return all_step_result

    try:
        side_channels = [env_parameters, engine_configuration_channel, stats_channel]
        if training_analytics_channel is not None:
            side_channels.append(training_analytics_channel)

        env = env_factory(worker_id, side_channels)
        if (
            not env.academy_capabilities
            or not env.academy_capabilities.trainingAnalytics
        ):
            # Make sure we don't try to send training analytics if the environment doesn't know how to process
            # them. This wouldn't be catastrophic, but would result in unknown SideChannel UUIDs being used.
            training_analytics_channel = None
        if training_analytics_channel:
            training_analytics_channel.environment_initialized(run_options)

        while True:
            req: EnvironmentRequest = parent_conn.recv()
            if req.cmd == EnvironmentCommand.STEP:
                all_action_info = req.payload
                for brain_name, action_info in all_action_info.items():
                    if len(action_info.agent_ids) > 0:
                        env.set_actions(brain_name, action_info.env_action)
                env.step()
                all_step_result = _generate_all_results()
                # The timers in this process are independent from all the processes and the "main" process
                # So after we send back the root timer, we can safely clear them.
                # Note that we could randomly return timers a fraction of the time if we wanted to reduce
                # the data transferred.
                # TODO get gauges from the workers and merge them in the main process too.
                env_stats = stats_channel.get_and_reset_stats()
                step_response = StepResponse(
                    all_step_result, get_timer_root(), env_stats
                )
                step_queue.put(
                    EnvironmentResponse(
                        EnvironmentCommand.STEP, worker_id, step_response
                    )
                )
                reset_timers()
            elif req.cmd == EnvironmentCommand.BEHAVIOR_SPECS:
                _send_response(EnvironmentCommand.BEHAVIOR_SPECS, env.behavior_specs)
            elif req.cmd == EnvironmentCommand.ENVIRONMENT_PARAMETERS:
                for k, v in req.payload.items():
                    if isinstance(v, ParameterRandomizationSettings):
                        v.apply(k, env_parameters)
            elif req.cmd == EnvironmentCommand.TRAINING_STARTED:
                behavior_name, trainer_config = req.payload
                if training_analytics_channel:
                    training_analytics_channel.training_started(
                        behavior_name, trainer_config
                    )
            elif req.cmd == EnvironmentCommand.RESET:
                env.reset()
                all_step_result = _generate_all_results()
                _send_response(EnvironmentCommand.RESET, all_step_result)
            elif req.cmd == EnvironmentCommand.CLOSE:
                break
    except (
        KeyboardInterrupt,
        UnityCommunicationException,
        UnityTimeOutException,
        UnityEnvironmentException,
        UnityCommunicatorStoppedException,
    ) as ex:
        logger.info(f"UnityEnvironment worker {worker_id}: environment stopping.")
        step_queue.put(
            EnvironmentResponse(EnvironmentCommand.ENV_EXITED, worker_id, ex)
        )
        _send_response(EnvironmentCommand.ENV_EXITED, ex)
    except Exception as ex:
        logger.exception(
            f"UnityEnvironment worker {worker_id}: environment raised an unexpected exception."
        )
        step_queue.put(
            EnvironmentResponse(EnvironmentCommand.ENV_EXITED, worker_id, ex)
        )
        _send_response(EnvironmentCommand.ENV_EXITED, ex)
    finally:
        logger.debug(f"UnityEnvironment worker {worker_id} closing.")
        if env is not None:
            env.close()
        logger.debug(f"UnityEnvironment worker {worker_id} done.")
        parent_conn.close()
        step_queue.put(EnvironmentResponse(EnvironmentCommand.CLOSED, worker_id, None))
        step_queue.close()
Beispiel #8
0
class StorageEnvController(ConFormSimUnityEnvController):

    _BASE_PORT = 5004

    def __init__(self, config=DEFAULT_ENV_CONFIG):
        """
        Environment initialization
        :param config: Configuration of the environment.
        """

        # create side channels
        self.env_param_channel = EnvironmentParametersChannel()
        self.engine_channel = EngineConfigurationChannel()
        self.color_pool_channel = IntListPropertiesChannel()

        side_channels = [
            self.env_param_channel,
            self.engine_channel,
            self.color_pool_channel,
        ]

        # flag whether the config has been apllied to the environment
        self.is_already_initialized = False
        # create environment with config and side channels
        super().__init__(config,
                         DEFAULT_ENV_CONFIG,
                         side_channels=side_channels)

    def apply_config(self):
        # set FloatProperties
        grid_size_x = self.config.get("grid_size_x")
        if not isinstance(grid_size_x, list) or len(grid_size_x) != 2:
            raise ("The provided grid_size_x parameter is no list of type "
                   "[min, max]. Please correct this.")
        grid_size_y = self.config.get("grid_size_y")
        if not isinstance(grid_size_y, list) or len(grid_size_y) != 2:
            raise ("The provided grid_size_y parameter is no list of type "
                   "[min, max]. Please correct this.")

        vis_obs_size = self.config.get("vis_obs_size")
        if not isinstance(vis_obs_size, list) or len(vis_obs_size) != 2:
            raise ("The provided vis_obs_size parameter is no list of type "
                   "[min, max]. Please correct this.")

        base_size_x = self.config.get("base_size_x")
        if not isinstance(base_size_x, list) or len(base_size_x) != 2:
            raise ("The provided base_size_x parameter is no list of type "
                   "[min, max]. Please correct this.")
        base_size_y = self.config.get("base_size_x")
        if not isinstance(base_size_x, list) or len(base_size_x) != 2:
            raise ("The provided base_size_x parameter is no list of type "
                   "[min, max]. Please correct this.")
        num_per_base_type = self.config.get("num_per_base_type")
        if not isinstance(num_per_base_type,
                          list) or len(num_per_base_type) != 2:
            raise (
                "The provided num_per_base_type parameter is no list of type "
                "[min, max]. Please correct this.")

        num_per_item = self.config.get("num_per_item")
        if not isinstance(num_per_item, list) or len(num_per_item) != 2:
            raise ("The provided num_per_item parameter is no list of type "
                   "[min, max]. Please correct this.")

        color_pool = self.config.get("color_pool")
        if not isinstance(color_pool, list):
            raise ("The provided color_pool parameter is not of type list. "
                   "Please correct this.")

        camera_type = self.config.get("camera_type")
        camera_type_f: float = CAMERA_TYPES[camera_type] or 0.0

        # set properties in reset channel
        self.env_param_channel.set_float_parameter("minGridSizeX",
                                                   grid_size_x[0])
        self.env_param_channel.set_float_parameter("maxGridSizeX",
                                                   grid_size_x[1])
        self.env_param_channel.set_float_parameter("minGridSizeY",
                                                   grid_size_y[0])
        self.env_param_channel.set_float_parameter("maxGridSizeY",
                                                   grid_size_y[1])
        self.env_param_channel.set_float_parameter("cameraType", camera_type_f)
        # area settings
        # check if num train areas should be set
        if self.is_already_initialized:
            print("You're trying to change the number of "
                  "train areas, during runtime. This is only possible at "
                  "initialization.")
        else:
            self.env_param_channel.set_float_parameter(
                "numTrainAreas", self.config.get("num_train_areas"))

        self.env_param_channel.set_float_parameter(
            "numBaseTypesToUse", self.config.get("num_base_types"))
        self.env_param_channel.set_float_parameter("numberPerBaseTypeMax",
                                                   num_per_base_type[1])
        self.env_param_channel.set_float_parameter("numberPerBaseTypeMin",
                                                   num_per_base_type[0])
        self.env_param_channel.set_float_parameter("baseSizeXMax",
                                                   base_size_x[1])
        self.env_param_channel.set_float_parameter("baseSizeXMin",
                                                   base_size_x[0])
        self.env_param_channel.set_float_parameter("baseSizeZMax",
                                                   base_size_y[1])
        self.env_param_channel.set_float_parameter("baseSizeZMin",
                                                   base_size_y[0])
        self.env_param_channel.set_float_parameter(
            "baseInCornersOnly",
            1 if self.config.get("base_in_corners_only") else 0)
        self.env_param_channel.set_float_parameter(
            "boxesVanish", 1 if self.config.get("boxes_vanish") else 0)
        self.env_param_channel.set_float_parameter(
            "boxesNeedDrop", 1 if self.config.get("boxes_need_drop") else 0)
        self.env_param_channel.set_float_parameter(
            "sparseReward", 1 if self.config.get("sparse_reward_only") else 0)
        # color settings
        self.env_param_channel.set_float_parameter(
            "noBaseFillColor",
            1 if self.config.get("no_base_fill_color") else 0)
        self.env_param_channel.set_float_parameter(
            "brighterBases", 1 if self.config.get("brighter_bases") else 0)
        self.env_param_channel.set_float_parameter(
            "full_base_line", 1 if self.config.get("fullBaseLine") else 0)
        # item settings
        self.env_param_channel.set_float_parameter(
            "numItemTypesToUse", self.config.get("num_item_types"))
        self.env_param_channel.set_float_parameter("numberPerItemTypeMax",
                                                   num_per_item[1])
        self.env_param_channel.set_float_parameter("numberPerItemTypeMin",
                                                   num_per_item[0])
        # general settings
        self.env_param_channel.set_float_parameter(
            "noDisplay", 1 if self.config.get("no_display") else 0)
        self.env_param_channel.set_float_parameter("visObsWidth",
                                                   vis_obs_size[0])
        self.env_param_channel.set_float_parameter("visObsHeight",
                                                   vis_obs_size[1])
        self.env_param_channel.set_float_parameter(
            "useVisual", 1 if self.config.get("use_visual")
            and not self.config.get("use_object_property_camera") else 0)
        self.env_param_channel.set_float_parameter(
            "useRayPerception",
            1 if self.config.get("use_ray_perception") else 0)
        self.env_param_channel.set_float_parameter(
            "useObjectPropertyCamera",
            1 if self.config.get("use_object_property_camera") else 0)
        self.env_param_channel.set_float_parameter(
            "maxSteps", self.config.get("max_steps"))
        self.env_param_channel.set_float_parameter(
            "taskLevel", self.config.get("task_level"))

        # Read engine config
        engine_config = self.config.get("engine_config")
        # Configure the Engine
        engine_config = EngineConfig(
            width=engine_config.get("window_width"),
            height=engine_config.get("window_height"),
            quality_level=engine_config.get("quality_level"),
            time_scale=engine_config.get("sim_speed"),
            target_frame_rate=engine_config.get("target_frame_rate"),
            capture_frame_rate=60)
        self.engine_channel.set_configuration(engine_config)

        # set list properties
        self.color_pool_channel.set_property("colorPool",
                                             self.config.get("color_pool"))
        self.is_already_initialized = True