Fix typing errors and typos

This commit is contained in:
Antonin Raffin 2020-01-22 17:17:12 +01:00
parent 88f07bafb6
commit 44fce7c02a
15 changed files with 48 additions and 41 deletions

View file

@ -3,10 +3,10 @@ SHELL=/bin/bash
pytest: pytest:
./scripts/run_tests.sh ./scripts/run_tests.sh
pytype: type:
pytype pytype
doc: docs:
cd docs && make html cd docs && make html
spelling: spelling:

View file

@ -24,6 +24,7 @@ Notes
- Original paper: https://arxiv.org/abs/1707.06347 - Original paper: https://arxiv.org/abs/1707.06347
- Clear explanation of PPO on Arxiv Insights channel: https://www.youtube.com/watch?v=5P7I-xPq8u8 - Clear explanation of PPO on Arxiv Insights channel: https://www.youtube.com/watch?v=5P7I-xPq8u8
- OpenAI blog post: https://blog.openai.com/openai-baselines-ppo/ - OpenAI blog post: https://blog.openai.com/openai-baselines-ppo/
- Spinning Up guide: https://spinningup.openai.com/en/latest/algorithms/ppo.html
Can I use? Can I use?

View file

@ -113,3 +113,4 @@ optimizers
Deprecations Deprecations
forkserver forkserver
cuda cuda
Polyak

View file

@ -33,7 +33,7 @@ class CEMRL(TD3):
:param learning_starts: (int) how many steps of the model to collect transitions for before learning starts :param learning_starts: (int) how many steps of the model to collect transitions for before learning starts
:param gamma: (float) the discount factor :param gamma: (float) the discount factor
:param batch_size: (int) Minibatch size for each gradient update :param batch_size: (int) Minibatch size for each gradient update
:param tau: (float) the soft update coefficient ("polyak update" of the target networks, between 0 and 1) :param tau: (float) the soft update coefficient ("Polyak update" of the target networks, between 0 and 1)
:param action_noise: (ActionNoise) the action noise type. Cf common.noise for the different action noise type. :param action_noise: (ActionNoise) the action noise type. Cf common.noise for the different action noise type.
:param target_policy_noise: (float) Standard deviation of Gaussian noise added to target policy :param target_policy_noise: (float) Standard deviation of Gaussian noise added to target policy
(smoothing noise) (smoothing noise)
@ -103,6 +103,7 @@ class CEMRL(TD3):
eval_env=None, eval_freq=-1, n_eval_episodes=5, tb_log_name="CEMRL", reset_num_timesteps=True): eval_env=None, eval_freq=-1, n_eval_episodes=5, tb_log_name="CEMRL", reset_num_timesteps=True):
timesteps_since_eval, episode_num, evaluations, obs, eval_env = self._setup_learn(eval_env) timesteps_since_eval, episode_num, evaluations, obs, eval_env = self._setup_learn(eval_env)
actor_steps = 0
while self.num_timesteps < total_timesteps: while self.num_timesteps < total_timesteps:

View file

