365 lines
13 KiB
Python
365 lines
13 KiB
Python
import gymnasium as gym
|
|
from gymnasium.wrappers import AtariPreprocessing
|
|
|
|
from ray import tune
|
|
from ray.rllib.algorithms.dqn.dqn import DQNConfig
|
|
from ray.rllib.connectors.env_to_module.frame_stacking import FrameStackingEnvToModule
|
|
from ray.rllib.connectors.learner.frame_stacking import FrameStackingLearner
|
|
from ray.rllib.utils.metrics import (
|
|
ENV_RUNNER_RESULTS,
|
|
EPISODE_RETURN_MEAN,
|
|
NUM_ENV_STEPS_SAMPLED_LIFETIME,
|
|
)
|
|
from ray.tune import Stopper
|
|
|
|
# Might need `gymnasium[atari, other]` to be installed.
|
|
|
|
# See the following links for becnhmark results of other libraries:
|
|
# Original paper: https://arxiv.org/abs/1812.05905
|
|
# CleanRL: https://wandb.ai/cleanrl/cleanrl.benchmark/reports/Mujoco--VmlldzoxODE0NjE
|
|
# AgileRL: https://github.com/AgileRL/AgileRL?tab=readme-ov-file#benchmarks
|
|
|
|
benchmark_envs = {
|
|
"AlienNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 6022.9,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"AmidarNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 202.8,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"AssaultNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 14491.7,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"AsterixNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 280114.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"AsteroidsNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 2249.4,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"AtlantisNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 814684.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BankHeistNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 826.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BattleZoneNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 52040.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BeamRiderNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 21768.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BerzerkNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 1793.4,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BowlingNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 39.4,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BoxingNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 54.9,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"BreakoutNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 379.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"CentipedeNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 7160.9,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"ChopperCommandNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 10916.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"CrazyClimberNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 143962.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"DefenderNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 47671.3,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"DemonAttackNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 109670.7,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"DoubleDunkNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": -0.6,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"EnduroNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 2061.1,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"FishingDerbyNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 22.6,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"FreewayNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 29.1,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"FrostbiteNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 4141.1,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"GopherNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 72595.7,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"GravitarNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 567.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"HeroNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 50496.8,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"IceHockeyNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": -11685.8,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"KangarooNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 10841.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"KrullNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 6715.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"KungFuMasterNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 28999.8,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"MontezumaRevengeNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 154.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"MsPacmanNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 2570.2,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"NameThisGameNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 11686.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"PhoenixNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 103061.6,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"PitfallNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": -37.6,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"PongNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 19.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"PrivateEyeNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 1704.4,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"QbertNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 18397.6,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"RoadRunnerNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 54261.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"RobotankNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 55.2,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"SeaquestNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 19176.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"SkiingNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": -11685.8,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"SolarisNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 2860.7,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"SpaceInvadersNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 12629.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"StarGunnerNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 123853.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"SurroundNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 7.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"TennisNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": -2.2,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"TimePilotNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 11190.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"TutankhamNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 126.9,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"VentureNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 45.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"VideoPinballNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 506817.2,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"WizardOfWorNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 14631.5,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"YarsRevengeNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 93007.9,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
"ZaxxonNoFrameskip-v4": {
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}": 19658.0,
|
|
f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}": 200000000,
|
|
},
|
|
}
|
|
|
|
for env in benchmark_envs.keys():
|
|
tune.register_env(
|
|
env,
|
|
lambda ctx, e=env: AtariPreprocessing(
|
|
gym.make(e, **ctx), grayscale_newaxis=True, screen_size=84, noop_max=0
|
|
),
|
|
)
|
|
|
|
|
|
def _make_env_to_module_connector(env, spaces, device):
|
|
return FrameStackingEnvToModule(num_frames=4)
|
|
|
|
|
|
def _make_learner_connector(input_observation_space, input_action_space):
|
|
return FrameStackingLearner(num_frames=4)
|
|
|
|
|
|
# Define a `tune.Stopper` that stops the training if the benchmark is reached
|
|
# or the maximum number of timesteps is exceeded.
|
|
class BenchmarkStopper(Stopper):
|
|
def __init__(self, benchmark_envs):
|
|
self.benchmark_envs = benchmark_envs
|
|
|
|
def __call__(self, trial_id, result):
|
|
# Stop training if the mean reward is reached.
|
|
if (
|
|
result[ENV_RUNNER_RESULTS][EPISODE_RETURN_MEAN]
|
|
>= self.benchmark_envs[result["env"]][
|
|
f"{ENV_RUNNER_RESULTS}/{EPISODE_RETURN_MEAN}"
|
|
]
|
|
):
|
|
return True
|
|
# Otherwise check, if the total number of timesteps is exceeded.
|
|
elif (
|
|
result[f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}"]
|
|
>= self.benchmark_envs[result["env"]][f"{NUM_ENV_STEPS_SAMPLED_LIFETIME}"]
|
|
):
|
|
return True
|
|
# Otherwise continue training.
|
|
else:
|
|
return False
|
|
|
|
# Note, this needs to implemented b/c the parent class is abstract.
|
|
def stop_all(self):
|
|
return False
|
|
|
|
|
|
# See Table 1 in the Rainbow paper for the hyperparameters.
|
|
config = (
|
|
DQNConfig()
|
|
.environment(
|
|
env=tune.grid_search(list(benchmark_envs.keys())),
|
|
env_config={
|
|
"max_episode_steps": 108000,
|
|
"obs_type": "grayscale",
|
|
# The authors actually use an action repetition of 4.
|
|
"repeat_action_probability": 0.25,
|
|
},
|
|
clip_rewards=True,
|
|
)
|
|
.env_runners(
|
|
# Every 4 agent steps a training update is performed.
|
|
rollout_fragment_length=4,
|
|
num_env_runners=1,
|
|
env_to_module_connector=_make_env_to_module_connector,
|
|
)
|
|
# TODO (simon): Adjust to new model_config_dict.
|
|
.training(
|
|
# Note, the paper uses also an Adam epsilon of 0.00015.
|
|
lr=0.0000625,
|
|
n_step=3,
|
|
tau=1.0,
|
|
train_batch_size=32,
|
|
target_network_update_freq=32000,
|
|
replay_buffer_config={
|
|
"type": "PrioritizedEpisodeReplayBuffer",
|
|
"capacity": 1000000,
|
|
"alpha": 0.5,
|
|
# Note the paper used a linear schedule for beta.
|
|
"beta": 0.4,
|
|
},
|
|
# Note, these are frames.
|
|
num_steps_sampled_before_learning_starts=80000,
|
|
noisy=True,
|
|
num_atoms=51,
|
|
v_min=-10.0,
|
|
v_max=10.0,
|
|
double_q=True,
|
|
dueling=True,
|
|
model={
|
|
"cnn_filter_specifiers": [[32, 8, 4], [64, 4, 2], [64, 3, 1]],
|
|
"fcnet_activation": "tanh",
|
|
"post_fcnet_hiddens": [512],
|
|
"post_fcnet_activation": "relu",
|
|
"post_fcnet_weights_initializer": "orthogonal_",
|
|
"post_fcnet_weights_initializer_config": {"gain": 0.01},
|
|
},
|
|
learner_connector=_make_learner_connector,
|
|
)
|
|
.reporting(
|
|
metrics_num_episodes_for_smoothing=10,
|
|
min_sample_timesteps_per_iteration=1000,
|
|
)
|
|
.evaluation(
|
|
evaluation_duration="auto",
|
|
evaluation_interval=1,
|
|
evaluation_num_env_runners=1,
|
|
evaluation_parallel_to_training=True,
|
|
evaluation_config={
|
|
"explore": False,
|
|
},
|
|
)
|
|
)
|
|
|
|
tuner = tune.Tuner(
|
|
"DQN",
|
|
param_space=config,
|
|
run_config=tune.RunConfig(
|
|
stop=BenchmarkStopper(benchmark_envs=benchmark_envs),
|
|
name="benchmark_dqn_atari",
|
|
),
|
|
)
|
|
|
|
tuner.fit()
|