[RLlib] SAC algo cleanup. (#10825)

This commit is contained in:
Sven Mika
2020-09-20 11:27:02 +02:00
committed by GitHub
parent 1d06e025ae
commit 805dad3bc4
56 changed files with 764 additions and 285 deletions
+14 -5
View File
@@ -320,7 +320,9 @@ SpaceInvaders 650 1001 1025
Policy Gradients
----------------
|pytorch| |tensorflow|
`[paper] <https://papers.nips.cc/paper/1713-policy-gradient-methods-for-reinforcement-learning-with-function-approximation.pdf>`__ `[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/pg/pg.py>`__ We include a vanilla policy gradients implementation as an example algorithm.
`[paper] <https://papers.nips.cc/paper/1713-policy-gradient-methods-for-reinforcement-learning-with-function-approximation.pdf>`__
`[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/pg/pg.py>`__
We include a vanilla policy gradients implementation as an example algorithm.
.. figure:: a2c-arch.svg
@@ -340,7 +342,8 @@ Tuned examples: `CartPole-v0 <https://github.com/ray-project/ray/blob/master/rll
Proximal Policy Optimization (PPO)
----------------------------------
|pytorch| |tensorflow|
`[paper] <https://arxiv.org/abs/1707.06347>`__ `[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/ppo/ppo.py>`__
`[paper] <https://arxiv.org/abs/1707.06347>`__
`[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/ppo/ppo.py>`__
PPO's clipped objective supports multiple SGD passes over the same batch of experiences. RLlib's multi-GPU optimizer pins that data in GPU memory to avoid unnecessary transfers from host memory, substantially improving performance over a naive implementation. PPO scales out using multiple workers for experience collection, and also to multiple GPUs for SGD.
.. tip::
@@ -399,15 +402,21 @@ HalfCheetah 9664 ~7700
Soft Actor Critic (SAC)
------------------------
|pytorch| |tensorflow|
`[paper] <https://arxiv.org/pdf/1801.01290>`__ `[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/sac/sac.py>`__
`[original paper] <https://arxiv.org/pdf/1801.01290>`__, `[follow up paper] <https://arxiv.org/pdf/1812.05905.pdf>`__, `[discrete actions paper] <https://arxiv.org/pdf/1910.07207v2.pdf>`__
`[implementation] <https://github.com/ray-project/ray/blob/master/rllib/agents/sac/sac.py>`__
.. figure:: dqn-arch.svg
SAC architecture (same as DQN)
RLlib's soft-actor critic implementation is ported from the `official SAC repo <https://github.com/rail-berkeley/softlearning>`__ to better integrate with RLlib APIs. Note that SAC has two fields to configure for custom models: ``policy_model`` and ``Q_model``.
RLlib's soft-actor critic implementation is ported from the `official SAC repo <https://github.com/rail-berkeley/softlearning>`__ to better integrate with RLlib APIs.
Note that SAC has two fields to configure for custom models: ``policy_model`` and ``Q_model``, the ``model`` field of the config will be ignored.
Tuned examples: `Pendulum-v0 <https://github.com/ray-project/ray/blob/master/rllib/tuned_examples/sac/pendulum-sac.yaml>`__, `HalfCheetah-v3 <https://github.com/ray-project/ray/blob/master/rllib/tuned_examples/sac/halfcheetah-sac.yaml>`__
Tuned examples (continuous actions):
`Pendulum-v0 <https://github.com/ray-project/ray/blob/master/rllib/tuned_examples/sac/pendulum-sac.yaml>`__,
`HalfCheetah-v3 <https://github.com/ray-project/ray/blob/master/rllib/tuned_examples/sac/halfcheetah-sac.yaml>`__,
Tuned examples (discrete actions):
`CartPole-v0 <https://github.com/ray-project/ray/blob/master/rllib/tuned_examples/sac/cartpole-sac.yaml>`__
**MuJoCo results @3M steps:** `more details <https://github.com/ray-project/rl-experiments>`__
+3 -3
View File
@@ -130,7 +130,7 @@ class DDPGTFModel(TFModelV2):
This implements Q(s, a).
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Tensor): Actions to return the Q-values for.
@@ -149,7 +149,7 @@ class DDPGTFModel(TFModelV2):
This implements the twin Q(s, a).
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Tensor): Actions to return the Q-values for.
@@ -169,7 +169,7 @@ class DDPGTFModel(TFModelV2):
This outputs the support for pi(s). For continuous action spaces, this
is the action directly.
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
+3 -3
View File
@@ -135,7 +135,7 @@ class DDPGTorchModel(TorchModelV2, nn.Module):
This implements Q(s, a).
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Tensor): Actions to return the Q-values for.
@@ -151,7 +151,7 @@ class DDPGTorchModel(TorchModelV2, nn.Module):
This implements the twin Q(s, a).
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Optional[Tensor]): Actions to return the Q-values for.
@@ -168,7 +168,7 @@ class DDPGTorchModel(TorchModelV2, nn.Module):
This outputs the support for pi(s). For continuous action spaces, this
is the action directly. For discrete, is is the mean / std dev.
Arguments:
Args:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
@@ -176,7 +176,7 @@ class DistributionalQTFModel(TFModelV2):
Override this in your custom model to customize the Q output head.
Arguments:
Args:
model_out (Tensor): embedding from the model layers
Returns:
+1 -1
View File
@@ -112,7 +112,7 @@ class VTraceLoss:
def _make_time_major(policy, seq_lens, tensor, drop_last=False):
"""Swaps batch and trajectory axis.
Arguments:
Args:
policy: Policy reference
seq_lens: Sequence lengths if recurrent or None
tensor: A tensor or list of tensors to reshape.
+1 -1
View File
@@ -189,7 +189,7 @@ def build_vtrace_loss(policy, model, dist_class, train_batch):
def make_time_major(policy, seq_lens, tensor, drop_last=False):
"""Swaps batch and trajectory axis.
Arguments:
Args:
policy: Policy reference
seq_lens: Sequence lengths if recurrent or None
tensor: A tensor or list of tensors to reshape.
+5 -5
View File
@@ -104,7 +104,7 @@ class MetaUpdate:
"""Computes the MetaUpdate step in MAML, adapted for MBMPO
for multiple MAML Iterations
Arguments:
Args:
workers (WorkerSet): Set of Workers
num_steps (int): Number of meta-update steps per MAML Iteration
maml_steps (int): MAML Iterations per MBMPO Iteration
@@ -121,7 +121,7 @@ class MetaUpdate:
self.metrics = {}
def __call__(self, data_tuple):
"""Arguments:
"""Args:
data_tuple (tuple): 1st element is samples collected from MAML
Inner adaptation steps and 2nd element is accumulated metrics
"""
@@ -186,7 +186,7 @@ class MetaUpdate:
def postprocess_metrics(self, metrics, prefix=""):
"""Appends prefix to current metrics
Arguments:
Args:
metrics (dict): Dictionary of current metrics
prefix (str): Prefix string to be appended
"""
@@ -197,7 +197,7 @@ class MetaUpdate:
def post_process_metrics(prefix, workers, metrics):
"""Update Current Dataset Metrics and filter out specific keys
Arguments:
Args:
prefix (str): Prefix string to be appended
workers (WorkerSet): Set of workers
metrics (dict): Current metrics dictionary
@@ -221,7 +221,7 @@ def fit_dynamics(policy, pid):
def sync_ensemble(workers):
"""Syncs dynamics ensemble weights from main to workers
Arguments:
Args:
workers (WorkerSet): Set of workers, including main
"""
+1 -1
View File
@@ -86,7 +86,7 @@ def validate_config(config):
Args:
config (TrainerConfigDict): The Trainer's config to check.
Throws:
Raises:
ValueError: In case something is wrong with the config.
"""
+3 -2
View File
@@ -101,7 +101,7 @@ def validate_config(config: TrainerConfigDict) -> None:
Args:
config (TrainerConfigDict): The Trainer's config to check.
Throws:
Raises:
ValueError: In case something is wrong with the config.
"""
if isinstance(config["entropy_coeff"], int):
@@ -284,4 +284,5 @@ PPOTrainer = build_trainer(
validate_config=validate_config,
default_policy=PPOTFPolicy,
get_policy_class=get_policy_class,
execution_plan=execution_plan)
execution_plan=execution_plan,
)
+1 -1
View File
@@ -326,7 +326,7 @@ def setup_config(policy: Policy, obs_space: gym.spaces.Space,
def setup_mixins(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Call all mixin classes' constructors before PPOPolicy initialization.
"""Call mixin classes' constructors before Policy's loss initialization.
Args:
policy (Policy): The Policy object.
+1 -1
View File
@@ -36,7 +36,7 @@ class QMixer(nn.Module):
def forward(self, agent_qs, states):
"""Forward pass for the mixer.
Arguments:
Args:
agent_qs: Tensor of shape [B, T, n_agents, n_actions]
states: Tensor of shape [B, T, state_dim]
"""
+2 -2
View File
@@ -57,7 +57,7 @@ class QMixLoss(nn.Module):
next_state=None):
"""Forward pass of the loss.
Arguments:
Args:
rewards: Tensor of shape [B, T, n_agents]
actions: Tensor of shape [B, T, n_agents]
terminated: Tensor of shape [B, T, n_agents]
@@ -530,7 +530,7 @@ def _validate(obs_space, action_space):
def _mac(model, obs, h):
"""Forward pass of the multi-agent controller.
Arguments:
Args:
model: TorchModelV2 class
obs: Tensor of shape [B, n_agents, obs_size]
h: List of tensors of shape [B, n_agents, h_size]
+8 -6
View File
@@ -1,8 +1,10 @@
Implementation of the Soft Actor-Critic algorithm:
Soft Actor Critic (SAC)
=======================
[1] Soft Actor-Critic Algorithms and Applications - T. Haarnoja, A. Zhou, K. Hartikainen, et al.
https://arxiv.org/abs/1812.05905.pdf
Implementations of:
For supporting discrete action spaces, we implemented this patch on top of the original algorithm:
[2] Soft Actor-Critic for Discrete Action Settings - Petros Christodoulou
https://arxiv.org/pdf/1910.07207v2.pdf
Soft Actor-Critic Algorithm (SAC) and a discrete action extension.
**[Detailed Documentation](https://docs.ray.io/en/latest/rllib-algorithms.html#sac)**
**[Implementation](https://github.com/ray-project/ray/blob/master/rllib/agents/sac/sac.py)**
+1 -1
View File
@@ -3,8 +3,8 @@ from ray.rllib.agents.sac.sac_tf_policy import SACTFPolicy
from ray.rllib.agents.sac.sac_torch_policy import SACTorchPolicy
__all__ = [
"DEFAULT_CONFIG",
"SACTFPolicy",
"SACTorchPolicy",
"SACTrainer",
"DEFAULT_CONFIG",
]
+53 -13
View File
@@ -1,8 +1,22 @@
"""
Soft Actor Critic (SAC)
=======================
This file defines the distributed Trainer class for the soft actor critic
algorithm.
See `sac_[tf|torch]_policy.py` for the definition of the policy loss.
Detailed documentation: https://docs.ray.io/en/latest/rllib-algorithms.html#sac
"""
import logging
from typing import Optional, Type
from ray.rllib.agents.trainer import with_common_config
from ray.rllib.agents.dqn.dqn import GenericOffPolicyTrainer
from ray.rllib.agents.sac.sac_tf_policy import SACTFPolicy
from ray.rllib.policy.policy import Policy
from ray.rllib.utils.typing import TrainerConfigDict
logger = logging.getLogger(__name__)
@@ -14,16 +28,24 @@ OPTIMIZER_SHARED_CONFIGS = [
# yapf: disable
# __sphinx_doc_begin__
# Adds the following updates to the (base) `Trainer` config in
# rllib/agents/trainer.py (`COMMON_CONFIG` dict).
DEFAULT_CONFIG = with_common_config({
# === Model ===
# Use two Q-networks (instead of one) for action-value estimation.
# Note: Each Q-network will have its own target network.
"twin_q": True,
# Use a e.g. conv2D state preprocessing network before concatenating the
# resulting (feature) vector with the action input for the input to
# the Q-networks.
"use_state_preprocessor": False,
# RLlib model options for the Q function(s).
# Model options for the Q network(s).
"Q_model": {
"fcnet_activation": "relu",
"fcnet_hiddens": [256, 256],
},
# RLlib model options for the policy function.
# Model options for the policy function.
"policy_model": {
"fcnet_activation": "relu",
"fcnet_hiddens": [256, 256],
@@ -43,10 +65,10 @@ DEFAULT_CONFIG = with_common_config({
# Target entropy lower bound. If "auto", will be set to -|A| (e.g. -2.0 for
# Discrete(2), -3.0 for Box(shape=(3,))).
# This is the inverse of reward scale, and will be optimized automatically.
"target_entropy": "auto",
# N-step target updates.
"target_entropy": None,
# N-step target updates. If >1, sars' tuples in trajectories will be
# postprocessed to become sa[discounted sum of R][s t+n] tuples.
"n_step": 1,
# Number of env steps to optimize for before returning.
"timesteps_per_iteration": 100,
@@ -117,15 +139,15 @@ DEFAULT_CONFIG = with_common_config({
# yapf: enable
def get_policy_class(config):
if config["framework"] == "torch":
from ray.rllib.agents.sac.sac_torch_policy import SACTorchPolicy
return SACTorchPolicy
else:
return SACTFPolicy
def validate_config(config: TrainerConfigDict) -> None:
"""Validates the Trainer's config dict.
Args:
config (TrainerConfigDict): The Trainer's config to check.
def validate_config(config):
Raises:
ValueError: In case something is wrong with the config.
"""
if config["model"].get("custom_model"):
logger.warning(
"Setting use_state_preprocessor=True since a custom model "
@@ -136,10 +158,28 @@ def validate_config(config):
raise ValueError("`grad_clip` value must be > 0.0!")
def get_policy_class(config: TrainerConfigDict) -> Optional[Type[Policy]]:
"""Policy class picker function. Class is chosen based on DL-framework.
Args:
config (TrainerConfigDict): The trainer's configuration dict.
Returns:
Optional[Type[Policy]]: The Policy class to use with PPOTrainer.
If None, use `default_policy` provided in build_trainer().
"""
if config["framework"] == "torch":
from ray.rllib.agents.sac.sac_torch_policy import SACTorchPolicy
return SACTorchPolicy
# Build a child class of `Trainer` (based on the kwargs used to create the
# GenericOffPolicyTrainer class and the kwargs used in the call below), which
# uses the framework specific Policy determined in `get_policy_class()` above.
SACTrainer = GenericOffPolicyTrainer.with_updates(
name="SAC",
default_config=DEFAULT_CONFIG,
validate_config=validate_config,
default_policy=SACTFPolicy,
get_policy_class=get_policy_class,
validate_config=validate_config,
)
+72 -50
View File
@@ -1,47 +1,58 @@
import gym
from gym.spaces import Discrete
import numpy as np
from typing import Optional, Tuple
from ray.rllib.models.tf.tf_modelv2 import TFModelV2
from ray.rllib.utils.framework import try_import_tf
from ray.rllib.utils.typing import ModelConfigDict, TensorType
tf1, tf, tfv = try_import_tf()
class SACTFModel(TFModelV2):
"""Extension of standard TFModel for SAC.
"""Extension of the standard TFModelV2 for SAC.
Instances of this Model get created via wrapping this class around another
default- or custom model (inside
rllib/agents/sac/sac_tf_policy.py::build_sac_model). Doing so simply adds
this class' methods (`get_q_values`, etc..) to the wrapped model, such that
the wrapped model can be used by the SAC algorithm.
Data flow:
obs -> forward() -> model_out
model_out -> get_policy_output() -> pi(s)
model_out, actions -> get_q_values() -> Q(s, a)
model_out, actions -> get_twin_q_values() -> Q_twin(s, a)
Note that this class by itself is not a valid model unless you
implement forward() in a subclass."""
`obs` -> forward() -> `model_out`
`model_out` -> get_policy_output() -> pi(actions|obs)
`model_out`, `actions` -> get_q_values() -> Q(s, a)
`model_out`, `actions` -> get_twin_q_values() -> Q_twin(s, a)
"""
def __init__(self,
obs_space,
action_space,
num_outputs,
model_config,
name,
actor_hidden_activation="relu",
actor_hiddens=(256, 256),
critic_hidden_activation="relu",
critic_hiddens=(256, 256),
twin_q=False,
initial_alpha=1.0,
target_entropy=None):
"""Initialize variables of this model.
obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
num_outputs: Optional[int],
model_config: ModelConfigDict,
name: str,
actor_hidden_activation: str = "relu",
actor_hiddens: Tuple[int] = (256, 256),
critic_hidden_activation: str = "relu",
critic_hiddens: Tuple[int] = (256, 256),
twin_q: bool = False,
initial_alpha: float = 1.0,
target_entropy: Optional[float] = None):
"""Initialize a SACTFModel instance.
Extra model kwargs:
actor_hidden_activation (str): activation for actor network
actor_hiddens (list): hidden layers sizes for actor network
critic_hidden_activation (str): activation for critic network
critic_hiddens (list): hidden layers sizes for critic network
twin_q (bool): build twin Q networks.
Args:
actor_hidden_activation (str): Activation for the actor network.
actor_hiddens (list): Hidden layers sizes for the actor network.
critic_hidden_activation (str): Activation for the critic network.
critic_hiddens (list): Hidden layers sizes for the critic network.
twin_q (bool): Build twin Q networks (Q-net and target) for more
stable Q-learning.
initial_alpha (float): The initial value for the to-be-optimized
alpha parameter (default: 1.0).
target_entropy (Optional[float]): A target entropy value for
the to-be-optimized alpha parameter. If None, will use the
defaults described in the papers for SAC (and discrete SAC).
Note that the core layers for forward() are not defined here, this
only defines the layers for the output heads. Those layers for
@@ -131,58 +142,69 @@ class SACTFModel(TFModelV2):
self.register_variables([self.log_alpha])
def get_q_values(self, model_out, actions=None):
"""Return the Q estimates for the most recent forward pass.
def get_q_values(self,
model_out: TensorType,
actions: Optional[TensorType] = None) -> TensorType:
"""Returns Q-values, given the output of self.__call__().
This implements Q(s, a).
This implements Q(s, a) -> [single Q-value] for the continuous case and
Q(s) -> [Q-values for all actions] for the discrete case.
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Optional[Tensor]): Actions to return the Q-values for.
Shape: [BATCH_SIZE, action_dim]. If None (discrete action
case), return Q-values for all actions.
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
actions (Optional[TensorType]): Continuous action batch to return
Q-values for. Shape: [BATCH_SIZE, action_dim]. If None
(discrete action case), return Q-values for all actions.
Returns:
tensor of shape [BATCH_SIZE].
TensorType: Q-values tensor of shape [BATCH_SIZE, 1].
"""
# Continuous case -> concat actions to model_out.
if actions is not None:
return self.q_net([model_out, actions])
# Discrete case -> return q-vals for all actions.
else:
return self.q_net(model_out)
def get_twin_q_values(self, model_out, actions=None):
def get_twin_q_values(self,
model_out: TensorType,
actions: Optional[TensorType] = None) -> TensorType:
"""Same as get_q_values but using the twin Q net.
This implements the twin Q(s, a).
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
actions (Optional[Tensor]): Actions to return the Q-values for.
Shape: [BATCH_SIZE, action_dim]. If None (discrete action
case), return Q-values for all actions.
Returns:
tensor of shape [BATCH_SIZE].
TensorType: Q-values tensor of shape [BATCH_SIZE, 1].
"""
# Continuous case -> concat actions to model_out.
if actions is not None:
return self.twin_q_net([model_out, actions])
# Discrete case -> return q-vals for all actions.
else:
return self.twin_q_net(model_out)
def get_policy_output(self, model_out):
"""Return the action output for the most recent forward pass.
def get_policy_output(self, model_out: TensorType) -> TensorType:
"""Returns policy outputs, given the output of self.__call__().
This outputs the support for pi(s). For continuous action spaces, this
is the action directly. For discrete, is is the mean / std dev.
For continuous action spaces, these will be the mean/stddev
distribution inputs for the (SquashedGaussian) action distribution.
For discrete action spaces, these will be the logits for a categorical
distribution.
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
Returns:
tensor of shape [BATCH_SIZE, action_out_size]
TensorType: Distribution inputs for sampling actions.
"""
return self.action_model(model_out)
+270 -44
View File
@@ -1,6 +1,12 @@
"""
TensorFlow policy class used for SAC.
"""
import gym
from gym.spaces import Box, Discrete
from functools import partial
import logging
from typing import Dict, List, Optional, Tuple, Type, Union
import ray
import ray.experimental.tf_utils
@@ -9,14 +15,19 @@ from ray.rllib.agents.ddpg.ddpg_tf_policy import ComputeTDErrorMixin, \
from ray.rllib.agents.dqn.dqn_tf_policy import postprocess_nstep_and_prio
from ray.rllib.agents.sac.sac_tf_model import SACTFModel
from ray.rllib.agents.sac.sac_torch_model import SACTorchModel
from ray.rllib.evaluation.episode import MultiAgentEpisode
from ray.rllib.models import ModelCatalog
from ray.rllib.models.modelv2 import ModelV2
from ray.rllib.models.tf.tf_action_dist import Beta, Categorical, \
DiagGaussian, SquashedGaussian
DiagGaussian, SquashedGaussian, TFActionDistribution
from ray.rllib.policy.policy import Policy
from ray.rllib.policy.sample_batch import SampleBatch
from ray.rllib.policy.tf_policy_template import build_tf_policy
from ray.rllib.utils.error import UnsupportedSpaceException
from ray.rllib.utils.framework import get_variable, try_import_tf, \
try_import_tfp
from ray.rllib.utils.typing import AgentID, LocalOptimizer, ModelGradients, \
TensorType, TrainerConfigDict
tf1, tf, tfv = try_import_tf()
tfp = try_import_tfp()
@@ -24,12 +35,26 @@ tfp = try_import_tfp()
logger = logging.getLogger(__name__)
def build_sac_model(policy, obs_space, action_space, config):
# 2 cases:
# 1) with separate state-preprocessor (before obs+action concat).
# 2) no separate state-preprocessor: concat obs+actions right away.
def build_sac_model(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> ModelV2:
"""Constructs the necessary ModelV2 for the Policy and returns it.
Args:
policy (Policy): The TFPolicy that will use the models.
obs_space (gym.spaces.Space): The observation space.
action_space (gym.spaces.Space): The action space.
config (TrainerConfigDict): The SAC trainer's config dict.
Returns:
ModelV2: The ModelV2 to be used by the Policy. Note: An additional
target model will be created in this function and assigned to
`policy.target_model`.
"""
# With separate state-preprocessor (before obs+action concat).
if config["use_state_preprocessor"]:
num_outputs = 256 # Flatten last Conv2D to this many nodes.
# No separate state-preprocessor: concat obs+actions right away.
else:
num_outputs = 0
# No state preprocessor: fcnet_hiddens should be empty.
@@ -44,7 +69,7 @@ def build_sac_model(policy, obs_space, action_space, config):
# Force-ignore any additionally provided hidden layer sizes.
# Everything should be configured using SAC's "Q_model" and "policy_model"
# settings.
policy.model = ModelCatalog.get_model_v2(
model = ModelCatalog.get_model_v2(
obs_space=obs_space,
action_space=action_space,
num_outputs=num_outputs,
@@ -61,6 +86,10 @@ def build_sac_model(policy, obs_space, action_space, config):
initial_alpha=config["initial_alpha"],
target_entropy=config["target_entropy"])
# Create an exact copy of the model and store it in `policy.target_model`.
# This will be used for tau-synched Q-target models that run behind the
# actual Q-networks and are used for target q-value calculations in the
# loss terms.
policy.target_model = ModelCatalog.get_model_v2(
obs_space=obs_space,
action_space=action_space,
@@ -78,17 +107,51 @@ def build_sac_model(policy, obs_space, action_space, config):
initial_alpha=config["initial_alpha"],
target_entropy=config["target_entropy"])
return policy.model
return model
def postprocess_trajectory(policy,
sample_batch,
other_agent_batches=None,
episode=None):
def postprocess_trajectory(
policy: Policy,
sample_batch: SampleBatch,
other_agent_batches: Optional[Dict[AgentID, SampleBatch]] = None,
episode: Optional[MultiAgentEpisode] = None) -> SampleBatch:
"""Postprocesses a trajectory and returns the processed trajectory.
The trajectory contains only data from one episode and from one agent.
- If `config.batch_mode=truncate_episodes` (default), sample_batch may
contain a truncated (at-the-end) episode, in case the
`config.rollout_fragment_length` was reached by the sampler.
- If `config.batch_mode=complete_episodes`, sample_batch will contain
exactly one episode (no matter how long).
New columns can be added to sample_batch and existing ones may be altered.
Args:
policy (Policy): The Policy used to generate the trajectory
(`sample_batch`)
sample_batch (SampleBatch): The SampleBatch to postprocess.
other_agent_batches (Optional[Dict[AgentID, SampleBatch]]): Optional
dict of AgentIDs mapping to other agents' trajectory data (from the
same episode). NOTE: The other agents use the same policy.
episode (Optional[MultiAgentEpisode]): Optional multi-agent episode
object in which the agents operated.
Returns:
SampleBatch: The postprocessed, modified SampleBatch (or a new one).
"""
return postprocess_nstep_and_prio(policy, sample_batch)
def get_dist_class(config, action_space):
def _get_dist_class(config: TrainerConfigDict, action_space: gym.spaces.Space
) -> Type[TFActionDistribution]:
"""Helper function to return a dist class based on config and action space.
Args:
config (TrainerConfigDict): The Trainer's config dict.
action_space (gym.spaces.Space): The action space used.
Returns:
Type[TFActionDistribution]: A TF distribution class.
"""
if isinstance(action_space, Discrete):
return Categorical
else:
@@ -99,43 +162,89 @@ def get_dist_class(config, action_space):
return DiagGaussian
def get_distribution_inputs_and_class(policy,
model,
obs_batch,
*,
explore=True,
**kwargs):
# Get base-model output.
def get_distribution_inputs_and_class(
policy: Policy,
model: ModelV2,
obs_batch: TensorType,
*,
explore: bool = True,
**kwargs) \
-> Tuple[TensorType, Type[TFActionDistribution], List[TensorType]]:
"""The action distribution function to be used the algorithm.
An action distribution function is used to customize the choice of action
distribution class and the resulting action distribution inputs (to
parameterize the distribution object).
After parameterizing the distribution, a `sample()` call
will be made on it to generate actions.
Args:
policy (Policy): The Policy being queried for actions and calling this
function.
model (SACTFModel): The SAC specific Model to use to generate the
distribution inputs (see sac_tf|torch_model.py). Must support the
`get_policy_output` method.
obs_batch (TensorType): The observations to be used as inputs to the
model.
explore (bool): Whether to activate exploration or not.
Returns:
Tuple[TensorType, Type[TFActionDistribution], List[TensorType]]: The
dist inputs, dist class, and a list of internal state outputs
(in the RNN case).
"""
# Get base-model output (w/o the SAC specific parts of the network).
model_out, state_out = model({
"obs": obs_batch,
"is_training": policy._get_is_training_placeholder(),
}, [], None)
# Get action model output from base-model output.
# Use the base output to get the policy outputs from the SAC model's
# policy components.
distribution_inputs = model.get_policy_output(model_out)
action_dist_class = get_dist_class(policy.config, policy.action_space)
# Get a distribution class to be used with the just calculated dist-inputs.
action_dist_class = _get_dist_class(policy.config, policy.action_space)
return distribution_inputs, action_dist_class, state_out
def sac_actor_critic_loss(policy, model, _, train_batch):
def sac_actor_critic_loss(
policy: Policy, model: ModelV2, dist_class: Type[TFActionDistribution],
train_batch: SampleBatch) -> Union[TensorType, List[TensorType]]:
"""Constructs the loss for the Soft Actor Critic.
Args:
policy (Policy): The Policy to calculate the loss for.
model (ModelV2): The Model to calculate the loss for.
dist_class (Type[ActionDistribution]: The action distr. class.
train_batch (SampleBatch): The training data.
Returns:
Union[TensorType, List[TensorType]]: A single loss tensor or a list
of loss tensors.
"""
# Should be True only for debugging purposes (e.g. test cases)!
deterministic = policy.config["_deterministic_loss"]
# Get the base model output from the train batch.
model_out_t, _ = model({
"obs": train_batch[SampleBatch.CUR_OBS],
"is_training": policy._get_is_training_placeholder(),
}, [], None)
# Get the base model output from the next observations in the train batch.
model_out_tp1, _ = model({
"obs": train_batch[SampleBatch.NEXT_OBS],
"is_training": policy._get_is_training_placeholder(),
}, [], None)
# Get the target model's base outputs from the next observations in the
# train batch.
target_model_out_tp1, _ = policy.target_model({
"obs": train_batch[SampleBatch.NEXT_OBS],
"is_training": policy._get_is_training_placeholder(),
}, [], None)
# Discrete case.
# Discrete actions case.
if model.discrete:
# Get all action probs directly from pi and form their logp.
log_pis_t = tf.nn.log_softmax(model.get_policy_output(model_out_t), -1)
@@ -168,7 +277,7 @@ def sac_actor_critic_loss(policy, model, _, train_batch):
# Continuous actions case.
else:
# Sample simgle actions from distribution.
action_dist_class = get_dist_class(policy.config, policy.action_space)
action_dist_class = _get_dist_class(policy.config, policy.action_space)
action_dist_t = action_dist_class(
model.get_policy_output(model_out_t), policy.model)
policy_t = action_dist_t.sample() if not deterministic else \
@@ -212,7 +321,7 @@ def sac_actor_critic_loss(policy, model, _, train_batch):
q_tp1_best_masked = (1.0 - tf.cast(train_batch[SampleBatch.DONES],
tf.float32)) * q_tp1_best
# compute RHS of bellman equation
# Compute RHS of bellman equation for the Q-loss (critic(s)).
q_t_selected_target = tf.stop_gradient(
train_batch[SampleBatch.REWARDS] +
policy.config["gamma"]**policy.config["n_step"] * q_tp1_best_masked)
@@ -225,6 +334,7 @@ def sac_actor_critic_loss(policy, model, _, train_batch):
else:
td_error = base_td_error
# Calculate one or two critic losses (2 in the twin_q case).
critic_loss = [
0.5 * tf.keras.losses.MSE(
y_true=q_t_selected_target, y_pred=q_t_selected)
@@ -258,7 +368,7 @@ def sac_actor_critic_loss(policy, model, _, train_batch):
tf.stop_gradient(log_pis_t + model.target_entropy))
actor_loss = tf.reduce_mean(model.alpha * log_pis_t - q_t_det_policy)
# save for stats function
# Save for stats function.
policy.policy_t = policy_t
policy.q_t = q_t
policy.td_error = td_error
@@ -268,13 +378,35 @@ def sac_actor_critic_loss(policy, model, _, train_batch):
policy.alpha_value = model.alpha
policy.target_entropy = model.target_entropy
# in a custom apply op we handle the losses separately, but return them
# combined in one loss for now
# In a custom apply op we handle the losses separately, but return them
# combined in one loss here.
return actor_loss + tf.math.add_n(critic_loss) + alpha_loss
def gradients_fn(policy, optimizer, loss):
# Eager: Use GradientTape.
def compute_and_clip_gradients(policy: Policy, optimizer: LocalOptimizer,
loss: TensorType) -> ModelGradients:
"""Gradients computing function (from loss tensor, using local optimizer).
Note: For SAC, optimizer and loss are ignored b/c we have 3
losses and 3 local optimizers (all stored in policy).
`optimizer` will be used, though, in the tf-eager case b/c it is then a
fake optimizer (OptimizerWrapper) object with a `tape` property to
generate a GradientTape object for gradient recording.
Args:
policy (Policy): The Policy object that generated the loss tensor and
that holds the given local optimizer.
optimizer (LocalOptimizer): The tf (local) optimizer object to
calculate the gradients with.
loss (TensorType): The loss tensor for which gradients should be
calculated.
Returns:
ModelGradients: List of the possibly clipped gradients- and variable
tuples.
"""
# Eager: Use GradientTape (which is a property of the `optimizer` object
# (an OptimizerWrapper): see rllib/policy/eager_tf_policy.py).
if policy.config["framework"] in ["tf2", "tfe"]:
tape = optimizer.tape
pol_weights = policy.model.policy_variables()
@@ -343,7 +475,26 @@ def gradients_fn(policy, optimizer, loss):
return grads_and_vars
def apply_gradients(policy, optimizer, grads_and_vars):
def apply_gradients(
policy: Policy, optimizer: LocalOptimizer,
grads_and_vars: ModelGradients) -> Union["tf.Operation", None]:
"""Gradients applying function (from list of "grad_and_var" tuples).
Note: For SAC, optimizer and grads_and_vars are ignored b/c we have 3
losses and optimizers (stored in policy).
Args:
policy (Policy): The Policy object whose Model(s) the given gradients
should be applied to.
optimizer (LocalOptimizer): The tf (local) optimizer object through
which to apply the gradients.
grads_and_vars (ModelGradients): The list of grad_and_var tuples to
apply via the given optimizer.
Returns:
Union[tf.Operation, None]: The tf op to be used to run the apply
operation. None for eager mode.
"""
actor_apply_ops = policy._actor_optimizer.apply_gradients(
policy._actor_grads_and_vars)
@@ -359,9 +510,11 @@ def apply_gradients(policy, optimizer, grads_and_vars):
policy._critic_optimizer[0].apply_gradients(cgrads)
]
# Eager mode -> Just apply and return None.
if policy.config["framework"] in ["tf2", "tfe"]:
policy._alpha_optimizer.apply_gradients(policy._alpha_grads_and_vars)
return
# Tf static graph -> Return op.
else:
alpha_apply_ops = policy._alpha_optimizer.apply_gradients(
policy._alpha_grads_and_vars,
@@ -369,10 +522,17 @@ def apply_gradients(policy, optimizer, grads_and_vars):
return tf.group([actor_apply_ops, alpha_apply_ops] + critic_apply_ops)
def stats(policy, train_batch):
def stats(policy: Policy, train_batch: SampleBatch) -> Dict[str, TensorType]:
"""Stats function for SAC. Returns a dict with important loss stats.
Args:
policy (Policy): The Policy to generate stats for.
train_batch (SampleBatch): The SampleBatch (already) used for training.
Returns:
Dict[str, TensorType]: The stats dict.
"""
return {
# "policy_t": policy.policy_t,
# "td_error": policy.td_error,
"mean_td_error": tf.reduce_mean(policy.td_error),
"actor_loss": tf.reduce_mean(policy.actor_loss),
"critic_loss": tf.reduce_mean(policy.critic_loss),
@@ -386,9 +546,14 @@ def stats(policy, train_batch):
class ActorCriticOptimizerMixin:
"""Mixin class to generate the necessary optimizers for actor-critic algos.
- Creates global step for counting the number of update operations.
- Creates separate optimizers for actor, critic, and alpha.
"""
def __init__(self, config):
# - Create global step for counting the number of update operations.
# - Use separate optimizers for actor & critic.
# Eager mode.
if config["framework"] in ["tf2", "tfe"]:
self.global_step = get_variable(0, tf_name="global_step")
self._actor_optimizer = tf.keras.optimizers.Adam(
@@ -403,6 +568,7 @@ class ActorCriticOptimizerMixin:
"optimization"]["critic_learning_rate"]))
self._alpha_optimizer = tf.keras.optimizers.Adam(
learning_rate=config["optimization"]["entropy_learning_rate"])
# Static graph mode.
else:
self.global_step = tf1.train.get_or_create_global_step()
self._actor_optimizer = tf1.train.AdamOptimizer(
@@ -419,31 +585,91 @@ class ActorCriticOptimizerMixin:
learning_rate=config["optimization"]["entropy_learning_rate"])
def setup_early_mixins(policy, obs_space, action_space, config):
def setup_early_mixins(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Call mixin classes' constructors before Policy's initialization.
Adds the necessary optimizers to the given Policy.
Args:
policy (Policy): The Policy object.
obs_space (gym.spaces.Space): The Policy's observation space.
action_space (gym.spaces.Space): The Policy's action space.
config (TrainerConfigDict): The Policy's config.
"""
ActorCriticOptimizerMixin.__init__(policy, config)
def setup_mid_mixins(policy, obs_space, action_space, config):
def setup_mid_mixins(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Call mixin classes' constructors before Policy's loss initialization.
Adds the `compute_td_error` method to the given policy.
Calling `compute_td_error` with batch data will re-calculate the loss
on that batch AND return the per-batch-item TD-error for prioritized
replay buffer record weight updating (in case a prioritized replay buffer
is used).
Args:
policy (Policy): The Policy object.
obs_space (gym.spaces.Space): The Policy's observation space.
action_space (gym.spaces.Space): The Policy's action space.
config (TrainerConfigDict): The Policy's config.
"""
ComputeTDErrorMixin.__init__(policy, sac_actor_critic_loss)
def setup_late_mixins(policy, obs_space, action_space, config):
def setup_late_mixins(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Call mixin classes' constructors after Policy initialization.
Adds the `update_target` method to the given policy.
Calling `update_target` updates all target Q-networks' weights from their
respective "main" Q-metworks, based on tau (smooth, partial updating).
Args:
policy (Policy): The Policy object.
obs_space (gym.spaces.Space): The Policy's observation space.
action_space (gym.spaces.Space): The Policy's action space.
config (TrainerConfigDict): The Policy's config.
"""
TargetNetworkMixin.__init__(policy, config)
def validate_spaces(pid, observation_space, action_space, config):
def validate_spaces(policy: Policy, observation_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Validates the observation- and action spaces used for the Policy.
Args:
policy (Policy): The policy, whose spaces are being validated.
observation_space (gym.spaces.Space): The observation space to
validate.
action_space (gym.spaces.Space): The action space to validate.
config (TrainerConfigDict): The Policy's config dict.
Raises:
UnsupportedSpaceException: If one of the spaces is not supported.
"""
# Only support single Box or single Discreete spaces.
if not isinstance(action_space, (Box, Discrete)):
raise UnsupportedSpaceException(
"Action space ({}) of {} is not supported for "
"SAC.".format(action_space, pid))
if isinstance(action_space, Box) and len(action_space.shape) > 1:
"SAC.".format(action_space, policy))
# If Box, make sure it's a 1D vector space.
elif isinstance(action_space, Box) and len(action_space.shape) > 1:
raise UnsupportedSpaceException(
"Action space ({}) of {} has multiple dimensions "
"{}. ".format(action_space, pid, action_space.shape) +
"{}. ".format(action_space, policy, action_space.shape) +
"Consider reshaping this into a single dimension, "
"using a Tuple action space, or the multi-agent API.")
# Build a child class of `DynamicTFPolicy`, given the custom functions defined
# above.
SACTFPolicy = build_tf_policy(
name="SACTFPolicy",
get_default_config=lambda: ray.rllib.agents.sac.sac.DEFAULT_CONFIG,
@@ -452,7 +678,7 @@ SACTFPolicy = build_tf_policy(
action_distribution_fn=get_distribution_inputs_and_class,
loss_fn=sac_actor_critic_loss,
stats_fn=stats,
gradients_fn=gradients_fn,
gradients_fn=compute_and_clip_gradients,
apply_gradients_fn=apply_gradients,
extra_learn_fetches_fn=lambda policy: {"td_error": policy.td_error},
mixins=[
+73 -55
View File
@@ -1,52 +1,59 @@
import gym
from gym.spaces import Discrete
import numpy as np
from typing import Optional, Tuple
from ray.rllib.models.torch.misc import SlimFC
from ray.rllib.models.torch.torch_modelv2 import TorchModelV2
from ray.rllib.utils.framework import get_activation_fn, try_import_torch
from ray.rllib.utils.typing import ModelConfigDict, TensorType
torch, nn = try_import_torch()
class SACTorchModel(TorchModelV2, nn.Module):
"""Extension of standard TorchModelV2 for SAC.
"""Extension of the standard TorchModelV2 for SAC.
Instances of this Model get created via wrapping this class around another
default- or custom model (inside
rllib/agents/sac/sac_torch_policy.py::build_sac_model). Doing so simply
adds this class' methods (`get_q_values`, etc..) to the wrapped model, such
that the wrapped model can be used by the SAC algorithm.
Data flow:
obs -> forward() -> model_out
model_out -> get_policy_output() -> pi(s)
model_out, actions -> get_q_values() -> Q(s, a)
model_out, actions -> get_twin_q_values() -> Q_twin(s, a)
Note that this class by itself is not a valid model unless you
implement forward() in a subclass."""
`obs` -> forward() -> `model_out`
`model_out` -> get_policy_output() -> pi(actions|obs)
`model_out`, `actions` -> get_q_values() -> Q(s, a)
`model_out`, `actions` -> get_twin_q_values() -> Q_twin(s, a)
"""
def __init__(self,
obs_space,
action_space,
num_outputs,
model_config,
name,
actor_hidden_activation="relu",
actor_hiddens=(256, 256),
critic_hidden_activation="relu",
critic_hiddens=(256, 256),
twin_q=False,
initial_alpha=1.0,
target_entropy=None):
"""Initialize variables of this model.
Extra model kwargs:
actor_hidden_activation (str): activation for actor network
actor_hiddens (list): hidden layers sizes for actor network
critic_hidden_activation (str): activation for critic network
critic_hiddens (list): hidden layers sizes for critic network
twin_q (bool): build twin Q networks.
obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
num_outputs: Optional[int],
model_config: ModelConfigDict,
name: str,
actor_hidden_activation: str = "relu",
actor_hiddens: Tuple[int] = (256, 256),
critic_hidden_activation: str = "relu",
critic_hiddens: Tuple[int] = (256, 256),
twin_q: bool = False,
initial_alpha: float = 1.0,
target_entropy: Optional[float] = None):
"""Initializes a SACTorchModel instance.
7
Args:
actor_hidden_activation (str): Activation for the actor network.
actor_hiddens (list): Hidden layers sizes for the actor network.
critic_hidden_activation (str): Activation for the critic network.
critic_hiddens (list): Hidden layers sizes for the critic network.
twin_q (bool): Build twin Q networks (Q-net and target) for more
stable Q-learning.
initial_alpha (float): The initial value for the to-be-optimized
alpha parameter (default: 1.0).
target_entropy (Optional[float]): An optional fixed value for the
SAC alpha loss term. None or "auto" for automatic calculation
of this value according to [1] (cont. actions) or [2]
(discrete actions).
target_entropy (Optional[float]): A target entropy value for
the to-be-optimized alpha parameter. If None, will use the
defaults described in the papers for SAC (and discrete SAC).
Note that the core layers for forward() are not defined here, this
only defines the layers for the output heads. Those layers for
@@ -142,58 +149,69 @@ class SACTorchModel(TorchModelV2, nn.Module):
self.target_entropy = torch.tensor(
data=[target_entropy], dtype=torch.float32, requires_grad=False)
def get_q_values(self, model_out, actions=None):
"""Return the Q estimates for the most recent forward pass.
def get_q_values(self,
model_out: TensorType,
actions: Optional[TensorType] = None) -> TensorType:
"""Returns Q-values, given the output of self.__call__().
This implements Q(s, a).
This implements Q(s, a) -> [single Q-value] for the continuous case and
Q(s) -> [Q-values for all actions] for the discrete case.
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
actions (Optional[Tensor]): Actions to return the Q-values for.
Shape: [BATCH_SIZE, action_dim]. If None (discrete action
case), return Q-values for all actions.
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
actions (Optional[TensorType]): Continuous action batch to return
Q-values for. Shape: [BATCH_SIZE, action_dim]. If None
(discrete action case), return Q-values for all actions.
Returns:
tensor of shape [BATCH_SIZE].
TensorType: Q-values tensor of shape [BATCH_SIZE, 1].
"""
# Continuous case -> concat actions to model_out.
if actions is not None:
return self.q_net(torch.cat([model_out, actions], -1))
# Discrete case -> return q-vals for all actions.
else:
return self.q_net(model_out)
def get_twin_q_values(self, model_out, actions=None):
def get_twin_q_values(self,
model_out: TensorType,
actions: Optional[TensorType] = None) -> TensorType:
"""Same as get_q_values but using the twin Q net.
This implements the twin Q(s, a).
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
actions (Optional[Tensor]): Actions to return the Q-values for.
Shape: [BATCH_SIZE, action_dim]. If None (discrete action
case), return Q-values for all actions.
Returns:
tensor of shape [BATCH_SIZE].
TensorType: Q-values tensor of shape [BATCH_SIZE, 1].
"""
# Continuous case -> concat actions to model_out.
if actions is not None:
return self.twin_q_net(torch.cat([model_out, actions], -1))
# Discrete case -> return q-vals for all actions.
else:
return self.twin_q_net(model_out)
def get_policy_output(self, model_out):
"""Return the action output for the most recent forward pass.
def get_policy_output(self, model_out: TensorType) -> TensorType:
"""Returns policy outputs, given the output of self.__call__().
This outputs the support for pi(s). For continuous action spaces, this
is the action directly. For discrete, is is the mean / std dev.
For continuous action spaces, these will be the mean/stddev
distribution inputs for the (SquashedGaussian) action distribution.
For discrete action spaces, these will be the logits for a categorical
distribution.
Arguments:
model_out (Tensor): obs embeddings from the model layers, of shape
[BATCH_SIZE, num_outputs].
Args:
model_out (TensorType): Feature outputs from the model layers
(result of doing `self.__call__(obs)`).
Returns:
tensor of shape [BATCH_SIZE, action_out_size]
TensorType: Distribution inputs for sampling actions.
"""
return self.action_model(model_out)
+169 -21
View File
@@ -1,5 +1,11 @@
"""
PyTorch policy class used for SAC.
"""
import gym
from gym.spaces import Discrete
import logging
from typing import Dict, List, Optional, Tuple, Type, Union
import ray
import ray.experimental.tf_utils
@@ -7,11 +13,16 @@ from ray.rllib.agents.a3c.a3c_torch_policy import apply_grad_clipping
from ray.rllib.agents.sac.sac_tf_policy import build_sac_model, \
postprocess_trajectory, validate_spaces
from ray.rllib.agents.dqn.dqn_tf_policy import PRIO_WEIGHTS
from ray.rllib.models.modelv2 import ModelV2
from ray.rllib.models.torch.torch_action_dist import TorchDistributionWrapper
from ray.rllib.policy.policy import Policy
from ray.rllib.policy.sample_batch import SampleBatch
from ray.rllib.policy.torch_policy_template import build_torch_policy
from ray.rllib.models.torch.torch_action_dist import (
TorchCategorical, TorchSquashedGaussian, TorchDiagGaussian, TorchBeta)
from ray.rllib.utils.framework import try_import_torch
from ray.rllib.utils.typing import LocalOptimizer, TensorType, \
TrainerConfigDict
torch, nn = try_import_torch()
F = nn.functional
@@ -19,13 +30,41 @@ F = nn.functional
logger = logging.getLogger(__name__)
def build_sac_model_and_action_dist(policy, obs_space, action_space, config):
def build_sac_model_and_action_dist(
policy: Policy,
obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> \
Tuple[ModelV2, Type[TorchDistributionWrapper]]:
"""Constructs the necessary ModelV2 and action dist class for the Policy.
Args:
policy (Policy): The TFPolicy that will use the models.
obs_space (gym.spaces.Space): The observation space.
action_space (gym.spaces.Space): The action space.
config (TrainerConfigDict): The SAC trainer's config dict.
Returns:
ModelV2: The ModelV2 to be used by the Policy. Note: An additional
target model will be created in this function and assigned to
`policy.target_model`.
"""
model = build_sac_model(policy, obs_space, action_space, config)
action_dist_class = get_dist_class(config, action_space)
action_dist_class = _get_dist_class(config, action_space)
return model, action_dist_class
def get_dist_class(config, action_space):
def _get_dist_class(config: TrainerConfigDict, action_space: gym.spaces.Space
) -> Type[TorchDistributionWrapper]:
"""Helper function to return a dist class based on config and action space.
Args:
config (TrainerConfigDict): The Trainer's config dict.
action_space (gym.spaces.Space): The action space used.
Returns:
Type[TFActionDistribution]: A TF distribution class.
"""
if isinstance(action_space, Discrete):
return TorchCategorical
else:
@@ -36,28 +75,83 @@ def get_dist_class(config, action_space):
return TorchDiagGaussian
def action_distribution_fn(policy,
model,
obs_batch,
*,
state_batches=None,
seq_lens=None,
prev_action_batch=None,
prev_reward_batch=None,
explore=None,
timestep=None,
is_training=None):
def action_distribution_fn(
policy: Policy,
model: ModelV2,
obs_batch: TensorType,
*,
state_batches: Optional[List[TensorType]] = None,
seq_lens: Optional[TensorType] = None,
prev_action_batch: Optional[TensorType] = None,
prev_reward_batch=None,
explore: Optional[bool] = None,
timestep: Optional[int] = None,
is_training: Optional[bool] = None) -> \
Tuple[TensorType, Type[TorchDistributionWrapper], List[TensorType]]:
"""The action distribution function to be used the algorithm.
An action distribution function is used to customize the choice of action
distribution class and the resulting action distribution inputs (to
parameterize the distribution object).
After parameterizing the distribution, a `sample()` call
will be made on it to generate actions.
Args:
policy (Policy): The Policy being queried for actions and calling this
function.
model (TorchModelV2): The SAC specific Model to use to generate the
distribution inputs (see sac_tf|torch_model.py). Must support the
`get_policy_output` method.
obs_batch (TensorType): The observations to be used as inputs to the
model.
state_batches (Optional[List[TensorType]]): The list of internal state
tensor batches.
seq_lens (Optional[TensorType]): The tensor of sequence lengths used
in RNNs.
prev_action_batch (Optional[TensorType]): Optional batch of prev
actions used by the model.
prev_reward_batch (Optional[TensorType]): Optional batch of prev
rewards used by the model.
explore (Optional[bool]): Whether to activate exploration or not. If
None, use value of `config.explore`.
timestep (Optional[int]): An optional timestep.
is_training (Optional[bool]): An optional is-training flag.
Returns:
Tuple[TensorType, Type[TorchDistributionWrapper], List[TensorType]]:
The dist inputs, dist class, and a list of internal state outputs
(in the RNN case).
"""
# Get base-model output (w/o the SAC specific parts of the network).
model_out, _ = model({
"obs": obs_batch,
"is_training": is_training,
}, [], None)
# Use the base output to get the policy outputs from the SAC model's
# policy components.
distribution_inputs = model.get_policy_output(model_out)
action_dist_class = get_dist_class(policy.config, policy.action_space)
# Get a distribution class to be used with the just calculated dist-inputs.
action_dist_class = _get_dist_class(policy.config, policy.action_space)
return distribution_inputs, action_dist_class, []
def actor_critic_loss(policy, model, _, train_batch):
def actor_critic_loss(
policy: Policy, model: ModelV2,
dist_class: Type[TorchDistributionWrapper],
train_batch: SampleBatch) -> Union[TensorType, List[TensorType]]:
"""Constructs the loss for the Soft Actor Critic.
Args:
policy (Policy): The Policy to calculate the loss for.
model (ModelV2): The Model to calculate the loss for.
dist_class (Type[TorchDistributionWrapper]: The action distr. class.
train_batch (SampleBatch): The training data.
Returns:
Union[TensorType, List[TensorType]]: A single loss tensor or a list
of loss tensors.
"""
# Should be True only for debugging purposes (e.g. test cases)!
deterministic = policy.config["_deterministic_loss"]
@@ -110,7 +204,7 @@ def actor_critic_loss(policy, model, _, train_batch):
# Continuous actions case.
else:
# Sample single actions from distribution.
action_dist_class = get_dist_class(policy.config, policy.action_space)
action_dist_class = _get_dist_class(policy.config, policy.action_space)
action_dist_t = action_dist_class(
model.get_policy_output(model_out_t), policy.model)
policy_t = action_dist_t.sample() if not deterministic else \
@@ -218,7 +312,16 @@ def actor_critic_loss(policy, model, _, train_batch):
[policy.alpha_loss])
def stats(policy, train_batch):
def stats(policy: Policy, train_batch: SampleBatch) -> Dict[str, TensorType]:
"""Stats function for SAC. Returns a dict with important loss stats.
Args:
policy (Policy): The Policy to generate stats for.
train_batch (SampleBatch): The SampleBatch (already) used for training.
Returns:
Dict[str, TensorType]: The stats dict.
"""
return {
"td_error": policy.td_error,
"mean_td_error": torch.mean(policy.td_error),
@@ -235,11 +338,19 @@ def stats(policy, train_batch):
}
def optimizer_fn(policy, config):
def optimizer_fn(policy: Policy, config: TrainerConfigDict) -> \
Tuple[LocalOptimizer]:
"""Creates all necessary optimizers for SAC learning.
The 3 or 4 (twin_q=True) optimizers returned here correspond to the
number of loss terms returned by the loss function.
Args:
policy (Policy): The policy object to be trained.
config (TrainerConfigDict): The Trainer's config dict.
Returns:
Tuple[LocalOptimizer]: The local optimizers to use for policy training.
"""
policy.actor_optim = torch.optim.Adam(
params=policy.model.policy_variables(),
@@ -276,6 +387,12 @@ def optimizer_fn(policy, config):
class ComputeTDErrorMixin:
"""Mixin class calculating TD-error (part of critic loss) per batch item.
- Adds `policy.compute_td_error()` method for TD-error calculation from a
batch of observations/actions/rewards/etc..
"""
def __init__(self):
def compute_td_error(obs_t, act_t, rew_t, obs_tp1, done_mask,
importance_weights):
@@ -291,13 +408,22 @@ class ComputeTDErrorMixin:
# (one TD-error value per item in batch to update PR weights).
actor_critic_loss(self, self.model, None, input_dict)
# Self.td_error is set within actor_critic_loss call.
# `self.td_error` is set within actor_critic_loss call. Return
# its updated value here.
return self.td_error
# Assign the method to policy (self) for later usage.
self.compute_td_error = compute_td_error
class TargetNetworkMixin:
"""Mixin class adding a method for (soft) target net(s) synchronizations.
- Adds the `update_target` method to the policy.
Calling `update_target` updates all target Q-networks' weights from their
respective "main" Q-metworks, based on tau (smooth, partial updating).
"""
def __init__(self):
# Hard initial update from Q-net(s) to target Q-net(s).
self.update_target(tau=1.0)
@@ -318,7 +444,27 @@ class TargetNetworkMixin:
self.target_model.load_state_dict(model_state_dict)
def setup_late_mixins(policy, obs_space, action_space, config):
def setup_late_mixins(policy: Policy, obs_space: gym.spaces.Space,
action_space: gym.spaces.Space,
config: TrainerConfigDict) -> None:
"""Call mixin classes' constructors after Policy initialization.
- Moves the target model(s) to the GPU, if necessary.
- Adds the `compute_td_error` method to the given policy.
Calling `compute_td_error` with batch data will re-calculate the loss
on that batch AND return the per-batch-item TD-error for prioritized
replay buffer record weight updating (in case a prioritized replay buffer
is used).
- Also adds the `update_target` method to the given policy.
Calling `update_target` updates all target Q-networks' weights from their
respective "main" Q-metworks, based on tau (smooth, partial updating).
Args:
policy (Policy): The Policy object.
obs_space (gym.spaces.Space): The Policy's observation space.
action_space (gym.spaces.Space): The Policy's action space.
config (TrainerConfigDict): The Policy's config.
"""
policy.target_model = policy.target_model.to(policy.device)
policy.model.log_alpha = policy.model.log_alpha.to(policy.device)
policy.model.target_entropy = policy.model.target_entropy.to(policy.device)
@@ -326,6 +472,8 @@ def setup_late_mixins(policy, obs_space, action_space, config):
TargetNetworkMixin.__init__(policy)
# Build a child class of `DynamicTFPolicy`, given the custom functions defined
# above.
SACTorchPolicy = build_torch_policy(
name="SACTorchPolicy",
loss_fn=actor_critic_loss,
+8 -8
View File
@@ -770,7 +770,7 @@ class Trainer(Trainable):
Note that you can also access the policy object through
self.get_policy(policy_id) and call compute_actions() on it directly.
Arguments:
Args:
observation (TensorStructType): observation from the environment.
state (List[TensorStructType]): RNN hidden state, if any. If state
is not None, then all of compute_single_action(...) is returned
@@ -831,7 +831,7 @@ class Trainer(Trainable):
Note that you can also access the policy object through
self.get_policy(policy_id) and call compute_actions() on it directly.
Arguments:
Args:
observation (obj): observation from the environment.
state (dict): RNN hidden state, if any. If state is not None,
then all of compute_single_action(...) is returned
@@ -920,7 +920,7 @@ class Trainer(Trainable):
def get_policy(self, policy_id: PolicyID = DEFAULT_POLICY_ID) -> Policy:
"""Return policy for the specified id, or None.
Arguments:
Args:
policy_id (str): id of policy to return.
"""
return self.workers.local_worker().get_policy(policy_id)
@@ -929,7 +929,7 @@ class Trainer(Trainable):
def get_weights(self, policies: List[PolicyID] = None) -> dict:
"""Return a dictionary of policy ids to weights.
Arguments:
Args:
policies (list): Optional list of policies to return weights for,
or None for all policies.
"""
@@ -939,7 +939,7 @@ class Trainer(Trainable):
def set_weights(self, weights: Dict[PolicyID, dict]):
"""Set policy weights by policy id.
Arguments:
Args:
weights (dict): Map of policy ids to weights to set.
"""
self.workers.local_worker().set_weights(weights)
@@ -950,7 +950,7 @@ class Trainer(Trainable):
policy_id: PolicyID = DEFAULT_POLICY_ID):
"""Export policy model with given policy_id to local directory.
Arguments:
Args:
export_dir (string): Writable local directory.
policy_id (string): Optional policy id to export.
@@ -969,7 +969,7 @@ class Trainer(Trainable):
policy_id: PolicyID = DEFAULT_POLICY_ID):
"""Export tensorflow policy model checkpoint to local directory.
Arguments:
Args:
export_dir (string): Writable local directory.
filename_prefix (string): file name prefix of checkpoint files.
policy_id (string): Optional policy id to export.
@@ -989,7 +989,7 @@ class Trainer(Trainable):
policy_id: PolicyID = DEFAULT_POLICY_ID):
"""Imports a policy's model with given policy_id from a local h5 file.
Arguments:
Args:
import_file (str): The h5 file to import from.
policy_id (string): Optional policy id to import into.
+12 -1
View File
@@ -155,11 +155,22 @@ def build_trainer(
@staticmethod
@override(Trainer)
def with_updates(**overrides) -> Type[Trainer]:
"""Build a copy of this trainer with the specified overrides.
"""Build a copy of this trainer class with the specified overrides.
Keyword Args:
overrides (dict): use this to override any of the arguments
originally passed to build_trainer() for this policy.
Returns:
Type[Trainer]: A the Trainer sub-class using `original_kwargs`
and `overrides`.
Examples:
>>> MyClass = SomeOtherClass.with_updates({"name": "Mine"})
>>> issubclass(MyClass, SomeOtherClass)
... False
>>> issubclass(MyClass, Trainer)
... True
"""
return build_trainer(**dict(original_kwargs, **overrides))
+2 -2
View File
@@ -165,7 +165,7 @@ class BaseEnv:
Actions should be sent for each ready agent that returned observations
in the previous poll() call.
Arguments:
Args:
action_dict (dict): Actions values keyed by env_id and agent_id.
"""
raise NotImplementedError
@@ -364,7 +364,7 @@ class _MultiAgentEnvToBaseEnv(BaseEnv):
existing_envs: List[MultiAgentEnv], num_envs: int):
"""Wrap existing multi-agent envs.
Arguments:
Args:
make_env (func|None): Factory that produces a new multiagent env.
Must be defined if the number of existing envs is less than
num_envs.
+4 -4
View File
@@ -87,7 +87,7 @@ class ExternalMultiAgentEnv(ExternalEnv):
observation_dict is expected to contain the observation
of all agents acting in this episode step.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation_dict (dict): Current environment observation.
@@ -104,7 +104,7 @@ class ExternalMultiAgentEnv(ExternalEnv):
action_dict: MultiAgentDict) -> None:
"""Record an observation and (off-policy) action taken.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation_dict (dict): Current environment observation.
action_dict (dict): Action for the observation.
@@ -126,7 +126,7 @@ class ExternalMultiAgentEnv(ExternalEnv):
episode. Rewards accumulate until the next action. If no reward is
logged before the next action, a reward of 0.0 is assumed.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
reward_dict (dict): Reward from the environment agents.
info_dict (dict): Optional info dict.
@@ -156,7 +156,7 @@ class ExternalMultiAgentEnv(ExternalEnv):
observation_dict: MultiAgentDict) -> None:
"""Record the end of an episode.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation_dict (dict): Current environment observation.
"""
+1 -1
View File
@@ -18,7 +18,7 @@ class _GroupAgentsWrapper(MultiAgentEnv):
See MultiAgentEnv.with_agent_groups() for usage info.
Arguments:
Args:
env (MultiAgentEnv): env to wrap
groups (dict): Grouping spec as documented in MultiAgentEnv
obs_space (Space): Optional observation space for the grouped
+1 -1
View File
@@ -100,7 +100,7 @@ class MultiAgentEnv:
This API is experimental.
Arguments:
Args:
groups (dict): Mapping from group id to a list of the agent ids
of group members. If an agent id is not present in any group
value, it will be left ungrouped.
+5 -5
View File
@@ -102,7 +102,7 @@ class PolicyClient:
) -> Union[EnvActionType, MultiAgentDict]:
"""Record an observation and get the on-policy action.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation (obj): Current environment observation.
@@ -133,7 +133,7 @@ class PolicyClient:
action: Union[EnvActionType, MultiAgentDict]) -> None:
"""Record an observation and (off-policy) action taken.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation (obj): Current environment observation.
action (obj): Action for the observation.
@@ -163,7 +163,7 @@ class PolicyClient:
episode. Rewards accumulate until the next action. If no reward is
logged before the next action, a reward of 0.0 is assumed.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
reward (float): Reward from the environment.
info (dict): Extra info dict.
@@ -191,7 +191,7 @@ class PolicyClient:
observation: Union[EnvObsType, MultiAgentDict]) -> None:
"""Record the end of an episode.
Arguments:
Args:
episode_id (str): Episode id returned from start_episode().
observation (obj): Current environment observation.
"""
@@ -323,7 +323,7 @@ def _auto_wrap_external(real_env_creator):
def _create_embedded_rollout_worker(kwargs, send_fn):
"""Create a local rollout worker and a thread that samples from it.
Arguments:
Args:
kwargs (dict): args for the RolloutWorker constructor.
send_fn (fn): function to send a JSON request to the server.
"""
+1 -1
View File
@@ -68,7 +68,7 @@ class VectorEnv:
) -> Tuple[List[EnvObsType], List[float], List[bool], List[EnvInfoDict]]:
"""Performs a vectorized step on all sub environments using `actions`.
Arguments:
Args:
actions (List[any]): List of actions (one for each sub-env).
Returns:
+1 -1
View File
@@ -91,7 +91,7 @@ def summarize_episodes(
) -> ResultDict:
"""Summarizes a set of episode metrics tuples.
Arguments:
Args:
episodes: smoothed set of episodes including historical ones
new_episodes: just the new episodes in this iteration. This must be
a subset of `episodes`. If None, assumes all episodes are new.
+2 -2
View File
@@ -782,7 +782,7 @@ class RolloutWorker(ParallelIteratorWorker):
This is typically used in combination with distributed allreduce.
Arguments:
Args:
expected_batch_size (int): Expected number of samples to learn on.
num_sgd_iter (int): Number of SGD iterations.
sgd_minibatch_size (int): SGD minibatch size.
@@ -827,7 +827,7 @@ class RolloutWorker(ParallelIteratorWorker):
self, policy_id: Optional[PolicyID] = DEFAULT_POLICY_ID) -> Policy:
"""Return policy for the specified id, or None.
Arguments:
Args:
policy_id (str): id of policy to return.
"""
+1 -1
View File
@@ -141,7 +141,7 @@ class MultiAgentSampleBatchBuilder:
**values: Any) -> None:
"""Add the given dictionary (row) of values to this batch.
Arguments:
Args:
agent_id (obj): Unique id for the agent we are adding values for.
policy_id (obj): Unique id for policy controlling the agent.
values (dict): Row of values to add for this agent.
+1 -1
View File
@@ -1477,7 +1477,7 @@ def _get_or_raise(mapping: Dict[PolicyID, Union[Policy, Preprocessor, Filter]],
Returns:
Union[Policy, Preprocessor, Filter]: The found object.
Throws:
Raises:
ValueError: If `policy_id` cannot be found in `mapping`.
"""
if policy_id not in mapping:
+1 -1
View File
@@ -39,7 +39,7 @@ class WorkerSet:
_setup: bool = True):
"""Create a new WorkerSet and initialize its workers.
Arguments:
Args:
env_creator (Optional[Callable[[EnvContext], EnvType]]): Function
that returns env given env config.
policy (Optional[Type[Policy]]): A rllib.policy.Policy class.
+1 -1
View File
@@ -82,7 +82,7 @@ parser.add_argument("--no-custom-eval", action="store_true")
def custom_eval_function(trainer, eval_workers):
"""Example of a custom evaluation function.
Arguments:
Args:
trainer (Trainer): trainer class to evaluate.
eval_workers (WorkerSet): evaluation workers.
+2 -2
View File
@@ -12,7 +12,7 @@ def Concurrently(ops: List[LocalIterator],
round_robin_weights=None):
"""Operator that runs the given parent iterators concurrently.
Arguments:
Args:
mode (str): One of {'round_robin', 'async'}.
- In 'round_robin' mode, we alternate between pulling items from
each parent iterator in order deterministically.
@@ -105,7 +105,7 @@ def Dequeue(input_queue: queue.Queue, check=lambda: True):
The dequeue is non-blocking, so Dequeue operations can executed with
Enqueue via the Concurrently() operator.
Arguments:
Args:
input_queue (Queue): queue to pull items from.
check (fn): liveness check. When this function returns false,
Dequeue() will raise an error to halt execution.
+1 -1
View File
@@ -25,7 +25,7 @@ class LearnerThread(threading.Thread):
learner_queue_size, learner_queue_timeout):
"""Initialize the learner thread.
Arguments:
Args:
local_worker (RolloutWorker): process local rollout worker holding
policies this thread will call learn_on_batch() on
minibatch_buffer_size (int): max number of train batches to store
+1 -1
View File
@@ -15,7 +15,7 @@ def StandardMetricsReporting(
selected_workers: List["ActorHandle"] = None) -> LocalIterator[dict]:
"""Operator to periodically collect and report metrics.
Arguments:
Args:
train_op (LocalIterator): Operator for executing training steps.
We ignore the output values.
workers (WorkerSet): Rollout workers to collect metrics from.
+1 -1
View File
@@ -7,7 +7,7 @@ class MinibatchBuffer:
def __init__(self, inqueue, size, timeout, num_passes, init_num_passes=1):
"""Initialize a minibatch buffer.
Arguments:
Args:
inqueue: Queue to populate the internal ring buffer from.
size: Max number of data items to buffer.
timeout: Queue timeout
+1 -1
View File
@@ -38,7 +38,7 @@ class TFMultiGPULearner(LearnerThread):
_fake_gpus=False):
"""Initialize a multi-gpu learner thread.
Arguments:
Args:
local_worker (RolloutWorker): process local rollout worker holding
policies this thread will call learn_on_batch() on
num_gpus (int): number of GPUs to use for data-parallel SGD
+1 -1
View File
@@ -60,7 +60,7 @@ def Replay(*,
This should be combined with the StoreToReplayActors operation using the
Concurrently() operator.
Arguments:
Args:
local_buffer (LocalReplayBuffer): Local buffer to use. Only one of this
and replay_actors can be specified.
actors (list): List of replay actors. Only one of this and
+2 -2
View File
@@ -25,7 +25,7 @@ def ParallelRollouts(workers: WorkerSet, *, mode="bulk_sync",
If there are no remote workers, experiences will be collected serially from
the local worker instance instead.
Arguments:
Args:
workers (WorkerSet): set of rollout workers to use.
mode (str): One of {'async', 'bulk_sync', 'raw'}.
- In 'async' mode, batches are returned as soon as they are
@@ -94,7 +94,7 @@ def AsyncGradients(
workers: WorkerSet) -> LocalIterator[Tuple[ModelGradients, int]]:
"""Operator to compute gradients in parallel from rollout workers.
Arguments:
Args:
workers (WorkerSet): set of rollout workers to use.
Returns:
+1 -1
View File
@@ -273,7 +273,7 @@ class ApplyGradients:
update_all=True):
"""Creates an ApplyGradients instance.
Arguments:
Args:
workers (WorkerSet): workers to apply gradients to.
update_all (bool): If true, updates all workers. Otherwise, only
update the worker that produced the sample batch we are
+2 -2
View File
@@ -142,7 +142,7 @@ class ModelV2:
You can find an runnable example in examples/custom_loss.py.
Arguments:
Args:
policy_loss (Union[List[Tensor],Tensor]): List of or single policy
loss(es) from the policy.
loss_inputs (dict): map of input placeholders for rollout data.
@@ -181,7 +181,7 @@ class ModelV2:
Custom models should override forward() instead of __call__.
Arguments:
Args:
input_dict (dict): dictionary of input tensors, including "obs",
"prev_action", "prev_reward", "is_training"
state (list): list of state tensors with sizes matching those
+1 -1
View File
@@ -65,7 +65,7 @@ class RecurrentNetwork(TFModelV2):
def forward_rnn(self, inputs, state, seq_lens):
"""Call the model with the given input tensors and state.
Arguments:
Args:
inputs (dict): observation tensor with shape [B, T, obs_size].
state (list): list of state tensors, each with shape [B, T, size].
seq_lens (Tensor): 1d tensor holding input sequence lengths.
+1 -1
View File
@@ -37,7 +37,7 @@ class InputReader:
This method creates a queue runner thread that will call next() on this
reader repeatedly to feed the TensorFlow queue.
Arguments:
Args:
queue_size (int): Max elements to allow in the TF queue.
Example:
+1 -1
View File
@@ -34,7 +34,7 @@ class JsonReader(InputReader):
def __init__(self, inputs: List[str], ioctx: IOContext = None):
"""Initialize a JsonReader.
Arguments:
Args:
inputs (str|list): either a glob expression for files, e.g.,
"/tmp/**/*.json", or a list of single file paths or URIs, e.g.,
["s3://bucket/file.json", "s3://bucket/file2.json"].
+1 -1
View File
@@ -36,7 +36,7 @@ class JsonWriter(OutputWriter):
compress_columns: List[str] = frozenset(["obs", "new_obs"])):
"""Initialize a JsonWriter.
Arguments:
Args:
path (str): a path/URI of the output directory to save files in.
ioctx (IOContext): current IO context object.
max_file_size (int): max size of single files before rolling over.
+1 -1
View File
@@ -24,7 +24,7 @@ class MixedInput(InputReader):
def __init__(self, dist: Dict[JsonReader, float], ioctx: IOContext):
"""Initialize a MixedInput.
Arguments:
Args:
dist (dict): dict mapping JSONReader paths or "sampler" to
probabilities. The probabilities must sum to 1.0.
ioctx (IOContext): current IO context object.
+1 -1
View File
@@ -25,7 +25,7 @@ class OffPolicyEstimator:
def __init__(self, policy: Policy, gamma: float):
"""Creates an off-policy estimator.
Arguments:
Args:
policy (Policy): Policy to evaluate.
gamma (float): Discount of the MDP.
"""
+1 -1
View File
@@ -11,7 +11,7 @@ class OutputWriter:
def write(self, sample_batch: SampleBatchType):
"""Save a batch of experiences.
Arguments:
Args:
sample_batch: SampleBatch or MultiAgentBatch to save.
"""
raise NotImplementedError
+1 -1
View File
@@ -20,7 +20,7 @@ class ShuffledInput(InputReader):
def __init__(self, child: InputReader, n: int = 0):
"""Initialize a MixedInput.
Arguments:
Args:
child (InputReader): child input reader to shuffle.
n (int): if positive, shuffle input over this many batches.
"""
+1 -1
View File
@@ -80,7 +80,7 @@ class DynamicTFPolicy(TFPolicy):
obs_include_prev_action_reward: bool = True):
"""Initialize a dynamic TF policy.
Arguments:
Args:
observation_space (gym.spaces.Space): Observation space of the
policy.
action_space (gym.spaces.Space): Action space of the policy.
+12 -10
View File
@@ -1,5 +1,5 @@
import gym
from typing import Callable, Dict, List, Optional, Tuple, Type, Union
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from ray.rllib.models.catalog import ModelCatalog
from ray.rllib.models.modelv2 import ModelV2
@@ -29,8 +29,9 @@ def build_torch_policy(
stats_fn: Optional[Callable[[Policy, SampleBatch], Dict[
str, TensorType]]] = None,
postprocess_fn: Optional[Callable[[
Policy, SampleBatch, List[SampleBatch], "MultiAgentEpisode"
], None]] = None,
Policy, SampleBatch, Optional[Dict[Any, SampleBatch]], Optional[
"MultiAgentEpisode"]
], SampleBatch]] = None,
extra_action_out_fn: Optional[Callable[[
Policy, Dict[str, TensorType], List[TensorType], ModelV2,
TorchDistributionWrapper
@@ -59,7 +60,7 @@ def build_torch_policy(
], ModelV2]] = None,
make_model_and_action_dist: Optional[Callable[[
Policy, gym.spaces.Space, gym.spaces.Space, TrainerConfigDict
], Tuple[ModelV2, TorchDistributionWrapper]]] = None,
], Tuple[ModelV2, Type[TorchDistributionWrapper]]]] = None,
apply_gradients_fn: Optional[Callable[
[Policy, "torch.optim.Optimizer"], None]] = None,
mixins: Optional[List[type]] = None,
@@ -77,9 +78,9 @@ def build_torch_policy(
overrides. If None, uses only(!) the user-provided
PartialTrainerConfigDict as dict for this Policy.
postprocess_fn (Optional[Callable[[Policy, SampleBatch,
List[SampleBatch], MultiAgentEpisode], None]]): Optional callable
for post-processing experience batches (called after the
super's `postprocess_trajectory` method).
Optional[Dict[Any, SampleBatch]], Optional["MultiAgentEpisode"]],
SampleBatch]]): Optional callable for post-processing experience
batches (called after the super's `postprocess_trajectory` method).
stats_fn (Optional[Callable[[Policy, SampleBatch],
Dict[str, TensorType]]]): Optional callable that returns a dict of
values given the policy and training batch. If None,
@@ -143,9 +144,10 @@ def build_torch_policy(
a default Model will be created.
make_model_and_action_dist (Optional[Callable[[Policy,
gym.spaces.Space, gym.spaces.Space, TrainerConfigDict],
Tuple[ModelV2, TorchDistributionWrapper]]]): Optional callable that
takes the same arguments as Policy.__init__ and returns a tuple
of model instance and torch action distribution class.
Tuple[ModelV2, Type[TorchDistributionWrapper]]]]): Optional
callable that takes the same arguments as Policy.__init__ and
returns a tuple of model instance and torch action distribution
class.
Note: Only one of `make_model` or `make_model_and_action_dist`
should be provided. If both are None, a default Model will be
created.
+1 -1
View File
@@ -1,7 +1,7 @@
def override(cls):
"""Annotation for documenting method overrides.
Arguments:
Args:
cls (type): The superclass that provides the overriden method. If this
cls does not actually have the method, an error is raised.
"""
+4 -4
View File
@@ -18,7 +18,7 @@ def averaged(kv, axis=None):
For non-scalar values, we simply pick the first value.
Arguments:
Args:
kv (dict): dictionary with values that are lists of floats.
Returns:
@@ -36,7 +36,7 @@ def averaged(kv, axis=None):
def standardized(array):
"""Normalize the values in an array.
Arguments:
Args:
array (np.ndarray): Array of values to normalize.
Returns:
@@ -48,7 +48,7 @@ def standardized(array):
def minibatches(samples, sgd_minibatch_size):
"""Return a generator yielding minibatches from a sample batch.
Arguments:
Args:
samples (SampleBatch): batch of samples to split up.
sgd_minibatch_size (int): size of minibatches to return.
@@ -98,7 +98,7 @@ def do_minibatch_sgd(samples, policies, local_worker, num_sgd_iter,
sgd_minibatch_size, standardize_fields):
"""Execute minibatch SGD.
Arguments:
Args:
samples (SampleBatch): batch of samples to optimize.
policies (dict): dictionary of policies to optimize.
local_worker (RolloutWorker): master rollout worker instance.
+2 -2
View File
@@ -253,7 +253,7 @@ def check_learning_achieved(tune_results, min_reward):
tune_results: The tune.run returned results object.
min_reward (float): The min reward that must be reached.
Throws:
Raises:
ValueError: If `min_reward` not reached.
"""
if tune_results.trials[0].last_result["episode_reward_mean"] < min_reward:
@@ -273,7 +273,7 @@ def check_compute_single_action(trainer,
include_prev_action_reward (bool): Whether to include the prev-action
and -reward in the `compute_action` call.
Throws:
Raises:
ValueError: If anything unexpected happens.
"""
try:
+1 -1
View File
@@ -55,7 +55,7 @@ def make_tf_callable(session_or_none, dynamic_shape=False):
will build a function that executes a session run with placeholders
internally.
Arguments:
Args:
session_or_none (tf.Session): tf.Session if in graph mode, else None.
dynamic_shape (bool): True if the placeholders should have a dynamic
batch dimension. Otherwise they will be fixed shape.