@ -2,6 +2,8 @@ import time
import os import os
import io import io
import zipfile import zipfile
import typing
from typing import Union, Type, Optional
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections import deque from collections import deque
@ -10,13 +12,16 @@ import torch as th
import numpy as np import numpy as np
from torchy_baselines.common import logger from torchy_baselines.common import logger
from torchy_baselines.common.policies import get_policy_from_name from torchy_baselines.common.policies import BasePolicy, get_policy_from_name
from torchy_baselines.common.utils import set_random_seed, get_schedule_fn, update_learning_rate from torchy_baselines.common.utils import set_random_seed, get_schedule_fn, update_learning_rate
from torchy_baselines.common.vec_env import DummyVecEnv, VecEnv, unwrap_vec_normalize, sync_envs_normalization from torchy_baselines.common.vec_env import DummyVecEnv, VecEnv, unwrap_vec_normalize, sync_envs_normalization
from torchy_baselines.common.monitor import Monitor from torchy_baselines.common.monitor import Monitor
from torchy_baselines.common.evaluation import evaluate_policy from torchy_baselines.common.evaluation import evaluate_policy
from torchy_baselines.common.save_util import data_to_json, json_to_data from torchy_baselines.common.save_util import data_to_json, json_to_data
if typing.TYPE_CHECKING:
from torchy_baselines.common.noise import ActionNoise
class BaseRLModel(ABC): class BaseRLModel(ABC):
""" """
@ -43,7 +48,7 @@ class BaseRLModel(ABC):
:param sde_sample_freq: (int) Sample a new noise matrix every n steps when using SDE :param sde_sample_freq: (int) Sample a new noise matrix every n steps when using SDE
Default: -1 (only sample at the beginning of the rollout) Default: -1 (only sample at the beginning of the rollout)
""" """
def __init__(self, policy, env, policy_base, policy_kwargs=None, def __init__(self, policy: Type[BasePolicy], env: Union[gym.Env, VecEnv, str], policy_base, policy_kwargs=None,
verbose=0, device='auto', support_multi_env=False, verbose=0, device='auto', support_multi_env=False,
create_eval_env=False, monitor_wrapper=True, seed=None, create_eval_env=False, monitor_wrapper=True, seed=None,
use_sde=False, sde_sample_freq=-1): use_sde=False, sde_sample_freq=-1):
@ -59,7 +64,7 @@ class BaseRLModel(ABC):
if verbose > 0: if verbose > 0:
print(f"Using {self.device} device") print(f"Using {self.device} device")
self.env = env self.env = None # type: Union[gym.Env, VecEnv]
# get VecNormalize object if needed # get VecNormalize object if needed
self._vec_normalize_env = unwrap_vec_normalize(env) self._vec_normalize_env = unwrap_vec_normalize(env)
self.verbose = verbose self.verbose = verbose
@ -71,7 +76,10 @@ class BaseRLModel(ABC):
self.eval_env = None self.eval_env = None
self.replay_buffer = None self.replay_buffer = None
self.seed = seed self.seed = seed
self.action_noise = None self.action_noise = None # type: ActionNoise
self.start_time = None
self.policy, self.actor = None, None
self.learning_rate = None
# Used for SDE only # Used for SDE only
self.rollout_data = None self.rollout_data = None
self.on_policy_exploration = False self.on_policy_exploration = False
@ -407,7 +415,7 @@ class BaseRLModel(ABC):
return data, params, opt_params return data, params, opt_params
def set_random_seed(self, seed=None): def set_random_seed(self, seed: Optional[int] = None):
""" """
Set the seed of the pseudo-random generators Set the seed of the pseudo-random generators
(python, numpy, pytorch, gym, action_space) (python, numpy, pytorch, gym, action_space)
@ -443,7 +451,7 @@ class BaseRLModel(ABC):
eval_env.seed(self.seed) eval_env.seed(self.seed)
eval_env = self._get_eval_env(eval_env) eval_env = self._get_eval_env(eval_env)
obs = self.env.reset() obs = self.env.reset() # type: Union[gym.Env, VecEnv]
return timesteps_since_eval, episode_num, evaluations, obs, eval_env return timesteps_since_eval, episode_num, evaluations, obs, eval_env
def _update_info_buffer(self, infos): def _update_info_buffer(self, infos):

View file

@ -146,6 +146,17 @@ class VecEnv(ABC):
""" """
raise NotImplementedError() raise NotImplementedError()
def seed(self, seed, indices=None):
"""
:param seed: (int or [int])
:param indices: ([int])
"""
indices = self._get_indices(indices)
if not hasattr(seed, 'len'):
seed = [seed] * len(indices)
assert len(seed) == len(indices)
return [self.env_method('seed', seed[i], indices=i) for i in indices]
@property @property
def unwrapped(self): def unwrapped(self):
if isinstance(self, VecEnvWrapper): if isinstance(self, VecEnvWrapper):

View file

@ -3,7 +3,7 @@ from copy import deepcopy
import numpy as np import numpy as np
from torchy_baselines.common.vec_env import VecEnv from torchy_baselines.common.vec_env.base_vec_env import VecEnv
from torchy_baselines.common.vec_env.util import copy_obs_dict, dict_to_obs, obs_space_info from torchy_baselines.common.vec_env.util import copy_obs_dict, dict_to_obs, obs_space_info
@ -54,17 +54,6 @@ class DummyVecEnv(VecEnv):
self._save_obs(env_idx, obs) self._save_obs(env_idx, obs)
return self._obs_from_buf() return self._obs_from_buf()
def seed(self, seed, indices=None):
"""
:param seed: (int or [int])
:param indices: ([int])
"""
indices = self._get_indices(indices)
if not hasattr(seed, 'len'):
seed = [seed] * len(indices)
assert len(seed) == len(indices)
return [self.envs[i].seed(seed[i]) for i in indices]
def close(self): def close(self):
for env in self.envs: for env in self.envs:
env.close() env.close()

