chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,465 @@
|
||||
.. _rllib-checkpoints-docs:
|
||||
|
||||
Checkpointing
|
||||
=============
|
||||
|
||||
.. include:: /_includes/rllib/new_api_stack.rst
|
||||
|
||||
RLlib offers a powerful checkpointing system for all its major classes, allowing you to save the
|
||||
states of :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` instances and their subcomponents
|
||||
to local disk or cloud storage, and restore previously run experiment states and individual subcomponents.
|
||||
This system allows you to continue training models from a previous state or deploy bare-bones PyTorch
|
||||
models into production.
|
||||
|
||||
.. figure:: images/checkpointing/save_and_restore.svg
|
||||
:width: 500
|
||||
:align: left
|
||||
|
||||
**Saving to and restoring from disk or cloud storage**: Use the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.save_to_path` method
|
||||
to write the current state of any :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable` component or your entire Algorithm to
|
||||
disk or cloud storage. To load a saved state back into a running component or into your Algorithm, use
|
||||
the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.restore_from_path` method.
|
||||
|
||||
A checkpoint is a directory on disk or some `PyArrow <https://arrow.apache.org/>`__-supported cloud location, like
|
||||
`gcs <https://cloud.google.com/storage>`__ or `S3 <https://aws.amazon.com/de/s3/>`__.
|
||||
It contains architecture information, such as the class and the constructor arguments for creating a new instance,
|
||||
a ``pickle`` or ``msgpack`` file with state information, and a human readable ``metadata.json`` file with information about the Ray version,
|
||||
git commit, and checkpoint version.
|
||||
|
||||
You can generate a new :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` instance or other subcomponent,
|
||||
like an :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule`, from an existing checkpoint using
|
||||
the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.from_checkpoint` method.
|
||||
For example, you can deploy a previously trained :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule`, without
|
||||
any of the other RLlib components, into production.
|
||||
|
||||
.. figure:: images/checkpointing/from_checkpoint.svg
|
||||
:width: 750
|
||||
:align: left
|
||||
|
||||
**Creating a new instance directly from a checkpoint**: Use the ``classmethod``
|
||||
:py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.from_checkpoint` to instantiate objects directly
|
||||
from a checkpoint. RLlib first uses the saved meta data to create a bare-bones instance of the originally
|
||||
checkpointed object, and then restores its state from the state information in the checkpoint dir.
|
||||
|
||||
Another possibility is to load only a certain subcomponent's state into the containing
|
||||
higher-level object. For example, you may want to load only the state of your :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule`,
|
||||
located inside your :py:class:`~ray.rllib.algorithms.algorithm.Algorithm`, but leave all the other components
|
||||
as-is.
|
||||
|
||||
|
||||
Checkpointable API
|
||||
------------------
|
||||
|
||||
RLlib manages checkpointing through the :py:class:`~ray.rllib.utils.checkpoints.Checkpointable` API,
|
||||
which exposes the following three main methods:
|
||||
|
||||
- :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.save_to_path` for creating a new checkpoint
|
||||
- :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.restore_from_path` for loading a state from a checkpoint into a running object
|
||||
- :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.from_checkpoint` for creating a new object from a checkpoint
|
||||
|
||||
RLlib classes, which thus far support the :py:class:`~ray.rllib.utils.checkpoints.Checkpointable` API are:
|
||||
|
||||
- :py:class:`~ray.rllib.algorithms.algorithm.Algorithm`
|
||||
- :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule` (and :py:class:`~ray.rllib.core.rl_module.multi_rl_module.MultiRLModule`)
|
||||
- :py:class:`~ray.rllib.env.env_runner.EnvRunner` (thus, also :py:class:`~ray.rllib.env.single_agent_env_runner.SingleAgentEnvRunner` and :py:class:`~ray.rllib.env.multi_agent_env_runner.MultiAgentEnvRunner`)
|
||||
- :py:class:`~ray.rllib.connectors.connector_v2.ConnectorV2` (thus, also :py:class:`~ray.rllib.connectors.connector_pipeline_v2.ConnectorPipelineV2`)
|
||||
- :py:class:`~ray.rllib.core.learner.learner_group.LearnerGroup`
|
||||
- :py:class:`~ray.rllib.core.learner.learner.Learner`
|
||||
|
||||
|
||||
.. _rllib-checkpoints-save-to-path:
|
||||
|
||||
Creating a new checkpoint with `save_to_path()`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You create a new checkpoint from an instantiated RLlib object through the
|
||||
:py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.save_to_path` method.
|
||||
|
||||
The following are two examples, single- and multi-agent, using the :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` class, showing
|
||||
how to create checkpoints:
|
||||
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Single-agent setup
|
||||
|
||||
.. testcode::
|
||||
|
||||
from ray.rllib.algorithms.ppo import PPOConfig
|
||||
|
||||
# Configure and build an initial algorithm.
|
||||
config = (
|
||||
PPOConfig()
|
||||
.environment("Pendulum-v1")
|
||||
)
|
||||
ppo = config.build()
|
||||
|
||||
# Train for one iteration, then save to a checkpoint.
|
||||
print(ppo.train())
|
||||
checkpoint_dir = ppo.save_to_path()
|
||||
print(f"saved algo to {checkpoint_dir}")
|
||||
|
||||
.. testcode::
|
||||
:hide:
|
||||
|
||||
_weights_check = ppo.get_module("default_policy").get_state()
|
||||
ppo.stop()
|
||||
|
||||
.. tab-item:: Multi-agent setup
|
||||
|
||||
.. testcode::
|
||||
|
||||
from ray.rllib.algorithms.ppo import PPOConfig
|
||||
from ray.rllib.examples.envs.classes.multi_agent import MultiAgentPendulum
|
||||
from ray.tune import register_env
|
||||
|
||||
register_env("multi-pendulum", lambda cfg: MultiAgentPendulum({"num_agents": 2}))
|
||||
|
||||
# Configure and build an initial algorithm.
|
||||
multi_agent_config = (
|
||||
PPOConfig()
|
||||
.environment("multi-pendulum")
|
||||
.multi_agent(
|
||||
policies={"p0", "p1"},
|
||||
# Agent IDs are 0 and 1 -> map to p0 and p1, respectively.
|
||||
policy_mapping_fn=lambda aid, eps, **kw: f"p{aid}"
|
||||
)
|
||||
)
|
||||
ppo = multi_agent_config.build()
|
||||
|
||||
# Train for one iteration, then save to a checkpoint.
|
||||
print(ppo.train())
|
||||
multi_agent_checkpoint_dir = ppo.save_to_path()
|
||||
print(f"saved multi-agent algo to {multi_agent_checkpoint_dir}")
|
||||
|
||||
.. testcode::
|
||||
:hide:
|
||||
|
||||
ppo.stop()
|
||||
|
||||
.. note::
|
||||
When running your experiments with `Ray Tune <https://docs.ray.io/en/latest/tune/index.html>`__,
|
||||
Tune calls the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.save_to_path`
|
||||
method automatically on the :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` instance, whenever the training
|
||||
iteration matches the checkpoint frequency configured through Tune. The default location where Tune creates these checkpoints
|
||||
is ``~/ray_results/[your experiment name]/[Tune trial name]/checkpoint_[sequence number]``.
|
||||
|
||||
|
||||
Checkpoint versions
|
||||
+++++++++++++++++++
|
||||
|
||||
RLlib uses a checkpoint versioning system to figure out how to restore an Algorithm or any
|
||||
subcomponent from a given directory.
|
||||
|
||||
From Ray 2.40 on, you can find the checkpoint version in the human readable ``metadata.json``
|
||||
file inside all checkpoint directories.
|
||||
|
||||
Also starting from `Ray 2.40`, RLlib checkpoints are backward compatible. This means that
|
||||
a checkpoint created with Ray `2.x` can be read and handled by `Ray 2.x+n`, as long as `x >= 40`.
|
||||
The Ray team ensures backward compatibility with
|
||||
`comprehensive CI tests on checkpoints taken with previous Ray versions <https://github.com/ray-project/ray/blob/master/rllib/utils/tests/test_checkpointable.py>`__.
|
||||
|
||||
|
||||
.. _rllib-checkpoints-structure-of-checkpoint-dir:
|
||||
|
||||
Structure of a checkpoint directory
|
||||
+++++++++++++++++++++++++++++++++++
|
||||
|
||||
After saving your PPO's state in the ``checkpoint_dir`` directory, or somewhere in ``~/ray_results/`` if you use Ray Tune,
|
||||
the directory looks like the following:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ cd [your algo checkpoint dir]
|
||||
$ ls -la
|
||||
.
|
||||
..
|
||||
env_runner/
|
||||
learner_group/
|
||||
algorithm_state.pkl
|
||||
class_and_ctor_args.pkl
|
||||
metadata.json
|
||||
|
||||
Subdirectories inside a checkpoint dir, like ``env_runner/``, hint at a subcomponent's own checkpoint data.
|
||||
For example, an :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` always also saves its
|
||||
:py:class:`~ray.rllib.env.env_runner.EnvRunner` state and :py:class:`~ray.rllib.core.learner.learner_group.LearnerGroup` state.
|
||||
|
||||
.. note::
|
||||
Each of the subcomponent's directories themselves contain a ``metadata.json`` file, a ``class_and_ctor_args.pkl`` file,
|
||||
and a ``pickle`` or ``msgpack`` state file, all serving the same purpose as their counterparts in the main algorithm checkpoint directory.
|
||||
For example, inside the ``learner_group/`` subdirectory, you would find the :py:class:`~ray.rllib.core.learner.learner_group.LearnerGroup`'s own
|
||||
architecture, state, and meta information:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ cd env_runner/
|
||||
$ ls -la
|
||||
.
|
||||
..
|
||||
state.pkl
|
||||
class_and_ctor_args.pkl
|
||||
metadata.json
|
||||
|
||||
See :ref:`RLlib component tree <rllib-checkpoints-component-tree>` for details.
|
||||
|
||||
The ``metadata.json`` file exists for your convenience only and RLlib doesn't need it.
|
||||
|
||||
.. note::
|
||||
The ``metadata.json`` file contains information about the Ray version used to create the checkpoint,
|
||||
the Ray commit, the RLlib checkpoint version, and the names of the state- and constructor-information
|
||||
files in the same directory.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ more metadata.json
|
||||
{
|
||||
"class_and_ctor_args_file": "class_and_ctor_args.pkl",
|
||||
"state_file": "state",
|
||||
"ray_version": ..,
|
||||
"ray_commit": ..,
|
||||
"checkpoint_version": "2.1"
|
||||
}
|
||||
|
||||
The ``class_and_ctor_args.pkl`` file stores meta information needed to construct a "fresh" object, without any particular state.
|
||||
This information, as the filename suggests, contains the class of the saved object and its constructor arguments and keyword arguments.
|
||||
RLlib uses this file to create the initial new object when calling :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.from_checkpoint`.
|
||||
|
||||
Finally, the ``.._state.[pkl|msgpack]`` file contains the pickled or msgpacked state dict of the saved object.
|
||||
RLlib obtains this state dict, when saving a checkpoint, through calling the object's
|
||||
:py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.get_state` method.
|
||||
|
||||
.. note::
|
||||
Support for ``msgpack`` based checkpoints is experimental, but might become the default in the future.
|
||||
Unlike ``pickle``, ``msgpack`` has the advantage of being independent of the python-version, thus allowing
|
||||
users to recover experiment and model states from old checkpoints they have generated with older python
|
||||
versions.
|
||||
|
||||
The Ray team is working on completely separating state from architecture within checkpoints, meaning all state
|
||||
information should go into the ``state.msgpack`` file, which is python-version independent,
|
||||
whereas all architecture information should go into the ``class_and_ctor_args.pkl`` file, which still depends on
|
||||
the python version. At the time of loading from checkpoint, the user would have to provide the latter/architecture part
|
||||
of the checkpoint.
|
||||
|
||||
`See here for an example that illustrates this in more detail <https://github.com/ray-project/ray/blob/master/rllib/examples/checkpoints/change_config_during_training.py>`__.
|
||||
|
||||
|
||||
.. _rllib-checkpoints-component-tree:
|
||||
|
||||
RLlib component tree
|
||||
+++++++++++++++++++++++
|
||||
|
||||
The following is the structure of the RLlib component tree, showing under which name you can
|
||||
access a subcomponent's own checkpoint within the higher-level checkpoint. At the highest level
|
||||
is the :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` class:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
algorithm/
|
||||
learner_group/
|
||||
learner/
|
||||
rl_module/
|
||||
default_policy/ # <- single-agent case
|
||||
[module ID 1]/ # <- multi-agent case
|
||||
[module ID 2]/ # ...
|
||||
env_runner/
|
||||
env_to_module_connector/
|
||||
module_to_env_connector/
|
||||
|
||||
.. note::
|
||||
The ``env_runner/`` subcomponent currently doesn't hold a copy of the :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule`
|
||||
checkpoint because it's already saved under ``learner/``. The Ray team is working on resolving
|
||||
this issue, probably through soft-linking to avoid duplicate files and unnecessary disk usage.
|
||||
|
||||
|
||||
.. _rllib-checkpoints-from-checkpoint:
|
||||
|
||||
Creating instances from a checkpoint with `from_checkpoint`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once you have a checkpoint of either a trained :py:class:`~ray.rllib.algorithms.algorithm.Algorithm` or
|
||||
any of its :ref:`subcomponents <rllib-checkpoints-component-tree>`, you can recreate new objects directly
|
||||
from this checkpoint.
|
||||
|
||||
The following are two examples:
|
||||
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Create a new Algorithm from a checkpoint
|
||||
|
||||
To recreate an entire :py:class:`~ray.rllib.algorithms.algorithm.Algorithm`
|
||||
instance from a checkpoint, you can do the following:
|
||||
|
||||
.. testcode::
|
||||
|
||||
# Import the correct class to create from scratch using the checkpoint.
|
||||
from ray.rllib.algorithms.algorithm import Algorithm
|
||||
|
||||
# Use the already existing checkpoint in `checkpoint_dir`.
|
||||
new_ppo = Algorithm.from_checkpoint(checkpoint_dir)
|
||||
# Confirm the `new_ppo` matches the originally checkpointed one.
|
||||
assert new_ppo.config.env == "Pendulum-v1"
|
||||
|
||||
# Continue training.
|
||||
new_ppo.train()
|
||||
|
||||
.. testcode::
|
||||
:hide:
|
||||
|
||||
new_ppo.stop()
|
||||
|
||||
.. tab-item:: Create a new RLModule from an Algorithm checkpoint
|
||||
|
||||
Creating a new RLModule from an Algorithm checkpoint is useful when deploying trained models
|
||||
into production or evaluating them in a separate process while training is ongoing.
|
||||
To recreate only the :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule` from
|
||||
the algorithm's checkpoint, you can do the following.
|
||||
|
||||
.. testcode::
|
||||
|
||||
from pathlib import Path
|
||||
import torch
|
||||
|
||||
# Import the correct class to create from scratch using the checkpoint.
|
||||
from ray.rllib.core.rl_module.rl_module import RLModule
|
||||
|
||||
# Use the already existing checkpoint in `checkpoint_dir`, but go further down
|
||||
# into its subdirectory for the single RLModule.
|
||||
# See the preceding section on "RLlib component tree" for the various elements in the RLlib
|
||||
# component tree.
|
||||
rl_module_checkpoint_dir = Path(checkpoint_dir) / "learner_group" / "learner" / "rl_module" / "default_policy"
|
||||
|
||||
# Now that you have the correct subdirectory, create the actual RLModule.
|
||||
rl_module = RLModule.from_checkpoint(rl_module_checkpoint_dir)
|
||||
|
||||
# Run a forward pass to compute action logits.
|
||||
# Use a dummy Pendulum observation tensor (3d) and add a batch dim (B=1).
|
||||
results = rl_module.forward_inference(
|
||||
{"obs": torch.tensor([0.5, 0.25, -0.3]).unsqueeze(0).float()}
|
||||
)
|
||||
print(results)
|
||||
|
||||
See this `example of how to run policy inference after training <https://github.com/ray-project/ray/blob/master/rllib/examples/inference/policy_inference_after_training.py>`__
|
||||
and this `example of how to run policy inference with an LSTM <https://github.com/ray-project/ray/blob/master/rllib/examples/inference/policy_inference_after_training_w_connector.py>`__.
|
||||
|
||||
.. hint::
|
||||
Because your :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule` is also a
|
||||
`PyTorch Module <https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module>`__,
|
||||
you can easily export your model to `ONNX <https://onnx.ai/>`__, `IREE <https://iree.dev/>`__,
|
||||
or other deployment-friendly formats.
|
||||
See this `example script supporting ONNX <https://github.com/ray-project/ray/blob/master/rllib/examples/inference/policy_inference_after_training.py>`__ for more details.
|
||||
|
||||
|
||||
Restoring state from a checkpoint with `restore_from_path`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Normally, the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.save_to_path` and
|
||||
:py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.from_checkpoint` methods are all you need to create
|
||||
checkpoints and re-create instances from them.
|
||||
|
||||
However, sometimes, you already have an instantiated object up and running and would like to "load" another
|
||||
state into it. For example, consider training two :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule` networks
|
||||
through multi-agent training, playing against each other in a self-play fashion. After a while, you would like to swap out,
|
||||
without interrupting your experiment, one of the ``RLModules`` with a third one that you have saved to disk or cloud storage a while back.
|
||||
|
||||
This is where the :py:meth:`~ray.rllib.utils.checkpoints.Checkpointable.restore_from_path` method comes in handy.
|
||||
It loads a state into an already running object, for example your Algorithm, or into a subcomponent of that object,
|
||||
for example a particular :py:class:`~ray.rllib.core.rl_module.rl_module.RLModule` within your :py:class:`~ray.rllib.algorithms.algorithm.Algorithm`.
|
||||
|
||||
.. tab-set::
|
||||
|
||||
.. tab-item:: Continue training
|
||||
|
||||
When using RLlib directly, meaning without Ray Tune, the problem of loading a state
|
||||
into a running instance is straightforward:
|
||||
|
||||
.. testcode::
|
||||
|
||||
# Recreate the preceding PPO from the config.
|
||||
new_ppo = config.build()
|
||||
|
||||
# Load the state stored previously in `checkpoint_dir` into the
|
||||
# running algorithm instance.
|
||||
new_ppo.restore_from_path(checkpoint_dir)
|
||||
|
||||
# Run another training iteration.
|
||||
new_ppo.train()
|
||||
|
||||
.. testcode::
|
||||
:hide:
|
||||
|
||||
new_ppo.stop()
|
||||
|
||||
.. tab-item:: Continue training with Ray Tune
|
||||
|
||||
However, when running through Ray Tune, you don't have direct access to the
|
||||
Algorithm object or any of its subcomponents.
|
||||
You can use :ref:`RLlib's callbacks APIs <rllib-callback-docs>` to inject custom code and solve for this.
|
||||
|
||||
Also, see here for an
|
||||
`example on how to continue training with a different config <https://github.com/ray-project/ray/blob/master/rllib/examples/checkpoints/change_config_during_training.py>`__.
|
||||
|
||||
.. testcode::
|
||||
|
||||
from ray import tune
|
||||
|
||||
# Reuse the preceding PPOConfig (`config`).
|
||||
# Inject custom callback code that runs right after algorithm's initialization.
|
||||
config.callbacks(
|
||||
on_algorithm_init=(
|
||||
lambda algorithm, _dir=checkpoint_dir, **kw: algorithm.restore_from_path(_dir)
|
||||
),
|
||||
)
|
||||
|
||||
# Run the experiment, continuing from the checkpoint, through Ray Tune.
|
||||
results = tune.Tuner(
|
||||
config.algo_class,
|
||||
param_space=config,
|
||||
run_config=tune.RunConfig(stop={"num_env_steps_sampled_lifetime": 4000})
|
||||
).fit()
|
||||
|
||||
.. tab-item:: Swap out one RLModule and continue multi-agent training
|
||||
|
||||
In the :ref:`preceding section on save_to_path <rllib-checkpoints-save-to-path>`, you created
|
||||
a single-agent checkpoint with the ``default_policy`` ModuleID, and a multi-agent checkpoint with two ModuleIDs,
|
||||
``p0`` and ``p1``.
|
||||
|
||||
Here is how you can continue training the multi-agent experiment, but swap out ``p1`` with
|
||||
the state of the ``default_policy`` from the single-agent experiment.
|
||||
You can use :ref:`RLlib's callbacks APIs <rllib-callback-docs>` to inject custom
|
||||
code into a Ray Tune experiment:
|
||||
|
||||
.. testcode::
|
||||
|
||||
# Reuse the preceding multi-agent PPOConfig (`multi_agent_config`).
|
||||
|
||||
# But swap out ``p1`` with the state of the ``default_policy`` from the
|
||||
# single-agent run, using a callback and the correct path through the
|
||||
# RLlib component tree:
|
||||
multi_rl_module_component_tree = "learner_group/learner/rl_module"
|
||||
|
||||
# Inject custom callback code that runs right after algorithm's initialization.
|
||||
|
||||
def _on_algo_init(algorithm, **kwargs):
|
||||
algorithm.restore_from_path(
|
||||
# Checkpoint was single-agent (has "default_policy" subdir).
|
||||
path=Path(checkpoint_dir) / multi_rl_module_component_tree / "default_policy",
|
||||
# Algo is multi-agent (has "p0" and "p1" subdirs).
|
||||
component=multi_rl_module_component_tree + "/p1",
|
||||
)
|
||||
|
||||
# Inject callback.
|
||||
multi_agent_config.callbacks(on_algorithm_init=_on_algo_init)
|
||||
|
||||
# Run the experiment through Ray Tune.
|
||||
results = tune.Tuner(
|
||||
multi_agent_config.algo_class,
|
||||
param_space=multi_agent_config,
|
||||
run_config=tune.RunConfig(stop={"num_env_steps_sampled_lifetime": 4000})
|
||||
).fit()
|
||||
|
||||
.. testcode::
|
||||
:hide:
|
||||
|
||||
from ray.rllib.utils.test_utils import check
|
||||
|
||||
_weights_check_2 = multi_agent_config.build().get_module("p1").get_state()
|
||||
check(_weights_check, _weights_check_2)
|
||||
Reference in New Issue
Block a user