Files
ray-project--ray/rllib/policy/tests/test_export_checkpoint_and_model.py
T
2026-07-13 13:17:40 +08:00

145 lines
4.7 KiB
Python

#!/usr/bin/env python
import os
import shutil
import unittest
import numpy as np
import ray
import ray._common
from ray.rllib.examples.envs.classes.multi_agent import MultiAgentCartPole
from ray.rllib.policy.sample_batch import DEFAULT_POLICY_ID
from ray.rllib.utils.framework import try_import_torch
from ray.tune.registry import get_trainable_cls
torch, _ = try_import_torch()
def export_test(
alg_name,
framework="tf",
multi_agent=False,
):
cls = get_trainable_cls(alg_name)
config = cls.get_default_config()
config.api_stack(
enable_rl_module_and_learner=False,
enable_env_runner_and_connector_v2=False,
)
config.framework(framework)
# Switch on saving native DL-framework (tf, torch) model files.
config.checkpointing(export_native_model_files=True)
if "SAC" in alg_name:
algo = config.build(env="Pendulum-v1")
test_obs = np.array([[0.1, 0.2, 0.3]])
else:
if multi_agent:
config.multi_agent(
policies={"pol1", "pol2"},
policy_mapping_fn=(
lambda agent_id, episode, worker, **kwargs: "pol1"
if agent_id == "agent1"
else "pol2"
),
).environment(MultiAgentCartPole, env_config={"num_agents": 2})
else:
config.environment("CartPole-v1")
algo = config.build()
test_obs = np.array([[0.1, 0.2, 0.3, 0.4]])
export_dir = os.path.join(
ray._common.utils.get_default_ray_temp_dir(),
"export_dir_%s" % alg_name,
)
print("Exporting policy checkpoint", alg_name, export_dir)
if multi_agent:
algo.export_policy_checkpoint(export_dir, policy_id="pol1")
else:
algo.export_policy_checkpoint(export_dir, policy_id=DEFAULT_POLICY_ID)
# Only if keras model gets properly saved by the Policy's get_state() method.
# NOTE: This is not the case (yet) for TF Policies like SAC or DQN, which use
# ModelV2s that have more than one keras "base_model" properties in them. For
# example, SACTfModel contains `q_net` and `action_model`, both of which have
# their own `base_model`.
# Test loading exported model and perform forward pass.
if framework == "torch":
model = torch.load(
os.path.join(export_dir, "model", "model.pt"), weights_only=False
)
assert model
results = model(
input_dict={"obs": torch.from_numpy(test_obs)},
# TODO (sven): Make non-RNN models NOT expect these args at all.
state=[torch.tensor(0)], # dummy value
seq_lens=torch.tensor(0), # dummy value
)
assert len(results) == 2
assert results[0].shape in [(1, 2), (1, 3), (1, 256)], results[0].shape
assert results[1] == [torch.tensor(0)] # dummy
shutil.rmtree(export_dir)
print("Exporting policy (`default_policy`) model ", alg_name, export_dir)
# Expect an error due to not being able to identify, which exact keras
# base_model to export (e.g. SACTfModel has two keras.Models in it:
# self.q_net.base_model and self.action_model.base_model).
if multi_agent:
algo.export_policy_model(export_dir, policy_id="pol1")
algo.export_policy_model(export_dir + "_2", policy_id="pol2")
else:
algo.export_policy_model(export_dir, policy_id=DEFAULT_POLICY_ID)
# Test loading exported model and perform forward pass.
if framework == "torch":
filename = os.path.join(export_dir, "model.pt")
model = torch.load(filename, weights_only=False)
assert model
results = model(
input_dict={"obs": torch.from_numpy(test_obs)},
# TODO (sven): Make non-RNN models NOT expect these args at all.
state=[torch.tensor(0)], # dummy value
seq_lens=torch.tensor(0), # dummy value
)
assert len(results) == 2
assert results[0].shape in [(1, 2), (1, 3), (1, 256)], results[0].shape
assert results[1] == [torch.tensor(0)] # dummy
if os.path.exists(export_dir):
shutil.rmtree(export_dir)
if multi_agent:
shutil.rmtree(export_dir + "_2")
algo.stop()
class TestExportCheckpointAndModel(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
ray.init()
@classmethod
def tearDownClass(cls) -> None:
ray.shutdown()
def test_export_appo(self):
export_test("APPO", "torch")
def test_export_ppo(self):
export_test("PPO", "torch")
def test_export_ppo_multi_agent(self):
export_test("PPO", "torch", multi_agent=True)
if __name__ == "__main__":
import sys
import pytest
sys.exit(pytest.main(["-v", __file__]))