View file

@ -4,7 +4,7 @@ from collections import OrderedDict
import gym import gym
import numpy as np import numpy as np
from torchy_baselines.common.vec_env import VecEnv, CloudpickleWrapper from torchy_baselines.common.vec_env.base_vec_env import VecEnv, CloudpickleWrapper
def _worker(remote, parent_remote, env_fn_wrapper): def _worker(remote, parent_remote, env_fn_wrapper):
@ -111,7 +111,7 @@ class SubprocVecEnv(VecEnv):
for work_remote, remote, env_fn in zip(self.work_remotes, self.remotes, env_fns): for work_remote, remote, env_fn in zip(self.work_remotes, self.remotes, env_fns):
args = (work_remote, remote, CloudpickleWrapper(env_fn)) args = (work_remote, remote, CloudpickleWrapper(env_fn))
# daemon=True: if the main process crashes, we should not cause things to hang # daemon=True: if the main process crashes, we should not cause things to hang
process = ctx.Process(target=_worker, args=args, daemon=True) process = ctx.Process(target=_worker, args=args, daemon=True) # pytype:disable=attribute-error
process.start() process.start()
self.processes.append(process) self.processes.append(process)
work_remote.close() work_remote.close()
@ -187,17 +187,6 @@ class SubprocVecEnv(VecEnv):
for remote in target_remotes: for remote in target_remotes:
remote.recv() remote.recv()
def seed(self, seed, indices=None):
"""
:param seed: (int or [int])
:param indices: ([int])
"""
indices = self._get_indices(indices)
if not hasattr(seed, 'len'):
seed = [seed] * len(indices)
assert len(seed) == len(indices)
return [self.env_method('seed', seed[i], indices=i) for i in indices]
def env_method(self, method_name, *method_args, indices=None, **method_kwargs): def env_method(self, method_name, *method_args, indices=None, **method_kwargs):
"""Call instance methods of vectorized environments.""" """Call instance methods of vectorized environments."""
target_remotes = self._get_target_remotes(indices) target_remotes = self._get_target_remotes(indices)

View file

@ -3,7 +3,7 @@ import warnings
import numpy as np import numpy as np
from gym import spaces from gym import spaces
from torchy_baselines.common.vec_env import VecEnvWrapper from torchy_baselines.common.vec_env.base_vec_env import VecEnvWrapper
class VecFrameStack(VecEnvWrapper): class VecFrameStack(VecEnvWrapper):

View file

@ -2,7 +2,7 @@ import pickle
import numpy as np import numpy as np
from torchy_baselines.common.vec_env import VecEnvWrapper from torchy_baselines.common.vec_env.base_vec_env import VecEnvWrapper
from torchy_baselines.common.running_mean_std import RunningMeanStd from torchy_baselines.common.running_mean_std import RunningMeanStd

View file

@ -76,18 +76,20 @@ class PPOPolicy(BasePolicy):
self.sde_feature_extractor = None self.sde_feature_extractor = None
self.sde_net_arch = sde_net_arch self.sde_net_arch = sde_net_arch
self.use_sde = use_sde
# Action distribution # Action distribution
self.action_dist = make_proba_distribution(action_space, use_sde=use_sde, dist_kwargs=dist_kwargs) self.action_dist = make_proba_distribution(action_space, use_sde=use_sde, dist_kwargs=dist_kwargs)
self._build(learning_rate) self._build(learning_rate)
def reset_noise(self, n_envs=1): def reset_noise(self, n_envs: int = 1):
""" """
Sample new weights for the exploration matrix. Sample new weights for the exploration matrix.
:param n_envs: (int) :param n_envs: (int)
""" """
assert isinstance(self.action_dist, StateDependentNoiseDistribution), 'reset_noise() is only available when using SDE'
self.action_dist.sample_weights(self.log_std, batch_size=n_envs) self.action_dist.sample_weights(self.log_std, batch_size=n_envs)
def _build(self, learning_rate): def _build(self, learning_rate):

View file

