mirror of
https://github.com/saymrwulf/stable-baselines3.git
synced 2026-09-16 22:20:26 +00:00
Support for device=auto buffers and set it as default value (#1009)
* Default device is "auto" for buffer + auto device support in BufferBaseClass * Update docstring * Update tests * Unify tests * Update changelog * Fix tests on CUDA device Co-authored-by: Antonin RAFFIN <antonin.raffin@ensta.org> Co-authored-by: Antonin Raffin <antonin.raffin@dlr.de>
This commit is contained in:
parent
792e3bcc27
commit
73822c34da
4 changed files with 61 additions and 13 deletions
|
|
@ -29,6 +29,8 @@ Others:
|
||||||
^^^^^^^
|
^^^^^^^
|
||||||
- Fixed ``DictReplayBuffer.next_observations`` typing (@qgallouedec)
|
- Fixed ``DictReplayBuffer.next_observations`` typing (@qgallouedec)
|
||||||
|
|
||||||
|
- Added support for ``device="auto"`` in buffers and made it default (@qgallouedec)
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
- Fixed typo in docstring "nature" -> "Nature" (@Melanol)
|
- Fixed typo in docstring "nature" -> "Nature" (@Melanol)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from stable_baselines3.common.type_aliases import (
|
||||||
ReplayBufferSamples,
|
ReplayBufferSamples,
|
||||||
RolloutBufferSamples,
|
RolloutBufferSamples,
|
||||||
)
|
)
|
||||||
|
from stable_baselines3.common.utils import get_device
|
||||||
from stable_baselines3.common.vec_env import VecNormalize
|
from stable_baselines3.common.vec_env import VecNormalize
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -39,7 +40,7 @@ class BaseBuffer(ABC):
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
observation_space: spaces.Space,
|
observation_space: spaces.Space,
|
||||||
action_space: spaces.Space,
|
action_space: spaces.Space,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
n_envs: int = 1,
|
n_envs: int = 1,
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
@ -51,7 +52,7 @@ class BaseBuffer(ABC):
|
||||||
self.action_dim = get_action_dim(action_space)
|
self.action_dim = get_action_dim(action_space)
|
||||||
self.pos = 0
|
self.pos = 0
|
||||||
self.full = False
|
self.full = False
|
||||||
self.device = device
|
self.device = get_device(device)
|
||||||
self.n_envs = n_envs
|
self.n_envs = n_envs
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -157,7 +158,7 @@ class ReplayBuffer(BaseBuffer):
|
||||||
:param buffer_size: Max number of element in the buffer
|
:param buffer_size: Max number of element in the buffer
|
||||||
:param observation_space: Observation space
|
:param observation_space: Observation space
|
||||||
:param action_space: Action space
|
:param action_space: Action space
|
||||||
:param device:
|
:param device: PyTorch device
|
||||||
:param n_envs: Number of parallel environments
|
:param n_envs: Number of parallel environments
|
||||||
:param optimize_memory_usage: Enable a memory efficient variant
|
:param optimize_memory_usage: Enable a memory efficient variant
|
||||||
of the replay buffer which reduces by almost a factor two the memory used,
|
of the replay buffer which reduces by almost a factor two the memory used,
|
||||||
|
|
@ -175,7 +176,7 @@ class ReplayBuffer(BaseBuffer):
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
observation_space: spaces.Space,
|
observation_space: spaces.Space,
|
||||||
action_space: spaces.Space,
|
action_space: spaces.Space,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
n_envs: int = 1,
|
n_envs: int = 1,
|
||||||
optimize_memory_usage: bool = False,
|
optimize_memory_usage: bool = False,
|
||||||
handle_timeout_termination: bool = True,
|
handle_timeout_termination: bool = True,
|
||||||
|
|
@ -328,7 +329,7 @@ class RolloutBuffer(BaseBuffer):
|
||||||
:param buffer_size: Max number of element in the buffer
|
:param buffer_size: Max number of element in the buffer
|
||||||
:param observation_space: Observation space
|
:param observation_space: Observation space
|
||||||
:param action_space: Action space
|
:param action_space: Action space
|
||||||
:param device:
|
:param device: PyTorch device
|
||||||
:param gae_lambda: Factor for trade-off of bias vs variance for Generalized Advantage Estimator
|
:param gae_lambda: Factor for trade-off of bias vs variance for Generalized Advantage Estimator
|
||||||
Equivalent to classic advantage when set to 1.
|
Equivalent to classic advantage when set to 1.
|
||||||
:param gamma: Discount factor
|
:param gamma: Discount factor
|
||||||
|
|
@ -340,7 +341,7 @@ class RolloutBuffer(BaseBuffer):
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
observation_space: spaces.Space,
|
observation_space: spaces.Space,
|
||||||
action_space: spaces.Space,
|
action_space: spaces.Space,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
gae_lambda: float = 1,
|
gae_lambda: float = 1,
|
||||||
gamma: float = 0.99,
|
gamma: float = 0.99,
|
||||||
n_envs: int = 1,
|
n_envs: int = 1,
|
||||||
|
|
@ -493,7 +494,7 @@ class DictReplayBuffer(ReplayBuffer):
|
||||||
:param buffer_size: Max number of element in the buffer
|
:param buffer_size: Max number of element in the buffer
|
||||||
:param observation_space: Observation space
|
:param observation_space: Observation space
|
||||||
:param action_space: Action space
|
:param action_space: Action space
|
||||||
:param device:
|
:param device: PyTorch device
|
||||||
:param n_envs: Number of parallel environments
|
:param n_envs: Number of parallel environments
|
||||||
:param optimize_memory_usage: Enable a memory efficient variant
|
:param optimize_memory_usage: Enable a memory efficient variant
|
||||||
Disabled for now (see https://github.com/DLR-RM/stable-baselines3/pull/243#discussion_r531535702)
|
Disabled for now (see https://github.com/DLR-RM/stable-baselines3/pull/243#discussion_r531535702)
|
||||||
|
|
@ -507,7 +508,7 @@ class DictReplayBuffer(ReplayBuffer):
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
observation_space: spaces.Space,
|
observation_space: spaces.Space,
|
||||||
action_space: spaces.Space,
|
action_space: spaces.Space,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
n_envs: int = 1,
|
n_envs: int = 1,
|
||||||
optimize_memory_usage: bool = False,
|
optimize_memory_usage: bool = False,
|
||||||
handle_timeout_termination: bool = True,
|
handle_timeout_termination: bool = True,
|
||||||
|
|
@ -658,7 +659,7 @@ class DictRolloutBuffer(RolloutBuffer):
|
||||||
:param buffer_size: Max number of element in the buffer
|
:param buffer_size: Max number of element in the buffer
|
||||||
:param observation_space: Observation space
|
:param observation_space: Observation space
|
||||||
:param action_space: Action space
|
:param action_space: Action space
|
||||||
:param device:
|
:param device: PyTorch device
|
||||||
:param gae_lambda: Factor for trade-off of bias vs variance for Generalized Advantage Estimator
|
:param gae_lambda: Factor for trade-off of bias vs variance for Generalized Advantage Estimator
|
||||||
Equivalent to Monte-Carlo advantage estimate when set to 1.
|
Equivalent to Monte-Carlo advantage estimate when set to 1.
|
||||||
:param gamma: Discount factor
|
:param gamma: Discount factor
|
||||||
|
|
@ -670,7 +671,7 @@ class DictRolloutBuffer(RolloutBuffer):
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
observation_space: spaces.Space,
|
observation_space: spaces.Space,
|
||||||
action_space: spaces.Space,
|
action_space: spaces.Space,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
gae_lambda: float = 1,
|
gae_lambda: float = 1,
|
||||||
gamma: float = 0.99,
|
gamma: float = 0.99,
|
||||||
n_envs: int = 1,
|
n_envs: int = 1,
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class HerReplayBuffer(DictReplayBuffer):
|
||||||
self,
|
self,
|
||||||
env: VecEnv,
|
env: VecEnv,
|
||||||
buffer_size: int,
|
buffer_size: int,
|
||||||
device: Union[th.device, str] = "cpu",
|
device: Union[th.device, str] = "auto",
|
||||||
replay_buffer: Optional[DictReplayBuffer] = None,
|
replay_buffer: Optional[DictReplayBuffer] = None,
|
||||||
max_episode_length: Optional[int] = None,
|
max_episode_length: Optional[int] = None,
|
||||||
n_sampled_goal: int = 4,
|
n_sampled_goal: int = 4,
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ import pytest
|
||||||
import torch as th
|
import torch as th
|
||||||
from gym import spaces
|
from gym import spaces
|
||||||
|
|
||||||
from stable_baselines3.common.buffers import DictReplayBuffer, ReplayBuffer
|
from stable_baselines3.common.buffers import DictReplayBuffer, DictRolloutBuffer, ReplayBuffer, RolloutBuffer
|
||||||
from stable_baselines3.common.env_util import make_vec_env
|
from stable_baselines3.common.env_util import make_vec_env
|
||||||
from stable_baselines3.common.type_aliases import DictReplayBufferSamples, ReplayBufferSamples
|
from stable_baselines3.common.type_aliases import DictReplayBufferSamples, ReplayBufferSamples
|
||||||
|
from stable_baselines3.common.utils import get_device
|
||||||
from stable_baselines3.common.vec_env import VecNormalize
|
from stable_baselines3.common.vec_env import VecNormalize
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -71,7 +72,7 @@ def test_replay_buffer_normalization(replay_buffer_cls):
|
||||||
env = make_vec_env(env)
|
env = make_vec_env(env)
|
||||||
env = VecNormalize(env)
|
env = VecNormalize(env)
|
||||||
|
|
||||||
buffer = replay_buffer_cls(100, env.observation_space, env.action_space)
|
buffer = replay_buffer_cls(100, env.observation_space, env.action_space, device="cpu")
|
||||||
|
|
||||||
# Interract and store transitions
|
# Interract and store transitions
|
||||||
env.reset()
|
env.reset()
|
||||||
|
|
@ -94,3 +95,47 @@ def test_replay_buffer_normalization(replay_buffer_cls):
|
||||||
assert th.allclose(observations.mean(0), th.zeros(1), atol=1)
|
assert th.allclose(observations.mean(0), th.zeros(1), atol=1)
|
||||||
# Test reward normalization
|
# Test reward normalization
|
||||||
assert np.allclose(sample.rewards.mean(0), np.zeros(1), atol=1)
|
assert np.allclose(sample.rewards.mean(0), np.zeros(1), atol=1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("replay_buffer_cls", [DictReplayBuffer, DictRolloutBuffer, ReplayBuffer, RolloutBuffer])
|
||||||
|
@pytest.mark.parametrize("device", ["cpu", "cuda", "auto"])
|
||||||
|
def test_device_buffer(replay_buffer_cls, device):
|
||||||
|
if device == "cuda" and not th.cuda.is_available():
|
||||||
|
pytest.skip("CUDA not available")
|
||||||
|
|
||||||
|
env = {
|
||||||
|
RolloutBuffer: DummyEnv,
|
||||||
|
DictRolloutBuffer: DummyDictEnv,
|
||||||
|
ReplayBuffer: DummyEnv,
|
||||||
|
DictReplayBuffer: DummyDictEnv,
|
||||||
|
}[replay_buffer_cls]
|
||||||
|
env = make_vec_env(env)
|
||||||
|
|
||||||
|
buffer = replay_buffer_cls(100, env.observation_space, env.action_space, device=device)
|
||||||
|
|
||||||
|
# Interract and store transitions
|
||||||
|
obs = env.reset()
|
||||||
|
for _ in range(100):
|
||||||
|
action = env.action_space.sample()
|
||||||
|
next_obs, reward, done, info = env.step(action)
|
||||||
|
if replay_buffer_cls in [RolloutBuffer, DictRolloutBuffer]:
|
||||||
|
episode_start, values, log_prob = np.zeros(1), th.zeros(1), th.ones(1)
|
||||||
|
buffer.add(obs, action, reward, episode_start, values, log_prob)
|
||||||
|
else:
|
||||||
|
buffer.add(obs, next_obs, action, reward, done, info)
|
||||||
|
obs = next_obs
|
||||||
|
|
||||||
|
# Get data from the buffer
|
||||||
|
if replay_buffer_cls in [RolloutBuffer, DictRolloutBuffer]:
|
||||||
|
data = buffer.get(50)
|
||||||
|
elif replay_buffer_cls in [ReplayBuffer, DictReplayBuffer]:
|
||||||
|
data = buffer.sample(50)
|
||||||
|
|
||||||
|
# Check that all data are on the desired device
|
||||||
|
desired_device = get_device(device).type
|
||||||
|
for value in list(data):
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for key in value.keys():
|
||||||
|
assert value[key].device.type == desired_device
|
||||||
|
elif isinstance(value, th.Tensor):
|
||||||
|
assert value.device.type == desired_device
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue