From 20450a4e82a9b9a83fc3b54018a540a13668a846 Mon Sep 17 00:00:00 2001 From: Eric Liang Date: Thu, 1 Aug 2019 13:03:59 -0700 Subject: [PATCH] [rllib] Add rock paper scissors multi-agent example (#5336) --- doc/source/rllib-api.svg | 2 +- doc/source/rllib-concepts.rst | 5 + doc/source/rllib-env.rst | 13 ++ doc/source/rllib-examples.rst | 12 +- doc/source/rllib-training.rst | 2 - doc/source/rllib.rst | 2 + doc/source/rock-paper-scissors.png | Bin 0 -> 52058 bytes python/ray/rllib/agents/ppo/ppo.py | 4 + .../rock_paper_scissors_multiagent.py | 215 ++++++++++++++++++ python/ray/rllib/models/__init__.py | 4 + 10 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 doc/source/rock-paper-scissors.png create mode 100644 python/ray/rllib/examples/rock_paper_scissors_multiagent.py diff --git a/doc/source/rllib-api.svg b/doc/source/rllib-api.svg index e157e106f..c5b338250 100644 --- a/doc/source/rllib-api.svg +++ b/doc/source/rllib-api.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/doc/source/rllib-concepts.rst b/doc/source/rllib-concepts.rst index 46d998256..e1f96f949 100644 --- a/doc/source/rllib-concepts.rst +++ b/doc/source/rllib-concepts.rst @@ -103,6 +103,11 @@ The above basic policy, when run, will produce batches of observations with the assert "other_value" in samples.keys() +Policies in Multi-Agent +~~~~~~~~~~~~~~~~~~~~~~~ + +Beyond being agnostic of framework implementation, one of the main reasons to have a Policy abstraction is for use in multi-agent environments. For example, the `rock-paper-scissors example `__ shows how you can leverage the Policy abstraction to evaluate heuristic policies against learned policies. + Building Policies in TensorFlow ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/rllib-env.rst b/doc/source/rllib-env.rst index b04b91c3c..d3b614e80 100644 --- a/doc/source/rllib-env.rst +++ b/doc/source/rllib-env.rst @@ -218,6 +218,15 @@ Here is a simple `example training script 1``. +Rock Paper Scissors Example +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `rock_paper_scissors_multiagent.py `__ example demonstrates several types of policies competing against each other: heuristic policies of repeating the same move, beating the last opponent move, and learned LSTM and feedforward policies. + +.. figure:: rock-paper-scissors.png + + TensorBoard output of running the rock-paper-scissors example, where a learned policy faces off between a random selection of the same-move and beat-last-move heuristics. Here the performance of heuristic policies vs the learned policy is compared with LSTM enabled (blue) and a plain feed-forward policy (red). While the feedforward policy can easily beat the same-move heuristic by simply avoiding the last move taken, it takes a LSTM policy to distinguish between and consistently beat both policies. + Hierarchical Environments ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -254,6 +263,10 @@ See this file for a runnable example: `hierarchical_training.py `__, you can put layers in global variables and straightforwardly share those layer objects between models instead of using variable scopes. + RLlib will create each policy's model in a separate ``tf.variable_scope``. However, variables can still be shared between policies by explicitly entering a globally shared variable scope with ``tf.VariableScope(reuse=tf.AUTO_REUSE)``: .. code-block:: python diff --git a/doc/source/rllib-examples.rst b/doc/source/rllib-examples.rst index b83a522dd..9e47cc18f 100644 --- a/doc/source/rllib-examples.rst +++ b/doc/source/rllib-examples.rst @@ -55,6 +55,8 @@ Serving and Offline Multi-Agent and Hierarchical ---------------------------- +- `Rock-paper-scissors `__: + Example of different heuristic and learned policies competing against each other in rock-paper-scissors. - `Two-step game `__: Example of the two-step game from the `QMIX paper `__. - `Hand-coded policy `__: @@ -72,13 +74,15 @@ Community Examples ------------------ - `CARLA `__: Example of training autonomous vehicles with RLlib and `CARLA `__ simulator. -- `Traffic Flow `__: - Example of optimizing mixed-autonomy traffic simulations with RLlib / multi-agent. +- `GFootball `__: + Example of setting up a multi-agent version of `GFootball `__ with RLlib. +- `NeuroCuts `__: + Example of building packet classification trees using RLlib / multi-agent in a bandit-like setting. - `Roboschool / SageMaker `__: Example of training robotic control policies in SageMaker with RLlib. - `StarCraft2 `__: Example of training in StarCraft2 maps with RLlib / multi-agent. -- `NeuroCuts `__: - Example of building packet classification trees using RLlib / multi-agent in a bandit-like setting. +- `Traffic Flow `__: + Example of optimizing mixed-autonomy traffic simulations with RLlib / multi-agent. - `Sequential Social Dilemma Games `__: Example of using the multi-agent API to model several `social dilemma games `__. diff --git a/doc/source/rllib-training.rst b/doc/source/rllib-training.rst index 9c365f8fb..196a1659c 100644 --- a/doc/source/rllib-training.rst +++ b/doc/source/rllib-training.rst @@ -372,8 +372,6 @@ TensorFlow Eager While RLlib uses TF graph mode for all computations, you can still leverage TF eager to inspect the intermediate state of computations using `tf.py_function `__. Here's an example of using eager mode in `a custom RLlib model and loss `__. -There is also experimental support for running the entire loss function in eager mode. This can be enabled with ``use_eager: True``, e.g., ``rllib train --env=CartPole-v0 --run=PPO --config='{"use_eager": true, "simple_optimizer": true}'``. However this currently only works for a couple algorithms. - Episode Traces ~~~~~~~~~~~~~~ diff --git a/doc/source/rllib.rst b/doc/source/rllib.rst index df2d06dff..6b232023b 100644 --- a/doc/source/rllib.rst +++ b/doc/source/rllib.rst @@ -98,6 +98,8 @@ Concepts and Custom Algorithms ------------------------------ * `Policies `__ + - `Policies in Multi-Agent `__ + - `Building Policies in TensorFlow `__ - `Building Policies in TensorFlow Eager `__ diff --git a/doc/source/rock-paper-scissors.png b/doc/source/rock-paper-scissors.png new file mode 100644 index 0000000000000000000000000000000000000000..fa8c27779c8b0d6a371cde52f6da3718a54918c5 GIT binary patch literal 52058 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 10, + } + return obs, rew, done, {} + + +class AlwaysSameHeuristic(Policy): + """Pick a random move and stick with it for the entire episode.""" + + def __init__(self, observation_space, action_space, config): + Policy.__init__(self, observation_space, action_space, config) + + def get_initial_state(self): + return [random.choice([ROCK, PAPER, SCISSORS])] + + def compute_actions(self, + obs_batch, + state_batches, + prev_action_batch=None, + prev_reward_batch=None, + info_batch=None, + episodes=None, + **kwargs): + return [x for x in state_batches[0]], state_batches, {} + + def learn_on_batch(self, samples): + pass + + def get_weights(self): + pass + + def set_weights(self, weights): + pass + + +class BeatLastHeuristic(Policy): + """Play the move that would beat the last move of the opponent.""" + + def __init__(self, observation_space, action_space, config): + Policy.__init__(self, observation_space, action_space, config) + + def compute_actions(self, + obs_batch, + state_batches, + prev_action_batch=None, + prev_reward_batch=None, + info_batch=None, + episodes=None, + **kwargs): + def successor(x): + if x[ROCK] == 1: + return PAPER + elif x[PAPER] == 1: + return SCISSORS + elif x[SCISSORS] == 1: + return ROCK + + return [successor(x) for x in obs_batch], [], {} + + def learn_on_batch(self, samples): + pass + + def get_weights(self): + pass + + def set_weights(self, weights): + pass + + +def run_same_policy(): + """Use the same policy for both agents (trivial case).""" + + tune.run("PG", config={"env": RockPaperScissorsEnv}) + + +def run_heuristic_vs_learned(use_lstm=False, trainer="PG"): + """Run heuristic policies vs a learned agent. + + The learned agent should eventually reach a reward of ~5 with + use_lstm=False, and ~7 with use_lstm=True. The reason the LSTM policy + can perform better is since it can distinguish between the always_same vs + beat_last heuristics. + """ + + def select_policy(agent_id): + if agent_id == "player1": + return "learned" + else: + return random.choice(["always_same", "beat_last"]) + + tune.run( + trainer, + stop={"timesteps_total": 400000}, + config={ + "env": RockPaperScissorsEnv, + "gamma": 0.9, + "num_workers": 4, + "num_envs_per_worker": 4, + "sample_batch_size": 10, + "train_batch_size": 200, + "multiagent": { + "policies_to_train": ["learned"], + "policies": { + "always_same": (AlwaysSameHeuristic, Discrete(3), + Discrete(3), {}), + "beat_last": (BeatLastHeuristic, Discrete(3), Discrete(3), + {}), + "learned": (None, Discrete(3), Discrete(3), { + "model": { + "use_lstm": use_lstm + } + }), + }, + "policy_mapping_fn": tune.function(select_policy), + }, + }) + + +def run_with_custom_entropy_loss(): + """Example of customizing the loss function of an existing policy. + + This performs about the same as the default loss does.""" + + def entropy_policy_gradient_loss(policy, batch_tensors): + actions = batch_tensors["actions"] + advantages = batch_tensors["advantages"] + return (-0.1 * policy.action_dist.entropy() - tf.reduce_mean( + policy.action_dist.logp(actions) * advantages)) + + EntropyPolicy = PGTFPolicy.with_updates( + loss_fn=entropy_policy_gradient_loss) + EntropyLossPG = PGTrainer.with_updates( + name="EntropyPG", get_policy_class=lambda _: EntropyPolicy) + run_heuristic_vs_learned(use_lstm=True, trainer=EntropyLossPG) + + +if __name__ == "__main__": + # run_same_policy() + # run_heuristic_vs_learned(use_lstm=False) + run_heuristic_vs_learned(use_lstm=False) + # run_with_custom_entropy_loss() diff --git a/python/ray/rllib/models/__init__.py b/python/ray/rllib/models/__init__.py index 70892f120..6f1f6d9cd 100644 --- a/python/ray/rllib/models/__init__.py +++ b/python/ray/rllib/models/__init__.py @@ -2,6 +2,8 @@ from ray.rllib.models.action_dist import ActionDistribution from ray.rllib.models.catalog import ModelCatalog, MODEL_DEFAULTS from ray.rllib.models.model import Model from ray.rllib.models.preprocessors import Preprocessor +from ray.rllib.models.tf.fcnet_v1 import FullyConnectedNetwork +from ray.rllib.models.tf.visionnet_v1 import VisionNetwork __all__ = [ "ActionDistribution", @@ -9,4 +11,6 @@ __all__ = [ "Model", "Preprocessor", "MODEL_DEFAULTS", + "FullyConnectedNetwork", # legacy + "VisionNetwork", # legacy ]