Esempio n. 1
0
def master(group_name: str,
           sum_worker_number: int,
           multiply_worker_number: int,
           is_immediate: bool = False):
    """
    The main master logic includes initialize proxy and allocate jobs to workers.

    Args:
        group_name (str): Identifier for the group of all communication components,
        sum_worker_number (int): The number of sum workers,
        multiply_worker_number (int): The number of multiply workers,
        is_immediate (bool): If True, it will be an async mode; otherwise, it will be an sync mode.
            Async Mode: The proxy only returns the session id for sending messages. Based on the local task priority,
                        you can do something with high priority before receiving replied messages from peers.
            Sync Mode: It will block until the proxy returns all the replied messages.
    """
    proxy = Proxy(group_name=group_name,
                  component_type="master",
                  expected_peers={
                      "sum_worker": sum_worker_number,
                      "multiply_worker": multiply_worker_number
                  })

    sum_list = np.random.randint(0, 10, 100)
    multiple_list = np.random.randint(1, 10, 20)
    print("Generate random sum/multiple list with length 100.")

    # Assign sum tasks for summation workers.
    destination_payload_list = []
    for idx, peer in enumerate(proxy.peers_name["sum_worker"]):
        data_length_per_peer = int(
            len(sum_list) / len(proxy.peers_name["sum_worker"]))
        destination_payload_list.append(
            (peer, sum_list[idx * data_length_per_peer:(idx + 1) *
                            data_length_per_peer]))

    # Assign multiply tasks for multiplication workers.
    for idx, peer in enumerate(proxy.peers_name["multiply_worker"]):
        data_length_per_peer = int(
            len(multiple_list) / len(proxy.peers_name["multiply_worker"]))
        destination_payload_list.append(
            (peer, multiple_list[idx * data_length_per_peer:(idx + 1) *
                                 data_length_per_peer]))

    if is_immediate:
        session_ids = proxy.iscatter(
            tag="job",
            session_type=SessionType.TASK,
            destination_payload_list=destination_payload_list)
        # Do some tasks with higher priority here.
        replied_msgs = proxy.receive_by_id(session_ids, timeout=-1)
    else:
        replied_msgs = proxy.scatter(
            tag="job",
            session_type=SessionType.TASK,
            destination_payload_list=destination_payload_list,
            timeout=-1)

    sum_result, multiply_result = 0, 1
    for msg in replied_msgs:
        if msg.tag == "sum":
            print(
                f"{proxy.name} receive message from {msg.source} with the sum result {msg.payload}."
            )
            sum_result += msg.payload
        elif msg.tag == "multiply":
            print(
                f"{proxy.name} receive message from {msg.source} with the multiply result {msg.payload}."
            )
            multiply_result *= msg.payload

    # Check task result correction.
    assert (sum(sum_list) == sum_result)
    assert (np.prod(multiple_list) == multiply_result)
Esempio n. 2
0
class ActorProxy(object):
    """Actor proxy that manages a set of remote actors.

    Args:
        group_name (str): Identifier of the group to which the actor belongs. It must be the same group name
            assigned to the actors (and roll-out clients, if any).
        num_actors (int): Expected number of actors in the group identified by ``group_name``.
        update_trigger (str): Number or percentage of ``MessageTag.FINISHED`` messages required to trigger
            learner updates, i.e., model training.
        proxy_options (dict): Keyword parameters for the internal ``Proxy`` instance. See ``Proxy`` class
            for details. Defaults to None.
    """
    def __init__(
        self,
        group_name: str,
        num_actors: int,
        update_trigger: str = None,
        proxy_options: dict = None
    ):
        self.agent = None
        peers = {"actor": num_actors}
        if proxy_options is None:
            proxy_options = {}
        self._proxy = Proxy(group_name, "learner", peers, **proxy_options)
        self._actors = self._proxy.peers_name["actor"]  # remote actor ID's
        self._registry_table = RegisterTable(self._proxy.peers_name)
        if update_trigger is None:
            update_trigger = len(self._actors)
        self._registry_table.register_event_handler(
            f"actor:{MessageTag.FINISHED.value}:{update_trigger}", self._on_rollout_finish
        )
        self.logger = InternalLogger("ACTOR_PROXY")

    def roll_out(self, index: int, training: bool = True, model_by_agent: dict = None, exploration_params=None):
        """Collect roll-out data from remote actors.

        Args:
            index (int): Index of roll-out requests.
            training (bool): If true, the roll-out request is for training purposes.
            model_by_agent (dict): Models to be broadcast to remote actors for inference. Defaults to None.
            exploration_params: Exploration parameters to be used by the remote roll-out actors. Defaults to None.
        """
        payload = {
            PayloadKey.ROLLOUT_INDEX: index,
            PayloadKey.TRAINING: training,
            PayloadKey.MODEL: model_by_agent,
            PayloadKey.EXPLORATION_PARAMS: exploration_params
        }
        self._proxy.iscatter(MessageTag.ROLLOUT, SessionType.TASK, [(actor, payload) for actor in self._actors])
        self.logger.info(f"Sent roll-out requests to {self._actors} for ep-{index}")

        # Receive roll-out results from remote actors
        for msg in self._proxy.receive():
            if msg.payload[PayloadKey.ROLLOUT_INDEX] != index:
                self.logger.info(
                    f"Ignore a message of type {msg.tag} with ep {msg.payload[PayloadKey.ROLLOUT_INDEX]} "
                    f"(expected {index} or greater)"
                )
                continue
            if msg.tag == MessageTag.FINISHED:
                # If enough update messages have been received, call update() and break out of the loop to start
                # the next episode.
                result = self._registry_table.push(msg)
                if result:
                    env_metrics, details = result[0]
                    break

        return env_metrics, details

    def _on_rollout_finish(self, messages: List[Message]):
        metrics = {msg.source: msg.payload[PayloadKey.METRICS] for msg in messages}
        details = {msg.source: msg.payload[PayloadKey.DETAILS] for msg in messages}
        return metrics, details

    def terminate(self):
        """Tell the remote actors to exit."""
        self._proxy.ibroadcast(
            component_type="actor", tag=MessageTag.EXIT, session_type=SessionType.NOTIFICATION
        )
        self.logger.info("Exiting...")