From 936cd3b1b7674063f1259d93c9672154cb57160f Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:23:31 -0400 Subject: [PATCH 01/38] init --- .../distributed_replay_buffer.py | 0 .../distributed_replay_buffer_slicesampler.py | 279 ++++++++++++++++++ 2 files changed, 279 insertions(+) rename examples/{distributed/replay_buffers => replay-buffers}/distributed_replay_buffer.py (100%) create mode 100644 examples/replay-buffers/distributed_replay_buffer_slicesampler.py diff --git a/examples/distributed/replay_buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py similarity index 100% rename from examples/distributed/replay_buffers/distributed_replay_buffer.py rename to examples/replay-buffers/distributed_replay_buffer.py diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py new file mode 100644 index 00000000000..494aff8262b --- /dev/null +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -0,0 +1,279 @@ +""" +Example use of a distributed replay buffer +========================================== + +To launch this script, run + +```bash +$ # In terminal0: Trainer node +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=0 +$ # In terminal1: Replay buffer node +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=1 +$ # In terminal2 to N: Collector nodes +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=2 + +``` +""" + +import argparse +import os +import random +import sys +import time + +import torch +import torch.distributed.rpc as rpc +from tensordict import TensorDict +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger +from torchrl.data.replay_buffers import RemoteTensorDictReplayBuffer +from torchrl.data.replay_buffers.samplers import SliceSampler +from torchrl.data.replay_buffers.storages import LazyMemmapStorage +from torchrl.data.replay_buffers.writers import RoundRobinWriter + +RETRY_LIMIT = 2 +RETRY_DELAY_SECS = 3 +REPLAY_BUFFER_NODE = "ReplayBuffer" +TRAINER_NODE = "Trainer" + +parser = argparse.ArgumentParser( + description="RPC Replay Buffer Example", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +parser.add_argument( + "--rank", + type=int, + default=-1, + help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", +) + + +class CollectorNode: + """Data collector node responsible for collecting experiences used for learning. + + Args: + replay_buffer (rpc.RRef): the RRef associated with the construction of the replay buffer + frames_per_batch (int): the ``frames_per_batch`` of the collector. This serves as an example of hyperparameters + to be passed to the collector. + + """ + + def __init__(self, replay_buffer: rpc.RRef, frames_per_batch: int = 128) -> None: + self.id = rpc.get_worker_info().id + self.replay_buffer = replay_buffer + # Write your collector here + # self.collector = SyncDataCollector(...) + assert frames_per_batch > 0 + self.frames_per_batch = frames_per_batch + torchrl_logger.info("Data Collector Node constructed") + + def _submit_item_async(self) -> rpc.RRef: + """Function that collects data and populates the replay buffer.""" + # Replace this by a call to next() over the data collector + done = torch.zeros(self.frames_per_batch, 1, dtype=torch.bool) + done[..., -1, 1] = True + td = TensorDict( + { + "action": torch.randint( + 100, + ( + self.frames_per_batch, + 1, + ), + ), + "done": torch.zeros(self.frames_per_batch, dtype=torch.bool), + "observation": torch.randn(self.frames_per_batch, 4), + "step_count": torch.arange(self.frames_per_batch), + "terminated": torch.zeros(self.frames_per_batch, dtype=torch.bool), + "truncated": torch.zeros(self.frames_per_batch, dtype=torch.bool), + "next": { + "done": done, + "observation": torch.randn(self.frames_per_batch, 4), + "reward": torch.randn(self.frames_per_batch, 1), + "step_count": torch.arange(1, self.frames_per_batch + 1), + "terminated": torch.zeros_like(done), + "truncated": done, + }, + }, + [self.frames_per_batch], + ) + return rpc.remote( + self.replay_buffer.owner(), + ReplayBufferNode.extend, + args=( + self.replay_buffer, + td, + ), + ) + + @accept_remote_rref_invocation + def collect(self): + """Method that begins experience collection (we just generate random TensorDicts in this example). + + `accept_remote_rref_invocation` enables this method to be invoked remotely provided the class instantiation + `rpc.RRef` is provided in place of the object reference. + """ + for elem in range(50): + time.sleep(random.randint(1, 4)) + item = self._submit_item_async() + torchrl_logger.info( + f"Collector [{self.id}] submission {elem}: {item.to_here()}" + ) + + +class TrainerNode: + """Trainer node responsible for learning from experiences sampled from an experience replay buffer.""" + + def __init__(self) -> None: + torchrl_logger.info("TrainerNode") + self.id = rpc.get_worker_info().id + self.replay_buffer = self._create_replay_buffer() + self._create_and_launch_data_collectors() + + def train(self, iterations: int) -> None: + """Write your training loop here.""" + for iteration in range(iterations): + torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") + # Wait until the buffer has elements + while not rpc.rpc_sync( + self.replay_buffer.owner(), + ReplayBufferNode.__len__, + ): + continue + + batch = rpc.rpc_sync( + self.replay_buffer.owner(), + ReplayBufferNode.sample, + args=(self.replay_buffer, 16), + ) + + torchrl_logger.info(f"[{self.id}] Sample Obtained Iteration: {iteration}") + torchrl_logger.info(f"{batch}") + # Process the sample here: forward, backward, ... + + def _create_replay_buffer(self) -> rpc.RRef: + while True: + try: + replay_buffer_info = rpc.get_worker_info(REPLAY_BUFFER_NODE) + buffer_rref = rpc.remote( + replay_buffer_info, ReplayBufferNode, args=(10000,) + ) + torchrl_logger.info(f"Connected to replay buffer {replay_buffer_info}") + return buffer_rref + except Exception as e: + torchrl_logger.info(f"Failed to connect to replay buffer: {e}") + time.sleep(RETRY_DELAY_SECS) + + def _create_and_launch_data_collectors(self) -> None: + data_collector_number = 2 + retries = 0 + data_collectors = [] + data_collector_infos = [] + # discover launched data collector nodes (with retry to allow collectors to dynamically join) + while True: + try: + data_collector_info = rpc.get_worker_info( + f"DataCollector{data_collector_number}" + ) + torchrl_logger.info(f"Data collector info: {data_collector_info}") + dc_ref = rpc.remote( + data_collector_info, + CollectorNode, + args=(self.replay_buffer,), + ) + data_collectors.append(dc_ref) + data_collector_infos.append(data_collector_info) + data_collector_number += 1 + retries = 0 + except Exception: + retries += 1 + torchrl_logger.info( + f"Failed to connect to DataCollector{data_collector_number} with {retries} retries" + ) + if retries >= RETRY_LIMIT: + torchrl_logger.info(f"{len(data_collectors)} data collectors") + for data_collector_info, data_collector in zip( + data_collector_infos, data_collectors + ): + rpc.remote( + data_collector_info, + CollectorNode.collect, + args=(data_collector,), + ) + break + else: + time.sleep(RETRY_DELAY_SECS) + + +class ReplayBufferNode(RemoteTensorDictReplayBuffer): + """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteTensorDictReplayBuffer` + means all of its public methods are remotely invokable using `torch.rpc`. + Using a LazyMemmapStorage is highly advised in distributed settings with shared storage due to the lower serialisation + cost of MemoryMappedTensors as well as the ability to specify file storage locations which can improve ability to recover from node failures. + + Args: + capacity (int): the maximum number of elements that can be stored in the replay buffer. + """ + + def __init__(self, capacity: int): + super().__init__( + storage=LazyMemmapStorage( + max_size=capacity, scratch_dir="/tmp/", device=torch.device("cpu") + ), + sampler=SliceSampler(num_slices=4), + writer=RoundRobinWriter(), + batch_size=32, + ) + + +if __name__ == "__main__": + + args = parser.parse_args() + rank = args.rank + torchrl_logger.info(f"Rank: {rank}") + + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29500" + os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" + str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( + num_worker_threads=16, init_method=str_init_method + ) + if rank == 0: + # rank 0 is the trainer + rpc.init_rpc( + TRAINER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised Trainer Node {rank}") + trainer = TrainerNode() + trainer.train(100) + breakpoint() + elif rank == 1: + # rank 1 is the replay buffer + # replay buffer waits passively for construction instructions from trainer node + torchrl_logger.info(REPLAY_BUFFER_NODE) + rpc.init_rpc( + REPLAY_BUFFER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised RB Node {rank}") + breakpoint() + elif rank >= 2: + # rank 2+ is a new data collector node + # data collectors also wait passively for construction instructions from trainer node + rpc.init_rpc( + f"DataCollector{rank}", + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised DC Node {rank}") + breakpoint() + else: + sys.exit(1) + rpc.shutdown() From ea1b4b66390b8b440b113c7b27c42456bf440649 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:27:44 -0400 Subject: [PATCH 02/38] amend --- .../distributed_replay_buffer_slicesampler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index 494aff8262b..ddcca31bac8 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -6,11 +6,11 @@ ```bash $ # In terminal0: Trainer node -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=0 +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=0 $ # In terminal1: Replay buffer node -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=1 +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=1 $ # In terminal2 to N: Collector nodes -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py -- rank=2 +$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=2 ``` """ @@ -138,6 +138,7 @@ def train(self, iterations: int) -> None: while not rpc.rpc_sync( self.replay_buffer.owner(), ReplayBufferNode.__len__, + args=(self.replay_buffer,) ): continue From 4a84b6a80e0acd07645396c9fa265135df0bd6da Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:29:31 -0400 Subject: [PATCH 03/38] amend --- torchrl/data/replay_buffers/replay_buffers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index a688bd8585e..3a5af50eafd 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -1450,6 +1450,10 @@ def update_priority( def update_tensordict_priority(self, data: TensorDictBase) -> None: return super().update_tensordict_priority(data) + def __len__(self): + return super().__len__() + def __iter__(self): + return super().__iter__() class InPlaceSampler: """A sampler to write tennsordicts in-place. From d3b5db4695a39bbdbc047e9d79d77ef0bdfb1884 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:33:30 -0400 Subject: [PATCH 04/38] amend --- .../distributed_replay_buffer_slicesampler.py | 6 +-- torchrl/data/replay_buffers/__init__.py | 2 +- torchrl/data/replay_buffers/replay_buffers.py | 38 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index ddcca31bac8..55ec0e7fd87 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -25,7 +25,7 @@ import torch.distributed.rpc as rpc from tensordict import TensorDict from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteTensorDictReplayBuffer +from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage from torchrl.data.replay_buffers.writers import RoundRobinWriter @@ -206,8 +206,8 @@ def _create_and_launch_data_collectors(self) -> None: time.sleep(RETRY_DELAY_SECS) -class ReplayBufferNode(RemoteTensorDictReplayBuffer): - """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteTensorDictReplayBuffer` +class ReplayBufferNode(RemoteReplayBuffer): + """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteReplayBuffer` means all of its public methods are remotely invokable using `torch.rpc`. Using a LazyMemmapStorage is highly advised in distributed settings with shared storage due to the lower serialisation cost of MemoryMappedTensors as well as the ability to specify file storage locations which can improve ability to recover from node failures. diff --git a/torchrl/data/replay_buffers/__init__.py b/torchrl/data/replay_buffers/__init__.py index 25822dcfe4c..cb90ac22a6e 100644 --- a/torchrl/data/replay_buffers/__init__.py +++ b/torchrl/data/replay_buffers/__init__.py @@ -17,7 +17,7 @@ RemoteTensorDictReplayBuffer, ReplayBuffer, ReplayBufferEnsemble, - TensorDictPrioritizedReplayBuffer, + TensorDictPrioritizedReplayBuffer,RemoteReplayBuffer, TensorDictReplayBuffer, ) from .samplers import ( diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index 3a5af50eafd..c36a6c52388 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -1452,6 +1452,44 @@ def update_tensordict_priority(self, data: TensorDictBase) -> None: def __len__(self): return super().__len__() + + def __iter__(self): + return super().__iter__() + +@accept_remote_rref_udf_invocation +class RemoteReplayBuffer(ReplayBuffer): + """A remote invocation friendly ReplayBuffer class. Public methods can be invoked by remote agents using `torch.rpc` or called locally as normal.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def sample( + self, + batch_size: int | None = None, + include_info: bool = None, + return_info: bool = False, + ) -> TensorDictBase: + return super().sample( + batch_size=batch_size, include_info=include_info, return_info=return_info + ) + + def add(self, data: TensorDictBase) -> int: + return super().add(data) + + def extend(self, tensordicts: Union[List, TensorDictBase]) -> torch.Tensor: + return super().extend(tensordicts) + + def update_priority( + self, index: Union[int, torch.Tensor], priority: Union[int, torch.Tensor] + ) -> None: + return super().update_priority(index, priority) + + def update_tensordict_priority(self, data: TensorDictBase) -> None: + return super().update_tensordict_priority(data) + + def __len__(self): + return super().__len__() + def __iter__(self): return super().__iter__() From 0639f82d7e5312b2683f8cdabeff836ade980c1d Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:35:35 -0400 Subject: [PATCH 05/38] amend --- .../replay-buffers/distributed_replay_buffer_slicesampler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index 55ec0e7fd87..e83956a43e3 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -24,7 +24,7 @@ import torch import torch.distributed.rpc as rpc from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger, accept_remote_rref_udf_invocation from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage @@ -206,6 +206,7 @@ def _create_and_launch_data_collectors(self) -> None: time.sleep(RETRY_DELAY_SECS) +@accept_remote_rref_udf_invocation class ReplayBufferNode(RemoteReplayBuffer): """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteReplayBuffer` means all of its public methods are remotely invokable using `torch.rpc`. From b6c6ff8afaa8110a23f0c98de56fbe1cf426561e Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:36:56 -0400 Subject: [PATCH 06/38] amend --- .../distributed_replay_buffer_slicesampler.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index e83956a43e3..bbe1db57ad7 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -134,13 +134,14 @@ def train(self, iterations: int) -> None: """Write your training loop here.""" for iteration in range(iterations): torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") - # Wait until the buffer has elements - while not rpc.rpc_sync( - self.replay_buffer.owner(), - ReplayBufferNode.__len__, - args=(self.replay_buffer,) - ): - continue + # # Wait until the buffer has elements + time.sleep(3) + # while not rpc.rpc_sync( + # self.replay_buffer.owner(), + # ReplayBufferNode.__len__, + # args=(self.replay_buffer,) + # ): + # continue batch = rpc.rpc_sync( self.replay_buffer.owner(), @@ -206,7 +207,6 @@ def _create_and_launch_data_collectors(self) -> None: time.sleep(RETRY_DELAY_SECS) -@accept_remote_rref_udf_invocation class ReplayBufferNode(RemoteReplayBuffer): """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteReplayBuffer` means all of its public methods are remotely invokable using `torch.rpc`. From 41e63594df8e17934f5a0bfc5e41141883f7e0bd Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:39:34 -0400 Subject: [PATCH 07/38] amend --- .../distributed_replay_buffer_slicesampler.py | 12 ++++++------ torchrl/data/replay_buffers/replay_buffers.py | 12 ++++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index bbe1db57ad7..d4f20ea2d5e 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -136,12 +136,12 @@ def train(self, iterations: int) -> None: torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") # # Wait until the buffer has elements time.sleep(3) - # while not rpc.rpc_sync( - # self.replay_buffer.owner(), - # ReplayBufferNode.__len__, - # args=(self.replay_buffer,) - # ): - # continue + while not rpc.rpc_sync( + self.replay_buffer.owner(), + ReplayBufferNode.__len__, + args=(self.replay_buffer,) + ): + continue batch = rpc.rpc_sync( self.replay_buffer.owner(), diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index c36a6c52388..bac7159955a 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -331,10 +331,13 @@ def set_sampler(self, sampler: Sampler): self._sampler = sampler return prev_sampler - def __len__(self) -> int: + def _len(self): with self._replay_lock: return len(self._storage) + def __len__(self) -> int: + return self._len() + def __repr__(self) -> str: from torchrl.envs.transforms import Compose @@ -1466,11 +1469,10 @@ def __init__(self, *args, **kwargs): def sample( self, batch_size: int | None = None, - include_info: bool = None, return_info: bool = False, ) -> TensorDictBase: return super().sample( - batch_size=batch_size, include_info=include_info, return_info=return_info + batch_size=batch_size, return_info=return_info ) def add(self, data: TensorDictBase) -> int: @@ -1488,7 +1490,9 @@ def update_tensordict_priority(self, data: TensorDictBase) -> None: return super().update_tensordict_priority(data) def __len__(self): - return super().__len__() + return self._len() + def _len(self): + return super()._len() def __iter__(self): return super().__iter__() From b4520c54ffff6012cee6ef5e35334a8626e7e4ff Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:40:29 -0400 Subject: [PATCH 08/38] amend --- .../replay-buffers/distributed_replay_buffer_slicesampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index d4f20ea2d5e..274743d6497 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -138,7 +138,7 @@ def train(self, iterations: int) -> None: time.sleep(3) while not rpc.rpc_sync( self.replay_buffer.owner(), - ReplayBufferNode.__len__, + ReplayBufferNode._len, args=(self.replay_buffer,) ): continue From 3a9a285258ab73795fb695332e3daab23f8ca267 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:40:45 -0400 Subject: [PATCH 09/38] amend --- torchrl/data/replay_buffers/replay_buffers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index bac7159955a..d08e09bbecf 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -1454,7 +1454,9 @@ def update_tensordict_priority(self, data: TensorDictBase) -> None: return super().update_tensordict_priority(data) def __len__(self): - return super().__len__() + return self._len() + def _len(self): + return super()._len() def __iter__(self): return super().__iter__() From 4aef5c9391252752953595ef12c488daca727d67 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:43:49 -0400 Subject: [PATCH 10/38] amend --- .../distributed_replay_buffer_slicesampler.py | 2 +- torchrl/_utils.py | 2 +- torchrl/data/replay_buffers/replay_buffers.py | 13 +++---------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index 274743d6497..ce46cf58f73 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -71,7 +71,7 @@ def _submit_item_async(self) -> rpc.RRef: """Function that collects data and populates the replay buffer.""" # Replace this by a call to next() over the data collector done = torch.zeros(self.frames_per_batch, 1, dtype=torch.bool) - done[..., -1, 1] = True + done[..., -1, 0] = True td = TensorDict( { "action": torch.randint( diff --git a/torchrl/_utils.py b/torchrl/_utils.py index 895f3d80fdc..3ae3deca15c 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -488,7 +488,7 @@ def accept_remote_rref_udf_invocation(decorated_class): # ignores private methods for name in dir(decorated_class): method = getattr(decorated_class, name) - if callable(method) and not name.startswith("_"): + if callable(method) and not (name.startswith("_") and not name.startswith("__")): setattr(decorated_class, name, accept_remote_rref_invocation(method)) return decorated_class diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index d08e09bbecf..9d34568ec6e 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -331,13 +331,10 @@ def set_sampler(self, sampler: Sampler): self._sampler = sampler return prev_sampler - def _len(self): + def __len__(self) -> int: with self._replay_lock: return len(self._storage) - def __len__(self) -> int: - return self._len() - def __repr__(self) -> str: from torchrl.envs.transforms import Compose @@ -1454,9 +1451,7 @@ def update_tensordict_priority(self, data: TensorDictBase) -> None: return super().update_tensordict_priority(data) def __len__(self): - return self._len() - def _len(self): - return super()._len() + return super().__len__() def __iter__(self): return super().__iter__() @@ -1492,9 +1487,7 @@ def update_tensordict_priority(self, data: TensorDictBase) -> None: return super().update_tensordict_priority(data) def __len__(self): - return self._len() - def _len(self): - return super()._len() + return super().__len__() def __iter__(self): return super().__iter__() From cbffaf6c10b494d73479b40b41a842dcdae5f17a Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:46:12 -0400 Subject: [PATCH 11/38] amend --- torchrl/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torchrl/_utils.py b/torchrl/_utils.py index 3ae3deca15c..6fb954909cb 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -488,7 +488,7 @@ def accept_remote_rref_udf_invocation(decorated_class): # ignores private methods for name in dir(decorated_class): method = getattr(decorated_class, name) - if callable(method) and not (name.startswith("_") and not name.startswith("__")): + if callable(method) and name.startswith("__") or not name.startswith("_"): setattr(decorated_class, name, accept_remote_rref_invocation(method)) return decorated_class From 8727f6d44afee52e7b45035814192cf9f0f749fa Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:46:42 -0400 Subject: [PATCH 12/38] amend --- torchrl/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torchrl/_utils.py b/torchrl/_utils.py index 6fb954909cb..ea515a1f243 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -488,7 +488,7 @@ def accept_remote_rref_udf_invocation(decorated_class): # ignores private methods for name in dir(decorated_class): method = getattr(decorated_class, name) - if callable(method) and name.startswith("__") or not name.startswith("_"): + if callable(method) and (name.startswith("__") or not name.startswith("_")): setattr(decorated_class, name, accept_remote_rref_invocation(method)) return decorated_class From 1c82f32621c1ec926ce2e71ca83c18d2b0fda105 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:50:12 -0400 Subject: [PATCH 13/38] amend --- torchrl/_utils.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/torchrl/_utils.py b/torchrl/_utils.py index ea515a1f243..2f591af15ae 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -486,9 +486,18 @@ def unpack_rref_and_invoke_function(self, *args, **kwargs): def accept_remote_rref_udf_invocation(decorated_class): """Class decorator that applies `accept_remote_rref_invocation` to all public methods.""" # ignores private methods + __allowed_methods__ = { + "__add__", "__sub__", "__mul__", "__truediv__", "__floordiv__", "__mod__", "__pow__", + "__iadd__", "__isub__", "__imul__", "__itruediv__", "__ifloordiv__", "__imod__", "__ipow__", + "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__invert__", + "__iand__", "__ior__", "__ixor__", "__ilshift__", "__irshift__", + "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", + "__bool__", "__iter__", "__len__", +} + for name in dir(decorated_class): method = getattr(decorated_class, name) - if callable(method) and (name.startswith("__") or not name.startswith("_")): + if callable(method) and (not name.startswith("_") or name in __allowed_methods__): setattr(decorated_class, name, accept_remote_rref_invocation(method)) return decorated_class From 67beaa412f4962275a15daef275727e2316059c4 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 12:51:02 -0400 Subject: [PATCH 14/38] amend --- .../replay-buffers/distributed_replay_buffer_slicesampler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py index ce46cf58f73..099ef440d07 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_replay_buffer_slicesampler.py @@ -135,10 +135,9 @@ def train(self, iterations: int) -> None: for iteration in range(iterations): torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") # # Wait until the buffer has elements - time.sleep(3) while not rpc.rpc_sync( self.replay_buffer.owner(), - ReplayBufferNode._len, + ReplayBufferNode.__len__, args=(self.replay_buffer,) ): continue From 7ee142016d4e699356cb05a8438c7be17240535b Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:09:12 -0400 Subject: [PATCH 15/38] amend --- ...licesampler.py => distributed_rb_utils.py} | 94 +--------- .../distributed_replay_buffer.py | 169 ++++-------------- .../distributed_replay_buffer_distlaunch.py | 113 ++++++++++++ .../distributed_replay_buffer_submitit.py | 112 ++++++++++++ .../distributed_replay_buffer_torchrun.py | 95 ++++++++++ torchrl/_utils.py | 50 ++++-- torchrl/data/replay_buffers/__init__.py | 3 +- torchrl/data/replay_buffers/replay_buffers.py | 6 +- 8 files changed, 405 insertions(+), 237 deletions(-) rename examples/replay-buffers/{distributed_replay_buffer_slicesampler.py => distributed_rb_utils.py} (74%) create mode 100644 examples/replay-buffers/distributed_replay_buffer_distlaunch.py create mode 100644 examples/replay-buffers/distributed_replay_buffer_submitit.py create mode 100644 examples/replay-buffers/distributed_replay_buffer_torchrun.py diff --git a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py b/examples/replay-buffers/distributed_rb_utils.py similarity index 74% rename from examples/replay-buffers/distributed_replay_buffer_slicesampler.py rename to examples/replay-buffers/distributed_rb_utils.py index 099ef440d07..fcfa0112298 100644 --- a/examples/replay-buffers/distributed_replay_buffer_slicesampler.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -1,19 +1,8 @@ -""" -Example use of a distributed replay buffer -========================================== +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. -To launch this script, run - -```bash -$ # In terminal0: Trainer node -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=0 -$ # In terminal1: Replay buffer node -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=1 -$ # In terminal2 to N: Collector nodes -$ python examples/replay-buffers/distributed_replay_buffer_slicesampler.py --rank=2 - -``` -""" import argparse import os @@ -24,7 +13,10 @@ import torch import torch.distributed.rpc as rpc from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger, accept_remote_rref_udf_invocation +from torchrl._utils import ( + accept_remote_rref_invocation, + logger as torchrl_logger, +) from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage @@ -32,21 +24,6 @@ RETRY_LIMIT = 2 RETRY_DELAY_SECS = 3 -REPLAY_BUFFER_NODE = "ReplayBuffer" -TRAINER_NODE = "Trainer" - -parser = argparse.ArgumentParser( - description="RPC Replay Buffer Example", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, -) - -parser.add_argument( - "--rank", - type=int, - default=-1, - help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", -) - class CollectorNode: """Data collector node responsible for collecting experiences used for learning. @@ -138,7 +115,7 @@ def train(self, iterations: int) -> None: while not rpc.rpc_sync( self.replay_buffer.owner(), ReplayBufferNode.__len__, - args=(self.replay_buffer,) + args=(self.replay_buffer,), ): continue @@ -225,56 +202,3 @@ def __init__(self, capacity: int): writer=RoundRobinWriter(), batch_size=32, ) - - -if __name__ == "__main__": - - args = parser.parse_args() - rank = args.rank - torchrl_logger.info(f"Rank: {rank}") - - os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29500" - os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" - options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, init_method=str_init_method - ) - if rank == 0: - # rank 0 is the trainer - rpc.init_rpc( - TRAINER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode() - trainer.train(100) - breakpoint() - elif rank == 1: - # rank 1 is the replay buffer - # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(REPLAY_BUFFER_NODE) - rpc.init_rpc( - REPLAY_BUFFER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised RB Node {rank}") - breakpoint() - elif rank >= 2: - # rank 2+ is a new data collector node - # data collectors also wait passively for construction instructions from trainer node - rpc.init_rpc( - f"DataCollector{rank}", - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised DC Node {rank}") - breakpoint() - else: - sys.exit(1) - rpc.shutdown() diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index c7504fbf8ee..39026f8786c 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -1,12 +1,31 @@ """ Example use of a distributed replay buffer -=========================== +========================================== -This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion with communication between nodes/workers handled using `torch.rpc`. -It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits any learning component such as parameter updates that may be required for a complete distributed reinforcement learning algorithm implementation. -In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter updates to any required models. +This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion +with communication between nodes/workers handled using `torch.rpc`. +It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits +any learning component such as parameter updates that may be required for a complete distributed reinforcement learning +algorithm implementation. + +In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay +buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter +updates to any required models. + +To launch this script, run + +```bash +$ # In terminal0: Trainer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=0 +$ # In terminal1: Replay buffer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=1 +$ # In terminal2 to N: Collector nodes +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=2 + +``` """ +from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode import argparse import os import random @@ -16,14 +35,15 @@ import torch import torch.distributed.rpc as rpc from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteTensorDictReplayBuffer -from torchrl.data.replay_buffers.samplers import RandomSampler +from torchrl._utils import ( + accept_remote_rref_invocation, + logger as torchrl_logger, +) +from torchrl.data.replay_buffers import RemoteReplayBuffer +from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage from torchrl.data.replay_buffers.writers import RoundRobinWriter -RETRY_LIMIT = 2 -RETRY_DELAY_SECS = 3 REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" @@ -40,136 +60,9 @@ ) -class DummyDataCollectorNode: - """Data collector node responsible for collecting experiences used for learning. - - Args: - replay_buffer (rpc.RRef): the RRef associated with the construction of the replay buffer - """ - - def __init__(self, replay_buffer: rpc.RRef) -> None: - self.id = rpc.get_worker_info().id - self.replay_buffer = replay_buffer - torchrl_logger.info("Data Collector Node constructed") - - def _submit_random_item_async(self) -> rpc.RRef: - td = TensorDict({"a": torch.randint(100, (1,))}, []) - return rpc.remote( - self.replay_buffer.owner(), - ReplayBufferNode.add, - args=( - self.replay_buffer, - td, - ), - ) - - @accept_remote_rref_invocation - def collect(self): - """Method that begins experience collection (we just generate random TensorDicts in this example). `accept_remote_rref_invocation` enables this method to be invoked remotely provided the class instantiation `rpc.RRef` is provided in place of the object reference.""" - for elem in range(50): - time.sleep(random.randint(1, 4)) - torchrl_logger.info( - f"Collector [{self.id}] submission {elem}: {self._submit_random_item_async().to_here()}" - ) - - -class DummyTrainerNode: - """Trainer node responsible for learning from experiences sampled from an experience replay buffer.""" - - def __init__(self) -> None: - torchrl_logger.info("DummyTrainerNode") - self.id = rpc.get_worker_info().id - self.replay_buffer = self._create_replay_buffer() - self._create_and_launch_data_collectors() - - def train(self, iterations: int) -> None: - for iteration in range(iterations): - torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") - time.sleep(3) - batch = rpc.rpc_sync( - self.replay_buffer.owner(), - ReplayBufferNode.sample, - args=(self.replay_buffer, 16), - ) - torchrl_logger.info(f"[{self.id}] Sample Obtained Iteration: {iteration}") - torchrl_logger.info(f"{batch}") - - def _create_replay_buffer(self) -> rpc.RRef: - while True: - try: - replay_buffer_info = rpc.get_worker_info(REPLAY_BUFFER_NODE) - buffer_rref = rpc.remote( - replay_buffer_info, ReplayBufferNode, args=(10000,) - ) - torchrl_logger.info(f"Connected to replay buffer {replay_buffer_info}") - return buffer_rref - except Exception as e: - torchrl_logger.info(f"Failed to connect to replay buffer: {e}") - time.sleep(RETRY_DELAY_SECS) - - def _create_and_launch_data_collectors(self) -> None: - data_collector_number = 2 - retries = 0 - data_collectors = [] - data_collector_infos = [] - # discover launched data collector nodes (with retry to allow collectors to dynamically join) - while True: - try: - data_collector_info = rpc.get_worker_info( - f"DataCollector{data_collector_number}" - ) - torchrl_logger.info(f"Data collector info: {data_collector_info}") - dc_ref = rpc.remote( - data_collector_info, - DummyDataCollectorNode, - args=(self.replay_buffer,), - ) - data_collectors.append(dc_ref) - data_collector_infos.append(data_collector_info) - data_collector_number += 1 - retries = 0 - except Exception: - retries += 1 - torchrl_logger.info( - f"Failed to connect to DataCollector{data_collector_number} with {retries} retries" - ) - if retries >= RETRY_LIMIT: - torchrl_logger.info(f"{len(data_collectors)} data collectors") - for data_collector_info, data_collector in zip( - data_collector_infos, data_collectors - ): - rpc.remote( - data_collector_info, - DummyDataCollectorNode.collect, - args=(data_collector,), - ) - break - else: - time.sleep(RETRY_DELAY_SECS) - - -class ReplayBufferNode(RemoteTensorDictReplayBuffer): - """Experience replay buffer node that is capable of accepting remote connections. Being a `RemoteTensorDictReplayBuffer` - means all of it's public methods are remotely invokable using `torch.rpc`. - Using a LazyMemmapStorage is highly advised in distributed settings with shared storage due to the lower serialisation - cost of MemoryMappedTensors as well as the ability to specify file storage locations which can improve ability to recover from node failures. - - Args: - capacity (int): the maximum number of elements that can be stored in the replay buffer. - """ - - def __init__(self, capacity: int): - super().__init__( - storage=LazyMemmapStorage( - max_size=capacity, scratch_dir="/tmp/", device=torch.device("cpu") - ), - sampler=RandomSampler(), - writer=RoundRobinWriter(), - collate_fn=lambda x: x, - ) - if __name__ == "__main__": + args = parser.parse_args() rank = args.rank torchrl_logger.info(f"Rank: {rank}") @@ -190,7 +83,7 @@ def __init__(self, capacity: int): rpc_backend_options=options, ) torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = DummyTrainerNode() + trainer = TrainerNode() trainer.train(100) breakpoint() elif rank == 1: diff --git a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py new file mode 100644 index 00000000000..cdf33fad081 --- /dev/null +++ b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py @@ -0,0 +1,113 @@ +""" +Example use of a distributed replay buffer +========================================== + +This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion +with communication between nodes/workers handled using `torch.rpc`. +It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits +any learning component such as parameter updates that may be required for a complete distributed reinforcement learning +algorithm implementation. + +In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay +buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter +updates to any required models. + +To launch this script, run + +```bash +$ # In terminal0: Trainer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=0 +$ # In terminal1: Replay buffer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=1 +$ # In terminal2 to N: Collector nodes +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=2 + +``` +""" + +import argparse +import os +import random +import sys +import time + +import torch +import torch.distributed.rpc as rpc +from tensordict import TensorDict +from torchrl._utils import ( + accept_remote_rref_invocation, + logger as torchrl_logger, +) +from torchrl.data.replay_buffers import RemoteReplayBuffer +from torchrl.data.replay_buffers.samplers import SliceSampler +from torchrl.data.replay_buffers.storages import LazyMemmapStorage +from torchrl.data.replay_buffers.writers import RoundRobinWriter +from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode + +REPLAY_BUFFER_NODE = "ReplayBuffer" +TRAINER_NODE = "Trainer" + +parser = argparse.ArgumentParser( + description="RPC Replay Buffer Example", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +parser.add_argument( + "--rank", + type=int, + default=-1, + help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", +) + + +if __name__ == "__main__": + + args = parser.parse_args() + rank = args.rank + torchrl_logger.info(f"Rank: {rank}") + + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29500" + os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" + str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( + num_worker_threads=16, init_method=str_init_method + ) + if rank == 0: + # rank 0 is the trainer + rpc.init_rpc( + TRAINER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised Trainer Node {rank}") + trainer = TrainerNode() + trainer.train(100) + breakpoint() + elif rank == 1: + # rank 1 is the replay buffer + # replay buffer waits passively for construction instructions from trainer node + torchrl_logger.info(REPLAY_BUFFER_NODE) + rpc.init_rpc( + REPLAY_BUFFER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised RB Node {rank}") + breakpoint() + elif rank >= 2: + # rank 2+ is a new data collector node + # data collectors also wait passively for construction instructions from trainer node + rpc.init_rpc( + f"DataCollector{rank}", + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised DC Node {rank}") + breakpoint() + else: + sys.exit(1) + rpc.shutdown() diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py new file mode 100644 index 00000000000..8cdbae15e1c --- /dev/null +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -0,0 +1,112 @@ +""" +Example use of a distributed replay buffer +========================================== + +This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion +with communication between nodes/workers handled using `torch.rpc`. +It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits +any learning component such as parameter updates that may be required for a complete distributed reinforcement learning +algorithm implementation. + +In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay +buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter +updates to any required models. + +To launch this script, run + +```bash +$ # In terminal0: Trainer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=0 +$ # In terminal1: Replay buffer node +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=1 +$ # In terminal2 to N: Collector nodes +$ python examples/replay-buffers/distributed_replay_buffer.py --rank=2 + +``` +""" + +import argparse +import os +import random +import sys +import time + +import torch +import torch.distributed.rpc as rpc +from tensordict import TensorDict +from torchrl._utils import ( + accept_remote_rref_invocation, + logger as torchrl_logger, +) +from torchrl.data.replay_buffers import RemoteReplayBuffer +from torchrl.data.replay_buffers.samplers import SliceSampler +from torchrl.data.replay_buffers.storages import LazyMemmapStorage +from torchrl.data.replay_buffers.writers import RoundRobinWriter +from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode + +REPLAY_BUFFER_NODE = "ReplayBuffer" +TRAINER_NODE = "Trainer" + +parser = argparse.ArgumentParser( + description="RPC Replay Buffer Example", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +parser.add_argument( + "--rank", + type=int, + default=-1, + help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", +) + +if __name__ == "__main__": + + args = parser.parse_args() + rank = args.rank + torchrl_logger.info(f"Rank: {rank}") + + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29500" + os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" + str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( + num_worker_threads=16, init_method=str_init_method + ) + if rank == 0: + # rank 0 is the trainer + rpc.init_rpc( + TRAINER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised Trainer Node {rank}") + trainer = TrainerNode() + trainer.train(100) + breakpoint() + elif rank == 1: + # rank 1 is the replay buffer + # replay buffer waits passively for construction instructions from trainer node + torchrl_logger.info(REPLAY_BUFFER_NODE) + rpc.init_rpc( + REPLAY_BUFFER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised RB Node {rank}") + breakpoint() + elif rank >= 2: + # rank 2+ is a new data collector node + # data collectors also wait passively for construction instructions from trainer node + rpc.init_rpc( + f"DataCollector{rank}", + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised DC Node {rank}") + breakpoint() + else: + sys.exit(1) + rpc.shutdown() diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_torchrun.py new file mode 100644 index 00000000000..e83aa831005 --- /dev/null +++ b/examples/replay-buffers/distributed_replay_buffer_torchrun.py @@ -0,0 +1,95 @@ +""" +Example use of a distributed replay buffer +========================================== + +This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion +with communication between nodes/workers handled using `torch.rpc`. +It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits +any learning component such as parameter updates that may be required for a complete distributed reinforcement learning +algorithm implementation. + +In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay +buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter +updates to any required models. + +To launch this script, run + +```bash +$ torchrun examples/replay-buffers/distributed_replay_buffer_torchrun.py --nnodes=1 +``` + +""" + +import argparse +import os +import random +import sys +import time + +import torch +import torch.distributed.rpc as rpc +from tensordict import TensorDict +from torchrl._utils import ( + accept_remote_rref_invocation, + logger as torchrl_logger, +) +from torchrl.data.replay_buffers import RemoteReplayBuffer +from torchrl.data.replay_buffers.samplers import SliceSampler +from torchrl.data.replay_buffers.storages import LazyMemmapStorage +from torchrl.data.replay_buffers.writers import RoundRobinWriter +from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode + +REPLAY_BUFFER_NODE = "ReplayBuffer" +TRAINER_NODE = "Trainer" + +if __name__ == "__main__": + + rank = int(os.environ["LOCAL_RANK"]) + torchrl_logger.info(f"Rank: {rank}") + + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29500" + os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" + str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( + num_worker_threads=16, init_method=str_init_method + ) + + if rank == 0: + # rank 0 is the trainer + rpc.init_rpc( + TRAINER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised Trainer Node {rank}") + trainer = TrainerNode() + trainer.train(100) + breakpoint() + elif rank == 1: + # rank 1 is the replay buffer + # replay buffer waits passively for construction instructions from trainer node + torchrl_logger.info(REPLAY_BUFFER_NODE) + rpc.init_rpc( + REPLAY_BUFFER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised RB Node {rank}") + breakpoint() + elif rank >= 2: + # rank 2+ is a new data collector node + # data collectors also wait passively for construction instructions from trainer node + rpc.init_rpc( + f"DataCollector{rank}", + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + ) + torchrl_logger.info(f"Initialised DC Node {rank}") + breakpoint() + else: + sys.exit(1) + rpc.shutdown() diff --git a/torchrl/_utils.py b/torchrl/_utils.py index 2f591af15ae..29086fa5bb4 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -487,17 +487,47 @@ def accept_remote_rref_udf_invocation(decorated_class): """Class decorator that applies `accept_remote_rref_invocation` to all public methods.""" # ignores private methods __allowed_methods__ = { - "__add__", "__sub__", "__mul__", "__truediv__", "__floordiv__", "__mod__", "__pow__", - "__iadd__", "__isub__", "__imul__", "__itruediv__", "__ifloordiv__", "__imod__", "__ipow__", - "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__invert__", - "__iand__", "__ior__", "__ixor__", "__ilshift__", "__irshift__", - "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", - "__bool__", "__iter__", "__len__", -} - - for name in dir(decorated_class): + "__add__", + "__sub__", + "__mul__", + "__truediv__", + "__floordiv__", + "__mod__", + "__pow__", + "__iadd__", + "__isub__", + "__imul__", + "__itruediv__", + "__ifloordiv__", + "__imod__", + "__ipow__", + "__and__", + "__or__", + "__xor__", + "__lshift__", + "__rshift__", + "__invert__", + "__iand__", + "__ior__", + "__ixor__", + "__ilshift__", + "__irshift__", + "__eq__", + "__ne__", + "__lt__", + "__le__", + "__gt__", + "__ge__", + "__bool__", + "__iter__", + "__len__", + } + + for name in inspect.getmembers(decorated_class): method = getattr(decorated_class, name) - if callable(method) and (not name.startswith("_") or name in __allowed_methods__): + if callable(method) and ( + not name.startswith("_") or name in __allowed_methods__ + ): setattr(decorated_class, name, accept_remote_rref_invocation(method)) return decorated_class diff --git a/torchrl/data/replay_buffers/__init__.py b/torchrl/data/replay_buffers/__init__.py index cb90ac22a6e..6e33e72dd1d 100644 --- a/torchrl/data/replay_buffers/__init__.py +++ b/torchrl/data/replay_buffers/__init__.py @@ -14,10 +14,11 @@ ) from .replay_buffers import ( PrioritizedReplayBuffer, + RemoteReplayBuffer, RemoteTensorDictReplayBuffer, ReplayBuffer, ReplayBufferEnsemble, - TensorDictPrioritizedReplayBuffer,RemoteReplayBuffer, + TensorDictPrioritizedReplayBuffer, TensorDictReplayBuffer, ) from .samplers import ( diff --git a/torchrl/data/replay_buffers/replay_buffers.py b/torchrl/data/replay_buffers/replay_buffers.py index 9d34568ec6e..17c6086ceaf 100644 --- a/torchrl/data/replay_buffers/replay_buffers.py +++ b/torchrl/data/replay_buffers/replay_buffers.py @@ -1456,6 +1456,7 @@ def __len__(self): def __iter__(self): return super().__iter__() + @accept_remote_rref_udf_invocation class RemoteReplayBuffer(ReplayBuffer): """A remote invocation friendly ReplayBuffer class. Public methods can be invoked by remote agents using `torch.rpc` or called locally as normal.""" @@ -1468,9 +1469,7 @@ def sample( batch_size: int | None = None, return_info: bool = False, ) -> TensorDictBase: - return super().sample( - batch_size=batch_size, return_info=return_info - ) + return super().sample(batch_size=batch_size, return_info=return_info) def add(self, data: TensorDictBase) -> int: return super().add(data) @@ -1492,6 +1491,7 @@ def __len__(self): def __iter__(self): return super().__iter__() + class InPlaceSampler: """A sampler to write tennsordicts in-place. From 44179c25d8cf94fec1942ccdad63d4549b507b40 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:11:02 -0400 Subject: [PATCH 16/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 6 ++---- examples/replay-buffers/distributed_replay_buffer.py | 8 ++------ .../distributed_replay_buffer_distlaunch.py | 7 ++----- .../replay-buffers/distributed_replay_buffer_submitit.py | 7 ++----- .../replay-buffers/distributed_replay_buffer_torchrun.py | 7 ++----- torchrl/_utils.py | 3 +-- 6 files changed, 11 insertions(+), 27 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index fcfa0112298..13f9c0ef301 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -13,10 +13,7 @@ import torch import torch.distributed.rpc as rpc from tensordict import TensorDict -from torchrl._utils import ( - accept_remote_rref_invocation, - logger as torchrl_logger, -) +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage @@ -25,6 +22,7 @@ RETRY_LIMIT = 2 RETRY_DELAY_SECS = 3 + class CollectorNode: """Data collector node responsible for collecting experiences used for learning. diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index 39026f8786c..bc2c7ea165a 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -25,7 +25,6 @@ ``` """ -from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode import argparse import os import random @@ -34,11 +33,9 @@ import torch import torch.distributed.rpc as rpc +from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode from tensordict import TensorDict -from torchrl._utils import ( - accept_remote_rref_invocation, - logger as torchrl_logger, -) +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage @@ -60,7 +57,6 @@ ) - if __name__ == "__main__": args = parser.parse_args() diff --git a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py index cdf33fad081..bc2c7ea165a 100644 --- a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py +++ b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py @@ -33,16 +33,13 @@ import torch import torch.distributed.rpc as rpc +from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode from tensordict import TensorDict -from torchrl._utils import ( - accept_remote_rref_invocation, - logger as torchrl_logger, -) +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage from torchrl.data.replay_buffers.writers import RoundRobinWriter -from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py index 8cdbae15e1c..043621c12f7 100644 --- a/examples/replay-buffers/distributed_replay_buffer_submitit.py +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -33,16 +33,13 @@ import torch import torch.distributed.rpc as rpc +from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode from tensordict import TensorDict -from torchrl._utils import ( - accept_remote_rref_invocation, - logger as torchrl_logger, -) +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage from torchrl.data.replay_buffers.writers import RoundRobinWriter -from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_torchrun.py index e83aa831005..6b2fed91b83 100644 --- a/examples/replay-buffers/distributed_replay_buffer_torchrun.py +++ b/examples/replay-buffers/distributed_replay_buffer_torchrun.py @@ -28,16 +28,13 @@ import torch import torch.distributed.rpc as rpc +from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode from tensordict import TensorDict -from torchrl._utils import ( - accept_remote_rref_invocation, - logger as torchrl_logger, -) +from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler from torchrl.data.replay_buffers.storages import LazyMemmapStorage from torchrl.data.replay_buffers.writers import RoundRobinWriter -from distributed_rb_utils import TrainerNode, CollectorNode, ReplayBufferNode REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/torchrl/_utils.py b/torchrl/_utils.py index 29086fa5bb4..b58003dd952 100644 --- a/torchrl/_utils.py +++ b/torchrl/_utils.py @@ -523,8 +523,7 @@ def accept_remote_rref_udf_invocation(decorated_class): "__len__", } - for name in inspect.getmembers(decorated_class): - method = getattr(decorated_class, name) + for name, method in inspect.getmembers(decorated_class): if callable(method) and ( not name.startswith("_") or name in __allowed_methods__ ): From 31f0f9375a0b6536e6e60e093df48476a247d84c Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:11:58 -0400 Subject: [PATCH 17/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 4 +--- .../replay-buffers/distributed_replay_buffer.py | 13 +++---------- .../distributed_replay_buffer_distlaunch.py | 13 +++---------- .../distributed_replay_buffer_submitit.py | 13 +++---------- .../distributed_replay_buffer_torchrun.py | 14 +++----------- 5 files changed, 13 insertions(+), 44 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 13f9c0ef301..d6bb8eca797 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -4,15 +4,13 @@ # LICENSE file in the root directory of this source tree. -import argparse -import os import random -import sys import time import torch import torch.distributed.rpc as rpc from tensordict import TensorDict + from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger from torchrl.data.replay_buffers import RemoteReplayBuffer from torchrl.data.replay_buffers.samplers import SliceSampler diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index bc2c7ea165a..10c06d8dd83 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -27,19 +27,12 @@ import argparse import os -import random import sys -import time -import torch import torch.distributed.rpc as rpc -from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode -from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteReplayBuffer -from torchrl.data.replay_buffers.samplers import SliceSampler -from torchrl.data.replay_buffers.storages import LazyMemmapStorage -from torchrl.data.replay_buffers.writers import RoundRobinWriter + +from distributed_rb_utils import TrainerNode +from torchrl._utils import logger as torchrl_logger REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py index bc2c7ea165a..10c06d8dd83 100644 --- a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py +++ b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py @@ -27,19 +27,12 @@ import argparse import os -import random import sys -import time -import torch import torch.distributed.rpc as rpc -from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode -from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteReplayBuffer -from torchrl.data.replay_buffers.samplers import SliceSampler -from torchrl.data.replay_buffers.storages import LazyMemmapStorage -from torchrl.data.replay_buffers.writers import RoundRobinWriter + +from distributed_rb_utils import TrainerNode +from torchrl._utils import logger as torchrl_logger REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py index 043621c12f7..7d94b31b67f 100644 --- a/examples/replay-buffers/distributed_replay_buffer_submitit.py +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -27,19 +27,12 @@ import argparse import os -import random import sys -import time -import torch import torch.distributed.rpc as rpc -from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode -from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteReplayBuffer -from torchrl.data.replay_buffers.samplers import SliceSampler -from torchrl.data.replay_buffers.storages import LazyMemmapStorage -from torchrl.data.replay_buffers.writers import RoundRobinWriter + +from distributed_rb_utils import TrainerNode +from torchrl._utils import logger as torchrl_logger REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_torchrun.py index 6b2fed91b83..3c034e9a7ee 100644 --- a/examples/replay-buffers/distributed_replay_buffer_torchrun.py +++ b/examples/replay-buffers/distributed_replay_buffer_torchrun.py @@ -20,21 +20,13 @@ """ -import argparse import os -import random import sys -import time -import torch import torch.distributed.rpc as rpc -from distributed_rb_utils import CollectorNode, ReplayBufferNode, TrainerNode -from tensordict import TensorDict -from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger -from torchrl.data.replay_buffers import RemoteReplayBuffer -from torchrl.data.replay_buffers.samplers import SliceSampler -from torchrl.data.replay_buffers.storages import LazyMemmapStorage -from torchrl.data.replay_buffers.writers import RoundRobinWriter + +from distributed_rb_utils import TrainerNode +from torchrl._utils import logger as torchrl_logger REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" From 7bd0876ac5d1e17b9c2fb1a2c11526d4db70ece5 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:23:09 -0400 Subject: [PATCH 18/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 8 +++++--- .../replay-buffers/distributed_replay_buffer_torchrun.py | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index d6bb8eca797..6b2b14a4333 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -9,6 +9,7 @@ import torch import torch.distributed.rpc as rpc +import tqdm from tensordict import TensorDict from torchrl._utils import accept_remote_rref_invocation, logger as torchrl_logger @@ -97,15 +98,16 @@ def collect(self): class TrainerNode: """Trainer node responsible for learning from experiences sampled from an experience replay buffer.""" - def __init__(self) -> None: + def __init__(self, replay_buffer_node="ReplayBuffer") -> None: torchrl_logger.info("TrainerNode") self.id = rpc.get_worker_info().id self.replay_buffer = self._create_replay_buffer() self._create_and_launch_data_collectors() + self.replay_buffer_node = replay_buffer_node def train(self, iterations: int) -> None: """Write your training loop here.""" - for iteration in range(iterations): + for iteration in tqdm.tqdm(iterations): torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") # # Wait until the buffer has elements while not rpc.rpc_sync( @@ -128,7 +130,7 @@ def train(self, iterations: int) -> None: def _create_replay_buffer(self) -> rpc.RRef: while True: try: - replay_buffer_info = rpc.get_worker_info(REPLAY_BUFFER_NODE) + replay_buffer_info = rpc.get_worker_info(self.replay_buffer_node) buffer_rref = rpc.remote( replay_buffer_info, ReplayBufferNode, args=(10000,) ) diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_torchrun.py index 3c034e9a7ee..34865347462 100644 --- a/examples/replay-buffers/distributed_replay_buffer_torchrun.py +++ b/examples/replay-buffers/distributed_replay_buffer_torchrun.py @@ -15,7 +15,7 @@ To launch this script, run ```bash -$ torchrun examples/replay-buffers/distributed_replay_buffer_torchrun.py --nnodes=1 +torchrun --rdzv-backend=c10d --rdzv-endpoint=localhost:0 --standalone --nnodes=1 --nproc-per-node=3 examples/replay-buffers/distributed_replay_buffer_torchrun.py ``` """ @@ -53,7 +53,7 @@ rpc_backend_options=options, ) torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode() + trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) trainer.train(100) breakpoint() elif rank == 1: From d72001bfb9af2701d86ce94084b1e534a6e1ebed Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:28:18 -0400 Subject: [PATCH 19/38] amend --- examples/replay-buffers/distributed_replay_buffer_torchrun.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_torchrun.py index 34865347462..c29fd0d75c7 100644 --- a/examples/replay-buffers/distributed_replay_buffer_torchrun.py +++ b/examples/replay-buffers/distributed_replay_buffer_torchrun.py @@ -46,6 +46,7 @@ if rank == 0: # rank 0 is the trainer + torchrl_logger.info(f"Init RPC on {TRAINER_NODE}...") rpc.init_rpc( TRAINER_NODE, rank=rank, @@ -59,7 +60,7 @@ elif rank == 1: # rank 1 is the replay buffer # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(REPLAY_BUFFER_NODE) + torchrl_logger.info(f"Init RPC on {REPLAY_BUFFER_NODE}...") rpc.init_rpc( REPLAY_BUFFER_NODE, rank=rank, @@ -71,6 +72,7 @@ elif rank >= 2: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node + torchrl_logger.info(f"Init RPC on {rank} collector node") rpc.init_rpc( f"DataCollector{rank}", rank=rank, From d0ac62189ca5fd97cb73c3402094f524bd21f59c Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:37:18 -0400 Subject: [PATCH 20/38] amend --- .../replay-buffers/distributed_replay_buffer.py | 8 ++++++-- ...y => distributed_replay_buffer_multiproc.py} | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) rename examples/replay-buffers/{distributed_replay_buffer_torchrun.py => distributed_replay_buffer_multiproc.py} (90%) diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index 10c06d8dd83..c0981b35640 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -60,11 +60,14 @@ os.environ["MASTER_PORT"] = "29500" os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( num_worker_threads=16, init_method=str_init_method ) + if rank == 0: # rank 0 is the trainer + torchrl_logger.info(f"Init RPC on {TRAINER_NODE}...") rpc.init_rpc( TRAINER_NODE, rank=rank, @@ -72,13 +75,13 @@ rpc_backend_options=options, ) torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode() + trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) trainer.train(100) breakpoint() elif rank == 1: # rank 1 is the replay buffer # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(REPLAY_BUFFER_NODE) + torchrl_logger.info(f"Init RPC on {REPLAY_BUFFER_NODE}...") rpc.init_rpc( REPLAY_BUFFER_NODE, rank=rank, @@ -90,6 +93,7 @@ elif rank >= 2: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node + torchrl_logger.info(f"Init RPC on {rank} collector node") rpc.init_rpc( f"DataCollector{rank}", rank=rank, diff --git a/examples/replay-buffers/distributed_replay_buffer_torchrun.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py similarity index 90% rename from examples/replay-buffers/distributed_replay_buffer_torchrun.py rename to examples/replay-buffers/distributed_replay_buffer_multiproc.py index c29fd0d75c7..ea4782932ae 100644 --- a/examples/replay-buffers/distributed_replay_buffer_torchrun.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -15,7 +15,7 @@ To launch this script, run ```bash -torchrun --rdzv-backend=c10d --rdzv-endpoint=localhost:0 --standalone --nnodes=1 --nproc-per-node=3 examples/replay-buffers/distributed_replay_buffer_torchrun.py +python examples/replay-buffers/distributed_replay_buffer_multiproc.py ``` """ @@ -27,19 +27,21 @@ from distributed_rb_utils import TrainerNode from torchrl._utils import logger as torchrl_logger +from torch import multiprocessing as mp + REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" -if __name__ == "__main__": - rank = int(os.environ["LOCAL_RANK"]) +def main(rank): torchrl_logger.info(f"Rank: {rank}") os.environ["MASTER_ADDR"] = "localhost" os.environ["MASTER_PORT"] = "29500" os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" str_init_method = "tcp://localhost:10000" + options = rpc.TensorPipeRpcBackendOptions( num_worker_threads=16, init_method=str_init_method ) @@ -84,3 +86,12 @@ else: sys.exit(1) rpc.shutdown() + +if __name__ == "__main__": + ctx = mp.current_context() + procs = [] + for i in range(3): + procs.append(ctx.Process(target=main, args=(i,))) + procs[-1].start() + for p in procs: + p.join() From 73324c62cf74ffcb0b51170bfc24f91d0fb03b7f Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:37:46 -0400 Subject: [PATCH 21/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index ea4782932ae..17ce006fdaf 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -88,7 +88,7 @@ def main(rank): rpc.shutdown() if __name__ == "__main__": - ctx = mp.current_context() + ctx = mp.get_context() procs = [] for i in range(3): procs.append(ctx.Process(target=main, args=(i,))) From e0a3c1f55410e2c4d978dfeedac859a59bebdc0a Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:38:14 -0400 Subject: [PATCH 22/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 17ce006fdaf..c6adeb5714c 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -40,7 +40,7 @@ def main(rank): os.environ["MASTER_ADDR"] = "localhost" os.environ["MASTER_PORT"] = "29500" os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" + str_init_method = "tcp://localhost:10001" options = rpc.TensorPipeRpcBackendOptions( num_worker_threads=16, init_method=str_init_method From 87277f205a11862c7adf35c2df4ed12b754710fd Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:39:17 -0400 Subject: [PATCH 23/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index c6adeb5714c..04f5b71ce1a 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -38,7 +38,7 @@ def main(rank): torchrl_logger.info(f"Rank: {rank}") os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29500" + os.environ["MASTER_PORT"] = "29501" os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" str_init_method = "tcp://localhost:10001" From 4aeb163b97587ba91ef344ac27c75a14854c447a Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:39:27 -0400 Subject: [PATCH 24/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 04f5b71ce1a..67fb3d9d75e 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -88,7 +88,7 @@ def main(rank): rpc.shutdown() if __name__ == "__main__": - ctx = mp.get_context() + ctx = mp.get_context("spawn") procs = [] for i in range(3): procs.append(ctx.Process(target=main, args=(i,))) From 1b509440cb670eac0965f318d7fb927e15c9f364 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:40:39 -0400 Subject: [PATCH 25/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 6b2b14a4333..b78b549eea2 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -99,11 +99,11 @@ class TrainerNode: """Trainer node responsible for learning from experiences sampled from an experience replay buffer.""" def __init__(self, replay_buffer_node="ReplayBuffer") -> None: + self.replay_buffer_node = replay_buffer_node torchrl_logger.info("TrainerNode") self.id = rpc.get_worker_info().id self.replay_buffer = self._create_replay_buffer() self._create_and_launch_data_collectors() - self.replay_buffer_node = replay_buffer_node def train(self, iterations: int) -> None: """Write your training loop here.""" From 2e287d5ae777737b7ae5c216dd57c5afab77fd34 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:45:21 -0400 Subject: [PATCH 26/38] amend --- .../replay-buffers/distributed_replay_buffer_multiproc.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 67fb3d9d75e..28f9d9056e2 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -33,14 +33,13 @@ REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" - def main(rank): torchrl_logger.info(f"Rank: {rank}") os.environ["MASTER_ADDR"] = "localhost" os.environ["MASTER_PORT"] = "29501" os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10001" + str_init_method = "tcp://localhost:10000" options = rpc.TensorPipeRpcBackendOptions( num_worker_threads=16, init_method=str_init_method @@ -71,7 +70,7 @@ def main(rank): ) torchrl_logger.info(f"Initialised RB Node {rank}") breakpoint() - elif rank >= 2: + else: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node torchrl_logger.info(f"Init RPC on {rank} collector node") @@ -83,8 +82,6 @@ def main(rank): ) torchrl_logger.info(f"Initialised DC Node {rank}") breakpoint() - else: - sys.exit(1) rpc.shutdown() if __name__ == "__main__": @@ -93,5 +90,6 @@ def main(rank): for i in range(3): procs.append(ctx.Process(target=main, args=(i,))) procs[-1].start() + for p in procs: p.join() From 2f41fbad6776c1fe048ca6246217065db3b081fe Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:48:13 -0400 Subject: [PATCH 27/38] amend --- .../replay-buffers/distributed_replay_buffer_multiproc.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 28f9d9056e2..9c04439df84 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -42,7 +42,8 @@ def main(rank): str_init_method = "tcp://localhost:10000" options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, init_method=str_init_method + num_worker_threads=16, + init_method=str_init_method ) if rank == 0: @@ -57,7 +58,6 @@ def main(rank): torchrl_logger.info(f"Initialised Trainer Node {rank}") trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) trainer.train(100) - breakpoint() elif rank == 1: # rank 1 is the replay buffer # replay buffer waits passively for construction instructions from trainer node @@ -69,7 +69,6 @@ def main(rank): rpc_backend_options=options, ) torchrl_logger.info(f"Initialised RB Node {rank}") - breakpoint() else: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node @@ -81,7 +80,6 @@ def main(rank): rpc_backend_options=options, ) torchrl_logger.info(f"Initialised DC Node {rank}") - breakpoint() rpc.shutdown() if __name__ == "__main__": @@ -91,5 +89,5 @@ def main(rank): procs.append(ctx.Process(target=main, args=(i,))) procs[-1].start() - for p in procs: + for p in reversed(procs): p.join() From 2fedd8bfaebc79eab40cff779600afc636f8e77d Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 14:57:37 -0400 Subject: [PATCH 28/38] amend --- .../replay-buffers/distributed_rb_utils.py | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index b78b549eea2..88113fa84e3 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -141,43 +141,32 @@ def _create_replay_buffer(self) -> rpc.RRef: time.sleep(RETRY_DELAY_SECS) def _create_and_launch_data_collectors(self) -> None: - data_collector_number = 2 + data_collector_number = 1 retries = 0 data_collectors = [] data_collector_infos = [] # discover launched data collector nodes (with retry to allow collectors to dynamically join) - while True: - try: - data_collector_info = rpc.get_worker_info( - f"DataCollector{data_collector_number}" - ) - torchrl_logger.info(f"Data collector info: {data_collector_info}") - dc_ref = rpc.remote( - data_collector_info, - CollectorNode, - args=(self.replay_buffer,), - ) - data_collectors.append(dc_ref) - data_collector_infos.append(data_collector_info) - data_collector_number += 1 - retries = 0 - except Exception: - retries += 1 - torchrl_logger.info( - f"Failed to connect to DataCollector{data_collector_number} with {retries} retries" - ) - if retries >= RETRY_LIMIT: - torchrl_logger.info(f"{len(data_collectors)} data collectors") - for data_collector_info, data_collector in zip( - data_collector_infos, data_collectors - ): - rpc.remote( - data_collector_info, - CollectorNode.collect, - args=(data_collector,), - ) - break - else: + def connect(n): + data_collector_info = rpc.get_worker_info( + f"DataCollector{n + 2}" # 2, 3, 4, ... + ) + torchrl_logger.info(f"Data collector info: {data_collector_info}") + dc_ref = rpc.remote( + data_collector_info, + CollectorNode, + args=(self.replay_buffer,), + ) + data_collectors.append(dc_ref) + data_collector_infos.append(data_collector_info) + + for n in range(data_collector_number): + for retry in range(RETRY_LIMIT): + try: + connect(n) + except Exception: + torchrl_logger.info( + f"Failed to connect to DataCollector{n} with {retry} retries" + ) time.sleep(RETRY_DELAY_SECS) From 9aa50142171b34981b184fc5152f482a5699f0ce Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:02:24 -0400 Subject: [PATCH 29/38] amend --- .../replay-buffers/distributed_replay_buffer_multiproc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 9c04439df84..5530fc61543 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -55,7 +55,7 @@ def main(rank): backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, ) - torchrl_logger.info(f"Initialised Trainer Node {rank}") + torchrl_logger.info(f"Initialised {TRAINER_NODE}") trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) trainer.train(100) elif rank == 1: @@ -68,18 +68,18 @@ def main(rank): backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, ) - torchrl_logger.info(f"Initialised RB Node {rank}") + torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") else: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node - torchrl_logger.info(f"Init RPC on {rank} collector node") + torchrl_logger.info(f"Init RPC on DataCollector{rank}") rpc.init_rpc( f"DataCollector{rank}", rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, ) - torchrl_logger.info(f"Initialised DC Node {rank}") + torchrl_logger.info(f"Initialised DataCollector{rank}") rpc.shutdown() if __name__ == "__main__": From 99fdc0286dcc1dcd8453168b62c1af6b053845ab Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:03:42 -0400 Subject: [PATCH 30/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 88113fa84e3..0a268000848 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -107,7 +107,7 @@ def __init__(self, replay_buffer_node="ReplayBuffer") -> None: def train(self, iterations: int) -> None: """Write your training loop here.""" - for iteration in tqdm.tqdm(iterations): + for iteration in tqdm.tqdm(range(iterations)): torchrl_logger.info(f"[{self.id}] Training Iteration: {iteration}") # # Wait until the buffer has elements while not rpc.rpc_sync( From f4a2150ab430a67c369a232414e2fb9d1bda3bc4 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:07:59 -0400 Subject: [PATCH 31/38] amend --- .../replay-buffers/distributed_rb_utils.py | 25 +++++++++++-------- .../distributed_replay_buffer_multiproc.py | 2 ++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 0a268000848..04a9324105e 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -128,14 +128,17 @@ def train(self, iterations: int) -> None: # Process the sample here: forward, backward, ... def _create_replay_buffer(self) -> rpc.RRef: + def connect(): + replay_buffer_info = rpc.get_worker_info(self.replay_buffer_node) + buffer_rref = rpc.remote( + replay_buffer_info, ReplayBufferNode, args=(10000,) + ) + torchrl_logger.info(f"Connected to replay buffer {replay_buffer_info}") + return buffer_rref + while True: try: - replay_buffer_info = rpc.get_worker_info(self.replay_buffer_node) - buffer_rref = rpc.remote( - replay_buffer_info, ReplayBufferNode, args=(10000,) - ) - torchrl_logger.info(f"Connected to replay buffer {replay_buffer_info}") - return buffer_rref + return connect() except Exception as e: torchrl_logger.info(f"Failed to connect to replay buffer: {e}") time.sleep(RETRY_DELAY_SECS) @@ -146,11 +149,11 @@ def _create_and_launch_data_collectors(self) -> None: data_collectors = [] data_collector_infos = [] # discover launched data collector nodes (with retry to allow collectors to dynamically join) - def connect(n): + def connect(n, retry): data_collector_info = rpc.get_worker_info( f"DataCollector{n + 2}" # 2, 3, 4, ... ) - torchrl_logger.info(f"Data collector info: {data_collector_info}") + torchrl_logger.info(f"Data collector info: {data_collector_info}-retry={retry}") dc_ref = rpc.remote( data_collector_info, CollectorNode, @@ -162,10 +165,10 @@ def connect(n): for n in range(data_collector_number): for retry in range(RETRY_LIMIT): try: - connect(n) - except Exception: + connect(n, retry) + except Exception as e: torchrl_logger.info( - f"Failed to connect to DataCollector{n} with {retry} retries" + f"Failed to connect to DataCollector{n} with {retry} retries (err={e})" ) time.sleep(RETRY_DELAY_SECS) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 5530fc61543..eb9e2aecab5 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -22,6 +22,7 @@ import os import sys +import time import torch.distributed.rpc as rpc @@ -80,6 +81,7 @@ def main(rank): rpc_backend_options=options, ) torchrl_logger.info(f"Initialised DataCollector{rank}") + time.sleep(10) rpc.shutdown() if __name__ == "__main__": From ac3ac30e4ded1463b0b5c2694a8f8961ca527a11 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:09:22 -0400 Subject: [PATCH 32/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index eb9e2aecab5..57045fc8993 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -55,6 +55,7 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, + world_size=3, ) torchrl_logger.info(f"Initialised {TRAINER_NODE}") trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) @@ -68,6 +69,7 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, + world_size=3, ) torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") else: @@ -79,6 +81,7 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, + world_size=3, ) torchrl_logger.info(f"Initialised DataCollector{rank}") time.sleep(10) From f498020a51b296e39404b1f237e96369c08c8c13 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:11:58 -0400 Subject: [PATCH 33/38] amend --- examples/replay-buffers/distributed_replay_buffer_multiproc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 57045fc8993..6dfb906ad91 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -44,7 +44,7 @@ def main(rank): options = rpc.TensorPipeRpcBackendOptions( num_worker_threads=16, - init_method=str_init_method + # init_method=str_init_method ) if rank == 0: From b0b42e8dd881c15d880a3b1a817029a5748322c8 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:17:13 -0400 Subject: [PATCH 34/38] amend --- examples/replay-buffers/distributed_rb_utils.py | 3 +++ .../replay-buffers/distributed_replay_buffer_multiproc.py | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 04a9324105e..ea950d2c658 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -166,11 +166,14 @@ def connect(n, retry): for retry in range(RETRY_LIMIT): try: connect(n, retry) + break except Exception as e: torchrl_logger.info( f"Failed to connect to DataCollector{n} with {retry} retries (err={e})" ) time.sleep(RETRY_DELAY_SECS) + else: + raise Exception class ReplayBufferNode(RemoteReplayBuffer): diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 6dfb906ad91..87d0e4f07a4 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -60,6 +60,7 @@ def main(rank): torchrl_logger.info(f"Initialised {TRAINER_NODE}") trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) trainer.train(100) + rpc.shutdown() elif rank == 1: # rank 1 is the replay buffer # replay buffer waits passively for construction instructions from trainer node @@ -72,6 +73,7 @@ def main(rank): world_size=3, ) torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") + rpc.shutdown() else: # rank 2+ is a new data collector node # data collectors also wait passively for construction instructions from trainer node @@ -84,8 +86,7 @@ def main(rank): world_size=3, ) torchrl_logger.info(f"Initialised DataCollector{rank}") - time.sleep(10) - rpc.shutdown() + rpc.shutdown() if __name__ == "__main__": ctx = mp.get_context("spawn") From 77df0127c156782025e942e46175810df335bebb Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:21:36 -0400 Subject: [PATCH 35/38] amend --- .../replay-buffers/distributed_rb_utils.py | 20 ++++++++++++------- .../distributed_replay_buffer_multiproc.py | 14 +++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index ea950d2c658..e23d5339a39 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -98,8 +98,9 @@ def collect(self): class TrainerNode: """Trainer node responsible for learning from experiences sampled from an experience replay buffer.""" - def __init__(self, replay_buffer_node="ReplayBuffer") -> None: + def __init__(self, replay_buffer_node="ReplayBuffer", world_size=3) -> None: self.replay_buffer_node = replay_buffer_node + self.world_size = world_size torchrl_logger.info("TrainerNode") self.id = rpc.get_worker_info().id self.replay_buffer = self._create_replay_buffer() @@ -144,10 +145,9 @@ def connect(): time.sleep(RETRY_DELAY_SECS) def _create_and_launch_data_collectors(self) -> None: - data_collector_number = 1 - retries = 0 - data_collectors = [] - data_collector_infos = [] + data_collector_number = self.world_size-2 + self.data_collectors = [] + self.data_collector_infos = [] # discover launched data collector nodes (with retry to allow collectors to dynamically join) def connect(n, retry): data_collector_info = rpc.get_worker_info( @@ -159,8 +159,8 @@ def connect(n, retry): CollectorNode, args=(self.replay_buffer,), ) - data_collectors.append(dc_ref) - data_collector_infos.append(data_collector_info) + self.data_collectors.append(dc_ref) + self.data_collector_infos.append(data_collector_info) for n in range(data_collector_number): for retry in range(RETRY_LIMIT): @@ -174,6 +174,12 @@ def connect(n, retry): time.sleep(RETRY_DELAY_SECS) else: raise Exception + for collector, data_collector_info in zip(self.data_collectors, self.data_collector_infos): + rpc.remote( + data_collector_info, + CollectorNode.collect, + args=(collector,), + ) class ReplayBufferNode(RemoteReplayBuffer): diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 87d0e4f07a4..036bac1116d 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -34,7 +34,7 @@ REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" -def main(rank): +def main(rank, world_size): torchrl_logger.info(f"Rank: {rank}") os.environ["MASTER_ADDR"] = "localhost" @@ -55,7 +55,7 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, - world_size=3, + world_size=world_size, ) torchrl_logger.info(f"Initialised {TRAINER_NODE}") trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) @@ -70,7 +70,7 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, - world_size=3, + world_size=world_size, ) torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") rpc.shutdown() @@ -83,16 +83,18 @@ def main(rank): rank=rank, backend=rpc.BackendType.TENSORPIPE, rpc_backend_options=options, - world_size=3, + world_size=world_size, ) torchrl_logger.info(f"Initialised DataCollector{rank}") rpc.shutdown() + print('exiting', rank) if __name__ == "__main__": ctx = mp.get_context("spawn") procs = [] - for i in range(3): - procs.append(ctx.Process(target=main, args=(i,))) + world_size = 3 + for i in range(world_size): + procs.append(ctx.Process(target=main, args=(i, world_size))) procs[-1].start() for p in reversed(procs): From cbc04dfc73d8592af3599abff6af4660eab81a75 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:49:44 -0400 Subject: [PATCH 36/38] amend --- .../replay-buffers/distributed_rb_utils.py | 69 +++++++++++- .../distributed_replay_buffer.py | 60 +--------- .../distributed_replay_buffer_distlaunch.py | 103 ------------------ .../distributed_replay_buffer_multiproc.py | 58 +--------- .../distributed_replay_buffer_submitit.py | 94 ++++------------ 5 files changed, 95 insertions(+), 289 deletions(-) delete mode 100644 examples/replay-buffers/distributed_replay_buffer_distlaunch.py diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index e23d5339a39..1d77e93306c 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. +import os import random import time @@ -21,6 +22,9 @@ RETRY_LIMIT = 2 RETRY_DELAY_SECS = 3 +REPLAY_BUFFER_NODE = "ReplayBuffer" +TRAINER_NODE = "Trainer" + class CollectorNode: """Data collector node responsible for collecting experiences used for learning. @@ -145,7 +149,7 @@ def connect(): time.sleep(RETRY_DELAY_SECS) def _create_and_launch_data_collectors(self) -> None: - data_collector_number = self.world_size-2 + data_collector_number = self.world_size - 2 self.data_collectors = [] self.data_collector_infos = [] # discover launched data collector nodes (with retry to allow collectors to dynamically join) @@ -153,7 +157,9 @@ def connect(n, retry): data_collector_info = rpc.get_worker_info( f"DataCollector{n + 2}" # 2, 3, 4, ... ) - torchrl_logger.info(f"Data collector info: {data_collector_info}-retry={retry}") + torchrl_logger.info( + f"Data collector info: {data_collector_info}-retry={retry}" + ) dc_ref = rpc.remote( data_collector_info, CollectorNode, @@ -174,7 +180,9 @@ def connect(n, retry): time.sleep(RETRY_DELAY_SECS) else: raise Exception - for collector, data_collector_info in zip(self.data_collectors, self.data_collector_infos): + for collector, data_collector_info in zip( + self.data_collectors, self.data_collector_infos + ): rpc.remote( data_collector_info, CollectorNode.collect, @@ -201,3 +209,58 @@ def __init__(self, capacity: int): writer=RoundRobinWriter(), batch_size=32, ) + + +def main(rank, world_size, **tensorpipe_kwargs): + torchrl_logger.info(f"Rank: {rank}") + + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = "29500" + os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" + # + + options = rpc.TensorPipeRpcBackendOptions( + num_worker_threads=16, **tensorpipe_kwargs + ) + + if rank == 0: + # rank 0 is the trainer + torchrl_logger.info(f"Init RPC on {TRAINER_NODE}...") + rpc.init_rpc( + TRAINER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + world_size=world_size, + ) + torchrl_logger.info(f"Initialised {TRAINER_NODE}") + trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) + trainer.train(100) + rpc.shutdown() + elif rank == 1: + # rank 1 is the replay buffer + # replay buffer waits passively for construction instructions from trainer node + torchrl_logger.info(f"Init RPC on {REPLAY_BUFFER_NODE}...") + rpc.init_rpc( + REPLAY_BUFFER_NODE, + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + world_size=world_size, + ) + torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") + rpc.shutdown() + else: + # rank 2+ is a new data collector node + # data collectors also wait passively for construction instructions from trainer node + torchrl_logger.info(f"Init RPC on DataCollector{rank}") + rpc.init_rpc( + f"DataCollector{rank}", + rank=rank, + backend=rpc.BackendType.TENSORPIPE, + rpc_backend_options=options, + world_size=world_size, + ) + torchrl_logger.info(f"Initialised DataCollector{rank}") + rpc.shutdown() + print("exiting", rank) diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index c0981b35640..253b6c8a3be 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -26,13 +26,8 @@ """ import argparse -import os -import sys -import torch.distributed.rpc as rpc - -from distributed_rb_utils import TrainerNode -from torchrl._utils import logger as torchrl_logger +from distributed_rb_utils import main REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" @@ -48,60 +43,13 @@ default=-1, help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", ) +parser.add_argument("--world_size", type=int, default=3, help="Number of nodes/workers") if __name__ == "__main__": args = parser.parse_args() rank = args.rank - torchrl_logger.info(f"Rank: {rank}") - - os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29500" - os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" - - options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, init_method=str_init_method - ) + world_size = args.world_size - if rank == 0: - # rank 0 is the trainer - torchrl_logger.info(f"Init RPC on {TRAINER_NODE}...") - rpc.init_rpc( - TRAINER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) - trainer.train(100) - breakpoint() - elif rank == 1: - # rank 1 is the replay buffer - # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(f"Init RPC on {REPLAY_BUFFER_NODE}...") - rpc.init_rpc( - REPLAY_BUFFER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised RB Node {rank}") - breakpoint() - elif rank >= 2: - # rank 2+ is a new data collector node - # data collectors also wait passively for construction instructions from trainer node - torchrl_logger.info(f"Init RPC on {rank} collector node") - rpc.init_rpc( - f"DataCollector{rank}", - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised DC Node {rank}") - breakpoint() - else: - sys.exit(1) - rpc.shutdown() + main(rank, world_size, str_init_method="tcp://localhost:10000") diff --git a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py b/examples/replay-buffers/distributed_replay_buffer_distlaunch.py deleted file mode 100644 index 10c06d8dd83..00000000000 --- a/examples/replay-buffers/distributed_replay_buffer_distlaunch.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -Example use of a distributed replay buffer -========================================== - -This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion -with communication between nodes/workers handled using `torch.rpc`. -It focusses on how to set up a replay buffer worker that accepts remote operation requests efficiently, and so omits -any learning component such as parameter updates that may be required for a complete distributed reinforcement learning -algorithm implementation. - -In this model, >= 1 data collectors workers are responsible for collecting experiences in an environment, the replay -buffer worker receives all of these experiences and exposes them to a trainer that is responsible for making parameter -updates to any required models. - -To launch this script, run - -```bash -$ # In terminal0: Trainer node -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=0 -$ # In terminal1: Replay buffer node -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=1 -$ # In terminal2 to N: Collector nodes -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=2 - -``` -""" - -import argparse -import os -import sys - -import torch.distributed.rpc as rpc - -from distributed_rb_utils import TrainerNode -from torchrl._utils import logger as torchrl_logger - -REPLAY_BUFFER_NODE = "ReplayBuffer" -TRAINER_NODE = "Trainer" - -parser = argparse.ArgumentParser( - description="RPC Replay Buffer Example", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, -) - -parser.add_argument( - "--rank", - type=int, - default=-1, - help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", -) - - -if __name__ == "__main__": - - args = parser.parse_args() - rank = args.rank - torchrl_logger.info(f"Rank: {rank}") - - os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29500" - os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" - options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, init_method=str_init_method - ) - if rank == 0: - # rank 0 is the trainer - rpc.init_rpc( - TRAINER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode() - trainer.train(100) - breakpoint() - elif rank == 1: - # rank 1 is the replay buffer - # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(REPLAY_BUFFER_NODE) - rpc.init_rpc( - REPLAY_BUFFER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised RB Node {rank}") - breakpoint() - elif rank >= 2: - # rank 2+ is a new data collector node - # data collectors also wait passively for construction instructions from trainer node - rpc.init_rpc( - f"DataCollector{rank}", - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised DC Node {rank}") - breakpoint() - else: - sys.exit(1) - rpc.shutdown() diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 036bac1116d..7c90f6e9f81 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -26,69 +26,13 @@ import torch.distributed.rpc as rpc -from distributed_rb_utils import TrainerNode -from torchrl._utils import logger as torchrl_logger +from distributed_rb_utils import main from torch import multiprocessing as mp REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" -def main(rank, world_size): - torchrl_logger.info(f"Rank: {rank}") - - os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29501" - os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" - - options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, - # init_method=str_init_method - ) - - if rank == 0: - # rank 0 is the trainer - torchrl_logger.info(f"Init RPC on {TRAINER_NODE}...") - rpc.init_rpc( - TRAINER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - world_size=world_size, - ) - torchrl_logger.info(f"Initialised {TRAINER_NODE}") - trainer = TrainerNode(replay_buffer_node=REPLAY_BUFFER_NODE) - trainer.train(100) - rpc.shutdown() - elif rank == 1: - # rank 1 is the replay buffer - # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(f"Init RPC on {REPLAY_BUFFER_NODE}...") - rpc.init_rpc( - REPLAY_BUFFER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - world_size=world_size, - ) - torchrl_logger.info(f"Initialised {REPLAY_BUFFER_NODE}") - rpc.shutdown() - else: - # rank 2+ is a new data collector node - # data collectors also wait passively for construction instructions from trainer node - torchrl_logger.info(f"Init RPC on DataCollector{rank}") - rpc.init_rpc( - f"DataCollector{rank}", - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - world_size=world_size, - ) - torchrl_logger.info(f"Initialised DataCollector{rank}") - rpc.shutdown() - print('exiting', rank) - if __name__ == "__main__": ctx = mp.get_context("spawn") procs = [] diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py index 7d94b31b67f..5e45ee65d1c 100644 --- a/examples/replay-buffers/distributed_replay_buffer_submitit.py +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -15,88 +15,42 @@ To launch this script, run ```bash -$ # In terminal0: Trainer node -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=0 -$ # In terminal1: Replay buffer node -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=1 -$ # In terminal2 to N: Collector nodes -$ python examples/replay-buffers/distributed_replay_buffer.py --rank=2 - +python examples/replay-buffers/distributed_replay_buffer_submitit.py ``` + """ -import argparse import os import sys +import time + +import submitit import torch.distributed.rpc as rpc -from distributed_rb_utils import TrainerNode +from distributed_rb_utils import main +from torch import multiprocessing as mp from torchrl._utils import logger as torchrl_logger -REPLAY_BUFFER_NODE = "ReplayBuffer" -TRAINER_NODE = "Trainer" -parser = argparse.ArgumentParser( - description="RPC Replay Buffer Example", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, -) - -parser.add_argument( - "--rank", - type=int, - default=-1, - help="Node Rank [0 = Replay Buffer, 1 = Dummy Trainer, 2+ = Dummy Data Collector]", -) +DEFAULT_SLURM_CONF = { + "timeout_min": 10, + "slurm_partition": "train", + "slurm_cpus_per_task": 32, + "slurm_gpus_per_node": 0, +} #: Default value of the SLURM jobs if __name__ == "__main__": - args = parser.parse_args() - rank = args.rank - torchrl_logger.info(f"Rank: {rank}") + executor = submitit.AutoExecutor(folder="log_test") + executor.update_parameters(**DEFAULT_SLURM_CONF) + + ctx = mp.get_context("spawn") + jobs = [] + world_size = 3 + for i in range(world_size): + job = executor.submit(main, i, world_size) + jobs.append(job) - os.environ["MASTER_ADDR"] = "localhost" - os.environ["MASTER_PORT"] = "29500" - os.environ["TORCH_DISTRIBUTED_DEBUG"] = "DETAIL" - str_init_method = "tcp://localhost:10000" - options = rpc.TensorPipeRpcBackendOptions( - num_worker_threads=16, init_method=str_init_method - ) - if rank == 0: - # rank 0 is the trainer - rpc.init_rpc( - TRAINER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised Trainer Node {rank}") - trainer = TrainerNode() - trainer.train(100) - breakpoint() - elif rank == 1: - # rank 1 is the replay buffer - # replay buffer waits passively for construction instructions from trainer node - torchrl_logger.info(REPLAY_BUFFER_NODE) - rpc.init_rpc( - REPLAY_BUFFER_NODE, - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised RB Node {rank}") - breakpoint() - elif rank >= 2: - # rank 2+ is a new data collector node - # data collectors also wait passively for construction instructions from trainer node - rpc.init_rpc( - f"DataCollector{rank}", - rank=rank, - backend=rpc.BackendType.TENSORPIPE, - rpc_backend_options=options, - ) - torchrl_logger.info(f"Initialised DC Node {rank}") - breakpoint() - else: - sys.exit(1) - rpc.shutdown() + for i in range(world_size): + jobs[i].result() From 68d9819ef5d5c2daf0014c072f38eda57a41277e Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 15:51:04 -0400 Subject: [PATCH 37/38] amend --- .../replay-buffers/distributed_replay_buffer.py | 4 ++-- .../distributed_replay_buffer_multiproc.py | 12 +++--------- .../distributed_replay_buffer_submitit.py | 14 +++----------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/examples/replay-buffers/distributed_replay_buffer.py b/examples/replay-buffers/distributed_replay_buffer.py index 253b6c8a3be..325ceb6ea9a 100644 --- a/examples/replay-buffers/distributed_replay_buffer.py +++ b/examples/replay-buffers/distributed_replay_buffer.py @@ -1,6 +1,6 @@ """ -Example use of a distributed replay buffer -========================================== +Example use of a distributed replay buffer (custom) +=================================================== This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion with communication between nodes/workers handled using `torch.rpc`. diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index 7c90f6e9f81..bb65ee719f0 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -1,6 +1,6 @@ """ -Example use of a distributed replay buffer -========================================== +Example use of a distributed replay buffer (single node) +======================================================== This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion with communication between nodes/workers handled using `torch.rpc`. @@ -20,15 +20,9 @@ """ -import os -import sys -import time - -import torch.distributed.rpc as rpc - -from distributed_rb_utils import main from torch import multiprocessing as mp +from distributed_rb_utils import main REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py index 5e45ee65d1c..040b8b0186f 100644 --- a/examples/replay-buffers/distributed_replay_buffer_submitit.py +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -1,6 +1,6 @@ """ -Example use of a distributed replay buffer -========================================== +Example use of a distributed replay buffer (submitit) +===================================================== This example illustrates how a skeleton reinforcement learning algorithm can be implemented in a distributed fashion with communication between nodes/workers handled using `torch.rpc`. @@ -20,18 +20,10 @@ """ -import os -import sys -import time - import submitit - -import torch.distributed.rpc as rpc - -from distributed_rb_utils import main from torch import multiprocessing as mp -from torchrl._utils import logger as torchrl_logger +from distributed_rb_utils import main DEFAULT_SLURM_CONF = { "timeout_min": 10, From cb23ae2d8a53fe0d9abb4d47cfd1edb86a79a093 Mon Sep 17 00:00:00 2001 From: Vincent Moens Date: Wed, 7 Aug 2024 16:54:47 -0400 Subject: [PATCH 38/38] amend --- docs/source/reference/data.rst | 3 ++ .../replay-buffers/distributed_rb_utils.py | 7 +++ .../distributed_replay_buffer_multiproc.py | 3 +- .../distributed_replay_buffer_submitit.py | 2 +- knowledge_base/DISTRIBUTED_BUFFER.md | 43 ++++++++++++++++++ knowledge_base/distributed-collectors.png | Bin 0 -> 50078 bytes knowledge_base/distributed-rb.png | Bin 0 -> 197863 bytes 7 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 knowledge_base/DISTRIBUTED_BUFFER.md create mode 100644 knowledge_base/distributed-collectors.png create mode 100644 knowledge_base/distributed-rb.png diff --git a/docs/source/reference/data.rst b/docs/source/reference/data.rst index ed5639fcf59..653f61f2db4 100644 --- a/docs/source/reference/data.rst +++ b/docs/source/reference/data.rst @@ -188,6 +188,9 @@ were found from rough benchmarking in https://github.com/pytorch/rl/tree/main/be | :class:`LazyMemmapStorage` | 3.44x | +-------------------------------+-----------+ +You can also read more about distributed replay buffers in https://github.com/pytorch/rl/tree/main/knowledge_base/DISTRIBUTED_BUFFER.md +and find examples of dummy training loops in https://github.com/pytorch/rl/tree/main/examples/replay-buffers/ + Sharing replay buffers across processes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/replay-buffers/distributed_rb_utils.py b/examples/replay-buffers/distributed_rb_utils.py index 1d77e93306c..d79c7a78c34 100644 --- a/examples/replay-buffers/distributed_rb_utils.py +++ b/examples/replay-buffers/distributed_rb_utils.py @@ -212,6 +212,13 @@ def __init__(self, capacity: int): def main(rank, world_size, **tensorpipe_kwargs): + """Dispatcher for the distributed workflow. + + rank 0 will be assigned the TRAINER job, + rank 1 will be assigned the REPLAY BUFFER job, + rank 2 to world_size-1 will be assigned the COLLECTOR jobs. + + """ torchrl_logger.info(f"Rank: {rank}") os.environ["MASTER_ADDR"] = "localhost" diff --git a/examples/replay-buffers/distributed_replay_buffer_multiproc.py b/examples/replay-buffers/distributed_replay_buffer_multiproc.py index bb65ee719f0..79967340bd0 100644 --- a/examples/replay-buffers/distributed_replay_buffer_multiproc.py +++ b/examples/replay-buffers/distributed_replay_buffer_multiproc.py @@ -20,9 +20,8 @@ """ -from torch import multiprocessing as mp - from distributed_rb_utils import main +from torch import multiprocessing as mp REPLAY_BUFFER_NODE = "ReplayBuffer" TRAINER_NODE = "Trainer" diff --git a/examples/replay-buffers/distributed_replay_buffer_submitit.py b/examples/replay-buffers/distributed_replay_buffer_submitit.py index 040b8b0186f..5bb2c943815 100644 --- a/examples/replay-buffers/distributed_replay_buffer_submitit.py +++ b/examples/replay-buffers/distributed_replay_buffer_submitit.py @@ -21,9 +21,9 @@ """ import submitit -from torch import multiprocessing as mp from distributed_rb_utils import main +from torch import multiprocessing as mp DEFAULT_SLURM_CONF = { "timeout_min": 10, diff --git a/knowledge_base/DISTRIBUTED_BUFFER.md b/knowledge_base/DISTRIBUTED_BUFFER.md new file mode 100644 index 00000000000..01d5865773b --- /dev/null +++ b/knowledge_base/DISTRIBUTED_BUFFER.md @@ -0,0 +1,43 @@ +# Distributed replay buffers in TorchRL + +This documents gives an overview of the various ways one can play with multiple nodes to collect +data in TorchRL. + + +## Sharing buffer between nodes using torch RPC + +TorchRL provides an API to call replay buffer methods remotely on a dedicated node. +This can be used as described in the following drawing: + +![distributed-rb.png](distributed-rb.png) + +Three node categories are instantiated: a trainer, a buffer node and a set of collector nodes. + +When all nodes are ready, the collector nodes start sending data to the buffer node by calling +`buffer.extend(tensordict)` remotely. + +The buffer node passively receives these calls and writes the data it receives in the storage. + +Once enough data has been written, the trainer node starts asking the buffer node for data to process. +The `buffer` sends that data over the wire. + +In some cases, all nodes have access to a shared physical storage (check with your administrator if this +is the case and if they will allow you to do frequent read and writing operations). +If this is the case, a `LazyMemmapStorage` can be instantiated with the shared path as `scratch_dir`. +In this case, node-to-node communications will be drastically reduced as each node will be able to directly +read and write on the storage. The only data passing over the wire from node to node will be the metadata +(shape, number of elements, size of the buffer etc.). + +Have a look at the examples [here](https://github.com/pytorch/rl/tree/main/examples/replay-buffers/). + +## Distributed collectors + +![distributed-collectors.png](distributed-collectors.png) + +### Backends + +#### Ray + +#### torch.distributed + +#### RPC diff --git a/knowledge_base/distributed-collectors.png b/knowledge_base/distributed-collectors.png new file mode 100644 index 0000000000000000000000000000000000000000..c9d52c7212e1287ec7efd92748819a4075216cb5 GIT binary patch literal 50078 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 PAwIH_N)i=fhW`Hxoxj)` literal 0 HcmV?d00001 diff --git a/knowledge_base/distributed-rb.png b/knowledge_base/distributed-rb.png new file mode 100644 index 0000000000000000000000000000000000000000..5b868b7db91de0eff1bc5d28e7b8338377ab1074 GIT binary patch literal 197863 zcmc$`bzGHQ(>6>=NP~nl(rwV)DM;5QB&54HDJ|V09a7TLQc8DscXv1MiFI8*?|nai zec$i>OI&-OYt5QD=9pRQoY?`gGGfS&@g74!Kp;zq3(G@5JW7UufMI}#1x8++EFJ;> zK-$WS2|^V05o|(0kU&TX3n)5i?IgoZV6{&A!Hs-qxie*cA-Pl90t-J8f+rO{QQD3z zEOPnWAtV9U1@cJ4x!T*b}5Q86I{P(Ru zK;@zH+sPnPJQeso>3`UE#w)%5JGdT*{w4`hROCb_qX%+6x}3kqy2pMb+yZ(Tr)&2JB!$wc7wQ% zRtWzXi9a9hVkwAe#=YmqD?-f8oyS%*B8CoZq-Kk37J#*)0>n8BD8C;MThw2$yN zxBDKBT>Evl#*ihqXVbMpC>$*el@q#o%*#c!dp3v+<>4T=(@}5VRv!dR$;&zLda{Kt zma=#j!AsA7v`9_q`9iO)Ix~#-t0Ko_!u4LQ<-&(>(WbfA-p|1NX%z@0oZ|zH+U}QG z*X?|Fi^?E#7Pe`#ve9tpss~saA$dwfQP#ZSy=*z%7$mbXB|HY5-M$1L=~s19CRTgg zZfgtZ2>GMf6A}{UVcksVh1DcGOwn}gS58|XVq?4P*H^h5_p*7XGSu#T`QE>tWZO5= zMNS6KPeKH_HsO?1{TNuo0%{^LWS`HscEYBcK?*AZqEObtm|~~5Ts#sLMm-TC!xs70 z6eK3YcWcM?_S<_rn}t|qs|v-VW~)>}yNe$|wo=?g7Gp@ha;>mW!-9cE8@m z;q%5-(Y0)Q-$H@*{=JZ$3_Cot=lu#5AHv>H#soh%h^;Bwv0CJn!*(kNtC1KZ~8Fx(o+D*{znSk$b>+RoNG7SmW-*vQP4 zKhCu3Wf`}7T)0qHvyl-rlbvXxeuWNLk!&3Rg-yNlDJ|B?$?%(;hBW1*jmEpvVu7d4 z{-}-s2&4}zTWxulgI{@h+#mS!*`e~?SW&`t>c5G=AQ?!4iPuXkn?EWz-L0D6JDc~o zPwNmu3*%vR^4MzL3iG&GZW^hd zrS+;;>mh19pL3bja@oaFlyO+MAJ>fg?CpKjI!A9XuRsU?Bm_V}6H$b0<;jo~oMWfL zLApPYWIS|S6(?k?3CpsoR$pN9Xwl~I8$SEu`m+R=)fkl-%s1TVA2jB#=gwz5?yu+N z>8EYX$O9!xv~4;mrm?i8cd_>o8LPi(dfc8yoEO*beHCyb@zp@n_DFBLQN}zHX6y9c zU5R>wvL`2w>^mkNxz~8_p2J}f#&Z_mDm8mF>AYPy`>LNC^G2nA_E``;#tkUwWUk&N zE~OrwOq5+y3ZS_o(r*NbsOtudBDHVJ@kMEN3lDl*R{iiTHcs5@_8YEedvV&nSdMy=?QY z5@kjK+hJUL?2eP~;$o)0G^22_mzJ*h=MDAWo#gP<0Nj^BF{QO4`qmP=#<3wk(UPgF zTaENAl6fq{1N-*?b;70S#;)uZ1gH_|yMKP?^+pwok%`(d3mbM`s3FpSGFW z=MkQpO+2sKt(>Op0>TM8BcmS#%x56AxFb$0Zn)~|E6rm$yO-CN#@7T@5j9 zQY{NX1Ap$6asn*QBs_|hBG8nc`XmP&r|EzIb8T~~@7~>b-N$$D>NsVb^XL&E>!d~P zZl#oB00JhZ-B+;`I(Jv2cWZo64jkE-34>0RodufdF|#jpclU=eKMRDW@cty&ApQ#FdNyOe)x=swQv;mm+BOozq8u zqsTh--6_X;w<yBgHb5gsdL^elNw2^s_n1!wY)|ufspTTSq zQJ~i^Rk~Vb@_0%x6pN)tSU~*-n(#GE1jrhETEJBD4Jx_B7YFhP_A8LQ%zo)+1feq> zgYGi>=NSto`Y0J&3Ilk@#6Og*5Mvneajixxc*W02a&9QY&G|*`BNLtx1%Ysiy!mS} z24o28yYJ4b8XqlwN/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 Pfj=$WS+x>XtDye}G4~u2 literal 0 HcmV?d00001