From 4076c7c476af47bbb6d28464a04db7dddde40eac Mon Sep 17 00:00:00 2001
From: Sasha Abramowitz
Date: Thu, 19 Dec 2024 09:53:28 +0200
Subject: [PATCH] feat: readme revamp (#1108)
* feat: initial readme revamp
* chore: some readme fixes
* fix: convert images to png
* chore: changes around performance plots in readme
* chore: add more benchmark images
* chore: update images
* chore: rename legend
* chore: add legend to readme
* chore: move install + getting started near the top
* feat: update system readmes
* chore: a note on ISAC
* chore: update branch naming convention doc
* chore: some readme updates
* feat: switch detailed install instruction to uv
* docs: python badge
* wip: system level docs
* feat: readme badges
* chore: add speed plot and move tables out of collapsible
* fix: run pre commits
* fix: tests budge link
* feat: system level configs
* chore: github math render fix
* chore: github math render fix and linting
* docs: add links to system readmes, papers and hydra
* docs: qlearning paper links
* docs: reword sebulba section to be distribution architectures
* docs: change reference to sable paper
* docs: clarify distribution architectures that are support for different envs
* docs: general spelling mistake fixes and relative links to docs and files
* docs: typo fixes
* docs: replace absolute website links with relative links
* docs: sable diagram caption
* docs: sable caption math
* docs: another sable diagram caption fix
* docs: sable diagram math render
* docs: add environment code and paper links
---------
Co-authored-by: RuanJohn
Co-authored-by: OmaymaMahjoub
Co-authored-by: Ruan de Kock <33461981+RuanJohn@users.noreply.github.com>
---
README.md | 237 +++++++-----------
docs/CONTRIBUTING.md | 2 +-
docs/DETAILED_INSTALL.md | 22 +-
docs/images/algo_images/sable-arch.png | Bin 0 -> 361715 bytes
docs/images/benchmark_results/connector.png | Bin 0 -> 178668 bytes
docs/images/benchmark_results/lbf.png | Bin 0 -> 102125 bytes
docs/images/benchmark_results/legend.jpg | Bin 0 -> 96900 bytes
docs/images/benchmark_results/mabrax.png | Bin 0 -> 310919 bytes
docs/images/benchmark_results/mpe.png | Bin 0 -> 232746 bytes
docs/images/benchmark_results/rware.png | Bin 0 -> 166699 bytes
docs/images/benchmark_results/smax.png | Bin 0 -> 216699 bytes
.../lbf_results/15x15-4p-3f_rec_mappo.png | Bin 226464 -> 0 bytes
.../2s-8x8-2p-2f-coop_rec_mappo.png | Bin 166031 -> 0 bytes
docs/images/lbf_results/legend_rec_mappo.png | Bin 8302 -> 0 bytes
.../rware_results/ff_ippo/small-4ag.png | Bin 353684 -> 0 bytes
.../images/rware_results/ff_ippo/tiny-2ag.png | Bin 330080 -> 0 bytes
.../images/rware_results/ff_ippo/tiny-4ag.png | Bin 332423 -> 0 bytes
.../ff_mappo/main_readme/legend.png | Bin 10273 -> 0 bytes
.../ff_mappo/main_readme/small-4ag-1.png | Bin 190457 -> 0 bytes
.../ff_mappo/main_readme/tiny-2ag-1.png | Bin 213343 -> 0 bytes
.../ff_mappo/main_readme/tiny-4ag-1.png | Bin 194982 -> 0 bytes
.../rware_results/ff_mappo/small-4ag.png | Bin 358899 -> 0 bytes
.../rware_results/ff_mappo/tiny-2ag.png | Bin 369484 -> 0 bytes
.../rware_results/ff_mappo/tiny-4ag.png | Bin 404324 -> 0 bytes
.../rware_results/rec_ippo/small-4ag.png | Bin 565478 -> 0 bytes
.../rware_results/rec_ippo/tiny-2ag.png | Bin 532713 -> 0 bytes
.../rware_results/rec_ippo/tiny-4ag.png | Bin 577252 -> 0 bytes
.../rware_results/rec_mappo/small-4ag.png | Bin 417436 -> 0 bytes
.../rware_results/rec_mappo/tiny-2ag.png | Bin 527551 -> 0 bytes
.../rware_results/rec_mappo/tiny-4ag.png | Bin 488961 -> 0 bytes
docs/images/smax_results/10m_vs_11m.png | Bin 158047 -> 0 bytes
docs/images/smax_results/27m_vs_30m.png | Bin 153763 -> 0 bytes
docs/images/smax_results/2s3z.png | Bin 245373 -> 0 bytes
docs/images/smax_results/3s5z.png | Bin 120492 -> 0 bytes
docs/images/smax_results/3s5z_vs_3s6z.png | Bin 138883 -> 0 bytes
docs/images/smax_results/3s_vs_5z.png | Bin 128753 -> 0 bytes
docs/images/smax_results/5m_vs_6m.png | Bin 101716 -> 0 bytes
docs/images/smax_results/6h_vs_8z.png | Bin 112520 -> 0 bytes
docs/images/smax_results/legend.png | Bin 7325 -> 0 bytes
.../ff_mappo_speed_comparison.png | Bin 18570 -> 0 bytes
.../images/speed_results/mava_sps_results.png | Bin 370880 -> 0 bytes
docs/images/speed_results/speed.png | Bin 0 -> 37140 bytes
docs/jumanji_rware_comparison.md | 74 ------
docs/smax_benchmark.md | 43 ----
mava/systems/mat/README.md | 6 +
mava/systems/ppo/README.md | 17 ++
mava/systems/q_learning/README.md | 14 ++
mava/systems/sable/README.md | 24 ++
mava/systems/sac/README.md | 16 ++
49 files changed, 184 insertions(+), 271 deletions(-)
create mode 100644 docs/images/algo_images/sable-arch.png
create mode 100644 docs/images/benchmark_results/connector.png
create mode 100644 docs/images/benchmark_results/lbf.png
create mode 100644 docs/images/benchmark_results/legend.jpg
create mode 100644 docs/images/benchmark_results/mabrax.png
create mode 100644 docs/images/benchmark_results/mpe.png
create mode 100644 docs/images/benchmark_results/rware.png
create mode 100644 docs/images/benchmark_results/smax.png
delete mode 100644 docs/images/lbf_results/15x15-4p-3f_rec_mappo.png
delete mode 100644 docs/images/lbf_results/2s-8x8-2p-2f-coop_rec_mappo.png
delete mode 100644 docs/images/lbf_results/legend_rec_mappo.png
delete mode 100644 docs/images/rware_results/ff_ippo/small-4ag.png
delete mode 100644 docs/images/rware_results/ff_ippo/tiny-2ag.png
delete mode 100644 docs/images/rware_results/ff_ippo/tiny-4ag.png
delete mode 100644 docs/images/rware_results/ff_mappo/main_readme/legend.png
delete mode 100644 docs/images/rware_results/ff_mappo/main_readme/small-4ag-1.png
delete mode 100644 docs/images/rware_results/ff_mappo/main_readme/tiny-2ag-1.png
delete mode 100644 docs/images/rware_results/ff_mappo/main_readme/tiny-4ag-1.png
delete mode 100644 docs/images/rware_results/ff_mappo/small-4ag.png
delete mode 100644 docs/images/rware_results/ff_mappo/tiny-2ag.png
delete mode 100644 docs/images/rware_results/ff_mappo/tiny-4ag.png
delete mode 100644 docs/images/rware_results/rec_ippo/small-4ag.png
delete mode 100644 docs/images/rware_results/rec_ippo/tiny-2ag.png
delete mode 100644 docs/images/rware_results/rec_ippo/tiny-4ag.png
delete mode 100644 docs/images/rware_results/rec_mappo/small-4ag.png
delete mode 100644 docs/images/rware_results/rec_mappo/tiny-2ag.png
delete mode 100644 docs/images/rware_results/rec_mappo/tiny-4ag.png
delete mode 100644 docs/images/smax_results/10m_vs_11m.png
delete mode 100644 docs/images/smax_results/27m_vs_30m.png
delete mode 100644 docs/images/smax_results/2s3z.png
delete mode 100644 docs/images/smax_results/3s5z.png
delete mode 100644 docs/images/smax_results/3s5z_vs_3s6z.png
delete mode 100644 docs/images/smax_results/3s_vs_5z.png
delete mode 100644 docs/images/smax_results/5m_vs_6m.png
delete mode 100644 docs/images/smax_results/6h_vs_8z.png
delete mode 100644 docs/images/smax_results/legend.png
delete mode 100644 docs/images/speed_results/ff_mappo_speed_comparison.png
delete mode 100644 docs/images/speed_results/mava_sps_results.png
create mode 100644 docs/images/speed_results/speed.png
delete mode 100644 docs/jumanji_rware_comparison.md
delete mode 100644 docs/smax_benchmark.md
create mode 100644 mava/systems/mat/README.md
create mode 100644 mava/systems/ppo/README.md
create mode 100644 mava/systems/q_learning/README.md
create mode 100644 mava/systems/sable/README.md
create mode 100644 mava/systems/sac/README.md
diff --git a/README.md b/README.md
index dee7a13311..cff9eb1abf 100644
--- a/README.md
+++ b/README.md
@@ -9,149 +9,39 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Finstadeepai%2FMava%2Fdevelop%2Fpyproject.toml)
+[![Tests](https://github.com/instadeepai/Mava/actions/workflows/ci.yaml/badge.svg)](https://github.com/instadeepai/Mava/actions/workflows/ci.yaml)
+[![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg)](https://opensource.org/licenses/Apache-2.0)
+[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
+[![MyPy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
+[![ArXiv](https://img.shields.io/badge/ArXiv-2410.01706-b31b1b.svg)](https://arxiv.org/abs/2410.01706)
+[![Collab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/instadeepai/Mava/blob/develop/examples/Quickstart.ipynb)
+
## Welcome to Mava! ๐ฆ
-[**Installation**](#installation-) | [**Quickstart**](#quickstart-)
+[**Installation**](#installation-) | [**Getting started**](#getting-started-)
-Mava provides simplified code for quickly iterating on ideas in multi-agent reinforcement learning (MARL) with useful implementations of MARL algorithms in JAX allowing for easy parallelisation across devices with JAX's `pmap`. Mava is a project originating in the Research Team at [InstaDeep](https://www.instadeep.com/).
-
-To join us in these efforts, please feel free to reach out, raise issues or read our [contribution guidelines](#contributing-) (or just star ๐ to stay up to date with the latest developments)!
+Mava allows researchers to experiment with multi-agent reinforcement learning (MARL) at lightning speed. The single-file JAX implementations are built for rapid research iteration - hack, modify, and test new ideas fast. Our [state-of-the-art algorithms][sable] scale seamlessly across devices. Created for researchers, by The Research Team at [InstaDeep](https://www.instadeep.com).
-## Overview ๐ฆ
+## Highlights ๐ฆ
-Mava currently offers the following building blocks for MARL research:
-
-- ๐ฅ **Implementations of MARL algorithms**: Implementations of multi-agent PPO systems that follow both the Centralised Training with Decentralised Execution (CTDE) and Decentralised Training with Decentralised Execution (DTDE) MARL paradigms.
-- ๐ฌ **Environment Wrappers**: Example wrappers for mapping Jumanji environments to an environment that is compatible with Mava. At the moment, we support [Robotic Warehouse][jumanji_rware] and [Level-Based Foraging][jumanji_lbf] with plans to support more environments soon. We have also recently added support for the SMAX environment from [JaxMARL][jaxmarl].
-- ๐ **Educational Material**: [Quickstart notebook][quickstart] to demonstrate how Mava can be used and to highlight the added value of JAX-based MARL.
+- ๐ฅ **Implementations of MARL algorithms**: Implementations of current state-of-the-art MARL algorithms that are distributed and effectively make use of available accelerators.
+- ๐ฌ **Environment Wrappers**: We provide first class support to a few JAX based MARL environment suites through the use of wrappers, however new environments can be easily added by using existing wrappers as a guide.
- ๐งช **Statistically robust evaluation**: Mava natively supports logging to json files which adhere to the standard suggested by [Gorsane et al. (2022)][toward_standard_eval]. This enables easy downstream experiment plotting and aggregation using the tools found in the [MARL-eval][marl_eval] library.
-
-## Performance and Speed ๐
-
-### SMAX
-For comparing Mavaโs stability to other JAX-based baseline algorithms, we train Mavaโs recurrent IPPO and MAPPO systems on a broad range of [SMAX][smax] tasks. In all cases we do not rerun baselines but instead take results for final win rates from the [JaxMARL technical report](https://arxiv.org/pdf/2311.10090.pdf). For the full SMAX experiments results, please see the following [page](docs/smax_benchmark.md).
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Mava Recurrent IPPO and MAPPO performance on the 3s5z
, 6h_vs_8z
and 3s5z_vs_3s6z
SMAX tasks.
-
-
-### Robotic Warehouse
-
-All of the experiments below were performed using an NVIDIA Quadro RTX 4000 GPU with 8GB Memory.
-
-In order to show the utility of end-to-end JAX-based MARL systems and JAX-based environments we compare the speed of Mava against [EPyMARL][epymarl] as measured in total training wallclock time on simple [Robotic Warehouse][rware] (RWARE) tasks with 2 and 4 agents. Our aim is to illustrate the speed increases that are possible with using end-to-end Jax-based systems and we do not necessarily make an effort to achieve optimal performance. For EPyMARL, we use the hyperparameters as recommended by [Papoudakis et al. (2020)](https://arxiv.org/pdf/2006.07869.pdf) and for Mava we performed a basic grid search. In both cases, systems were trained up to 20 million total environment steps using 16 vectorised environments.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Mava feedforward MAPPO performance on the tiny-2ag
, tiny-4ag
and small-4ag
RWARE tasks.
-
-
-
-### ๐ An important note on the differences in converged performance
-
-In order to benefit from the wallclock speed-ups afforded by JAX-based systems it is required that environments also be written in JAX. It is for this reason that Mava does not use the exact same version of the RWARE environment as EPyMARL but instead uses a JAX-based implementation of RWARE found in [Jumanji][jumanji_rware], under the name RobotWarehouse. One of the notable differences in the underlying environment logic is that RobotWarehouse will not attempt to resolve agent collisions but will instead terminate an episode when agents do collide. In our experiments, this appeared to make the environment more challenging. For this reason we show the performance of Mava on Jumanji with and without termination upon collision indicated with `w/o collision` in the figure legends. For a more detailed discussion, please see the following [page](docs/jumanji_rware_comparison.md).
-
-### Level-Based Foraging
-Mava also supports [Jumanji][jumanji_lbf]'s LBF. We evaluate Mava's recurrent MAPPO system on LBF, against [EPyMARL][epymarl] (we used original [LBF](https://github.com/semitable/lb-foraging) for EPyMARL) in 2 and 4 agent settings up to 20 million timesteps. Both systems were trained using 16 vectorized environments. For the EPyMARL systems we use a NVIDIA A100 GPU and for the Mava systems we use a GeForce RTX 3050 laptop GPU with 4GB of memory. To show how Mava can generalise to different hardware, we also train the Mava systems on a TPU v3-8. We plan to publish comprehensive performance benchmarks for all Mava's algorithms across various LBF scenarios soon.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Mava Recurrent MAPPO performance on the 2s-8x8-2p-2f-coop
, and 15x15-4p-3fz
Level-Based Foraging tasks.
-
-
-### ๐งจ Steps per second experiments using vectorised environments
-
-Furthermore, we illustrate the speed of Mava by showing the steps per second as the number of parallel environments is increased. These steps per second scaling plots were computed using a standard laptop GPU, specifically an RTX-3060 GPU with 6GB memory.
-
-
-
-
-
-
-
-
-
-
Mava steps per second scaling with increased vectorised environments and total training run time for 20M environment steps.
-
-
-## Code Philosophy ๐ง
-
-The current code in Mava is adapted from [PureJaxRL][purejaxrl] which provides high-quality single-file implementations with research-friendly features. In turn, PureJaxRL is inspired by the code philosophy from [CleanRL][cleanrl]. Along this vein of easy-to-use and understandable RL codebases, Mava is not designed to be a modular library and is not meant to be imported. Our repository focuses on simplicity and clarity in its implementations while utilising the advantages offered by JAX such as `pmap` and `vmap`, making it an excellent resource for researchers and practitioners to build upon.
+- ๐ฅ๏ธ **JAX Distrubution Architectures for Reinforcement Learning**: Mava supports both [Podracer][anakin_paper] architectures for scaling RL systems. The first of these is _Anakin_, which can be used when environments are written in JAX. This enables end-to-end JIT compilation of the full MARL training loop for fast experiment run times on hardware accelerators. The second is _Sebulba_, which can be used when environments are not written in JAX. Sebulba is particularly useful when running RL experiments where a hardware accelerator can interact with many CPU cores at a time.
+- โก **Blazingly fast experiments**: All of the above allow for very quick runtime for our experiments, especially when compared to other non-JAX based MARL libraries.
## Installation ๐ฌ
-At the moment Mava is not meant to be installed as a library, but rather to be used as a research tool.
-
-You can use Mava by cloning the repo and pip installing as follows:
+At the moment Mava is not meant to be installed as a library, but rather to be used as a research tool. We recommend cloning the Mava repo and pip installing as follows:
```bash
git clone https://github.com/instadeepai/mava.git
@@ -162,18 +52,18 @@ pip install -e .
We have tested `Mava` on Python 3.11 and 3.12, but earlier versions may also work. Specifically, we use Python 3.10 for the Quickstart notebook on Google Colab since Colab uses Python 3.10 by default. Note that because the installation of JAX differs depending on your hardware accelerator,
we advise users to explicitly install the correct JAX version (see the [official installation guide](https://github.com/google/jax#installation)). For more in-depth installation guides including Docker builds and virtual environments, please see our [detailed installation guide](docs/DETAILED_INSTALL.md).
-## Quickstart โก
+## Getting started โก
-To get started with training your first Mava system, simply run one of the system files. e.g.,
+To get started with training your first Mava system, simply run one of the system files:
```bash
-python mava/systems/ff_ippo.py
+python mava/systems/ppo/anakin/ff_ippo.py
```
-Mava makes use of Hydra for config management. In order to see our default system configs please see the `mava/configs/` directory. A benefit of Hydra is that configs can either be set in config yaml files or overwritten from the terminal on the fly. For an example of running a system on the LBF environment, the above code can simply be adapted as follows:
+Mava makes use of [Hydra](https://github.com/facebookresearch/hydra) for config management. In order to see our default system configs please see the `mava/configs/` directory. A benefit of Hydra is that configs can either be set in config yaml files or overwritten from the terminal on the fly. For an example of running a system on the Level-based Foraging environment, the above code can simply be adapted as follows:
```bash
-python mava/systems/ff_ippo.py env=lbf
+python mava/systems/ppo/anakin/ff_ippo.py env=lbf
```
Different scenarios can also be run by making the following config updates from the terminal:
@@ -182,11 +72,72 @@ Different scenarios can also be run by making the following config updates from
python mava/systems/ff_ippo.py env=rware env/scenario=tiny-4ag
```
-Additionally, we also have a [Quickstart notebook][quickstart] that can be used to quickly create and train your first Multi-agent system.
+Additionally, we also have a [Quickstart notebook][quickstart] that can be used to quickly create and train your first multi-agent system.
+
+Algorithms
+
+Mava has implementations of multiple on- and off-policy multi-agent algorithms that follow the independent learners (IL), centralised training with decentralised execution (CTDE) and heterogeneous agent learning paradigms. Aside from MARL learning paradigms, we also include implementations which follow the Anakin and Sebulba architectures to enable scalable training by default. The architecture that is relevant for a given problem depends on whether the environment being used in written in JAX or not. For more information on these paradigms, please see [here][anakin_paper].
-## Advanced Usage ๐ฝ
+| Algorithm | Variants | Continuous | Discrete | Anakin | Sebulba | Paper | Docs |
+|------------|----------------|------------|----------|--------|---------|-------|------|
+| PPO | [`ff_ippo.py`](mava/systems/ppo/anakin/ff_ippo.py) | โ
| โ
| โ
| โ
| [Link](https://arxiv.org/abs/2011.09533) | [Link](mava/systems/ppo/README.md) |
+| | [`ff_mappo.py`](mava/systems/ppo/anakin/ff_mappo.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2103.01955) | [Link](mava/systems/ppo/README.md) |
+| | [`rec_ippo.py`](mava/systems/ppo/anakin/rec_ippo.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2011.09533) | [Link](mava/systems/ppo/README.md) |
+| | [`rec_mappo.py`](mava/systems/ppo/anakin/rec_mappo.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2103.01955) | [Link](mava/systems/ppo/README.md) |
+| Q Learning | [`rec_iql.py`](mava/systems/q_learning/anakin/rec_iql.py) | | โ
| โ
| | [Link](https://arxiv.org/abs/1511.08779) | [Link](mava/systems/q_learning/README.md) |
+| | [`rec_qmix.py`](mava/systems/q_learning/anakin/rec_qmix.py) | | โ
| โ
| | [Link](https://arxiv.org/abs/1803.11485) | [Link](mava/systems/q_learning/README.md) |
+| SAC | [`ff_isac.py`](mava/systems/sac/anakin/ff_isac.py) | โ
| | โ
| | [Link](https://arxiv.org/abs/1801.01290) | [Link](mava/systems/sac/README.md) |
+| | [`ff_masac.py`](mava/systems/sac/anakin/ff_masac.py) | โ
| | โ
| | | [Link](mava/systems/sac/README.md) |
+| | [`ff_hasac.py`](mava/systems/sac/anakin/ff_hasac.py) | โ
| | โ
| | [Link](https://arxiv.org/abs/2306.10715) | [Link](mava/systems/sac/README.md) |
+| MAT | [`mat.py`](mava/systems/mat/anakin/mat.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2205.14953) | [Link](mava/systems/mat/README.md) |
+| Sable | [`ff_sable.py`](mava/systems/sable/anakin/ff_sable.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2410.01706) | [Link](mava/systems/sable/README.md) |
+| | [`rec_sable.py`](mava/systems/sable/anakin/rec_sable.py) | โ
| โ
| โ
| | [Link](https://arxiv.org/abs/2410.01706) | [Link](mava/systems/sable/README.md) |
+Environments
-Mava can be used in a wide array of advanced systems. As an example, we demonstrate recording experience data from one of our PPO systems into a [Flashbax](https://github.com/instadeepai/flashbax) `Vault`. This vault can then easily be integrated into offline MARL systems, such as those found in [OG-MARL](https://github.com/instadeepai/og-marl). See the [Advanced README](./examples/advanced_usage/README.md) for more information.
+These are the environments which Mava supports _out of the box_, to add a new environment, please use the [existing wrapper implementations](mava/wrappers/) as an example. We also indicate whether the environment is implemented in JAX or not. JAX-based environments can be used with algorithms that follow the Anakin distribution architecture, while non-JAX environments can be used with algorithms following the Sebulba architecture.
+
+
+| Environment | Action space | JAX | Non-JAX | Paper | JAX Source | Non-JAX Source |
+|---------------------------------|---------------------|-----|-------|-------|------------|----------------|
+| Mulit-Robot Warehouse | Discrete | โ
| โ
| [Link](http://arxiv.org/abs/2006.07869) | [Link](https://github.com/instadeepai/jumanji/tree/main/jumanji/environments/routing/robot_warehouse) | [Link](https://github.com/semitable/robotic-warehouse) |
+| Level-based Foraging | Discrete | โ
| โ
| [Link](https://arxiv.org/abs/2006.07169) | [Link](https://github.com/instadeepai/jumanji/tree/main/jumanji/environments/routing/lbf) | [Link](https://github.com/semitable/lb-foraging) |
+| StarCraft Multi-Agent Challenge | Discrete | โ
| โ
| [Link](https://arxiv.org/abs/1902.04043) | [Link](https://github.com/FLAIROx/JaxMARL/tree/main/jaxmarl/environments/smax) | [Link](https://github.com/uoe-agents/smaclite) |
+| Multi-Agent Brax | Continuous | โ
| | [Link](https://arxiv.org/abs/2003.06709) | [Link](https://github.com/FLAIROx/JaxMARL/tree/main/jaxmarl/environments/mabrax) | |
+| Matrax | Discrete | โ
| | [Link](https://www.cs.toronto.edu/~cebly/Papers/_download_/multirl.pdf) | [Link](https://github.com/instadeepai/matrax) | |
+| Multi Particle Environments | Discrete/Continuous | โ
| | [Link](https://arxiv.org/abs/1706.02275) | [Link](https://github.com/FLAIROx/JaxMARL/tree/main/jaxmarl/environments/mpe) | |
+
+## Performance and Speed ๐
+We have performed a rigorous benchmark across 45 different scenarios and 6 different environment suites to validate the performance of Mava's algorithm implementations. For more detailed results please see our [Sable paper][sable] and for all hyperparameters, please see the following [website](https://sites.google.com/view/sable-marl).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Mava's algorithm performance: Each algorithm was tuned for 40 trials with the TPE optimizer and benchmarked over 10 seeds for each scenario. Environments from top left Multi-Robot Warehouse (aggregated over 15 scenarios) Level-based Foraging (aggregated over 7 scenarios) StarCraft Multi-Agent Challenge in JAX (aggregated over 11 scenarios) Connector (aggregated over 4 scenarios) Multi-Agent Brax (aggregated over 5 scenarios) Multi Particle Environments (aggregated over 3 scenarios)
+
+
+## Code Philosophy ๐ง
+
+The original code in Mava was adapted from [PureJaxRL][purejaxrl] which provides high-quality single-file implementations with research-friendly features. In turn, PureJaxRL is inspired by the code philosophy from [CleanRL][cleanrl]. Along this vein of easy-to-use and understandable RL codebases, Mava is not designed to be a modular library and is not meant to be imported. Our repository focuses on simplicity and clarity in its implementations while utilising the advantages offered by JAX such as `pmap` and `vmap`, making it an excellent resource for researchers and practitioners to build upon. A notable difference between Mava and CleanRL is that Mava creates small utilities for heavily re-used elements, such as networks and logging, we've found that this, in addition to Hydra configs, greatly improves the readability of the algorithms.
## Contributing ๐ค
@@ -196,17 +147,16 @@ Please read our [contributing docs](docs/CONTRIBUTING.md) for details on how to
We plan to iteratively expand Mava in the following increments:
-- ๐ด Support for more environments.
-- ๐ More robust recurrent systems.
-- ๐ณ Support for non JAX-based environments.
-- ๐ฆพ Support for off-policy algorithms.
-- ๐ Continuous action space environments and algorithms.
+- [x] Support for more environments.
+- [x] More robust recurrent systems.
+- [x] Support for non JAX-based environments.
+- [ ] Add Sebulba versions of more algorithms.
+- [x] Support for off-policy algorithms.
+- [x] Continuous action space environments and algorithms.
+- [ ] Allow systems to easily scale across multiple TPUs/GPUs.
Please do follow along as we develop this next phase!
-## TensorFlow 2 Mava:
-Originally Mava was written in Tensorflow 2. Support for the TF2-based framework and systems has now been fully **deprecated**. If you would still like to use it, please install `v0.1.3` of Mava (i.e. `pip install id-mava==0.1.3`).
-
## See Also ๐
**InstaDeep's MARL ecosystem in JAX.** In particular, we suggest users check out the following sister repositories:
@@ -260,3 +210,4 @@ The development of Mava was supported with Cloud TPUs from Google's [TPU Researc
[toward_standard_eval]: https://arxiv.org/pdf/2209.10485.pdf
[marl_eval]: https://github.com/instadeepai/marl-eval
[smax]: https://github.com/FLAIROx/JaxMARL/tree/main/jaxmarl/environments/smax
+[sable]: https://arxiv.org/pdf/2410.01706
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index 791237ddc9..b7a7a14614 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -39,7 +39,7 @@ pre-commit run --all-files
## Naming Conventions
### Branch Names
-We name our feature and bugfix branches as follows - `feature/[BRANCH-NAME]`, `bugfix/[BRANCH-NAME]` or `maintenance/[BRANCH-NAME]`. Please ensure `[BRANCH-NAME]` is hyphen delimited.
+We name our feature and bugfix branches as follows - `feat/[BRANCH-NAME]`, `fix/[BRANCH-NAME]`. Please ensure `[BRANCH-NAME]` is hyphen delimited.
### Commit Messages
We follow the conventional commits [standard](https://www.conventionalcommits.org/en/v1.0.0/).
diff --git a/docs/DETAILED_INSTALL.md b/docs/DETAILED_INSTALL.md
index 28547c8aa5..04a499b72a 100644
--- a/docs/DETAILED_INSTALL.md
+++ b/docs/DETAILED_INSTALL.md
@@ -1,12 +1,11 @@
# Detailed installation guide
### Conda virtual environment
-We recommend using `conda` for package management. These instructions should allow you to install and run mava.
+We recommend using [uv](https://docs.astral.sh/uv/) for package management. These instructions should allow you to install and run mava.
-1. Create and activate a virtual environment
+1. Install `uv`
```bash
-conda create -n mava python=3.12
-conda activate mava
+curl -LsSf https://astral.sh/uv/install.sh | sh
```
2. Clone mava
@@ -15,19 +14,22 @@ git clone https://github.com/instadeepai/Mava.git
cd mava
```
-3. Install the dependencies
+3. Create and activate a virtual environment and install requirements
```bash
-pip install -e .
+uv venv -p=3.12
+source .venv/bin/activate
+uv pip install -e .
```
-4. Install jax on your accelerator. The example below is for an NVIDIA GPU, please the [official install guide](https://github.com/google/jax#installation) for other accelerators
+4. Install jax on your accelerator. The example below is for an NVIDIA GPU, please the [official install guide](https://github.com/google/jax#installation) for other accelerators.
+Note that the Jax version we use will change over time, please check the [requirements.txt](../requirements/requirements.txt) for our latest tested Jax verion.
```bash
-pip install "jax[cuda12]==0.4.30"
+uv pip install "jax[cuda12]==0.4.30"
```
5. Run a system!
```bash
-python mava/systems/ppo/ff_ippo.py env=rware
+python mava/systems/ppo/anakin/ff_ippo.py env=rware
```
### Docker
@@ -50,4 +52,4 @@ If you are having trouble with dependencies we recommend using our docker image
For example, `make run example=mava/systems/ppo/ff_ippo.py`.
- Alternatively, run bash inside a docker container with mava installed by running `make bash`, and from there systems can be run as follows: `python dir/to/system.py`.
+ Alternatively, run bash inside a docker container with Mava installed by running `make bash`, and from there systems can be run as follows: `python dir/to/system.py`.
diff --git a/docs/images/algo_images/sable-arch.png b/docs/images/algo_images/sable-arch.png
new file mode 100644
index 0000000000000000000000000000000000000000..1fd92c6c8fdade26e38905ad381aee4861c46c70
GIT binary patch
literal 361715
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
gqvT7qc%Y998Doq$m82ZRn
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