@ -25,7 +25,7 @@ class PPO(BaseRLModel):
Proximal Policy Optimization algorithm (PPO) (clip version) Proximal Policy Optimization algorithm (PPO) (clip version)
Paper: https://arxiv.org/abs/1707.06347 Paper: https://arxiv.org/abs/1707.06347
Code: This implementation borrows code from OpenAI spinningup (https://github.com/openai/spinningup/) Code: This implementation borrows code from OpenAI Spinning Up (https://github.com/openai/spinningup/)
https://github.com/ikostrikov/pytorch-a2c-ppo-acktr-gail and https://github.com/ikostrikov/pytorch-a2c-ppo-acktr-gail and
and Stable Baselines (PPO2 from https://github.com/hill-a/stable-baselines) and Stable Baselines (PPO2 from https://github.com/hill-a/stable-baselines)

View file

@ -94,6 +94,7 @@ class Actor(BaseNetwork):
:return: (th.Tensor) :return: (th.Tensor)
""" """
assert isinstance(self.action_dist, StateDependentNoiseDistribution), 'get_std() is only available when using SDE'
return self.action_dist.get_std(self.log_std) return self.action_dist.get_std(self.log_std)
def reset_noise(self, batch_size=1): def reset_noise(self, batch_size=1):
@ -102,6 +103,7 @@ class Actor(BaseNetwork):
:param batch_size: (int) :param batch_size: (int)
""" """
assert isinstance(self.action_dist, StateDependentNoiseDistribution), 'reset_noise() is only available when using SDE'
self.action_dist.sample_weights(self.log_std, batch_size=batch_size) self.action_dist.sample_weights(self.log_std, batch_size=batch_size)
def _get_latent(self, obs): def _get_latent(self, obs):

View file

@ -39,7 +39,7 @@ class SAC(BaseRLModel):
:param gradient_steps: (int) How many gradient update after each step :param gradient_steps: (int) How many gradient update after each step
:param n_episodes_rollout: (int) Update the model every `n_episodes_rollout` episodes. :param n_episodes_rollout: (int) Update the model every `n_episodes_rollout` episodes.
Note that this cannot be used at the same time as `train_freq` Note that this cannot be used at the same time as `train_freq`
:param target_entropy: (str or float) target entropy when learning ent_coef (ent_coef = 'auto') :param target_entropy: (str or float) target entropy when learning `ent_coef` (`ent_coef = 'auto'`)
:param action_noise: (ActionNoise) the action noise type (None by default), this can help :param action_noise: (ActionNoise) the action noise type (None by default), this can help
for hard exploration problem. Cf common.noise for the different action noise type. for hard exploration problem. Cf common.noise for the different action noise type.
:param gamma: (float) the discount factor :param gamma: (float) the discount factor
@ -161,7 +161,7 @@ class SAC(BaseRLModel):
""" """
return self.unscale_action(self.select_action(observation)) return self.unscale_action(self.select_action(observation))
def train(self, gradient_steps, batch_size=64): def train(self, gradient_steps: int, batch_size: int = 64):
# Update optimizers learning rate # Update optimizers learning rate
optimizers = [self.actor.optimizer, self.critic.optimizer] optimizers = [self.actor.optimizer, self.critic.optimizer]
if self.ent_coef_optimizer is not None: if self.ent_coef_optimizer is not None:
@ -169,6 +169,9 @@ class SAC(BaseRLModel):
self._update_learning_rate(optimizers) self._update_learning_rate(optimizers)
ent_coef_loss, ent_coef = th.zeros(1), th.zeros(1)
actor_loss, critic_loss = th.zeros(1), th.zeros(1)
for gradient_step in range(gradient_steps): for gradient_step in range(gradient_steps):
# Sample replay buffer # Sample replay buffer
replay_data = self.replay_buffer.sample(batch_size, env=self._vec_normalize_env) replay_data = self.replay_buffer.sample(batch_size, env=self._vec_normalize_env)

View file

@ -31,7 +31,7 @@ class TD3(BaseRLModel):
:param gradient_steps: (int) How many gradient update after each step :param gradient_steps: (int) How many gradient update after each step
:param n_episodes_rollout: (int) Update the model every `n_episodes_rollout` episodes. :param n_episodes_rollout: (int) Update the model every `n_episodes_rollout` episodes.
Note that this cannot be used at the same time as `train_freq` Note that this cannot be used at the same time as `train_freq`
:param tau: (float) the soft update coefficient ("polyak update" of the target networks, between 0 and 1) :param tau: (float) the soft update coefficient ("Polyak update" of the target networks, between 0 and 1)
:param action_noise: (ActionNoise) the action noise type. Cf common.noise for the different action noise type. :param action_noise: (ActionNoise) the action noise type. Cf common.noise for the different action noise type.
:param target_policy_noise: (float) Standard deviation of Gaussian noise added to target policy :param target_policy_noise: (float) Standard deviation of Gaussian noise added to target policy
(smoothing noise) (smoothing noise)