From 1d94337fc591955cc730133670ca813134e287d9 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 2 Mar 2022 15:26:25 +0100 Subject: [PATCH 01/47] Fixed hardcoded reward_treshold --- test/offline/test_cql.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index be43ea247..ef003a3f8 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -26,6 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=-1200) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64, 64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -78,8 +79,7 @@ def test_cql(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -1200 # too low? + env.spec.reward_threshold = args.reward_threshold args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] From 11c2875d9513d574a417d63884f91ffb60120210 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 2 Mar 2022 15:58:42 +0100 Subject: [PATCH 02/47] Added reward_treshold as argumenet for offline test scripts --- test/offline/gather_cartpole_data.py | 5 ++--- test/offline/gather_pendulum_data.py | 5 ++--- test/offline/test_bcq.py | 4 ++-- test/offline/test_cql.py | 9 +++++---- test/offline/test_discrete_bcq.py | 5 ++--- test/offline/test_discrete_cql.py | 5 ++--- test/offline/test_discrete_crr.py | 5 ++--- 7 files changed, 17 insertions(+), 21 deletions(-) diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index eeddf1a21..58e6748bf 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -22,6 +22,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward_threshold', type=float, default=190) # lower the goal parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -57,8 +58,6 @@ def get_args(): def gather_data(): args = get_args() env = gym.make(args.task) - if args.task == 'CartPole-v0': - env.spec.reward_threshold = 190 # lower the goal args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n # train_envs = gym.make(args.task) @@ -117,7 +116,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index 33fac4f74..1743ab842 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -23,6 +23,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=-250) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[128, 128]) @@ -65,8 +66,6 @@ def gather_data(): """Return expert buffer data.""" args = get_args() env = gym.make(args.task) - if args.task == 'Pendulum-v0': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] @@ -147,7 +146,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer offpolicy_trainer( diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 8a5ec982f..9a1745381 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -26,6 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=-1100) # too low? parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -73,8 +74,7 @@ def test_bcq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -1100 # too low? + env.spec.reward_threshold = args.reward_threshold args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index ef003a3f8..43445034e 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -26,7 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=-1200) + parser.add_argument('--reward-threshold', type=float, default=-1200) # too low? parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64, 64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -79,7 +79,6 @@ def test_cql(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float - env.spec.reward_threshold = args.reward_threshold args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] @@ -177,7 +176,9 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + if mean_rewards >= args.reward_threshold: + print(mean_rewards) + return mean_rewards >= args.reward_threshold def watch(): policy.load_state_dict( @@ -202,7 +203,7 @@ def watch(): stop_fn=stop_fn, logger=logger, ) - assert stop_fn(result['best_reward']) + # assert stop_fn(result['best_reward']) # Let's watch its performance! if __name__ == '__main__': diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index e83d13dde..b3ebe2a1c 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -25,6 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") + parser.add_argument('--reward_threshold', type=float, default=190) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-4) @@ -55,8 +56,6 @@ def get_args(): def test_discrete_bcq(args=get_args()): # envs env = gym.make(args.task) - if args.task == 'CartPole-v0': - env.spec.reward_threshold = 190 # lower the goal args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n test_envs = DummyVectorEnv( @@ -108,7 +107,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def save_checkpoint_fn(epoch, env_step, gradient_step): # see also: https://pytorch.org/tutorials/beginner/saving_loading_models.html diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index eaac481bc..6d9988d06 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -24,6 +24,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") + parser.add_argument('--reward_threshold', type=float, default=170) # lower the goal parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-3) @@ -52,8 +53,6 @@ def get_args(): def test_discrete_cql(args=get_args()): # envs env = gym.make(args.task) - if args.task == 'CartPole-v0': - env.spec.reward_threshold = 170 # lower the goal args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n test_envs = DummyVectorEnv( @@ -103,7 +102,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold result = offline_trainer( policy, diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index 2e8916ae2..9d92b4b67 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -25,6 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") + parser.add_argument('--reward_threshold', type=float, default=180) # lower the goal parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--lr", type=float, default=7e-4) parser.add_argument("--gamma", type=float, default=0.99) @@ -50,8 +51,6 @@ def get_args(): def test_discrete_crr(args=get_args()): # envs env = gym.make(args.task) - if args.task == 'CartPole-v0': - env.spec.reward_threshold = 180 # lower the goal args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n test_envs = DummyVectorEnv( @@ -106,7 +105,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold result = offline_trainer( policy, From 8288a1000db0f9e9b08ac68f21eb170f697d4556 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 2 Mar 2022 16:03:52 +0100 Subject: [PATCH 03/47] reward_treshold as argument for offline test scripts --- test/offline/test_cql.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index 43445034e..9e5a7392f 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -176,8 +176,6 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - if mean_rewards >= args.reward_threshold: - print(mean_rewards) return mean_rewards >= args.reward_threshold def watch(): @@ -203,7 +201,7 @@ def watch(): stop_fn=stop_fn, logger=logger, ) - # assert stop_fn(result['best_reward']) + assert stop_fn(result['best_reward']) # Let's watch its performance! if __name__ == '__main__': From 8467afdad2a2a5b5993483932234c6ccef9e5181 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Thu, 3 Mar 2022 11:27:33 +0100 Subject: [PATCH 04/47] reward_threshold defaults to None --- examples/offline/test_d4rl.py | 5 +++++ test/continuous/test_ddpg.py | 8 +++++--- test/continuous/test_npg.py | 8 +++++--- test/continuous/test_ppo.py | 8 +++++--- test/continuous/test_sac_with_il.py | 12 ++++++------ test/continuous/test_td3.py | 8 +++++--- test/continuous/test_trpo.py | 8 +++++--- test/modelbased/test_psrl.py | 11 +++++------ test/offline/gather_cartpole_data.py | 5 ++++- test/offline/gather_pendulum_data.py | 5 ++++- test/offline/test_bcq.py | 6 ++++-- test/offline/test_cql.py | 5 ++++- test/offline/test_discrete_bcq.py | 5 ++++- test/offline/test_discrete_cql.py | 5 ++++- test/offline/test_discrete_crr.py | 5 ++++- 15 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 examples/offline/test_d4rl.py diff --git a/examples/offline/test_d4rl.py b/examples/offline/test_d4rl.py new file mode 100644 index 000000000..ca47615d4 --- /dev/null +++ b/examples/offline/test_d4rl.py @@ -0,0 +1,5 @@ +import d4rl +import gym + +env = gym.make("halfcheetah-medium-v1") +dataset = d4rl.qlearning_dataset(env) \ No newline at end of file diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index 4f76bb8c8..e87226227 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -20,6 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -49,11 +50,12 @@ def get_args(): def test_ddpg(args=get_args()): torch.set_num_threads(1) # we just need only one thread for NN env = gym.make(args.task) - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -112,7 +114,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = offpolicy_trainer( diff --git a/test/continuous/test_npg.py b/test/continuous/test_npg.py index d369bfda0..3c85d4903 100644 --- a/test/continuous/test_npg.py +++ b/test/continuous/test_npg.py @@ -21,6 +21,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--lr', type=float, default=1e-3) @@ -52,11 +53,12 @@ def get_args(): def test_npg(args=get_args()): env = gym.make(args.task) - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -134,7 +136,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( diff --git a/test/continuous/test_ppo.py b/test/continuous/test_ppo.py index 4e95e923d..6ff43529b 100644 --- a/test/continuous/test_ppo.py +++ b/test/continuous/test_ppo.py @@ -20,6 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=1e-3) @@ -56,11 +57,12 @@ def get_args(): def test_ppo(args=get_args()): env = gym.make(args.task) - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -129,7 +131,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def save_checkpoint_fn(epoch, env_step, gradient_step): # see also: https://pytorch.org/tutorials/beginner/saving_loading_models.html diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index 7eaf8794f..e3e9e858b 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -23,6 +23,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v0') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -62,12 +63,12 @@ def test_sac_with_il(args=get_args()): args.task, num_envs=args.training_num, seed=args.seed ) test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) - reward_threshold = None - if args.task == 'Pendulum-v0': - reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # seed np.random.seed(args.seed) @@ -139,7 +140,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = offpolicy_trainer( @@ -160,8 +161,7 @@ def stop_fn(mean_rewards): # here we define an imitation collector with a trivial policy policy.eval() - if args.task == 'Pendulum-v0': - reward_threshold = -300 # lower the goal + args.reward_threshold = -300 # lower the goal net = Actor( Net( args.state_shape, diff --git a/test/continuous/test_td3.py b/test/continuous/test_td3.py index 023c02a6a..607a08b2e 100644 --- a/test/continuous/test_td3.py +++ b/test/continuous/test_td3.py @@ -20,6 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -52,11 +53,12 @@ def get_args(): def test_td3(args=get_args()): torch.set_num_threads(1) # we just need only one thread for NN env = gym.make(args.task) - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -130,7 +132,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = offpolicy_trainer( diff --git a/test/continuous/test_trpo.py b/test/continuous/test_trpo.py index 2824e6e97..82c78e8d8 100644 --- a/test/continuous/test_trpo.py +++ b/test/continuous/test_trpo.py @@ -21,6 +21,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--lr', type=float, default=1e-3) @@ -55,11 +56,12 @@ def get_args(): def test_trpo(args=get_args()): env = gym.make(args.task) - if args.task == 'Pendulum-v1': - env.spec.reward_threshold = -250 args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -138,7 +140,7 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( diff --git a/test/modelbased/test_psrl.py b/test/modelbased/test_psrl.py index d6501084f..24b415839 100644 --- a/test/modelbased/test_psrl.py +++ b/test/modelbased/test_psrl.py @@ -16,6 +16,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='NChain-v0') + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--epoch', type=int, default=5) @@ -44,12 +45,10 @@ def test_psrl(args=get_args()): args.task, num_envs=args.training_num, seed=args.seed ) test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) - if args.task == "NChain-v0": - reward_threshold = 3400 - # reward_threshold = 3647 # described in PSRL paper - else: - reward_threshold = None - print("reward threshold:", reward_threshold) + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + print("reward threshold:", args.reward_threshold) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n # seed diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index 58e6748bf..6ef1cc0ae 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -22,7 +22,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') - parser.add_argument('--reward_threshold', type=float, default=190) # lower the goal + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -60,6 +60,9 @@ def gather_data(): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 190, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # lower the goal? # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index 1743ab842..8835f5d89 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -23,7 +23,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=-250) + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[128, 128]) @@ -69,6 +69,9 @@ def gather_data(): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 9a1745381..902c3708b 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -26,7 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=-1100) # too low? + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -74,7 +74,9 @@ def test_bcq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float - env.spec.reward_threshold = args.reward_threshold + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # too low? args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index 9e5a7392f..a07012bed 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -26,7 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward-threshold', type=float, default=-1200) # too low? + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64, 64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -79,6 +79,9 @@ def test_cql(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} # too low? + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index b3ebe2a1c..67a982ff9 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -25,7 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=190) + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-4) @@ -61,6 +61,9 @@ def test_discrete_bcq(args=get_args()): test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index 6d9988d06..f0b65ecfb 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -24,7 +24,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=170) # lower the goal + parser.add_argument('--reward_threshold', type=float, default=None) # lower the goal parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-3) @@ -55,6 +55,9 @@ def test_discrete_cql(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 170, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index 9d92b4b67..dcba5c0b8 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -25,7 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=180) # lower the goal + parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--lr", type=float, default=7e-4) parser.add_argument("--gamma", type=float, default=0.99) @@ -53,6 +53,9 @@ def test_discrete_crr(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 180, "NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get(args.reward_threshold) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) From c5daa06b5af31edf007df046c5b99882a6aa40b1 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Thu, 3 Mar 2022 15:18:31 +0100 Subject: [PATCH 05/47] correction --- test/continuous/test_ddpg.py | 2 +- test/continuous/test_npg.py | 2 +- test/continuous/test_ppo.py | 2 +- test/continuous/test_sac_with_il.py | 2 +- test/continuous/test_td3.py | 2 +- test/continuous/test_trpo.py | 2 +- test/modelbased/test_psrl.py | 2 +- test/offline/gather_cartpole_data.py | 2 +- test/offline/gather_pendulum_data.py | 2 +- test/offline/test_bcq.py | 2 +- test/offline/test_cql.py | 2 +- test/offline/test_discrete_bcq.py | 2 +- test/offline/test_discrete_cql.py | 2 +- test/offline/test_discrete_crr.py | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index e87226227..122fc73a7 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -55,7 +55,7 @@ def test_ddpg(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_npg.py b/test/continuous/test_npg.py index 3c85d4903..d22bb46d0 100644 --- a/test/continuous/test_npg.py +++ b/test/continuous/test_npg.py @@ -58,7 +58,7 @@ def test_npg(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_ppo.py b/test/continuous/test_ppo.py index 6ff43529b..b876a7f43 100644 --- a/test/continuous/test_ppo.py +++ b/test/continuous/test_ppo.py @@ -62,7 +62,7 @@ def test_ppo(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index e3e9e858b..cf3fa2791 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -68,7 +68,7 @@ def test_sac_with_il(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # seed np.random.seed(args.seed) diff --git a/test/continuous/test_td3.py b/test/continuous/test_td3.py index 607a08b2e..ab9742526 100644 --- a/test/continuous/test_td3.py +++ b/test/continuous/test_td3.py @@ -58,7 +58,7 @@ def test_td3(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_trpo.py b/test/continuous/test_trpo.py index 82c78e8d8..818ae9283 100644 --- a/test/continuous/test_trpo.py +++ b/test/continuous/test_trpo.py @@ -61,7 +61,7 @@ def test_trpo(args=get_args()): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/modelbased/test_psrl.py b/test/modelbased/test_psrl.py index 24b415839..e4bf9f6be 100644 --- a/test/modelbased/test_psrl.py +++ b/test/modelbased/test_psrl.py @@ -47,7 +47,7 @@ def test_psrl(args=get_args()): test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) print("reward threshold:", args.reward_threshold) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index 6ef1cc0ae..ac2477a30 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -62,7 +62,7 @@ def gather_data(): args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 190, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # lower the goal? + args.reward_threshold = default_reward_threshold.get(args.task) # lower the goal? # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index 8835f5d89..67920183f 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -71,7 +71,7 @@ def gather_data(): args.max_action = env.action_space.high[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 902c3708b..38965b9cc 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -76,7 +76,7 @@ def test_bcq(args=get_args()): args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) # too low? + args.reward_threshold = default_reward_threshold.get(args.task) # too low? args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index a07012bed..b4da5e171 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -81,7 +81,7 @@ def test_cql(args=get_args()): args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} # too low? - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index 67a982ff9..add4bc02f 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -63,7 +63,7 @@ def test_discrete_bcq(args=get_args()): ) if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index f0b65ecfb..d7a5fb921 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -57,7 +57,7 @@ def test_discrete_cql(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 170, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index dcba5c0b8..a01f10967 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -55,7 +55,7 @@ def test_discrete_crr(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 180, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.reward_threshold) + args.reward_threshold = default_reward_threshold.get(args.task) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) From b5c2d1dc58ec6cd1a1b09ee16e03269927a7dcf6 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Fri, 11 Mar 2022 22:11:26 +0100 Subject: [PATCH 06/47] bdq implemented not tested yet --- draft.ipynb | 224 +++++++++++++++++++++++++++++++ tianshou/policy/imitation/cql.py | 21 ++- tianshou/policy/modelfree/bdq.py | 207 ++++++++++++++++++++++++++++ tianshou/utils/net/common.py | 50 +++++++ 4 files changed, 496 insertions(+), 6 deletions(-) create mode 100644 draft.ipynb create mode 100644 tianshou/policy/modelfree/bdq.py diff --git a/draft.ipynb b/draft.ipynb new file mode 100644 index 000000000..28674ce5f --- /dev/null +++ b/draft.ipynb @@ -0,0 +1,224 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import gym\n", + "import numpy as np\n", + "from torchsummary import summary\n", + "from tianshou.utils.net.common import BDQNet" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class DiscreteToContinuous(gym.ActionWrapper):\n", + " def __init__(self, env, action_per_branch):\n", + " super().__init__(env)\n", + " self.action_per_branch = action_per_branch\n", + " low = self.action_space.low\n", + " high = self.action_space.high\n", + " self.mesh = []\n", + " for l, h in zip(low, high):\n", + " self.mesh.append(np.linspace(l, h, action_per_branch))\n", + " \n", + " def action(self, act):\n", + " # modify act\n", + " act = np.array([self.mesh[i][a] for i, a in enumerate(act)])\n", + " return act" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "env = DiscreteToContinuous(gym.make('BipedalWalker-v3'), action_per_branch=2)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "state_shape = env.observation_space.shape[0]\n", + "action_shape = env.action_space.shape[0]\n", + "action_per_branch = env.action_per_branch\n", + "common_hidden_sizes = [512, 256]\n", + "value_hidden_sizes = [128]\n", + "action_hidden_sizes = [128]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "model = BDQNet(state_shape,\n", + " action_shape,\n", + " action_per_branch,\n", + " common_hidden_sizes,\n", + " value_hidden_sizes,\n", + " action_hidden_sizes)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([1, 4, 2])" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "\n", + "x = torch.randn(state_shape).unsqueeze(0)\n", + "y = model(x)\n", + "y[0].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[0, 0, 1, 0]])" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[0].max(dim=-1)[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "torch.Size([1, 4, 2])" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y[0].shape" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(y[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[[0]],\n", + "\n", + " [[1]],\n", + "\n", + " [[1]],\n", + "\n", + " [[1]],\n", + "\n", + " [[0]],\n", + "\n", + " [[0]],\n", + "\n", + " [[1]],\n", + "\n", + " [[1]],\n", + "\n", + " [[1]],\n", + "\n", + " [[1]]])" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = np.random.randint(0, 2, 10)\n", + "a.reshape(-1, 1, 1)" + ] + } + ], + "metadata": { + "interpreter": { + "hash": "f3d922253121c31a7b24bed1c151b936757524923ac49fbc20420da76bf88248" + }, + "kernelspec": { + "display_name": "Python 3.9.10 ('tianshou')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.10" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tianshou/policy/imitation/cql.py b/tianshou/policy/imitation/cql.py index 102ede058..50cd9d152 100644 --- a/tianshou/policy/imitation/cql.py +++ b/tianshou/policy/imitation/cql.py @@ -206,12 +206,21 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: random_actions = torch.FloatTensor( batch_size * self.num_repeat_actions, act.shape[-1] ).uniform_(-self.min_action, self.max_action).to(self.device) - tmp_obs = obs.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-1]) - tmp_obs_next = obs_next.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-1]) + + if len(obs.shape) > 2: + tmp_obs = obs.unsqueeze(1) \ + .repeat(1, self.num_repeat_actions, 1, 1) \ + .view(batch_size * self.num_repeat_actions, obs.shape[-2], obs.shape[-1]) + tmp_obs_next = obs_next.unsqueeze(1) \ + .repeat(1, self.num_repeat_actions, 1, 1) \ + .view(batch_size * self.num_repeat_actions, obs.shape[-2], obs.shape[-1]) + else: + tmp_obs = obs.unsqueeze(1) \ + .repeat(1, self.num_repeat_actions, 1) \ + .view(batch_size * self.num_repeat_actions, obs.shape[-1]) + tmp_obs_next = obs_next.unsqueeze(1) \ + .repeat(1, self.num_repeat_actions, 1) \ + .view(batch_size * self.num_repeat_actions, obs.shape[-1]) # tmp_obs & tmp_obs_next: (batch_size * num_repeat, state_dim) current_pi_value1, current_pi_value2 = self.calc_pi_values(tmp_obs, tmp_obs) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py new file mode 100644 index 000000000..9bd2898e8 --- /dev/null +++ b/tianshou/policy/modelfree/bdq.py @@ -0,0 +1,207 @@ +from copy import deepcopy +from typing import Any, Dict, Optional, Union, Callable + +import numpy as np +import torch + +from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch_as +from tianshou.policy import BasePolicy + + +class BDQPolicy(BasePolicy): + """Implementation of Deep Q Network. arXiv:1312.5602. + + Implementation of Double Q-Learning. arXiv:1509.06461. + + Implementation of Dueling DQN. arXiv:1511.06581 (the dueling DQN is + implemented in the network side, not here). + + :param torch.nn.Module model: a model following the rules in + :class:`~tianshou.policy.BasePolicy`. (s -> logits) + :param torch.optim.Optimizer optim: a torch.optim for optimizing the model. + :param float discount_factor: in [0, 1]. + :param int estimation_step: the number of steps to look ahead. Default to 1. + :param int target_update_freq: the target network update frequency (0 if + you do not use the target network). Default to 0. + :param bool reward_normalization: normalize the reward to Normal(0, 1). + Default to False. + :param bool is_double: use double dqn. Default to True. + + .. seealso:: + + Please refer to :class:`~tianshou.policy.BasePolicy` for more detailed + explanation. + """ + + def __init__( + self, + model: torch.nn.Module, + optim: torch.optim.Optimizer, + discount_factor: float = 0.99, + estimation_step: int = 1, + target_update_freq: int = 0, + reward_normalization: bool = False, + is_double: bool = True, + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + self.model = model + self.optim = optim + self.eps = 0.0 + assert 0.0 <= discount_factor <= 1.0, "discount factor should be in [0, 1]" + self._gamma = discount_factor + assert estimation_step > 0, "estimation_step should be greater than 0" + self._n_step = estimation_step + self._target = target_update_freq > 0 + self._freq = target_update_freq + self._iter = 0 + if self._target: + self.model_old = deepcopy(self.model) + self.model_old.eval() + self._rew_norm = reward_normalization + self._is_double = is_double + + def set_eps(self, eps: float) -> None: + """Set the eps for epsilon-greedy exploration.""" + self.eps = eps + + def train(self, mode: bool = True) -> "BDQPolicy": + """Set the module in training mode, except for the target network.""" + self.training = mode + self.model.train(mode) + return self + + def sync_weight(self) -> None: + """Synchronize the weight for the target network.""" + self.model_old.load_state_dict(self.model.state_dict()) + + def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: + batch = buffer[indices] # batch.obs_next: s_{t+n} + result = self(batch, input="obs_next") + if self._target: + # target_Q = Q_old(s_, argmax(Q_new(s_, *))) + target_q = self(batch, model="model_old", input="obs_next").logits + else: + target_q = result.logits + if self._is_double: + shape = result.act.shape + return target_q[np.arange(shape[0]), np.arange(shape[1]), result.act] + else: # Nature DQN, over estimate + return target_q.max(dim=-1)[0] + + @staticmethod + def _compute_return( + batch: Batch, + buffer: ReplayBuffer, + indice: np.ndarray, + target_q_fn: Callable[[ReplayBuffer, np.ndarray], torch.Tensor], + ) -> Batch: + with torch.no_grad(): + target_q_torch = target_q_fn(buffer, indice) # (bsz, ?) + target_q = to_numpy(target_q_torch) + target_q = target_q * BasePolicy.value_mask(buffer, indice).reshape(-1, 1, 1) + end_flag = buffer.done.copy() + end_flag[buffer.unfinished_index()] = True + + batch.returns = to_torch_as(target_q, target_q_torch) + if hasattr(batch, "weight"): # prio buffer update + batch.weight = to_torch_as(batch.weight, target_q_torch) + return batch + + def process_fn( + self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray + ) -> Batch: + """Compute the n-step return for Q-learning targets. + + More details can be found at + :meth:`~tianshou.policy.BasePolicy.compute_nstep_return`. + """ + batch = self._compute_return( + batch, buffer, indices, self._target_q + ) + return batch + + def compute_q_value( + self, logits: torch.Tensor, mask: Optional[np.ndarray] + ) -> torch.Tensor: + """Compute the q value based on the network's raw output and action mask.""" + if mask is not None: + # the masked q value should be smaller than logits.min() + min_value = logits.min() - logits.max() - 1.0 + logits = logits + to_torch_as(1 - mask, logits) * min_value + return logits + + def forward( + self, + batch: Batch, + state: Optional[Union[dict, Batch, np.ndarray]] = None, + model: str = "model", + input: str = "obs", + **kwargs: Any, + ) -> Batch: + """Compute action over the given batch data. + + If you need to mask the action, please add a "mask" into batch.obs, for + example, if we have an environment that has "0/1/2" three actions: + :: + + batch == Batch( + obs=Batch( + obs="original obs, with batch_size=1 for demonstration", + mask=np.array([[False, True, False]]), + # action 1 is available + # action 0 and 2 are unavailable + ), + ... + ) + + :param float eps: in [0, 1], for epsilon-greedy exploration method. + + :return: A :class:`~tianshou.data.Batch` which has 3 keys: + + * ``act`` the action. + * ``logits`` the network's raw output. + * ``state`` the hidden state. + + .. seealso:: + + Please refer to :meth:`~tianshou.policy.BasePolicy.forward` for + more detailed explanation. + """ + model = getattr(self, model) + obs = batch[input] + obs_next = obs.obs if hasattr(obs, "obs") else obs + logits, hidden = model(obs_next, state=state, info=batch.info) + q = self.compute_q_value(logits, getattr(obs, "mask", None)) + if not hasattr(self, "max_action_num"): + self.max_action_num = q.shape[1] + act = to_numpy(q.max(dim=-1)[1].squeeze()) + return Batch(logits=logits, act=act, state=hidden) + + def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: + if self._target and self._iter % self._freq == 0: + self.sync_weight() + self.optim.zero_grad() + weight = batch.pop("weight", 1.0) + q = self(batch).logits + q = q[np.arange(q.shape[0]), np.arange(q.shape[1]), batch.act] + returns = to_torch_as(batch.returns.flatten(), q) + td_error = returns - q + loss = (td_error.pow(2) * weight).mean() + batch.weight = td_error # prio-buffer + loss.backward() + self.optim.step() + self._iter += 1 + return {"loss": loss.item()} + + def exploration_noise(self, act: Union[np.ndarray, Batch], + batch: Batch) -> Union[np.ndarray, Batch]: + if isinstance(act, np.ndarray) and not np.isclose(self.eps, 0.0): + bsz = len(act) + rand_mask = np.random.rand(bsz) < self.eps + q = np.random.rand(bsz, self.max_action_num) # [0, 1] + if hasattr(batch.obs, "mask"): + q += batch.obs.mask + rand_act = q.argmax(axis=1) + act[rand_mask] = rand_act[rand_mask] + return act \ No newline at end of file diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 9d03b6120..3b9611dfc 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -311,3 +311,53 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, if not isinstance(obs, torch.Tensor): obs = torch.as_tensor(obs, dtype=torch.float32) return self.net(obs=obs.cuda(), *args, **kwargs) + +class BDQNet(nn.Module): + """Branching dual Q network + """ + def __init__( + self, + state_shape: Union[int, Sequence[int]], + action_shape: Union[int, Sequence[int]] = 0, + action_per_branch: Union[int, Sequence[int]] = 1, + common_hidden_sizes: Sequence[int] = (), + value_hidden_sizes: Sequence[int] = (), + action_hidden_sizes: Sequence[int] = (), + norm_layer: Optional[ModuleType] = None, + activation: Optional[ModuleType] = nn.ReLU, + device: Union[str, int, torch.device] = "cpu", + ) -> None: + super().__init__() + self.device = device + self.num_branches = action_shape + self.action_per_branch = action_per_branch + # common network + common_input_dim = int(np.prod(state_shape)) + common_output_dim = 0 + self.common = MLP(common_input_dim, common_output_dim, common_hidden_sizes, norm_layer, activation, device) + # value network + value_input_dim = common_hidden_sizes[-1] + value_output_dim = 1 + self.value = MLP(value_input_dim, value_output_dim, value_hidden_sizes, norm_layer, activation, device) + # action branching network + action_input_dim = common_hidden_sizes[-1] + action_output_dim = action_per_branch + self.branches = nn.ModuleList([MLP(action_input_dim, action_output_dim, action_hidden_sizes, norm_layer, activation, device) for _ in range(self.num_branches)]) + + def forward( + self, + obs: Union[np.ndarray, torch.Tensor], + state: Any = None, + info: Dict[str, Any] = {}, + ) -> Tuple[torch.Tensor, Any]: + """Mapping: obs -> flatten (inside MLP)-> logits.""" + common_out = self.common(obs) + value_out = self.value(common_out) + value_out = torch.unsqueeze(value_out, 1) + action_out = [] + for b in self.branches: + action_out.append(b(common_out)) + action_scores = torch.stack(action_out, 1) + action_scores = action_scores - torch.mean(action_scores, 2, keepdim=True) + logits = value_out + action_scores + return logits, state \ No newline at end of file From abc5db2d24e8af1e5c5decffe89de825c3f8952f Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Mon, 4 Apr 2022 17:15:27 +0200 Subject: [PATCH 07/47] Implement BDQ algorithm --- examples/box2d/bdq_train.py | 170 +++++++++++++++++++++++++++++++ tianshou/env/gym_wrappers.py | 23 +++++ tianshou/policy/modelfree/bdq.py | 101 ++++++++---------- tianshou/utils/net/common.py | 56 +++++++--- 4 files changed, 273 insertions(+), 77 deletions(-) create mode 100644 examples/box2d/bdq_train.py create mode 100644 tianshou/env/gym_wrappers.py diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_train.py new file mode 100644 index 000000000..010ee6625 --- /dev/null +++ b/examples/box2d/bdq_train.py @@ -0,0 +1,170 @@ +import argparse +import os +import pprint + +import gym +import numpy as np +import torch +from torch.utils.tensorboard import SummaryWriter + +from tianshou.data import Collector, PrioritizedVectorReplayBuffer, VectorReplayBuffer +from tianshou.env import DummyVectorEnv, SubprocVectorEnv +from tianshou.policy import BDQPolicy +from tianshou.trainer import offpolicy_trainer +from tianshou.utils import TensorboardLogger +from tianshou.utils.net.common import BDQNet + +class DiscreteToContinuous(gym.ActionWrapper): + def __init__(self, env, action_per_branch): + super().__init__(env) + self.action_per_branch = action_per_branch + low = self.action_space.low + high = self.action_space.high + self.mesh = [] + for l, h in zip(low, high): + self.mesh.append(np.linspace(l, h, action_per_branch)) + + def action(self, act): + # modify act + act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) + return act + +def get_args(): + parser = argparse.ArgumentParser() + # task + parser.add_argument('--task', type=str, default='BipedalWalker-v3') + # network architecture + parser.add_argument('--common_hidden-sizes', type=int, nargs='*', default=[512, 256]) + parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) + parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) + parser.add_argument('--action_per_brach', type=int, default=32) + # training hyperparameters + parser.add_argument('--seed', type=int, default=0) + parser.add_argument('--eps-test', type=float, default=0.) + parser.add_argument('--eps-train', type=float, default=0.73) + parser.add_argument('--buffer-size', type=int, default=100000) + parser.add_argument('--lr', type=float, default=2e-5) + parser.add_argument('--gamma', type=float, default=0.99) + parser.add_argument('--target-update-freq', type=int, default=1000) + parser.add_argument('--epoch', type=int, default=100) + parser.add_argument('--step-per-epoch', type=int, default=80000) + parser.add_argument('--step-per-collect', type=int, default=16) + parser.add_argument('--update-per-step', type=float, default=0.0625) + parser.add_argument('--batch-size', type=int, default=512) + parser.add_argument('--training-num', type=int, default=16) + parser.add_argument('--test-num', type=int, default=100) + # other + parser.add_argument('--logdir', type=str, default='log') + parser.add_argument('--render', type=float, default=0.) + parser.add_argument( + '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + ) + return parser.parse_args() + + +def test_dqn(args=get_args()): + if args.task == 'Humanoid-v3': + args.reward_treshold = 3000 + + env = gym.make(args.task) + env = DiscreteToContinuous(env, args.action_per_branch) + + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + + print("Observations shape:", args.state_shape) + print("Actions shape:", args.action_shape) + print("Actions per branch:", args.action_per_branch) + + # train_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + # you can also use tianshou.env.SubprocVectorEnv + train_envs = DummyVectorEnv( + [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num)] + ) + # test_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + test_envs = SubprocVectorEnv( + [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num)] + ) + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + train_envs.seed(args.seed) + test_envs.seed(args.seed) + # model + net = BDQNet( + args.state_shape, + args.action_shape, + args.action_per_branch, + args.common_hidden_sizes, + args.value_hidden_sizes, + args.action_hidden_sizes, + device=args.device, + ).to(args.device) + optim = torch.optim.Adam(net.parameters(), lr=args.lr) + policy = BDQPolicy( + net, + optim, + args.gamma, + target_update_freq=args.target_update_freq + ) + # collector + train_collector = Collector( + policy, + train_envs, + VectorReplayBuffer(args.buffer_size, len(train_envs)), + exploration_noise=True + ) + test_collector = Collector(policy, test_envs, exploration_noise=True) + # policy.set_eps(1) + train_collector.collect(n_step=args.batch_size * args.training_num) + # log + log_path = os.path.join(args.logdir, args.task, 'bdq_lr2e-5') + writer = SummaryWriter(log_path) + logger = TensorboardLogger(writer) + + def save_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + + def stop_fn(mean_rewards): + return mean_rewards >= getattr(env, "spec.reward_threshold", args.reward_treshold) + + def train_fn(epoch, env_step): # exp decay + eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) + policy.set_eps(eps) + + def test_fn(epoch, env_step): + policy.set_eps(args.eps_test) + + # trainer + result = offpolicy_trainer( + policy, + train_collector, + test_collector, + args.epoch, + args.step_per_epoch, + args.step_per_collect, + args.test_num, + args.batch_size, + update_per_step=args.update_per_step, + # stop_fn=stop_fn, + train_fn=train_fn, + test_fn=test_fn, + save_fn=save_fn, + logger=logger + ) + + # assert stop_fn(result['best_reward']) + if __name__ == '__main__': + pprint.pprint(result) + # Let's watch its performance! + policy.eval() + policy.set_eps(args.eps_test) + test_envs.seed(args.seed) + test_collector.reset() + result = test_collector.collect(n_episode=args.test_num, render=args.render) + rews, lens = result["rews"], result["lens"] + print(f"Final reward: {rews.mean()}, length: {lens.mean()}") + + +if __name__ == '__main__': + test_dqn(get_args()) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py new file mode 100644 index 000000000..4cfcc798d --- /dev/null +++ b/tianshou/env/gym_wrappers.py @@ -0,0 +1,23 @@ +import gym +import numpy as np + +class DiscreteToContinuous(gym.ActionWrapper): + """Gym environment wrapper to take discrete action in a continous environment + + Args: + env (gym.Environment): gym envirionment with continous action space + action_per_branch (int): number of discrete actions in each dimension of the action space + """ + def __init__(self, env, action_per_branch): + super().__init__(env) + self.action_per_branch = action_per_branch + low = self.action_space.low + high = self.action_space.high + self.mesh = [] + for l, h in zip(low, high): + self.mesh.append(np.linspace(l, h, action_per_branch)) + + def action(self, act): + # modify act + act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) + return act \ No newline at end of file diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 9bd2898e8..defd44ba6 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -1,5 +1,5 @@ from copy import deepcopy -from typing import Any, Dict, Optional, Union, Callable +from typing import Any, Dict, Optional, Union import numpy as np import torch @@ -9,12 +9,7 @@ class BDQPolicy(BasePolicy): - """Implementation of Deep Q Network. arXiv:1312.5602. - - Implementation of Double Q-Learning. arXiv:1509.06461. - - Implementation of Dueling DQN. arXiv:1511.06581 (the dueling DQN is - implemented in the network side, not here). + """Implementation of the branching dueling network arXiv:1711.08946 :param torch.nn.Module model: a model following the rules in :class:`~tianshou.policy.BasePolicy`. (s -> logits) @@ -25,7 +20,7 @@ class BDQPolicy(BasePolicy): you do not use the target network). Default to 0. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. - :param bool is_double: use double dqn. Default to True. + :param bool is_double: use double network. Default to True. .. seealso:: @@ -38,7 +33,6 @@ def __init__( model: torch.nn.Module, optim: torch.optim.Optimizer, discount_factor: float = 0.99, - estimation_step: int = 1, target_update_freq: int = 0, reward_normalization: bool = False, is_double: bool = True, @@ -50,8 +44,6 @@ def __init__( self.eps = 0.0 assert 0.0 <= discount_factor <= 1.0, "discount factor should be in [0, 1]" self._gamma = discount_factor - assert estimation_step > 0, "estimation_step should be greater than 0" - self._n_step = estimation_step self._target = target_update_freq > 0 self._freq = target_update_freq self._iter = 0 @@ -75,8 +67,7 @@ def sync_weight(self) -> None: """Synchronize the weight for the target network.""" self.model_old.load_state_dict(self.model.state_dict()) - def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: - batch = buffer[indices] # batch.obs_next: s_{t+n} + def _target_q(self, batch: Batch) -> torch.Tensor: result = self(batch, input="obs_next") if self._target: # target_Q = Q_old(s_, argmax(Q_new(s_, *))) @@ -84,25 +75,29 @@ def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: else: target_q = result.logits if self._is_double: - shape = result.act.shape - return target_q[np.arange(shape[0]), np.arange(shape[1]), result.act] + act = self(batch, input="obs_next").act + return np.squeeze(np.take_along_axis(target_q, np.expand_dims(act, -1), -1)) else: # Nature DQN, over estimate - return target_q.max(dim=-1)[0] + return NotImplementedError - @staticmethod def _compute_return( + self, batch: Batch, buffer: ReplayBuffer, indice: np.ndarray, - target_q_fn: Callable[[ReplayBuffer, np.ndarray], torch.Tensor], + gamma: float = 0.99, ) -> Batch: + rew = batch.rew with torch.no_grad(): - target_q_torch = target_q_fn(buffer, indice) # (bsz, ?) + target_q_torch = self._target_q(batch) # (bsz, ?) target_q = to_numpy(target_q_torch) - target_q = target_q * BasePolicy.value_mask(buffer, indice).reshape(-1, 1, 1) end_flag = buffer.done.copy() end_flag[buffer.unfinished_index()] = True - + end_flag = end_flag[indice] + _target_q = rew + gamma * np.mean(target_q, -1) * (1 - end_flag) + target_q = np.repeat(_target_q[..., None], target_q.shape[-1], axis=-1) + target_q = np.repeat(target_q[..., None], self.max_action_num, axis=-1) + batch.returns = to_torch_as(target_q, target_q_torch) if hasattr(batch, "weight"): # prio buffer update batch.weight = to_torch_as(batch.weight, target_q_torch) @@ -111,26 +106,14 @@ def _compute_return( def process_fn( self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray ) -> Batch: - """Compute the n-step return for Q-learning targets. + """Compute the return for BDQ targets. - More details can be found at - :meth:`~tianshou.policy.BasePolicy.compute_nstep_return`. """ batch = self._compute_return( - batch, buffer, indices, self._target_q + batch, buffer, indices ) return batch - def compute_q_value( - self, logits: torch.Tensor, mask: Optional[np.ndarray] - ) -> torch.Tensor: - """Compute the q value based on the network's raw output and action mask.""" - if mask is not None: - # the masked q value should be smaller than logits.min() - min_value = logits.min() - logits.max() - 1.0 - logits = logits + to_torch_as(1 - mask, logits) * min_value - return logits - def forward( self, batch: Batch, @@ -141,20 +124,6 @@ def forward( ) -> Batch: """Compute action over the given batch data. - If you need to mask the action, please add a "mask" into batch.obs, for - example, if we have an environment that has "0/1/2" three actions: - :: - - batch == Batch( - obs=Batch( - obs="original obs, with batch_size=1 for demonstration", - mask=np.array([[False, True, False]]), - # action 1 is available - # action 0 and 2 are unavailable - ), - ... - ) - :param float eps: in [0, 1], for epsilon-greedy exploration method. :return: A :class:`~tianshou.data.Batch` which has 3 keys: @@ -172,10 +141,11 @@ def forward( obs = batch[input] obs_next = obs.obs if hasattr(obs, "obs") else obs logits, hidden = model(obs_next, state=state, info=batch.info) - q = self.compute_q_value(logits, getattr(obs, "mask", None)) if not hasattr(self, "max_action_num"): - self.max_action_num = q.shape[1] - act = to_numpy(q.max(dim=-1)[1].squeeze()) + self.max_action_num = logits.shape[-1] + act = to_numpy(logits.max(dim=-1)[1].squeeze()) + if len(act.shape) == 1: + act = np.expand_dims(act, 0) return Batch(logits=logits, act=act, state=hidden) def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: @@ -183,12 +153,16 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self.sync_weight() self.optim.zero_grad() weight = batch.pop("weight", 1.0) + act = torch.tensor(batch.act).to(batch.returns.get_device()) q = self(batch).logits - q = q[np.arange(q.shape[0]), np.arange(q.shape[1]), batch.act] - returns = to_torch_as(batch.returns.flatten(), q) - td_error = returns - q - loss = (td_error.pow(2) * weight).mean() - batch.weight = td_error # prio-buffer + act_mask = torch.zeros_like(q) + act_mask = act_mask.scatter_(-1, act.unsqueeze(-1), 1) + act_q = q * act_mask + returns = batch.returns + returns = returns * act_mask + td_error = (returns - act_q) + loss = (td_error.pow(2).sum(-1).mean(-1) * weight).mean() + batch.weight = td_error.sum(-1).sum(-1) # prio-buffer loss.backward() self.optim.step() self._iter += 1 @@ -197,11 +171,16 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: def exploration_noise(self, act: Union[np.ndarray, Batch], batch: Batch) -> Union[np.ndarray, Batch]: if isinstance(act, np.ndarray) and not np.isclose(self.eps, 0.0): + if len(act.shape) == 1: + act = np.expand_dims(act, 0) bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps - q = np.random.rand(bsz, self.max_action_num) # [0, 1] + rand_act = np.random.randint( + 0, self.max_action_num, (bsz, act.shape[-1])) # [0, 1] if hasattr(batch.obs, "mask"): - q += batch.obs.mask - rand_act = q.argmax(axis=1) + rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] - return act \ No newline at end of file + return act + + def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: + return act diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 3b9611dfc..5694d2e39 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -257,17 +257,17 @@ def forward( obs = obs.unsqueeze(-2) obs = self.fc1(obs) self.nn.flatten_parameters() - if state is None: - obs, (hidden, cell) = self.nn(obs) - else: - # we store the stack data in [bsz, len, ...] format - # but pytorch rnn needs [len, bsz, ...] - obs, (hidden, cell) = self.nn( - obs, ( - state["hidden"].transpose(0, 1).contiguous(), - state["cell"].transpose(0, 1).contiguous() - ) - ) + # if state is None: + obs, (hidden, cell) = self.nn(obs) + # else: + # # we store the stack data in [bsz, len, ...] format + # # but pytorch rnn needs [len, bsz, ...] + # obs, (hidden, cell) = self.nn( + # obs, ( + # state["hidden"].transpose(0, 1).contiguous(), + # state["cell"].transpose(0, 1).contiguous() + # ) + # ) obs = self.fc2(obs[:, -1]) # please ensure the first dim is batch size: [bsz, len, ...] return obs, { @@ -314,22 +314,46 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, class BDQNet(nn.Module): """Branching dual Q network + + Network for the BDQPolicy, it uses a common network module, a value module and action "branches" one for each dimension. + It allows for a linear scaling of Q-value the output w.r.t. the number of dimensions in the action space. + For more info please refer to: arXiv:1711.08946 + + :param state_shape: int or a sequence of int of the shape of state. + :param action_shape: int or a sequence of int of the shape of action. + :param action_peer_branch: int or a sequence of int of the number of actions in each dimension. + :param common_hidden_sizes: shape of the common MLP network passed in as a list. + :param value_hidden_sizes: shape of the value MLP network passed in as a list. + :param action_hidden_sizes: shape of the action MLP network passed in as a list. + :param norm_layer: use which normalization before activation, e.g., + ``nn.LayerNorm`` and ``nn.BatchNorm1d``. Default to no normalization. + You can also pass a list of normalization modules with the same length + of hidden_sizes, to use different normalization module in different + layers. Default to no normalization. + :param activation: which activation to use after each layer, can be both + the same activation for all layers if passed in nn.Module, or different + activation for different Modules if passed in a list. Default to + nn.ReLU. + :param device: specify the device when the network actually runs. Default + to "cpu". + :param bool softmax: whether to apply a softmax layer over the last layer's + output. """ def __init__( self, state_shape: Union[int, Sequence[int]], action_shape: Union[int, Sequence[int]] = 0, action_per_branch: Union[int, Sequence[int]] = 1, - common_hidden_sizes: Sequence[int] = (), - value_hidden_sizes: Sequence[int] = (), - action_hidden_sizes: Sequence[int] = (), + common_hidden_sizes: list[int] = (), + value_hidden_sizes: list[int] = (), + action_hidden_sizes: list[int] = (), norm_layer: Optional[ModuleType] = None, activation: Optional[ModuleType] = nn.ReLU, device: Union[str, int, torch.device] = "cpu", ) -> None: super().__init__() self.device = device - self.num_branches = action_shape + self.num_branches = action_shape[0] self.action_per_branch = action_per_branch # common network common_input_dim = int(np.prod(state_shape)) @@ -350,7 +374,7 @@ def forward( state: Any = None, info: Dict[str, Any] = {}, ) -> Tuple[torch.Tensor, Any]: - """Mapping: obs -> flatten (inside MLP)-> logits.""" + """Mapping: obs -> model -> logits.""" common_out = self.common(obs) value_out = self.value(common_out) value_out = torch.unsqueeze(value_out, 1) From c4f1d21e6699b5fab00033a89345fd3807205ef2 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Mon, 4 Apr 2022 17:19:42 +0200 Subject: [PATCH 08/47] Add bdq to policy package --- tianshou/policy/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tianshou/policy/__init__.py b/tianshou/policy/__init__.py index ced11aff5..17aea9138 100644 --- a/tianshou/policy/__init__.py +++ b/tianshou/policy/__init__.py @@ -4,6 +4,7 @@ from tianshou.policy.base import BasePolicy from tianshou.policy.random import RandomPolicy from tianshou.policy.modelfree.dqn import DQNPolicy +from tianshou.policy.modelfree.bdq import BDQPolicy from tianshou.policy.modelfree.c51 import C51Policy from tianshou.policy.modelfree.rainbow import RainbowPolicy from tianshou.policy.modelfree.qrdqn import QRDQNPolicy From 64e1c3fb2000f3446a3411306bbfcba72986ef9e Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 11:39:17 +0200 Subject: [PATCH 09/47] Change some training parameters --- examples/box2d/bdq_train.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_train.py index 010ee6625..50949d3e9 100644 --- a/examples/box2d/bdq_train.py +++ b/examples/box2d/bdq_train.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -37,22 +38,22 @@ def get_args(): parser.add_argument('--common_hidden-sizes', type=int, nargs='*', default=[512, 256]) parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--action_per_brach', type=int, default=32) + parser.add_argument('--action_per_branch', type=int, default=32) # training hyperparameters parser.add_argument('--seed', type=int, default=0) parser.add_argument('--eps-test', type=float, default=0.) parser.add_argument('--eps-train', type=float, default=0.73) parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=2e-5) + parser.add_argument('--lr', type=float, default=5e-5) parser.add_argument('--gamma', type=float, default=0.99) parser.add_argument('--target-update-freq', type=int, default=1000) parser.add_argument('--epoch', type=int, default=100) parser.add_argument('--step-per-epoch', type=int, default=80000) parser.add_argument('--step-per-collect', type=int, default=16) parser.add_argument('--update-per-step', type=float, default=0.0625) - parser.add_argument('--batch-size', type=int, default=512) - parser.add_argument('--training-num', type=int, default=16) - parser.add_argument('--test-num', type=int, default=100) + parser.add_argument('--batch-size', type=int, default=128) + parser.add_argument('--training-num', type=int, default=100) + parser.add_argument('--test-num', type=int, default=10) # other parser.add_argument('--logdir', type=str, default='log') parser.add_argument('--render', type=float, default=0.) @@ -62,7 +63,7 @@ def get_args(): return parser.parse_args() -def test_dqn(args=get_args()): +def test_bdq(args=get_args()): if args.task == 'Humanoid-v3': args.reward_treshold = 3000 @@ -78,12 +79,12 @@ def test_dqn(args=get_args()): # train_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) # you can also use tianshou.env.SubprocVectorEnv - train_envs = DummyVectorEnv( + train_envs = SubprocVectorEnv( [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num)] ) # test_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) test_envs = SubprocVectorEnv( - [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num)] + [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.test_num)] ) # seed np.random.seed(args.seed) @@ -114,11 +115,12 @@ def test_dqn(args=get_args()): VectorReplayBuffer(args.buffer_size, len(train_envs)), exploration_noise=True ) - test_collector = Collector(policy, test_envs, exploration_noise=True) + test_collector = Collector(policy, test_envs, exploration_noise=False) # policy.set_eps(1) train_collector.collect(n_step=args.batch_size * args.training_num) # log - log_path = os.path.join(args.logdir, args.task, 'bdq_lr2e-5') + current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + log_path = os.path.join(args.logdir, 'bdq', args.task, current_time) writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) @@ -167,4 +169,4 @@ def test_fn(epoch, env_step): if __name__ == '__main__': - test_dqn(get_args()) + test_bdq(get_args()) From da59357b5d482356c9e7f49b1de6da955e895578 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 11:45:50 +0200 Subject: [PATCH 10/47] Deleted test_d4rl.py file that was commited by mistake --- examples/offline/test_d4rl.py | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 examples/offline/test_d4rl.py diff --git a/examples/offline/test_d4rl.py b/examples/offline/test_d4rl.py deleted file mode 100644 index ca47615d4..000000000 --- a/examples/offline/test_d4rl.py +++ /dev/null @@ -1,5 +0,0 @@ -import d4rl -import gym - -env = gym.make("halfcheetah-medium-v1") -dataset = d4rl.qlearning_dataset(env) \ No newline at end of file From b3e582b34334d9b6dd9f31bb4052df64be87ebfc Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 11:48:16 +0200 Subject: [PATCH 11/47] Documents formated with yapf --- examples/box2d/bdq_train.py | 38 ++++++++++++++++++---------- test/continuous/test_ddpg.py | 6 ++++- test/continuous/test_npg.py | 6 ++++- test/continuous/test_ppo.py | 6 ++++- test/continuous/test_sac_with_il.py | 6 ++++- test/continuous/test_td3.py | 6 ++++- test/continuous/test_trpo.py | 6 ++++- test/modelbased/test_psrl.py | 6 ++++- test/offline/gather_cartpole_data.py | 10 ++++++-- test/offline/gather_pendulum_data.py | 6 ++++- test/offline/test_bcq.py | 8 ++++-- test/offline/test_cql.py | 6 ++++- test/offline/test_discrete_bcq.py | 6 ++++- test/offline/test_discrete_cql.py | 10 ++++++-- test/offline/test_discrete_crr.py | 6 ++++- tianshou/env/gym_wrappers.py | 6 +++-- tianshou/policy/modelfree/bdq.py | 11 ++++---- tianshou/utils/net/common.py | 25 ++++++++++++++---- 18 files changed, 131 insertions(+), 43 deletions(-) diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_train.py index 50949d3e9..05a23458e 100644 --- a/examples/box2d/bdq_train.py +++ b/examples/box2d/bdq_train.py @@ -15,7 +15,9 @@ from tianshou.utils import TensorboardLogger from tianshou.utils.net.common import BDQNet + class DiscreteToContinuous(gym.ActionWrapper): + def __init__(self, env, action_per_branch): super().__init__(env) self.action_per_branch = action_per_branch @@ -24,18 +26,21 @@ def __init__(self, env, action_per_branch): self.mesh = [] for l, h in zip(low, high): self.mesh.append(np.linspace(l, h, action_per_branch)) - + def action(self, act): # modify act act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) return act - + + def get_args(): parser = argparse.ArgumentParser() # task parser.add_argument('--task', type=str, default='BipedalWalker-v3') # network architecture - parser.add_argument('--common_hidden-sizes', type=int, nargs='*', default=[512, 256]) + parser.add_argument( + '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] + ) parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) parser.add_argument('--action_per_branch', type=int, default=32) @@ -66,25 +71,31 @@ def get_args(): def test_bdq(args=get_args()): if args.task == 'Humanoid-v3': args.reward_treshold = 3000 - + env = gym.make(args.task) env = DiscreteToContinuous(env, args.action_per_branch) - + args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n - + print("Observations shape:", args.state_shape) print("Actions shape:", args.action_shape) print("Actions per branch:", args.action_per_branch) - + # train_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) # you can also use tianshou.env.SubprocVectorEnv train_envs = SubprocVectorEnv( - [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num)] + [ + lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + for _ in range(args.training_num) + ] ) # test_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) test_envs = SubprocVectorEnv( - [lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) for _ in range(args.test_num)] + [ + lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + for _ in range(args.test_num) + ] ) # seed np.random.seed(args.seed) @@ -103,10 +114,7 @@ def test_bdq(args=get_args()): ).to(args.device) optim = torch.optim.Adam(net.parameters(), lr=args.lr) policy = BDQPolicy( - net, - optim, - args.gamma, - target_update_freq=args.target_update_freq + net, optim, args.gamma, target_update_freq=args.target_update_freq ) # collector train_collector = Collector( @@ -128,7 +136,9 @@ def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= getattr(env, "spec.reward_threshold", args.reward_treshold) + return mean_rewards >= getattr( + env, "spec.reward_threshold", args.reward_treshold + ) def train_fn(epoch, env_step): # exp decay eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index 122fc73a7..33f0ea4ee 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -54,7 +54,11 @@ def test_ddpg(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/continuous/test_npg.py b/test/continuous/test_npg.py index d22bb46d0..b3f7add05 100644 --- a/test/continuous/test_npg.py +++ b/test/continuous/test_npg.py @@ -57,7 +57,11 @@ def test_npg(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/continuous/test_ppo.py b/test/continuous/test_ppo.py index b876a7f43..dc1227ab6 100644 --- a/test/continuous/test_ppo.py +++ b/test/continuous/test_ppo.py @@ -61,7 +61,11 @@ def test_ppo(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index cf3fa2791..e8885e9c6 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -67,7 +67,11 @@ def test_sac_with_il(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # seed diff --git a/test/continuous/test_td3.py b/test/continuous/test_td3.py index ab9742526..dc3e47e18 100644 --- a/test/continuous/test_td3.py +++ b/test/continuous/test_td3.py @@ -57,7 +57,11 @@ def test_td3(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/continuous/test_trpo.py b/test/continuous/test_trpo.py index 818ae9283..89fc042c6 100644 --- a/test/continuous/test_trpo.py +++ b/test/continuous/test_trpo.py @@ -60,7 +60,11 @@ def test_trpo(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/modelbased/test_psrl.py b/test/modelbased/test_psrl.py index e4bf9f6be..ca80ee780 100644 --- a/test/modelbased/test_psrl.py +++ b/test/modelbased/test_psrl.py @@ -46,7 +46,11 @@ def test_psrl(args=get_args()): ) test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) print("reward threshold:", args.reward_threshold) args.state_shape = env.observation_space.shape or env.observation_space.n diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index ac2477a30..e34fb31fd 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -61,8 +61,14 @@ def gather_data(): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 190, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.task) # lower the goal? + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 190, + "NChain-v0": 3400 + } + args.reward_threshold = default_reward_threshold.get( + args.task + ) # lower the goal? # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index 67920183f..cd7b943ba 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -70,7 +70,11 @@ def gather_data(): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 38965b9cc..5bec8fc4d 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -75,8 +75,12 @@ def test_bcq(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} - args.reward_threshold = default_reward_threshold.get(args.task) # too low? + default_reward_threshold = { + "Pendulum-v1": -1100, + "CartPole-v0": 195, + "NChain-v0": 3400 + } + args.reward_threshold = default_reward_threshold.get(args.task) # too low? args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index b4da5e171..0c9f63af1 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -80,7 +80,11 @@ def test_cql(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-1100, "CartPole-v0": 195, "NChain-v0": 3400} # too low? + default_reward_threshold = { + "Pendulum-v1": -1100, + "CartPole-v0": 195, + "NChain-v0": 3400 + } # too low? args.reward_threshold = default_reward_threshold.get(args.task) args.state_dim = args.state_shape[0] diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index add4bc02f..138d2d99c 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -62,7 +62,11 @@ def test_discrete_bcq(args=get_args()): [lambda: gym.make(args.task) for _ in range(args.test_num)] ) if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 195, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 195, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) # seed np.random.seed(args.seed) diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index d7a5fb921..cbbc8225d 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -24,7 +24,9 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=None) # lower the goal + parser.add_argument( + '--reward_threshold', type=float, default=None + ) # lower the goal parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-3) @@ -56,7 +58,11 @@ def test_discrete_cql(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 170, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 170, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index a01f10967..c62d5a8df 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -54,7 +54,11 @@ def test_discrete_crr(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = {"Pendulum-v1":-250, "CartPole-v0": 180, "NChain-v0": 3400} + default_reward_threshold = { + "Pendulum-v1": -250, + "CartPole-v0": 180, + "NChain-v0": 3400 + } args.reward_threshold = default_reward_threshold.get(args.task) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 4cfcc798d..8e29982c1 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -1,6 +1,7 @@ import gym import numpy as np + class DiscreteToContinuous(gym.ActionWrapper): """Gym environment wrapper to take discrete action in a continous environment @@ -8,6 +9,7 @@ class DiscreteToContinuous(gym.ActionWrapper): env (gym.Environment): gym envirionment with continous action space action_per_branch (int): number of discrete actions in each dimension of the action space """ + def __init__(self, env, action_per_branch): super().__init__(env) self.action_per_branch = action_per_branch @@ -16,8 +18,8 @@ def __init__(self, env, action_per_branch): self.mesh = [] for l, h in zip(low, high): self.mesh.append(np.linspace(l, h, action_per_branch)) - + def action(self, act): # modify act act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) - return act \ No newline at end of file + return act diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index defd44ba6..562e654ac 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -76,7 +76,9 @@ def _target_q(self, batch: Batch) -> torch.Tensor: target_q = result.logits if self._is_double: act = self(batch, input="obs_next").act - return np.squeeze(np.take_along_axis(target_q, np.expand_dims(act, -1), -1)) + return np.squeeze( + np.take_along_axis(target_q, np.expand_dims(act, -1), -1) + ) else: # Nature DQN, over estimate return NotImplementedError @@ -109,9 +111,7 @@ def process_fn( """Compute the return for BDQ targets. """ - batch = self._compute_return( - batch, buffer, indices - ) + batch = self._compute_return(batch, buffer, indices) return batch def forward( @@ -176,7 +176,8 @@ def exploration_noise(self, act: Union[np.ndarray, Batch], bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps rand_act = np.random.randint( - 0, self.max_action_num, (bsz, act.shape[-1])) # [0, 1] + 0, self.max_action_num, (bsz, act.shape[-1]) + ) # [0, 1] if hasattr(batch.obs, "mask"): rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 5694d2e39..b79f3f481 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -312,6 +312,7 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, obs = torch.as_tensor(obs, dtype=torch.float32) return self.net(obs=obs.cuda(), *args, **kwargs) + class BDQNet(nn.Module): """Branching dual Q network @@ -339,6 +340,7 @@ class BDQNet(nn.Module): :param bool softmax: whether to apply a softmax layer over the last layer's output. """ + def __init__( self, state_shape: Union[int, Sequence[int]], @@ -358,16 +360,29 @@ def __init__( # common network common_input_dim = int(np.prod(state_shape)) common_output_dim = 0 - self.common = MLP(common_input_dim, common_output_dim, common_hidden_sizes, norm_layer, activation, device) + self.common = MLP( + common_input_dim, common_output_dim, common_hidden_sizes, norm_layer, + activation, device + ) # value network value_input_dim = common_hidden_sizes[-1] value_output_dim = 1 - self.value = MLP(value_input_dim, value_output_dim, value_hidden_sizes, norm_layer, activation, device) + self.value = MLP( + value_input_dim, value_output_dim, value_hidden_sizes, norm_layer, + activation, device + ) # action branching network action_input_dim = common_hidden_sizes[-1] action_output_dim = action_per_branch - self.branches = nn.ModuleList([MLP(action_input_dim, action_output_dim, action_hidden_sizes, norm_layer, activation, device) for _ in range(self.num_branches)]) - + self.branches = nn.ModuleList( + [ + MLP( + action_input_dim, action_output_dim, action_hidden_sizes, + norm_layer, activation, device + ) for _ in range(self.num_branches) + ] + ) + def forward( self, obs: Union[np.ndarray, torch.Tensor], @@ -384,4 +399,4 @@ def forward( action_scores = torch.stack(action_out, 1) action_scores = action_scores - torch.mean(action_scores, 2, keepdim=True) logits = value_out + action_scores - return logits, state \ No newline at end of file + return logits, state From 250ac5cec2ee60dd94f0480b245bf48efbde11ba Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 14:15:33 +0200 Subject: [PATCH 12/47] Pass tianshou contrib requirements --- examples/box2d/bdq_train.py | 21 +---- test/discrete/test_bdq.py | 150 +++++++++++++++++++++++++++++++ tianshou/env/__init__.py | 9 +- tianshou/env/gym_wrappers.py | 20 +++-- tianshou/policy/__init__.py | 1 + tianshou/policy/modelfree/bdq.py | 15 ++-- tianshou/utils/net/common.py | 15 ++-- 7 files changed, 183 insertions(+), 48 deletions(-) create mode 100644 test/discrete/test_bdq.py diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_train.py index 05a23458e..22493623a 100644 --- a/examples/box2d/bdq_train.py +++ b/examples/box2d/bdq_train.py @@ -9,34 +9,17 @@ from torch.utils.tensorboard import SummaryWriter from tianshou.data import Collector, PrioritizedVectorReplayBuffer, VectorReplayBuffer -from tianshou.env import DummyVectorEnv, SubprocVectorEnv +from tianshou.env import DiscreteToContinuous, DummyVectorEnv, SubprocVectorEnv from tianshou.policy import BDQPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils import TensorboardLogger from tianshou.utils.net.common import BDQNet -class DiscreteToContinuous(gym.ActionWrapper): - - def __init__(self, env, action_per_branch): - super().__init__(env) - self.action_per_branch = action_per_branch - low = self.action_space.low - high = self.action_space.high - self.mesh = [] - for l, h in zip(low, high): - self.mesh.append(np.linspace(l, h, action_per_branch)) - - def action(self, act): - # modify act - act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) - return act - - def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument('--task', type=str, default='BipedalWalker-v3') + parser.add_argument('--task', type=str, default='BipedalWalkerHardcore-v3') # network architecture parser.add_argument( '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py new file mode 100644 index 000000000..5df1e6d60 --- /dev/null +++ b/test/discrete/test_bdq.py @@ -0,0 +1,150 @@ +import argparse +import datetime +import os +import pprint + +import gym +import numpy as np +import torch + +from tianshou.data import Collector, VectorReplayBuffer +from tianshou.env import DiscreteToContinuous, SubprocVectorEnv +from tianshou.policy import BDQPolicy +from tianshou.trainer import offpolicy_trainer +from tianshou.utils.net.common import BDQNet + + +def get_args(): + parser = argparse.ArgumentParser() + # task + parser.add_argument('--task', type=str, default='BipedalWalker-v3') + # network architecture + parser.add_argument( + '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] + ) + parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) + parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) + parser.add_argument('--action_per_branch', type=int, default=32) + # training hyperparameters + parser.add_argument('--seed', type=int, default=1626) + parser.add_argument('--eps-test', type=float, default=0.05) + parser.add_argument('--eps-train', type=float, default=0.1) + parser.add_argument('--buffer-size', type=int, default=20000) + parser.add_argument('--lr', type=float, default=1e-3) + parser.add_argument('--gamma', type=float, default=0.9) + parser.add_argument('--n-step', type=int, default=3) + parser.add_argument('--target-update-freq', type=int, default=320) + parser.add_argument('--epoch', type=int, default=20) + parser.add_argument('--step-per-epoch', type=int, default=10000) + parser.add_argument('--step-per-collect', type=int, default=10) + parser.add_argument('--update-per-step', type=float, default=0.1) + parser.add_argument('--batch-size', type=int, default=64) + parser.add_argument('--training-num', type=int, default=10) + parser.add_argument('--test-num', type=int, default=100) + parser.add_argument('--logdir', type=str, default='log') + parser.add_argument('--render', type=float, default=0.) + parser.add_argument('--prioritized-replay', action="store_true", default=False) + parser.add_argument('--alpha', type=float, default=0.6) + parser.add_argument('--beta', type=float, default=0.4) + parser.add_argument( + '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + ) + args = parser.parse_known_args()[0] + return args + return parser.parse_args() + + +def test_bdq(args=get_args()): + if args.task == 'Humanoid-v3': + args.reward_treshold = 3000 + + env = gym.make(args.task) + env = DiscreteToContinuous(env, args.action_per_branch) + + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + + print("Observations shape:", args.state_shape) + print("Actions shape:", args.action_shape) + print("Actions per branch:", args.action_per_branch) + + train_envs = SubprocVectorEnv( + [ + lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + for _ in range(args.training_num) + ] + ) + test_envs = SubprocVectorEnv( + [ + lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + for _ in range(args.test_num) + ] + ) + + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + train_envs.seed(args.seed) + test_envs.seed(args.seed) + # model + net = BDQNet( + args.state_shape, + args.action_shape, + args.action_per_branch, + args.common_hidden_sizes, + args.value_hidden_sizes, + args.action_hidden_sizes, + device=args.device, + ).to(args.device) + optim = torch.optim.Adam(net.parameters(), lr=args.lr) + policy = BDQPolicy( + net, optim, args.gamma, target_update_freq=args.target_update_freq + ) + # collector + train_collector = Collector( + policy, + train_envs, + VectorReplayBuffer(args.buffer_size, args.training_num), + exploration_noise=True + ) + test_collector = Collector(policy, test_envs, exploration_noise=False) + # policy.set_eps(1) + train_collector.collect(n_step=args.batch_size * args.training_num) + + def train_fn(epoch, env_step): # exp decay + eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) + policy.set_eps(eps) + + def test_fn(epoch, env_step): + policy.set_eps(args.eps_test) + + # trainer + result = offpolicy_trainer( + policy, + train_collector, + test_collector, + args.epoch, + args.step_per_epoch, + args.step_per_collect, + args.test_num, + args.batch_size, + update_per_step=args.update_per_step, + train_fn=train_fn, + test_fn=test_fn, + ) + + # assert stop_fn(result['best_reward']) + if __name__ == '__main__': + pprint.pprint(result) + # Let's watch its performance! + policy.eval() + policy.set_eps(args.eps_test) + test_envs.seed(args.seed) + test_collector.reset() + result = test_collector.collect(n_episode=args.test_num, render=args.render) + rews, lens = result["rews"], result["lens"] + print(f"Final reward: {rews.mean()}, length: {lens.mean()}") + + +if __name__ == '__main__': + test_bdq(get_args()) diff --git a/tianshou/env/__init__.py b/tianshou/env/__init__.py index 3845f2691..f72181535 100644 --- a/tianshou/env/__init__.py +++ b/tianshou/env/__init__.py @@ -1,5 +1,6 @@ """Env package.""" +from tianshou.env.gym_wrappers import DiscreteToContinuous from tianshou.env.venvs import ( BaseVectorEnv, DummyVectorEnv, @@ -14,10 +15,6 @@ pass __all__ = [ - "BaseVectorEnv", - "DummyVectorEnv", - "SubprocVectorEnv", - "ShmemVectorEnv", - "RayVectorEnv", - "PettingZooEnv", + "BaseVectorEnv", "DummyVectorEnv", "SubprocVectorEnv", "ShmemVectorEnv", + "RayVectorEnv", "PettingZooEnv", "DiscreteToContinuous" ] diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 8e29982c1..e8692532e 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -3,23 +3,29 @@ class DiscreteToContinuous(gym.ActionWrapper): - """Gym environment wrapper to take discrete action in a continous environment + """Gym environment wrapper to take discrete action in a continous environment. Args: - env (gym.Environment): gym envirionment with continous action space - action_per_branch (int): number of discrete actions in each dimension of the action space + env (gym.Environment): gym envirionment with continous action space. + action_per_branch (int): number of discrete actions in each dimension of the action space. + """ - def __init__(self, env, action_per_branch): + def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) self.action_per_branch = action_per_branch - low = self.action_space.low - high = self.action_space.high + low = env.action_space.low + high = env.action_space.high + num_branches = env.action_space.shape[0] + self.action_space = gym.spaces.MultiDiscrete( + [action_per_branch] * num_branches + ) + setattr(self.action_space, "n", num_branches) self.mesh = [] for l, h in zip(low, high): self.mesh.append(np.linspace(l, h, action_per_branch)) - def action(self, act): + def action(self, act: np.ndarray) -> np.ndarray: # modify act act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) return act diff --git a/tianshou/policy/__init__.py b/tianshou/policy/__init__.py index 17aea9138..7417f29b8 100644 --- a/tianshou/policy/__init__.py +++ b/tianshou/policy/__init__.py @@ -33,6 +33,7 @@ "BasePolicy", "RandomPolicy", "DQNPolicy", + "BDQPolicy", "C51Policy", "RainbowPolicy", "QRDQNPolicy", diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 562e654ac..c3c8adbf7 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -9,7 +9,7 @@ class BDQPolicy(BasePolicy): - """Implementation of the branching dueling network arXiv:1711.08946 + """Implementation of the Branching dual Q network arXiv:1711.08946. :param torch.nn.Module model: a model following the rules in :class:`~tianshou.policy.BasePolicy`. (s -> logits) @@ -76,11 +76,10 @@ def _target_q(self, batch: Batch) -> torch.Tensor: target_q = result.logits if self._is_double: act = self(batch, input="obs_next").act - return np.squeeze( - np.take_along_axis(target_q, np.expand_dims(act, -1), -1) - ) - else: # Nature DQN, over estimate - return NotImplementedError + else: + act = target_q.max(dim=-1).indices.cpu() + + return np.squeeze(np.take_along_axis(target_q, np.expand_dims(act, -1), -1)) def _compute_return( self, @@ -108,9 +107,7 @@ def _compute_return( def process_fn( self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray ) -> Batch: - """Compute the return for BDQ targets. - - """ + """Compute the return for BDQ targets.""" batch = self._compute_return(batch, buffer, indices) return batch diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index b79f3f481..8cae5726c 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -314,11 +314,11 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, class BDQNet(nn.Module): - """Branching dual Q network + """Branching dual Q network. Network for the BDQPolicy, it uses a common network module, a value module and action "branches" one for each dimension. It allows for a linear scaling of Q-value the output w.r.t. the number of dimensions in the action space. - For more info please refer to: arXiv:1711.08946 + For more info please refer to: arXiv:1711.08946. :param state_shape: int or a sequence of int of the shape of state. :param action_shape: int or a sequence of int of the shape of action. @@ -345,17 +345,18 @@ def __init__( self, state_shape: Union[int, Sequence[int]], action_shape: Union[int, Sequence[int]] = 0, - action_per_branch: Union[int, Sequence[int]] = 1, - common_hidden_sizes: list[int] = (), - value_hidden_sizes: list[int] = (), - action_hidden_sizes: list[int] = (), + action_per_branch: int = 2, + common_hidden_sizes: list[int] = [], + value_hidden_sizes: list[int] = [], + action_hidden_sizes: list[int] = [], norm_layer: Optional[ModuleType] = None, activation: Optional[ModuleType] = nn.ReLU, device: Union[str, int, torch.device] = "cpu", ) -> None: super().__init__() self.device = device - self.num_branches = action_shape[0] + self.num_branches = action_shape if type(action_shape + ) is int else action_shape[0] self.action_per_branch = action_per_branch # common network common_input_dim = int(np.prod(state_shape)) From 6542e8805d576dc0908b325b686ee47925739321 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 20:22:52 +0200 Subject: [PATCH 13/47] Fixed merge conflicts --- draft.ipynb | 224 ----------------------------------- test/continuous/test_ddpg.py | 16 +-- 2 files changed, 3 insertions(+), 237 deletions(-) delete mode 100644 draft.ipynb diff --git a/draft.ipynb b/draft.ipynb deleted file mode 100644 index 28674ce5f..000000000 --- a/draft.ipynb +++ /dev/null @@ -1,224 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "import gym\n", - "import numpy as np\n", - "from torchsummary import summary\n", - "from tianshou.utils.net.common import BDQNet" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "class DiscreteToContinuous(gym.ActionWrapper):\n", - " def __init__(self, env, action_per_branch):\n", - " super().__init__(env)\n", - " self.action_per_branch = action_per_branch\n", - " low = self.action_space.low\n", - " high = self.action_space.high\n", - " self.mesh = []\n", - " for l, h in zip(low, high):\n", - " self.mesh.append(np.linspace(l, h, action_per_branch))\n", - " \n", - " def action(self, act):\n", - " # modify act\n", - " act = np.array([self.mesh[i][a] for i, a in enumerate(act)])\n", - " return act" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "env = DiscreteToContinuous(gym.make('BipedalWalker-v3'), action_per_branch=2)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "state_shape = env.observation_space.shape[0]\n", - "action_shape = env.action_space.shape[0]\n", - "action_per_branch = env.action_per_branch\n", - "common_hidden_sizes = [512, 256]\n", - "value_hidden_sizes = [128]\n", - "action_hidden_sizes = [128]" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "model = BDQNet(state_shape,\n", - " action_shape,\n", - " action_per_branch,\n", - " common_hidden_sizes,\n", - " value_hidden_sizes,\n", - " action_hidden_sizes)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([1, 4, 2])" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import torch\n", - "\n", - "x = torch.randn(state_shape).unsqueeze(0)\n", - "y = model(x)\n", - "y[0].shape" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[0, 0, 1, 0]])" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[0].max(dim=-1)[1]" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([1, 4, 2])" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[0].shape" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(y[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[0]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[0]],\n", - "\n", - " [[0]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]]])" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.random.randint(0, 2, 10)\n", - "a.reshape(-1, 1, 1)" - ] - } - ], - "metadata": { - "interpreter": { - "hash": "f3d922253121c31a7b24bed1c151b936757524923ac49fbc20420da76bf88248" - }, - "kernelspec": { - "display_name": "Python 3.9.10 ('tianshou')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.10" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index 5355d965f..33f0ea4ee 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -20,11 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') -<<<<<<< HEAD parser.add_argument('--reward_threshold', type=float, default=None) -======= - parser.add_argument('--reward-threshold', type=float, default=None) ->>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -52,24 +48,18 @@ def get_args(): def test_ddpg(args=get_args()): + torch.set_num_threads(1) # we just need only one thread for NN env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: -<<<<<<< HEAD default_reward_threshold = { "Pendulum-v1": -250, "CartPole-v0": 195, "NChain-v0": 3400 } args.reward_threshold = default_reward_threshold.get(args.task) -======= - default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} - args.reward_threshold = default_reward_threshold.get( - args.task, env.spec.reward_threshold - ) ->>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -124,7 +114,7 @@ def test_ddpg(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_best_fn(policy): + def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -142,7 +132,7 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_best_fn=save_best_fn, + save_fn=save_fn, logger=logger ) assert stop_fn(result['best_reward']) From 1d1ec6f585ebaf10daf724545d5fba5028c14528 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 20:24:52 +0200 Subject: [PATCH 14/47] Merge commit '6542e8805d576dc0908b325b686ee47925739321' --- .github/ISSUE_TEMPLATE.md | 4 +- LICENSE | 2 +- Makefile | 14 +- README.md | 5 +- docs/_static/js/benchmark.js | 83 +- docs/api/tianshou.policy.rst | 5 + docs/api/tianshou.trainer.rst | 44 +- docs/index.rst | 4 +- docs/spelling_wordlist.txt | 17 + docs/tutorials/benchmark.rst | 126 ++- docs/tutorials/concepts.rst | 20 + docs/tutorials/get_started.rst | 13 + docs/tutorials/logger.rst | 4 + docs/tutorials/tictactoe.rst | 903 +++++++++--------- draft.ipynb | 224 ----- examples/atari/README.md | 2 +- examples/atari/atari_c51.py | 104 +- examples/atari/atari_dqn.py | 113 ++- examples/atari/atari_fqf.py | 108 ++- examples/atari/atari_iqn.py | 108 ++- examples/atari/atari_ppo.py | 127 +-- examples/atari/atari_qrdqn.py | 100 +- examples/atari/atari_rainbow.py | 124 ++- .../BreakoutNoFrameskip-v4/result.json | 1 + .../EnduroNoFrameskip-v4/result.json | 1 + .../MsPacmanNoFrameskip-v4/result.json | 1 + .../benchmark/PongNoFrameskip-v4/result.json | 1 + .../benchmark/QbertNoFrameskip-v4/result.json | 1 + .../SeaquestNoFrameskip-v4/result.json | 1 + .../SpaceInvadersNoFrameskip-v4/result.json | 1 + examples/box2d/acrobot_dualdqn.py | 4 +- examples/box2d/bipedal_hardcore_sac.py | 4 +- examples/box2d/lunarlander_dqn.py | 4 +- examples/box2d/mcc_sac.py | 4 +- examples/inverse/README.md | 27 + examples/inverse/irl_gail.py | 277 ++++++ .../results/gail/HalfCheetah-v2_rew.png | Bin 0 -> 203438 bytes .../inverse/results/gail/Hopper-v2_rew.png | Bin 0 -> 238281 bytes .../inverse/results/gail/Walker2d-v2_rew.png | Bin 0 -> 210327 bytes examples/mujoco/README.md | 2 +- examples/mujoco/mujoco_a2c.py | 4 +- examples/mujoco/mujoco_ddpg.py | 4 +- examples/mujoco/mujoco_npg.py | 4 +- examples/mujoco/mujoco_ppo.py | 4 +- examples/mujoco/mujoco_reinforce.py | 4 +- examples/mujoco/mujoco_sac.py | 4 +- examples/mujoco/mujoco_td3.py | 4 +- examples/mujoco/mujoco_trpo.py | 4 +- examples/offline/README.md | 58 +- examples/offline/atari_bcq.py | 78 +- examples/offline/atari_cql.py | 80 +- examples/offline/atari_crr.py | 78 +- examples/offline/atari_il.py | 163 ++++ .../offline/{offline_bcq.py => d4rl_bcq.py} | 121 ++- .../offline/{offline_cql.py => d4rl_cql.py} | 123 +-- examples/offline/d4rl_il.py | 193 ++++ .../bcq/halfcheetah-expert-v1_reward.png | Bin 56131 -> 0 bytes .../bcq/halfcheetah-expert-v1_reward.svg | 1 - examples/vizdoom/vizdoom_c51.py | 4 +- examples/vizdoom/vizdoom_ppo.py | 4 +- setup.py | 3 +- test/base/test_env.py | 3 +- test/base/test_utils.py | 42 +- test/continuous/test_npg.py | 4 +- test/continuous/test_sac_with_il.py | 23 +- test/continuous/test_td3.py | 24 +- test/continuous/test_trpo.py | 4 +- test/discrete/test_a2c_with_il.py | 14 +- test/discrete/test_c51.py | 12 +- test/discrete/test_dqn.py | 12 +- test/discrete/test_drqn.py | 12 +- test/discrete/test_fqf.py | 12 +- test/discrete/test_iqn.py | 12 +- test/discrete/test_pg.py | 12 +- test/discrete/test_ppo.py | 12 +- test/discrete/test_qrdqn.py | 12 +- test/discrete/test_rainbow.py | 12 +- test/discrete/test_sac.py | 15 +- test/modelbased/test_dqn_icm.py | 12 +- test/modelbased/test_ppo_icm.py | 12 +- test/modelbased/test_psrl.py | 12 +- test/offline/gather_cartpole_data.py | 4 +- test/offline/gather_pendulum_data.py | 4 +- test/offline/test_bcq.py | 6 +- test/offline/test_cql.py | 20 +- test/offline/test_discrete_bcq.py | 9 +- test/offline/test_discrete_cql.py | 4 +- test/offline/test_discrete_crr.py | 4 +- test/offline/test_gail.py | 228 +++++ test/pettingzoo/pistonball.py | 6 +- test/pettingzoo/pistonball_continuous.py | 6 +- test/pettingzoo/tic_tac_toe.py | 6 +- tianshou/__init__.py | 2 +- tianshou/data/collector.py | 13 +- tianshou/env/pettingzoo_env.py | 9 +- tianshou/env/venvs.py | 3 +- tianshou/env/worker/base.py | 7 +- tianshou/env/worker/dummy.py | 4 +- tianshou/env/worker/ray.py | 6 +- tianshou/env/worker/subproc.py | 2 +- tianshou/policy/__init__.py | 2 + tianshou/policy/base.py | 35 +- tianshou/policy/imitation/base.py | 2 + tianshou/policy/imitation/bcq.py | 2 + tianshou/policy/imitation/cql.py | 2 + tianshou/policy/imitation/discrete_bcq.py | 2 + tianshou/policy/imitation/discrete_cql.py | 2 + tianshou/policy/imitation/discrete_crr.py | 2 + tianshou/policy/imitation/gail.py | 141 +++ tianshou/policy/modelbased/icm.py | 2 + tianshou/policy/modelbased/psrl.py | 2 + tianshou/policy/modelfree/a2c.py | 3 - tianshou/policy/modelfree/c51.py | 2 + tianshou/policy/modelfree/ddpg.py | 2 + tianshou/policy/modelfree/discrete_sac.py | 2 + tianshou/policy/modelfree/dqn.py | 2 + tianshou/policy/modelfree/fqf.py | 2 + tianshou/policy/modelfree/iqn.py | 2 + tianshou/policy/modelfree/npg.py | 4 - tianshou/policy/modelfree/pg.py | 5 - tianshou/policy/modelfree/ppo.py | 3 - tianshou/policy/modelfree/qrdqn.py | 2 + tianshou/policy/modelfree/rainbow.py | 2 + tianshou/policy/modelfree/sac.py | 16 +- tianshou/policy/modelfree/td3.py | 2 + tianshou/policy/modelfree/trpo.py | 4 - tianshou/trainer/__init__.py | 30 +- tianshou/trainer/base.py | 426 +++++++++ tianshou/trainer/offline.py | 198 ++-- tianshou/trainer/offpolicy.py | 275 +++--- tianshou/trainer/onpolicy.py | 310 +++--- tianshou/trainer/utils.py | 36 +- tianshou/utils/__init__.py | 14 +- tianshou/utils/logger/tensorboard.py | 14 +- tianshou/utils/logger/wandb.py | 44 +- tianshou/utils/lr_scheduler.py | 42 + tianshou/utils/net/discrete.py | 4 +- tianshou/utils/warning.py | 8 + 138 files changed, 3838 insertions(+), 1947 deletions(-) create mode 100644 docs/tutorials/get_started.rst delete mode 100644 draft.ipynb create mode 100644 examples/atari/benchmark/BreakoutNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/EnduroNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/MsPacmanNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/PongNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/QbertNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/SeaquestNoFrameskip-v4/result.json create mode 100644 examples/atari/benchmark/SpaceInvadersNoFrameskip-v4/result.json create mode 100644 examples/inverse/README.md create mode 100644 examples/inverse/irl_gail.py create mode 100644 examples/inverse/results/gail/HalfCheetah-v2_rew.png create mode 100644 examples/inverse/results/gail/Hopper-v2_rew.png create mode 100644 examples/inverse/results/gail/Walker2d-v2_rew.png create mode 100644 examples/offline/atari_il.py rename examples/offline/{offline_bcq.py => d4rl_bcq.py} (63%) rename examples/offline/{offline_cql.py => d4rl_cql.py} (63%) create mode 100644 examples/offline/d4rl_il.py delete mode 100644 examples/offline/results/bcq/halfcheetah-expert-v1_reward.png delete mode 100644 examples/offline/results/bcq/halfcheetah-expert-v1_reward.svg create mode 100644 test/offline/test_gail.py create mode 100644 tianshou/policy/imitation/gail.py create mode 100644 tianshou/trainer/base.py create mode 100644 tianshou/utils/lr_scheduler.py create mode 100644 tianshou/utils/warning.py diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index e1488688c..c5c07bf3f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -7,6 +7,6 @@ - [ ] I have searched through the [issue tracker](https://github.com/thu-ml/tianshou/issues) for duplicates - [ ] I have mentioned version numbers, operating system and environment, where applicable: ```python - import tianshou, torch, numpy, sys - print(tianshou.__version__, torch.__version__, numpy.__version__, sys.version, sys.platform) + import tianshou, gym, torch, numpy, sys + print(tianshou.__version__, gym.__version__, torch.__version__, numpy.__version__, sys.version, sys.platform) ``` diff --git a/LICENSE b/LICENSE index 6a7aa81e6..322a77c33 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Tianshou contributors +Copyright (c) 2022 Tianshou contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 616c4c983..b9967f886 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SHELL=/bin/bash PROJECT_NAME=tianshou PROJECT_PATH=${PROJECT_NAME}/ -LINT_PATHS=${PROJECT_PATH} test/ docs/conf.py examples/ setup.py +PYTHON_FILES = $(shell find setup.py ${PROJECT_NAME} test docs/conf.py examples -type f -name "*.py") check_install = python3 -c "import $(1)" || pip3 install $(1) --upgrade check_install_extra = python3 -c "import $(1)" || pip3 install $(2) --upgrade @@ -19,20 +19,18 @@ mypy: lint: $(call check_install, flake8) $(call check_install_extra, bugbear, flake8_bugbear) - flake8 ${LINT_PATHS} --count --show-source --statistics + flake8 ${PYTHON_FILES} --count --show-source --statistics format: - # sort imports $(call check_install, isort) - isort ${LINT_PATHS} - # reformat using yapf + isort ${PYTHON_FILES} $(call check_install, yapf) - yapf -ir ${LINT_PATHS} + yapf -ir ${PYTHON_FILES} check-codestyle: $(call check_install, isort) $(call check_install, yapf) - isort --check ${LINT_PATHS} && yapf -r -d ${LINT_PATHS} + isort --check ${PYTHON_FILES} && yapf -r -d ${PYTHON_FILES} check-docstyle: $(call check_install, pydocstyle) @@ -57,6 +55,6 @@ doc-clean: clean: doc-clean -commit-checks: format lint mypy check-docstyle spelling +commit-checks: lint check-codestyle mypy check-docstyle spelling .PHONY: clean spelling doc mypy lint format check-codestyle check-docstyle commit-checks diff --git a/README.md b/README.md index 1144a0cab..aaf610549 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- +
--- @@ -41,6 +41,7 @@ - [Discrete Batch-Constrained deep Q-Learning (BCQ-Discrete)](https://arxiv.org/pdf/1910.01708.pdf) - [Discrete Conservative Q-Learning (CQL-Discrete)](https://arxiv.org/pdf/2006.04779.pdf) - [Discrete Critic Regularized Regression (CRR-Discrete)](https://arxiv.org/pdf/2006.15134.pdf) +- [Generative Adversarial Imitation Learning (GAIL)](https://arxiv.org/pdf/1606.03476.pdf) - [Prioritized Experience Replay (PER)](https://arxiv.org/pdf/1511.05952.pdf) - [Generalized Advantage Estimator (GAE)](https://arxiv.org/pdf/1506.02438.pdf) - [Posterior Sampling Reinforcement Learning (PSRL)](https://www.ece.uvic.ca/~bctill/papers/learning/Strens_2000.pdf) @@ -274,7 +275,7 @@ $ python3 test/discrete/test_pg.py --seed 0 --render 0.03 ```
- +
## Contributing diff --git a/docs/_static/js/benchmark.js b/docs/_static/js/benchmark.js index 8b7b58043..c0663959c 100644 --- a/docs/_static/js/benchmark.js +++ b/docs/_static/js/benchmark.js @@ -1,4 +1,4 @@ -var envs = [ +var mujoco_envs = [ "Ant-v3", "HalfCheetah-v3", "Hopper-v3", @@ -9,11 +9,23 @@ var envs = [ "Swimmer-v3", "Walker2d-v3", ]; -function showEnv(elem) { - var selectEnv = elem.value || envs[0]; + +var atari_envs = [ + "PongNoFrameskip-v4", + "BreakoutNoFrameskip-v4", + "EnduroNoFrameskip-v4", + "QbertNoFrameskip-v4", + "MsPacmanNoFrameskip-v4", + "SeaquestNoFrameskip-v4", + "SpaceInvadersNoFrameskip-v4", +]; + +function showMujocoEnv(elem) { + var selectEnv = elem.value || mujoco_envs[0]; var dataSource = { $schema: "https://vega.github.io/schema/vega-lite/v5.json", data: { + // url: "/_static/js/mujoco/benchmark/" + selectEnv + "/result.json" url: "/en/master/_static/js/mujoco/benchmark/" + selectEnv + "/result.json" }, mark: "line", @@ -58,10 +70,67 @@ function showEnv(elem) { }; vegaEmbed("#vis-mujoco", dataSource); } + +function showAtariEnv(elem) { + var selectEnv = elem.value || atari_envs[0]; + var dataSource = { + $schema: "https://vega.github.io/schema/vega-lite/v5.json", + data: { + // url: "/_static/js/atari/benchmark/" + selectEnv + "/result.json" + url: "/en/master/_static/js/atari/benchmark/" + selectEnv + "/result.json" + }, + mark: "line", + height: 400, + width: 800, + params: [{name: "Range", value: 10000000, bind: {input: "range", min: 10000, max: 10000000}}], + transform: [ + {calculate: "datum.rew - datum.rew_std", as: "rew_std0"}, + {calculate: "datum.rew + datum.rew_std", as: "rew_std1"}, + {calculate: "datum.rew + ' ± ' + datum.rew_std", as: "tooltip_str"}, + {filter: "datum.env_step <= Range"}, + ], + encoding: { + color: {"field": "Agent", "type": "nominal"}, + x: {field: "env_step", type: "quantitative", title: "Env step"}, + }, + layer: [{ + "encoding": { + "opacity": {"value": 0.3}, + "y": { + "title": "Return", + "field": "rew_std0", + "type": "quantitative", + }, + "y2": {"field": "rew_std1"}, + tooltip: [ + {field: "env_step", type: "quantitative", title: "Env step"}, + {field: "Agent", type: "nominal"}, + {field: "tooltip_str", type: "nominal", title: "Return"}, + ] + }, + "mark": "area" + }, { + "encoding": { + "y": { + "field": "rew", + "type": "quantitative" + } + }, + "mark": "line" + }] + }; + vegaEmbed("#vis-atari", dataSource); +} + $(document).ready(function() { - var envSelect = $("#env-mujoco"); - if (envSelect.length) { - $.each(envs, function(idx, env) {envSelect.append($("").val(env).html(env));}) - showEnv(envSelect); + var envMujocoSelect = $("#env-mujoco"); + if (envMujocoSelect.length) { + $.each(mujoco_envs, function(idx, env) {envMujocoSelect.append($("").val(env).html(env));}) + showMujocoEnv(envMujocoSelect); + } + var envAtariSelect = $("#env-atari"); + if (envAtariSelect.length) { + $.each(atari_envs, function(idx, env) {envAtariSelect.append($("").val(env).html(env));}) + showAtariEnv(envAtariSelect); } }); diff --git a/docs/api/tianshou.policy.rst b/docs/api/tianshou.policy.rst index c3063665c..a0d9bed99 100644 --- a/docs/api/tianshou.policy.rst +++ b/docs/api/tianshou.policy.rst @@ -134,6 +134,11 @@ Imitation :undoc-members: :show-inheritance: +.. autoclass:: tianshou.policy.GAILPolicy + :members: + :undoc-members: + :show-inheritance: + Model-based ----------- diff --git a/docs/api/tianshou.trainer.rst b/docs/api/tianshou.trainer.rst index 9deed5053..13c6d66c9 100644 --- a/docs/api/tianshou.trainer.rst +++ b/docs/api/tianshou.trainer.rst @@ -1,7 +1,49 @@ tianshou.trainer ================ -.. automodule:: tianshou.trainer + +On-policy +--------- + +.. autoclass:: tianshou.trainer.OnpolicyTrainer + :members: + :undoc-members: + :show-inheritance: + +.. autofunction:: tianshou.trainer.onpolicy_trainer + +.. autoclass:: tianshou.trainer.onpolicy_trainer_iter + + +Off-policy +---------- + +.. autoclass:: tianshou.trainer.OffpolicyTrainer + :members: + :undoc-members: + :show-inheritance: + +.. autofunction:: tianshou.trainer.offpolicy_trainer + +.. autoclass:: tianshou.trainer.offpolicy_trainer_iter + + +Offline +------- + +.. autoclass:: tianshou.trainer.OfflineTrainer :members: :undoc-members: :show-inheritance: + +.. autofunction:: tianshou.trainer.offline_trainer + +.. autoclass:: tianshou.trainer.offline_trainer_iter + + +utils +----- + +.. autofunction:: tianshou.trainer.test_episode + +.. autofunction:: tianshou.trainer.gather_info diff --git a/docs/index.rst b/docs/index.rst index 15ac74037..6a82e6d52 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,7 +13,7 @@ Welcome to Tianshou! * :class:`~tianshou.policy.DQNPolicy` `Double DQN `_ * :class:`~tianshou.policy.DQNPolicy` `Dueling DQN `_ * :class:`~tianshou.policy.C51Policy` `Categorical DQN `_ -* :class:`~tianshou.policy.RainbowPolicy` `Rainbow DQN `_ +* :class:`~tianshou.policy.RainbowPolicy` `Rainbow DQN `_ * :class:`~tianshou.policy.QRDQNPolicy` `Quantile Regression DQN `_ * :class:`~tianshou.policy.IQNPolicy` `Implicit Quantile Network `_ * :class:`~tianshou.policy.FQFPolicy` `Fully-parameterized Quantile Function `_ @@ -32,6 +32,7 @@ Welcome to Tianshou! * :class:`~tianshou.policy.DiscreteBCQPolicy` `Discrete Batch-Constrained deep Q-Learning `_ * :class:`~tianshou.policy.DiscreteCQLPolicy` `Discrete Conservative Q-Learning `_ * :class:`~tianshou.policy.DiscreteCRRPolicy` `Critic Regularized Regression `_ +* :class:`~tianshou.policy.GAILPolicy` `Generative Adversarial Imitation Learning `_ * :class:`~tianshou.policy.PSRLPolicy` `Posterior Sampling Reinforcement Learning `_ * :class:`~tianshou.policy.ICMPolicy` `Intrinsic Curiosity Module `_ * :class:`~tianshou.data.PrioritizedReplayBuffer` `Prioritized Experience Replay `_ @@ -93,6 +94,7 @@ Tianshou is still under development, you can also check out the documents in sta :maxdepth: 1 :caption: Tutorials + tutorials/get_started tutorials/dqn tutorials/concepts tutorials/batch diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 9f0377b43..31e53fce0 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -18,18 +18,22 @@ numpy ndarray stackoverflow tensorboard +state_dict len tac fqf iqn qrdqn rl +offpolicy +onpolicy quantile quantiles dqn param async subprocess +deque nn equ cql @@ -140,3 +144,16 @@ Strens Ornstein Uhlenbeck mse +gail +airl +ppo +Jupyter +Colab +Colaboratory +IPendulum +Reacher +Runtime +Nvidia +Enduro +Qbert +Seaquest diff --git a/docs/tutorials/benchmark.rst b/docs/tutorials/benchmark.rst index c3cb0676a..b67ccbfd7 100644 --- a/docs/tutorials/benchmark.rst +++ b/docs/tutorials/benchmark.rst @@ -5,21 +5,139 @@ Benchmark Mujoco Benchmark ---------------- -Tianshou's Mujoco benchmark contains state-of-the-art results (even better than `SpinningUp `_!). +Tianshou's Mujoco benchmark contains state-of-the-art results. -Please refer to https://github.com/thu-ml/tianshou/tree/master/examples/mujoco +Every experiment is conducted under 10 random seeds for 1-10M steps. Please refer to https://github.com/thu-ml/tianshou/tree/master/examples/mujoco for source code and detailed results. .. raw:: html
- +

+The table below compares the performance of Tianshou against published results on OpenAI Gym MuJoCo benchmarks. We use max average return in 1M timesteps as the reward metric. ~ means the result is approximated from the plots because quantitative results are not provided. - means results are not provided. The best-performing baseline on each task is highlighted in boldface. Referenced baselines include `TD3 paper `_, `SAC paper `_, `PPO paper `_, `ACKTR paper `_, `OpenAI Baselines `_ and `Spinning Up `_. + ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|Task |Ant |HalfCheetah|Hopper |Walker2d |Swimmer |Humanoid |Reacher |IPendulum |IDPendulum| ++=========+================+==========+===========+==========+==========+=========+==========+========+==========+==========+ +|DDPG |Tianshou |990.4 |**11718.7**|**2197.0**|1400.6 |**144.1**|**177.3** |**-3.3**|**1000.0**|8364.3 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 Paper |**1005.3**|3305.6 |**2020.5**|1843.6 |/ |/ |-6.5 |**1000.0**|**9355.5**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 Paper (Our) |888.8 |8577.3 |1860.0 |**3098.1**|/ |/ |-4.0 |**1000.0**|8370.0 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |Spinning Up |~840 |~11000 |~1800 |~1950 |~137 |/ |/ |/ |/ | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|TD3 |Tianshou |**5116.4**|**10201.2**|3472.2 |3982.4 |**104.2**|**5189.5**|**-2.7**|**1000.0**|**9349.2**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 Paper |4372.4 |9637.0 |**3564.1**|**4682.8**|/ |/ |-3.6 |**1000.0**|9337.5 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |Spinning Up |~3800 |~9750 |~2860 |~4000 |~78 |/ |/ |/ |/ | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|SAC |Tianshou |**5850.2**|**12138.8**|**3542.2**|**5007.0**|**44.4** |**5488.5**|**-2.6**|**1000.0**|**9359.5**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |SAC Paper |~3720 |~10400 |~3370 |~3740 |/ |~5200 |/ |/ |/ | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 Paper |655.4 |2347.2 |2996.7 |1283.7 |/ |/ |-4.4 |**1000.0**|8487.2 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |Spinning Up |~3980 |~11520 |~3150 |~4250 |~41.7 |/ |/ |/ |/ | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|A2C |Tianshou |**3485.4**|**1829.9** |**1253.2**|**1091.6**|**36.6** |**1726.0**|**-6.7**|**1000.0**|**9257.7**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |PPO Paper |/ |~1000 |~900 |~850 |~31 |/ |~-24 |**~1000** |~7100 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |PPO Paper (TR) |/ |~930 |~1220 |~700 |**~36** |/ |~-27 |**~1000** |~8100 | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|PPO |Tianshou |**3258.4**|**5783.9** |**2609.3**|3588.5 |66.7 |**787.1** |**-4.1**|**1000.0**|**9231.3**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |PPO Paper |/ |~1800 |~2330 |~3460 |~108 |/ |~-7 |**~1000** |~8000 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 Paper |1083.2 |1795.4 |2164.7 |3317.7 |/ |/ |-6.2 |**1000.0**|8977.9 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |OpenAI Baselines|/ |~1700 |~2400 |~3510 |~111 |/ |~-6 |~940 |~7350 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |Spinning Up |~650 |~1670 |~1850 |~1230 |**~120** |/ |/ |/ |/ | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +|TRPO |Tianshou |**2866.7**|**4471.2** |2046.0 |**3826.7**|40.9 |**810.1** |**-5.1**|**1000.0**|**8435.2**| ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |ACKTR paper |~0 |~400 |~1400 |~550 |~40 |/ |-8 |**~1000** |~800 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |PPO Paper |/ |~0 |~2100 |~1100 |**~121** |/ |~-115 |**~1000** |~200 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |TD3 paper |-75.9 |-15.6 |**2471.3**|2321.5 |/ |/ |-111.4 |985.4 |205.9 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |OpenAI Baselines|/ |~1350 |**~2200** |~2350 |~95 |/ |**~-5** |~910 |~7000 | ++ +----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ +| |Spinning Up (TF)|~150 |~850 |~1200 |~600 |~85 |/ |/ |/ |/ | ++---------+----------------+----------+-----------+----------+----------+---------+----------+--------+----------+----------+ + +Runtime averaged on 8 MuJoCo benchmark tasks is listed below. All results are obtained using a single Nvidia TITAN X GPU and +up to 48 CPU cores (at most one CPU core for each thread). + +========= ========= ============ ============== ============ ============== ========== +Algorithm # of Envs 1M timesteps Collecting (%) Updating (%) Evaluating (%) Others (%) +========= ========= ============ ============== ============ ============== ========== +DDPG 1 2.9h 12.0 80.2 2.4 5.4 +TD3 1 3.3h 11.4 81.7 1.7 5.2 +SAC 1 5.2h 10.9 83.8 1.8 3.5 +REINFORCE 64 4min 84.9 1.8 12.5 0.8 +A2C 16 7min 62.5 28.0 6.6 2.9 +PPO 64 24min 11.4 85.3 3.2 0.2 +NPG 16 7min 65.1 24.9 9.5 0.6 +TRPO 16 7min 62.9 26.5 10.1 0.6 +========= ========= ============ ============== ============ ============== ========== + Atari Benchmark --------------- -Please refer to https://github.com/thu-ml/tianshou/tree/master/examples/atari +Tianshou also provides reliable and reproducible Atari 10M benchmark. + +Every experiment is conducted under 10 random seeds for 10M steps. Please refer to https://github.com/thu-ml/tianshou/tree/master/examples/atari for source code and refer to https://wandb.ai/tianshou/atari.benchmark/reports/Atari-Benchmark--VmlldzoxOTA1NzA5 for detailed results hosted on wandb. + +.. raw:: html + +
+ +
+
+
+
+ + +The table below compares the performance of Tianshou against published results on Atari games. We use max average return in 10M timesteps as the reward metric **(to be consistent with Mujoco)**. ``/`` means results are not provided. The best-performing baseline on each task is highlighted in boldface. Referenced baselines include `Google Dopamine `_ and `OpenAI Baselines `_. + ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|Task |Pong |Breakout |Enduro |Qbert |MsPacman |Seaquest |SpaceInvaders | ++=======+================+==============+================+==================+====================+==============+===================+==================+ +|DQN |Tianshou |**20.2 ± 2.3**|**133.5 ± 44.6**|997.9 ± 180.6 |**11620.2 ± 786.1** |2324.8 ± 359.8|**3213.9 ± 381.6** |947.9 ± 155.3 | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |Dopamine |9.8 |92.2 |**2126.9** |6836.7 |**2451.3** |1406.6 |**1559.1** | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |OpenAI Baselines|16.5 |131.5 |479.8 |3254.8 |/ |1164.1 |1129.5 ± 145.3 | ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|C51 |Tianshou |**20.6 ± 2.4**|**412.9 ± 35.8**|**940.8 ± 133.9** |**12513.2 ± 1274.6**|2254.9 ± 201.2|**3305.4 ± 1524.3**|557.3 | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |Dopamine |17.4 |222.4 |665.3 |9924.5 |**2860.4** |1706.6 |**604.6 ± 157.5** | ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|Rainbow|Tianshou |**20.2 ± 3.0**|**440.4 ± 50.1**|1496.1 ± 112.3 |14224.8 ± 1230.1 |2524.2 ± 338.8|1934.6 ± 376.4 |**1178.4** | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |Dopamine |19.1 |47.9 |**2185.1** |**15682.2** |**3161.7** |**3328.9** |459.9 | ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|IQN |Tianshou |**20.7 ± 2.9**|**355.9 ± 22.7**|**1252.7 ± 118.1**|**14409.2 ± 808.6** |2228.6 ± 253.1|5341.2 ± 670.2 |667.8 ± 81.5 | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |Dopamine |19.6 |96.3 |1227.6 |12496.7 |**4422.7** |**16418** |**1358.2 ± 267.6**| ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|PPO |Tianshou |**20.3 ± 1.2**|**283.0 ± 74.3**|**1098.9 ± 110.5**|**12341.8 ± 1760.7**|1699.4 ± 248.0|1035.2 ± 353.6 |1641.3 | ++ +----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +| |OpenAI Baselines|13.7 |114.3 |350.2 |7012.1 |/ |**1218.9** |**1787.5 ± 340.8**| ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|QR-DQN |Tianshou |20.7 ± 2.0 |228.3 ± 27.3 |951.7 ± 333.5 |14761.5 ± 862.9 |2259.3 ± 269.2|4187.6 ± 725.7 |1114.7 ± 116.9 | ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ +|FQF |Tianshou |20.4 ± 2.5 |382.6 ± 29.5 |1816.8 ± 314.3 |15301.2 ± 684.1 |2506.6 ± 402.5|8051.5 ± 3155.6 |2558.3 | ++-------+----------------+--------------+----------------+------------------+--------------------+--------------+-------------------+------------------+ + +Please note that the comparison table for both two benchmarks could NOT be used to prove which implementation is "better". The hyperparameters of the algorithms vary across different implementations. Also, the reward metric is not strictly the same (e.g. Tianshou uses max average return in 10M steps but OpenAI Baselines only report average return at 10M steps, which is unfair). Lastly, Tianshou always uses 10 random seeds while others might use fewer. The comparison is here only to show Tianshou's reliability. diff --git a/docs/tutorials/concepts.rst b/docs/tutorials/concepts.rst index d500787ee..cb6d616fe 100644 --- a/docs/tutorials/concepts.rst +++ b/docs/tutorials/concepts.rst @@ -380,6 +380,26 @@ Once you have a collector and a policy, you can start writing the training metho Tianshou has three types of trainer: :func:`~tianshou.trainer.onpolicy_trainer` for on-policy algorithms such as Policy Gradient, :func:`~tianshou.trainer.offpolicy_trainer` for off-policy algorithms such as DQN, and :func:`~tianshou.trainer.offline_trainer` for offline algorithms such as BCQ. Please check out :doc:`/api/tianshou.trainer` for the usage. +We also provide the corresponding iterator-based trainer classes :class:`~tianshou.trainer.OnpolicyTrainer`, :class:`~tianshou.trainer.OffpolicyTrainer`, :class:`~tianshou.trainer.OfflineTrainer` to facilitate users writing more flexible training logic: +:: + + trainer = OnpolicyTrainer(...) + for epoch, epoch_stat, info in trainer: + print(f"Epoch: {epoch}") + print(epoch_stat) + print(info) + do_something_with_policy() + query_something_about_policy() + make_a_plot_with(epoch_stat) + display(info) + + # or even iterate on several trainers at the same time + + trainer1 = OnpolicyTrainer(...) + trainer2 = OnpolicyTrainer(...) + for result1, result2, ... in zip(trainer1, trainer2, ...): + compare_results(result1, result2, ...) + .. _pseudocode: diff --git a/docs/tutorials/get_started.rst b/docs/tutorials/get_started.rst new file mode 100644 index 000000000..08e386a3b --- /dev/null +++ b/docs/tutorials/get_started.rst @@ -0,0 +1,13 @@ +Get Started with Jupyter Notebook +================================= + +In this tutorial, we will use Google Colaboratory to show you the most basic usages of common building blocks in Tianshou. You will be guided step by step to see how different modules in Tianshou collaborate with each other to conduct a classic DRL experiment (PPO algorithm for CartPole-v0 environment). + +- L0: `Overview `_ +- L1: `Batch `_ +- L2: `Replay Buffer `_ +- L3: `Vectorized Environment `_ +- L4: `Policy `_ +- L5: `Collector `_ +- L6: `Trainer `_ +- L7: `Experiment `_ diff --git a/docs/tutorials/logger.rst b/docs/tutorials/logger.rst index 6a65e3296..c8161374d 100644 --- a/docs/tutorials/logger.rst +++ b/docs/tutorials/logger.rst @@ -34,8 +34,12 @@ WandbLogger :: from tianshou.utils import WandbLogger + from torch.utils.tensorboard import SummaryWriter logger = WandbLogger(...) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + logger.load(writer) result = trainer(..., logger=logger) Please refer to :class:`~tianshou.utils.WandbLogger` documentation for advanced configuration. diff --git a/docs/tutorials/tictactoe.rst b/docs/tutorials/tictactoe.rst index 58e69906a..7031b5dc2 100644 --- a/docs/tutorials/tictactoe.rst +++ b/docs/tutorials/tictactoe.rst @@ -10,47 +10,47 @@ In this section, we describe how to use Tianshou to implement multi-agent reinfo Tic-Tac-Toe Environment ----------------------- -The scripts are located at ``test/multiagent/``. We have implemented a Tic-Tac-Toe environment inherit the :class:`~tianshou.env.MultiAgentEnv` that supports Tic-Tac-Toe of any scale. Let's first explore the environment. The 3x3 Tic-Tac-Toe is too easy, so we will focus on 6x6 Tic-Tac-Toe where 4 same signs in a row are considered to win. +The scripts are located at ``test/pettingzoo/``. We have implemented :class:`~tianshou.env.PettingZooEnv` which can wrap any [PettingZoo](https://www.pettingzoo.ml/) environment. PettingZoo offers a 3x3 Tic-Tac-Toe environment, let's first explore it. :: - >>> from tic_tac_toe_env import TicTacToeEnv # the module tic_tac_toe_env is in test/multiagent/ - >>> board_size = 6 # the size of board size - >>> win_size = 4 # how many signs in a row are considered to win - >>> - >>> # This board has 6 rows and 6 cols (36 places in total) + >>> from tianshou.env import PettingZooEnv # wrapper for PettingZoo environments + >>> from pettingzoo.classic import tictactoe_v3 # the Tic-Tac-Toe environment to be wrapped + >>> # This board has 3 rows and 3 cols (9 places in total) >>> # Players place 'x' and 'o' in turn on the board - >>> # The player who first gets 4 consecutive 'x's or 'o's wins + >>> # The player who first gets 3 consecutive 'x's or 'o's wins >>> - >>> env = TicTacToeEnv(size=board_size, win_size=win_size) + >>> env = PettingZooEnv(tictactoe_v3.env()) >>> obs = env.reset() - >>> env.render() # render the empty board + >>> env.render() # render the empty board board (step 0): - ================= - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ================= - >>> print(obs) # let's see the shape of the observation - {'agent_id': 1, - 'obs': array([[0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0]], dtype=int32), - 'mask': array([ True, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True])} + | | + - | - | - + _____|_____|_____ + | | + - | - | - + _____|_____|_____ + | | + - | - | - + | | + >>> print(obs) # let's see the shape of the observation + {'agent_id': 'player_1', 'obs': array([[[0, 0], + [0, 0], + [0, 0]], + + [[0, 0], + [0, 0], + [0, 0]], + + [[0, 0], + [0, 0], + [0, 0]]], dtype=int8), 'mask': [True, True, True, True, True, True, True, True, True]} + The observation variable ``obs`` returned from the environment is a ``dict``, with three keys ``agent_id``, ``obs``, ``mask``. This is a general structure in multi-agent RL where agents take turns. The meaning of these keys are: -- ``agent_id``: the id of the current acting agent, where agent_id :math:`\in [1, N]`, N is the number of agents. In our Tic-Tac-Toe case, N is 2. The agent_id starts at 1 because we reserve 0 for the environment itself. Sometimes the developer may want to control the behavior of the environment, for example, to determine how to dispatch cards in Poker. +- ``agent_id``: the id of the current acting agent. In our Tic-Tac-Toe case, the agent_id can be ``player_1`` or ``player_2``. -- ``obs``: the actual observation of the environment. In the Tic-Tac-Toe game above, the observation variable ``obs`` is a ``np.ndarray`` with the shape of (6, 6). The values can be "0/1/-1": 0 for empty, 1 for ``x``, -1 for ``o``. Agent 1 places ``x`` on the board, while agent 2 places ``o`` on the board. +- ``obs``: the actual observation of the environment. In the Tic-Tac-Toe game above, the observation variable ``obs`` is a ``np.ndarray`` with the shape of (3, 3, 2). For ``player_1``, the first 3x3 plane represents the placement of Xs, and the second plane shows the placement of Os. The possible values for each cell are 0 or 1; in the first plane, 1 indicates that an X has been placed in that cell, and 0 indicates that X is not in that cell. Similarly, in the second plane, 1 indicates that an O has been placed in that cell, while 0 indicates that an O has not been placed. For ``player_2``, the observation is the same, but Xs and Os swap positions, so Os are encoded in plane 1 and Xs in plane 2. - ``mask``: the action mask in the current timestep. In board games or card games, the legal action set varies with time. The mask is a boolean array. For Tic-Tac-Toe, index ``i`` means the place of ``i/N`` th row and ``i%N`` th column. If ``mask[i] == True``, the player can place an ``x`` or ``o`` at that position. Now the board is empty, so the mask is all the true, contains all the positions on the board. @@ -66,17 +66,17 @@ Let's play two steps to have an intuitive understanding of the environment. >>> action = 0 # action is either an integer, or an np.ndarray with one element >>> obs, reward, done, info = env.step(action) # the env.step follows the api of OpenAI Gym >>> print(obs) # notice the change in the observation - {'agent_id': 2, - 'obs': array([[1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0]], dtype=int32), - 'mask': array([False, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True, - True, True, True, True, True, True, True, True, True])}} + {'agent_id': 'player_2', 'obs': array([[[0, 1], + [0, 0], + [0, 0]], + + [[0, 0], + [0, 0], + [0, 0]], + + [[0, 0], + [0, 0], + [0, 0]]], dtype=int8), 'mask': [False, True, True, True, True, True, True, True, True]} >>> # reward has two items, one for each player: 1 for win, -1 for lose, and 0 otherwise >>> print(reward) [0. 0.] @@ -89,26 +89,26 @@ Let's play two steps to have an intuitive understanding of the environment. One worth-noting case is that the game is over when there is only one empty position, rather than when there is no position. This is because the player just has one choice (literally no choice) in this game. :: - >>> # omitted actions: 6, 1, 7, 2, 8 - >>> obs, reward, done, info = env.step(3) # player 1 wins + >>> # omitted actions: 3, 1, 4 + >>> obs, reward, done, info = env.step(2) # player_1 wins >>> print((reward, done)) - (array([ 1., -1.], dtype=float32), array(True)) - >>> env.render() # 'X' and 'O' indicate the last action - board (step 7): - ================= - ===x x x X _ _=== - ===o o o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ================= + ([1, -1], True) + >>> env.render() + | | + X | O | - + _____|_____|_____ + | | + X | O | - + _____|_____|_____ + | | + X | - | - + | | After being familiar with the environment, let's try to play with random agents first! -Two Random Agent ----------------- +Two Random Agents +----------------- .. sidebar:: The relationship between MultiAgentPolicyManager (Manager) and BasePolicy (Agent) @@ -119,12 +119,16 @@ Tianshou already provides some builtin classes for multi-agent learning. You can :: >>> from tianshou.data import Collector + >>> from tianshou.env import DummyVectorEnv >>> from tianshou.policy import RandomPolicy, MultiAgentPolicyManager >>> >>> # agents should be wrapped into one policy, >>> # which is responsible for calling the acting agent correctly >>> # here we use two random agents - >>> policy = MultiAgentPolicyManager([RandomPolicy(), RandomPolicy()]) + >>> policy = MultiAgentPolicyManager([RandomPolicy(), RandomPolicy()], env) + >>> + >>> # need to vectorize the environment for the collector + >>> env = DummyVectorEnv([lambda: env]) >>> >>> # use collectors to collect a episode of trajectories >>> # the reward is a vector, so we need a scalar metric to monitor the training @@ -133,33 +137,33 @@ Tianshou already provides some builtin classes for multi-agent learning. You can >>> # you will see a long trajectory showing the board status at each timestep >>> result = collector.collect(n_episode=1, render=.1) (only show the last 3 steps) - board (step 20): - ================= - ===o x _ o o o=== - ===_ _ x _ _ x=== - ===x _ o o x _=== - ===O _ o o x _=== - ===x _ o _ _ _=== - ===x _ _ _ x x=== - ================= - board (step 21): - ================= - ===o x _ o o o=== - ===_ _ x _ _ x=== - ===x _ o o x _=== - ===o _ o o x _=== - ===x _ o X _ _=== - ===x _ _ _ x x=== - ================= - board (step 22): - ================= - ===o x _ o o o=== - ===_ O x _ _ x=== - ===x _ o o x _=== - ===o _ o o x _=== - ===x _ o x _ _=== - ===x _ _ _ x x=== - ================= + | | + X | X | - + _____|_____|_____ + | | + X | O | - + _____|_____|_____ + | | + O | - | - + | | + | | + X | X | - + _____|_____|_____ + | | + X | O | - + _____|_____|_____ + | | + O | - | O + | | + | | + X | X | X + _____|_____|_____ + | | + X | O | - + _____|_____|_____ + | | + O | - | O + | | Random agents perform badly. In the above game, although agent 2 wins finally, it is clear that a smart agent 1 would place an ``x`` at row 4 col 4 to win directly. @@ -170,62 +174,99 @@ Train an MARL Agent So let's start to train our Tic-Tac-Toe agent! First, import some required modules. :: - import os - import torch import argparse - import numpy as np + import os from copy import deepcopy + from typing import Optional, Tuple + + import gym + import numpy as np + import torch + from pettingzoo.classic import tictactoe_v3 from torch.utils.tensorboard import SummaryWriter - from tianshou.utils import TensorboardLogger + from tianshou.data import Collector, VectorReplayBuffer from tianshou.env import DummyVectorEnv - from tianshou.utils.net.common import Net + from tianshou.env.pettingzoo_env import PettingZooEnv + from tianshou.policy import ( + BasePolicy, + DQNPolicy, + MultiAgentPolicyManager, + RandomPolicy, + ) from tianshou.trainer import offpolicy_trainer - from tianshou.data import Collector, VectorReplayBuffer - from tianshou.policy import BasePolicy, RandomPolicy, DQNPolicy, MultiAgentPolicyManager - - from tic_tac_toe_env import TicTacToeEnv + from tianshou.utils import TensorboardLogger + from tianshou.utils.net.common import Net The explanation of each Tianshou class/function will be deferred to their first usages. Here we define some arguments and hyperparameters of the experiment. The meaning of arguments is clear by just looking at their names. :: - def get_args(): + def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser() parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) parser.add_argument('--buffer-size', type=int, default=20000) - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--gamma', type=float, default=0.9, - help='a smaller gamma favors earlier win') + parser.add_argument('--lr', type=float, default=1e-4) + parser.add_argument( + '--gamma', type=float, default=0.9, help='a smaller gamma favors earlier win' + ) parser.add_argument('--n-step', type=int, default=3) parser.add_argument('--target-update-freq', type=int, default=320) - parser.add_argument('--epoch', type=int, default=20) - parser.add_argument('--step-per-epoch', type=int, default=5000) + parser.add_argument('--epoch', type=int, default=50) + parser.add_argument('--step-per-epoch', type=int, default=1000) parser.add_argument('--step-per-collect', type=int, default=10) parser.add_argument('--update-per-step', type=float, default=0.1) parser.add_argument('--batch-size', type=int, default=64) - parser.add_argument('--hidden-sizes', type=int, - nargs='*', default=[128, 128, 128, 128]) + parser.add_argument( + '--hidden-sizes', type=int, nargs='*', default=[128, 128, 128, 128] + ) parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=100) + parser.add_argument('--test-num', type=int, default=10) parser.add_argument('--logdir', type=str, default='log') parser.add_argument('--render', type=float, default=0.1) - parser.add_argument('--board-size', type=int, default=6) - parser.add_argument('--win-size', type=int, default=4) - parser.add_argument('--win-rate', type=float, default=0.9, - help='the expected winning rate') - parser.add_argument('--watch', default=False, action='store_true', - help='no training, watch the play of pre-trained models') - parser.add_argument('--agent-id', type=int, default=2, - help='the learned agent plays as the agent_id-th player. Choices are 1 and 2.') - parser.add_argument('--resume-path', type=str, default='', - help='the path of agent pth file for resuming from a pre-trained agent') - parser.add_argument('--opponent-path', type=str, default='', - help='the path of opponent agent pth file for resuming from a pre-trained agent') - parser.add_argument('--device', type=str, - default='cuda' if torch.cuda.is_available() else 'cpu') - return parser.parse_args() + parser.add_argument( + '--win-rate', + type=float, + default=0.6, + help='the expected winning rate: Optimal policy can get 0.7' + ) + parser.add_argument( + '--watch', + default=False, + action='store_true', + help='no training, ' + 'watch the play of pre-trained models' + ) + parser.add_argument( + '--agent-id', + type=int, + default=2, + help='the learned agent plays as the' + ' agent_id-th player. Choices are 1 and 2.' + ) + parser.add_argument( + '--resume-path', + type=str, + default='', + help='the path of agent pth file ' + 'for resuming from a pre-trained agent' + ) + parser.add_argument( + '--opponent-path', + type=str, + default='', + help='the path of opponent agent pth file ' + 'for resuming from a pre-trained agent' + ) + parser.add_argument( + '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + ) + return parser + + def get_args() -> argparse.Namespace: + parser = get_parser() + return parser.parse_known_args()[0] .. sidebar:: The relationship between MultiAgentPolicyManager (Manager) and BasePolicy (Agent) @@ -243,24 +284,34 @@ Here it is: :: def get_agents( - args=get_args(), - agent_learn=None, # BasePolicy - agent_opponent=None, # BasePolicy - optim=None, # torch.optim.Optimizer - ): # return a tuple of (BasePolicy, torch.optim.Optimizer) - - env = TicTacToeEnv(args.board_size, args.win_size) - args.state_shape = env.observation_space.shape or env.observation_space.n + args: argparse.Namespace = get_args(), + agent_learn: Optional[BasePolicy] = None, + agent_opponent: Optional[BasePolicy] = None, + optim: Optional[torch.optim.Optimizer] = None, + ) -> Tuple[BasePolicy, torch.optim.Optimizer, list]: + env = get_env() + observation_space = env.observation_space['observation'] if isinstance( + env.observation_space, gym.spaces.Dict + ) else env.observation_space + args.state_shape = observation_space.shape or observation_space.n args.action_shape = env.action_space.shape or env.action_space.n - if agent_learn is None: - net = Net(args.state_shape, args.action_shape, - hidden_sizes=args.hidden_sizes, device=args.device).to(args.device) + # model + net = Net( + args.state_shape, + args.action_shape, + hidden_sizes=args.hidden_sizes, + device=args.device + ).to(args.device) if optim is None: optim = torch.optim.Adam(net.parameters(), lr=args.lr) agent_learn = DQNPolicy( - net, optim, args.gamma, args.n_step, - target_update_freq=args.target_update_freq) + net, + optim, + args.gamma, + args.n_step, + target_update_freq=args.target_update_freq + ) if args.resume_path: agent_learn.load_state_dict(torch.load(args.resume_path)) @@ -275,94 +326,121 @@ Here it is: agents = [agent_learn, agent_opponent] else: agents = [agent_opponent, agent_learn] - policy = MultiAgentPolicyManager(agents) - return policy, optim + policy = MultiAgentPolicyManager(agents, env) + return policy, optim, env.agents With the above preparation, we are close to the first learned agent. The following code is almost the same as the code in the DQN tutorial. :: - args = get_args() - - # ======== a test function that tests a pre-trained agent and exit ====== - def watch(args=get_args(), - agent_learn=None, # BasePolicy - agent_opponent=None): # BasePolicy - env = TicTacToeEnv(args.board_size, args.win_size) - policy, optim = get_agents( - args, agent_learn=agent_learn, agent_opponent=agent_opponent) + def get_env(): + return PettingZooEnv(tictactoe_v3.env()) + + + def train_agent( + args: argparse.Namespace = get_args(), + agent_learn: Optional[BasePolicy] = None, + agent_opponent: Optional[BasePolicy] = None, + optim: Optional[torch.optim.Optimizer] = None, + ) -> Tuple[dict, BasePolicy]: + + # ======== environment setup ========= + train_envs = DummyVectorEnv([get_env for _ in range(args.training_num)]) + test_envs = DummyVectorEnv([get_env for _ in range(args.test_num)]) + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + train_envs.seed(args.seed) + test_envs.seed(args.seed) + + # ======== agent setup ========= + policy, optim, agents = get_agents( + args, agent_learn=agent_learn, agent_opponent=agent_opponent, optim=optim + ) + + # ======== collector setup ========= + train_collector = Collector( + policy, + train_envs, + VectorReplayBuffer(args.buffer_size, len(train_envs)), + exploration_noise=True + ) + test_collector = Collector(policy, test_envs, exploration_noise=True) + # policy.set_eps(1) + train_collector.collect(n_step=args.batch_size * args.training_num) + + # ======== tensorboard logging setup ========= + log_path = os.path.join(args.logdir, 'tic_tac_toe', 'dqn') + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + logger = TensorboardLogger(writer) + + # ======== callback functions used during training ========= + def save_best_fn(policy): + if hasattr(args, 'model_save_path'): + model_save_path = args.model_save_path + else: + model_save_path = os.path.join( + args.logdir, 'tic_tac_toe', 'dqn', 'policy.pth' + ) + torch.save( + policy.policies[agents[args.agent_id - 1]].state_dict(), model_save_path + ) + + def stop_fn(mean_rewards): + return mean_rewards >= args.win_rate + + def train_fn(epoch, env_step): + policy.policies[agents[args.agent_id - 1]].set_eps(args.eps_train) + + def test_fn(epoch, env_step): + policy.policies[agents[args.agent_id - 1]].set_eps(args.eps_test) + + def reward_metric(rews): + return rews[:, args.agent_id - 1] + + # trainer + result = offpolicy_trainer( + policy, + train_collector, + test_collector, + args.epoch, + args.step_per_epoch, + args.step_per_collect, + args.test_num, + args.batch_size, + train_fn=train_fn, + test_fn=test_fn, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + update_per_step=args.update_per_step, + logger=logger, + test_in_train=False, + reward_metric=reward_metric + ) + + return result, policy.policies[agents[args.agent_id - 1]] + + # ======== a test function that tests a pre-trained agent ====== + def watch( + args: argparse.Namespace = get_args(), + agent_learn: Optional[BasePolicy] = None, + agent_opponent: Optional[BasePolicy] = None, + ) -> None: + env = get_env() + policy, optim, agents = get_agents( + args, agent_learn=agent_learn, agent_opponent=agent_opponent + ) policy.eval() - policy.policies[args.agent_id - 1].set_eps(args.eps_test) - collector = Collector(policy, env) + policy.policies[agents[args.agent_id - 1]].set_eps(args.eps_test) + collector = Collector(policy, env, exploration_noise=True) result = collector.collect(n_episode=1, render=args.render) - print(f'Final reward: {result["rews"][:, args.agent_id - 1].mean()}, length: {result["lens"].mean()}') - if args.watch: - watch(args) - exit(0) - - # ======== environment setup ========= - env_func = lambda: TicTacToeEnv(args.board_size, args.win_size) - train_envs = DummyVectorEnv([env_func for _ in range(args.training_num)]) - test_envs = DummyVectorEnv([env_func for _ in range(args.test_num)]) - # seed - np.random.seed(args.seed) - torch.manual_seed(args.seed) - train_envs.seed(args.seed) - test_envs.seed(args.seed) - - # ======== agent setup ========= - policy, optim = get_agents() - - # ======== collector setup ========= - buffer = VectorReplayBuffer(args.buffer_size, args.training_num) - train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) - test_collector = Collector(policy, test_envs, exploration_noise=True) - train_collector.collect(n_step=args.batch_size * args.training_num) - - # ======== tensorboard logging setup ========= - log_path = os.path.join(args.logdir, 'tic_tac_toe', 'dqn') - writer = SummaryWriter(log_path) - writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) - - # ======== callback functions used during training ========= - - def save_fn(policy): - if hasattr(args, 'model_save_path'): - model_save_path = args.model_save_path - else: - model_save_path = os.path.join( - args.logdir, 'tic_tac_toe', 'dqn', 'policy.pth') - torch.save( - policy.policies[args.agent_id - 1].state_dict(), - model_save_path) - - def stop_fn(mean_rewards): - return mean_rewards >= args.win_rate # 95% winning rate by default - # the default args.win_rate is 0.9, but the reward is [-1, 1] - # instead of [0, 1], so args.win_rate == 0.9 is equal to 95% win rate. - - def train_fn(epoch, env_step): - policy.policies[args.agent_id - 1].set_eps(args.eps_train) - - def test_fn(epoch, env_step): - policy.policies[args.agent_id - 1].set_eps(args.eps_test) - - # the reward is a vector, we need a scalar metric to monitor the training. - # we choose the reward of the learning agent - def reward_metric(rews): - return rews[:, args.agent_id - 1] - - # start training, this may require about three minutes - result = offpolicy_trainer( - policy, train_collector, test_collector, args.epoch, - args.step_per_epoch, args.step_per_collect, args.test_num, - args.batch_size, train_fn=train_fn, test_fn=test_fn, - stop_fn=stop_fn, save_fn=save_fn, update_per_step=args.update_per_step, - logger=logger, test_in_train=False, reward_metric=reward_metric) - - agent = policy.policies[args.agent_id - 1] - # let's watch the match! + rews, lens = result["rews"], result["lens"] + print(f"Final reward: {rews[:, args.agent_id - 1].mean()}, length: {lens.mean()}") + + # train the agent and watch its performance in a match! + args = get_args() + result, agent = train_agent(args) watch(args, agent) That's it. By executing the code, you will see a progress bar indicating the progress of training. After about less than 1 minute, the agent has finished training, and you can see how it plays against the random agent. Here is an example: @@ -374,97 +452,79 @@ That's it. By executing the code, you will see a progress bar indicating the pro :: - board (step 1): - ================= - ===_ _ _ X _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ================= - board (step 2): - ================= - ===_ _ _ x _ _=== - ===_ _ _ _ _ _=== - ===_ _ O _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ================= - board (step 3): - ================= - ===_ _ _ x _ _=== - ===_ _ _ _ _ _=== - ===_ _ o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ X _ _=== - ===_ _ _ _ _ _=== - ================= - board (step 4): - ================= - ===_ _ _ x _ _=== - ===_ _ _ _ _ _=== - ===_ _ o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ x _ _=== - ===_ _ O _ _ _=== - ================= - board (step 5): - ================= - ===_ _ _ x _ _=== - ===_ _ _ _ X _=== - ===_ _ o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ x _ _=== - ===_ _ o _ _ _=== - ================= - board (step 6): - ================= - ===_ _ _ x _ _=== - ===_ _ _ _ x _=== - ===_ _ o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ O x _ _=== - ===_ _ o _ _ _=== - ================= - board (step 7): - ================= - ===_ _ _ x _ X=== - ===_ _ _ _ x _=== - ===_ _ o _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ o x _ _=== - ===_ _ o _ _ _=== - ================= - board (step 8): - ================= - ===_ _ _ x _ x=== - ===_ _ _ _ x _=== - ===_ _ o _ _ _=== - ===_ _ _ _ O _=== - ===_ _ o x _ _=== - ===_ _ o _ _ _=== - ================= - board (step 9): - ================= - ===_ _ _ x _ x=== - ===_ _ _ _ x _=== - ===_ _ o _ _ _=== - ===_ _ _ _ o _=== - ===X _ o x _ _=== - ===_ _ o _ _ _=== - ================= - board (step 10): - ================= - ===_ _ _ x _ x=== - ===_ _ _ _ x _=== - ===_ _ o _ _ _=== - ===_ _ O _ o _=== - ===x _ o x _ _=== - ===_ _ o _ _ _=== - ================= - Final reward: 1.0, length: 10.0 + | | + - | - | - + _____|_____|_____ + | | + - | - | X + _____|_____|_____ + | | + - | - | - + | | + | | + - | - | - + _____|_____|_____ + | | + - | O | X + _____|_____|_____ + | | + - | - | - + | | + | | + - | - | - + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | - | - + | | + | | + - | O | - + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | - | - + | | + | | + - | O | - + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | X | - + | | + | | + O | O | - + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | X | - + | | + | | + O | O | X + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | X | - + | | + | | + O | O | X + _____|_____|_____ + | | + X | O | X + _____|_____|_____ + | | + - | X | O + | | + Final reward: 1.0, length: 8.0 .. raw:: html @@ -472,7 +532,7 @@ That's it. By executing the code, you will see a progress bar indicating the pro Notice that, our learned agent plays the role of agent 2, placing ``o`` on the board. The agent performs pretty well against the random opponent! It learns the rule of the game by trial and error, and learns that four consecutive ``o`` means winning, so it does! -The above code can be executed in a python shell or can be saved as a script file (we have saved it in ``test/multiagent/test_tic_tac_toe.py``). In the latter case, you can train an agent by +The above code can be executed in a python shell or can be saved as a script file (we have saved it in ``test/pettingzoo/test_tic_tac_toe.py``). In the latter case, you can train an agent by .. code-block:: console @@ -493,168 +553,79 @@ Here is our output: :: - board (step 1): - ================= - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ X _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ================= - board (step 2): - ================= - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ O _ _ _=== - ================= - board (step 3): - ================= - ===_ _ _ _ _ _=== - ===_ _ X _ _ _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ o _ _ _=== - ================= - board (step 4): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ _ _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ o O _ _=== - ================= - board (step 5): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ _ _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ X _ _=== - ===_ _ o o _ _=== - ================= - board (step 6): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ _ _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ x _ _=== - ===_ _ o o O _=== - ================= - board (step 7): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ X _=== - ===_ _ x _ _ _=== - ===_ _ _ _ _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 8): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ _=== - ===O _ _ _ _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 9): - ================= - ===_ _ _ _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ _=== - ===o _ _ X _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 10): - ================= - ===_ O _ _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ _=== - ===o _ _ x _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 11): - ================= - ===_ o _ _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ X=== - ===o _ _ x _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 12): - ================= - ===_ o O _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x _ _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 13): - ================= - ===_ o o _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x X _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 14): - ================= - ===O o o _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x x _=== - ===_ _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 15): - ================= - ===o o o _ _ _=== - ===_ _ x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x x _=== - ===X _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 16): - ================= - ===o o o _ _ _=== - ===_ O x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x x _=== - ===x _ _ x _ _=== - ===_ _ o o o _=== - ================= - board (step 17): - ================= - ===o o o _ _ _=== - ===_ o x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x x _=== - ===x _ X x _ _=== - ===_ _ o o o _=== - ================= - board (step 18): - ================= - ===o o o _ _ _=== - ===_ o x _ x _=== - ===_ _ x _ _ x=== - ===o _ _ x x _=== - ===x _ x x _ _=== - ===_ O o o o _=== - ================= + | | + - | - | - + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | - | - + | | + | | + - | O | - + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | - | - + | | + | | + X | O | - + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | - | - + | | + | | + X | O | - + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | - | O + | | + | | + X | O | - + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | X | O + | | + | | + X | O | O + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + - | X | O + | | + | | + X | O | O + _____|_____|_____ + | | + - | X | - + _____|_____|_____ + | | + X | X | O + | | + | | + X | O | O + _____|_____|_____ + | | + - | X | O + _____|_____|_____ + | | + X | X | O + | | + Final reward: 1.0, length: 8.0 .. raw:: html diff --git a/draft.ipynb b/draft.ipynb deleted file mode 100644 index 28674ce5f..000000000 --- a/draft.ipynb +++ /dev/null @@ -1,224 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "import gym\n", - "import numpy as np\n", - "from torchsummary import summary\n", - "from tianshou.utils.net.common import BDQNet" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "class DiscreteToContinuous(gym.ActionWrapper):\n", - " def __init__(self, env, action_per_branch):\n", - " super().__init__(env)\n", - " self.action_per_branch = action_per_branch\n", - " low = self.action_space.low\n", - " high = self.action_space.high\n", - " self.mesh = []\n", - " for l, h in zip(low, high):\n", - " self.mesh.append(np.linspace(l, h, action_per_branch))\n", - " \n", - " def action(self, act):\n", - " # modify act\n", - " act = np.array([self.mesh[i][a] for i, a in enumerate(act)])\n", - " return act" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "env = DiscreteToContinuous(gym.make('BipedalWalker-v3'), action_per_branch=2)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "state_shape = env.observation_space.shape[0]\n", - "action_shape = env.action_space.shape[0]\n", - "action_per_branch = env.action_per_branch\n", - "common_hidden_sizes = [512, 256]\n", - "value_hidden_sizes = [128]\n", - "action_hidden_sizes = [128]" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "model = BDQNet(state_shape,\n", - " action_shape,\n", - " action_per_branch,\n", - " common_hidden_sizes,\n", - " value_hidden_sizes,\n", - " action_hidden_sizes)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([1, 4, 2])" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import torch\n", - "\n", - "x = torch.randn(state_shape).unsqueeze(0)\n", - "y = model(x)\n", - "y[0].shape" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "tensor([[0, 0, 1, 0]])" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[0].max(dim=-1)[1]" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "torch.Size([1, 4, 2])" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "y[0].shape" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(y[0])" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[0]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[0]],\n", - "\n", - " [[0]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]],\n", - "\n", - " [[1]]])" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = np.random.randint(0, 2, 10)\n", - "a.reshape(-1, 1, 1)" - ] - } - ], - "metadata": { - "interpreter": { - "hash": "f3d922253121c31a7b24bed1c151b936757524923ac49fbc20420da76bf88248" - }, - "kernelspec": { - "display_name": "Python 3.9.10 ('tianshou')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.10" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/atari/README.md b/examples/atari/README.md index 561255b20..313a6fa28 100644 --- a/examples/atari/README.md +++ b/examples/atari/README.md @@ -10,7 +10,7 @@ pip install envpool After that, `atari_wrapper` will automatically switch to envpool's Atari env. EnvPool's implementation is much faster (about 2\~3x faster for pure execution speed, 1.5x for overall RL training pipeline) than python vectorized env implementation, and it's behavior is consistent to that approach (OpenAI wrapper), which will describe below. -For more information, please refer to EnvPool's [GitHub](https://github.com/sail-sg/envpool/), [Docs](https://envpool.readthedocs.io/en/latest/api/atari.html), and [3rd-party report](https://ppo-details.cleanrl.dev/2021/11/05/ppo-implementation-details/#solving-pong-in-5-minutes-with-ppo--envpool). +For more information, please refer to EnvPool's [GitHub](https://github.com/sail-sg/envpool/), [Docs](https://envpool.readthedocs.io/en/latest/api/atari.html), and [3rd-party report](https://iclr-blog-track.github.io/2022/03/25/ppo-implementation-details/#solving-pong-in-5-minutes-with-ppo--envpool). ## ALE-py diff --git a/examples/atari/atari_c51.py b/examples/atari/atari_c51.py index 4d5a91c2b..c6c58e7ca 100644 --- a/examples/atari/atari_c51.py +++ b/examples/atari/atari_c51.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -11,46 +12,54 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.policy import C51Policy from tianshou.trainer import offpolicy_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=0.0001) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--num-atoms', type=int, default=51) - parser.add_argument('--v-min', type=float, default=-10.) - parser.add_argument('--v-max', type=float, default=10.) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=0.0001) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--num-atoms", type=int, default=51) + parser.add_argument("--v-min", type=float, default=-10.) + parser.add_argument("--v-max", type=float, default=10.) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--watch', + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") + parser.add_argument( + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) return parser.parse_args() @@ -101,19 +110,36 @@ def test_c51(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_path = os.path.join(args.logdir, args.task, 'c51') + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "c51" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -159,7 +185,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -180,7 +206,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -190,5 +216,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_c51(get_args()) diff --git a/examples/atari/atari_dqn.py b/examples/atari/atari_dqn.py index 4bae24baa..7935d9b4b 100644 --- a/examples/atari/atari_dqn.py +++ b/examples/atari/atari_dqn.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -18,62 +19,63 @@ def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=0.0001) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=0.0001) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) - parser.add_argument('--resume-id', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--logger', + "--logger", type=str, default="tensorboard", choices=["tensorboard", "wandb"], ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") parser.add_argument( - '--watch', + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) parser.add_argument( - '--icm-lr-scale', + "--icm-lr-scale", type=float, default=0., - help='use intrinsic curiosity module with this lr scale' + help="use intrinsic curiosity module with this lr scale" ) parser.add_argument( - '--icm-reward-scale', + "--icm-reward-scale", type=float, default=0.01, - help='scaling factor for intrinsic curiosity reward' + help="scaling factor for intrinsic curiosity reward" ) parser.add_argument( - '--icm-forward-loss-weight', + "--icm-forward-loss-weight", type=float, default=0.2, - help='weight for the forward model loss in ICM' + help="weight for the forward model loss in ICM" ) return parser.parse_args() @@ -140,29 +142,36 @@ def test_dqn(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_name = 'dqn_icm' if args.icm_lr_scale > 0 else 'dqn' - log_path = os.path.join(args.logdir, args.task, log_name) - if args.logger == "tensorboard": - writer = SummaryWriter(log_path) - writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) - else: + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "dqn_icm" if args.icm_lr_scale > 0 else "dqn" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": logger = WandbLogger( save_interval=1, - project=args.task, - name=log_name, + name=log_name.replace(os.path.sep, "__"), run_id=args.resume_id, config=args, + project=args.wandb_project, ) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -183,8 +192,8 @@ def test_fn(epoch, env_step): def save_checkpoint_fn(epoch, env_step, gradient_step): # see also: https://pytorch.org/tutorials/beginner/saving_loading_models.html - ckpt_path = os.path.join(log_path, 'checkpoint.pth') - torch.save({'model': policy.state_dict()}, ckpt_path) + ckpt_path = os.path.join(log_path, "checkpoint.pth") + torch.save({"model": policy.state_dict()}, ckpt_path) return ckpt_path # watch agent's performance @@ -214,7 +223,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -235,7 +244,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -247,5 +256,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_dqn(get_args()) diff --git a/examples/atari/atari_fqf.py b/examples/atari/atari_fqf.py index 4a8133556..5d848bc9f 100644 --- a/examples/atari/atari_fqf.py +++ b/examples/atari/atari_fqf.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -11,49 +12,57 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.policy import FQFPolicy from tianshou.trainer import offpolicy_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.discrete import FractionProposalNetwork, FullQuantileFunction def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=3128) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=5e-5) - parser.add_argument('--fraction-lr', type=float, default=2.5e-9) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--num-fractions', type=int, default=32) - parser.add_argument('--num-cosines', type=int, default=64) - parser.add_argument('--ent-coef', type=float, default=10.) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[512]) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=3128) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=5e-5) + parser.add_argument("--fraction-lr", type=float, default=2.5e-9) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--num-fractions", type=int, default=32) + parser.add_argument("--num-cosines", type=int, default=64) + parser.add_argument("--ent-coef", type=float, default=10.) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[512]) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--watch', + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") + parser.add_argument( + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) return parser.parse_args() @@ -118,19 +127,36 @@ def test_fqf(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_path = os.path.join(args.logdir, args.task, 'fqf') + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "fqf" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -176,7 +202,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -197,7 +223,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -207,5 +233,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_fqf(get_args()) diff --git a/examples/atari/atari_iqn.py b/examples/atari/atari_iqn.py index 0ae1d94a7..17d407a89 100644 --- a/examples/atari/atari_iqn.py +++ b/examples/atari/atari_iqn.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -11,49 +12,57 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.policy import IQNPolicy from tianshou.trainer import offpolicy_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.discrete import ImplicitQuantileNetwork def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=1234) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=0.0001) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--sample-size', type=int, default=32) - parser.add_argument('--online-sample-size', type=int, default=8) - parser.add_argument('--target-sample-size', type=int, default=8) - parser.add_argument('--num-cosines', type=int, default=64) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[512]) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=1234) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=0.0001) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--sample-size", type=int, default=32) + parser.add_argument("--online-sample-size", type=int, default=8) + parser.add_argument("--target-sample-size", type=int, default=8) + parser.add_argument("--num-cosines", type=int, default=64) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[512]) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--watch', + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") + parser.add_argument( + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) return parser.parse_args() @@ -113,19 +122,36 @@ def test_iqn(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_path = os.path.join(args.logdir, args.task, 'iqn') + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "iqn" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -171,7 +197,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -192,7 +218,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -202,5 +228,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_iqn(get_args()) diff --git a/examples/atari/atari_ppo.py b/examples/atari/atari_ppo.py index 94e2c3f47..22eff1034 100644 --- a/examples/atari/atari_ppo.py +++ b/examples/atari/atari_ppo.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -19,69 +20,70 @@ def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=4213) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=5e-5) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=1000) - parser.add_argument('--repeat-per-collect', type=int, default=4) - parser.add_argument('--batch-size', type=int, default=256) - parser.add_argument('--hidden-size', type=int, default=512) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--rew-norm', type=int, default=False) - parser.add_argument('--vf-coef', type=float, default=0.5) - parser.add_argument('--ent-coef', type=float, default=0.01) - parser.add_argument('--gae-lambda', type=float, default=0.95) - parser.add_argument('--lr-decay', type=int, default=True) - parser.add_argument('--max-grad-norm', type=float, default=0.5) - parser.add_argument('--eps-clip', type=float, default=0.2) - parser.add_argument('--dual-clip', type=float, default=None) - parser.add_argument('--value-clip', type=int, default=0) - parser.add_argument('--norm-adv', type=int, default=1) - parser.add_argument('--recompute-adv', type=int, default=0) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=4213) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=5e-5) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=1000) + parser.add_argument("--repeat-per-collect", type=int, default=4) + parser.add_argument("--batch-size", type=int, default=256) + parser.add_argument("--hidden-size", type=int, default=512) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--rew-norm", type=int, default=False) + parser.add_argument("--vf-coef", type=float, default=0.5) + parser.add_argument("--ent-coef", type=float, default=0.01) + parser.add_argument("--gae-lambda", type=float, default=0.95) + parser.add_argument("--lr-decay", type=int, default=True) + parser.add_argument("--max-grad-norm", type=float, default=0.5) + parser.add_argument("--eps-clip", type=float, default=0.2) + parser.add_argument("--dual-clip", type=float, default=None) + parser.add_argument("--value-clip", type=int, default=0) + parser.add_argument("--norm-adv", type=int, default=1) + parser.add_argument("--recompute-adv", type=int, default=0) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) - parser.add_argument('--resume-id', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--logger', + "--logger", type=str, default="tensorboard", choices=["tensorboard", "wandb"], ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") parser.add_argument( - '--watch', + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) parser.add_argument( - '--icm-lr-scale', + "--icm-lr-scale", type=float, default=0., - help='use intrinsic curiosity module with this lr scale' + help="use intrinsic curiosity module with this lr scale" ) parser.add_argument( - '--icm-reward-scale', + "--icm-reward-scale", type=float, default=0.01, - help='scaling factor for intrinsic curiosity reward' + help="scaling factor for intrinsic curiosity reward" ) parser.add_argument( - '--icm-forward-loss-weight', + "--icm-forward-loss-weight", type=float, default=0.2, - help='weight for the forward model loss in ICM' + help="weight for the forward model loss in ICM" ) return parser.parse_args() @@ -184,37 +186,44 @@ def dist(p): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_name = 'ppo_icm' if args.icm_lr_scale > 0 else 'ppo' - log_path = os.path.join(args.logdir, args.task, log_name) - if args.logger == "tensorboard": - writer = SummaryWriter(log_path) - writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) - else: + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "ppo_icm" if args.icm_lr_scale > 0 else "ppo" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": logger = WandbLogger( save_interval=1, - project=args.task, - name=log_name, + name=log_name.replace(os.path.sep, "__"), run_id=args.resume_id, config=args, + project=args.wandb_project, ) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False def save_checkpoint_fn(epoch, env_step, gradient_step): # see also: https://pytorch.org/tutorials/beginner/saving_loading_models.html - ckpt_path = os.path.join(log_path, 'checkpoint.pth') - torch.save({'model': policy.state_dict()}, ckpt_path) + ckpt_path = os.path.join(log_path, "checkpoint.pth") + torch.save({"model": policy.state_dict()}, ckpt_path) return ckpt_path # watch agent's performance @@ -243,7 +252,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -263,7 +272,7 @@ def watch(): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False, resume_from_log=args.resume_id is not None, @@ -274,5 +283,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_ppo(get_args()) diff --git a/examples/atari/atari_qrdqn.py b/examples/atari/atari_qrdqn.py index 1ae4a8c88..1fa03467e 100644 --- a/examples/atari/atari_qrdqn.py +++ b/examples/atari/atari_qrdqn.py @@ -1,4 +1,5 @@ import argparse +import datetime import os import pprint @@ -11,44 +12,52 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.policy import QRDQNPolicy from tianshou.trainer import offpolicy_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=0.0001) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--num-quantiles', type=int, default=200) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=0.0001) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--num-quantiles", type=int, default=200) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--watch', + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") + parser.add_argument( + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) return parser.parse_args() @@ -97,19 +106,36 @@ def test_qrdqn(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_path = os.path.join(args.logdir, args.task, 'qrdqn') + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "qrdqn" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -155,7 +181,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -176,7 +202,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -186,5 +212,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_qrdqn(get_args()) diff --git a/examples/atari/atari_rainbow.py b/examples/atari/atari_rainbow.py index 478a6d2b8..913df677a 100644 --- a/examples/atari/atari_rainbow.py +++ b/examples/atari/atari_rainbow.py @@ -12,55 +12,63 @@ from tianshou.data import Collector, PrioritizedVectorReplayBuffer, VectorReplayBuffer from tianshou.policy import RainbowPolicy from tianshou.trainer import offpolicy_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='PongNoFrameskip-v4') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--scale-obs', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.005) - parser.add_argument('--eps-train', type=float, default=1.) - parser.add_argument('--eps-train-final', type=float, default=0.05) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=0.0000625) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--num-atoms', type=int, default=51) - parser.add_argument('--v-min', type=float, default=-10.) - parser.add_argument('--v-max', type=float, default=10.) - parser.add_argument('--noisy-std', type=float, default=0.1) - parser.add_argument('--no-dueling', action='store_true', default=False) - parser.add_argument('--no-noisy', action='store_true', default=False) - parser.add_argument('--no-priority', action='store_true', default=False) - parser.add_argument('--alpha', type=float, default=0.5) - parser.add_argument('--beta', type=float, default=0.4) - parser.add_argument('--beta-final', type=float, default=1.) - parser.add_argument('--beta-anneal-step', type=int, default=5000000) - parser.add_argument('--no-weight-norm', action='store_true', default=False) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=500) - parser.add_argument('--epoch', type=int, default=100) - parser.add_argument('--step-per-epoch', type=int, default=100000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=32) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.005) + parser.add_argument("--eps-train", type=float, default=1.) + parser.add_argument("--eps-train-final", type=float, default=0.05) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=0.0000625) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--num-atoms", type=int, default=51) + parser.add_argument("--v-min", type=float, default=-10.) + parser.add_argument("--v-max", type=float, default=10.) + parser.add_argument("--noisy-std", type=float, default=0.1) + parser.add_argument("--no-dueling", action="store_true", default=False) + parser.add_argument("--no-noisy", action="store_true", default=False) + parser.add_argument("--no-priority", action="store_true", default=False) + parser.add_argument("--alpha", type=float, default=0.5) + parser.add_argument("--beta", type=float, default=0.4) + parser.add_argument("--beta-final", type=float, default=1.) + parser.add_argument("--beta-anneal-step", type=int, default=5000000) + parser.add_argument("--no-weight-norm", action="store_true", default=False) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=500) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--step-per-epoch", type=int, default=100000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) - parser.add_argument('--frames-stack', type=int, default=4) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--watch', + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="atari.benchmark") + parser.add_argument( + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only' + action="store_true", + help="watch the play of pre-trained policy only" ) - parser.add_argument('--save-buffer-name', type=str, default=None) + parser.add_argument("--save-buffer-name", type=str, default=None) return parser.parse_args() @@ -131,22 +139,36 @@ def test_rainbow(args=get_args()): # collector train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs, exploration_noise=True) + # log - log_path = os.path.join( - args.logdir, args.task, 'rainbow', - f'seed_{args.seed}_{datetime.datetime.now().strftime("%m%d-%H%M%S")}' - ) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "rainbow" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): if env.spec.reward_threshold: return mean_rewards >= env.spec.reward_threshold - elif 'Pong' in args.task: + elif "Pong" in args.task: return mean_rewards >= 20 else: return False @@ -203,7 +225,7 @@ def watch(): n_episode=args.test_num, render=args.render ) rew = result["rews"].mean() - print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + print(f"Mean reward (over {result['n/ep']} episodes): {rew}") if args.watch: watch() @@ -224,7 +246,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False, @@ -234,5 +256,5 @@ def watch(): watch() -if __name__ == '__main__': +if __name__ == "__main__": test_rainbow(get_args()) diff --git a/examples/atari/benchmark/BreakoutNoFrameskip-v4/result.json b/examples/atari/benchmark/BreakoutNoFrameskip-v4/result.json new file mode 100644 index 000000000..2b326e9a7 --- /dev/null +++ b/examples/atari/benchmark/BreakoutNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 1.489999993145466, "rew_std": 1.4842169361904596, "Agent": "c51"}, {"env_step": 100000, "rew": 7.160000157356262, "rew_std": 3.2809146348741707, "Agent": "c51"}, {"env_step": 200000, "rew": 17.44999990463257, "rew_std": 3.923327599934239, "Agent": "c51"}, {"env_step": 300000, "rew": 17.149999713897706, "rew_std": 4.067001119498604, "Agent": "c51"}, {"env_step": 400000, "rew": 25.739999961853027, "rew_std": 3.0522777522079583, "Agent": "c51"}, {"env_step": 500000, "rew": 31.940000152587892, "rew_std": 6.872292668284413, "Agent": "c51"}, {"env_step": 600000, "rew": 36.10000019073486, "rew_std": 4.652311404432131, "Agent": "c51"}, {"env_step": 700000, "rew": 44.069999885559085, "rew_std": 8.63215520480072, "Agent": "c51"}, {"env_step": 800000, "rew": 54.52999992370606, "rew_std": 6.331357911285241, "Agent": "c51"}, {"env_step": 900000, "rew": 75.43000068664551, "rew_std": 22.26365004429836, "Agent": "c51"}, {"env_step": 1000000, "rew": 73.68000030517578, "rew_std": 23.26932736029952, "Agent": "c51"}, {"env_step": 1100000, "rew": 116.59999771118164, "rew_std": 33.29786741329967, "Agent": "c51"}, {"env_step": 1200000, "rew": 118.80000152587891, "rew_std": 24.21891832224786, "Agent": "c51"}, {"env_step": 1300000, "rew": 149.72999954223633, "rew_std": 34.80965616483245, "Agent": "c51"}, {"env_step": 1400000, "rew": 155.19000167846679, "rew_std": 59.97181996860956, "Agent": "c51"}, {"env_step": 1500000, "rew": 227.85000076293946, "rew_std": 74.72283777482421, "Agent": "c51"}, {"env_step": 1600000, "rew": 224.7099994659424, "rew_std": 81.33929570370834, "Agent": "c51"}, {"env_step": 1700000, "rew": 269.3300064086914, "rew_std": 39.881227624530716, "Agent": "c51"}, {"env_step": 1800000, "rew": 294.8, "rew_std": 48.58571966090773, "Agent": "c51"}, {"env_step": 1900000, "rew": 299.05999450683595, "rew_std": 40.756084489018896, "Agent": "c51"}, {"env_step": 2000000, "rew": 306.51000213623047, "rew_std": 39.86726833847238, "Agent": "c51"}, {"env_step": 2100000, "rew": 277.07000122070315, "rew_std": 52.86110130603287, "Agent": "c51"}, {"env_step": 2200000, "rew": 329.5400024414063, "rew_std": 32.50145093140574, "Agent": "c51"}, {"env_step": 2300000, "rew": 337.4499984741211, "rew_std": 44.79243428344727, "Agent": "c51"}, {"env_step": 2400000, "rew": 364.02000122070314, "rew_std": 18.57825612929554, "Agent": "c51"}, {"env_step": 2500000, "rew": 321.4100006103516, "rew_std": 43.22805389464291, "Agent": "c51"}, {"env_step": 2600000, "rew": 361.55, "rew_std": 27.54516925199673, "Agent": "c51"}, {"env_step": 2700000, "rew": 333.14000244140624, "rew_std": 47.81977169887054, "Agent": "c51"}, {"env_step": 2800000, "rew": 322.52000579833987, "rew_std": 76.32684991482328, "Agent": "c51"}, {"env_step": 2900000, "rew": 330.7200012207031, "rew_std": 64.05682960403955, "Agent": "c51"}, {"env_step": 3000000, "rew": 365.2100006103516, "rew_std": 15.082475188932436, "Agent": "c51"}, {"env_step": 3100000, "rew": 355.52999725341795, "rew_std": 49.67731822769064, "Agent": "c51"}, {"env_step": 3200000, "rew": 365.6499969482422, "rew_std": 50.31155528215873, "Agent": "c51"}, {"env_step": 3300000, "rew": 346.89000091552737, "rew_std": 37.82696142293252, "Agent": "c51"}, {"env_step": 3400000, "rew": 337.4800048828125, "rew_std": 62.96080895743974, "Agent": "c51"}, {"env_step": 3500000, "rew": 362.2200012207031, "rew_std": 35.653072714280874, "Agent": "c51"}, {"env_step": 3600000, "rew": 333.90000305175784, "rew_std": 81.13762513523231, "Agent": "c51"}, {"env_step": 3700000, "rew": 376.25, "rew_std": 31.655335448058853, "Agent": "c51"}, {"env_step": 3800000, "rew": 362.44000244140625, "rew_std": 18.283176431620095, "Agent": "c51"}, {"env_step": 3900000, "rew": 366.27000427246094, "rew_std": 35.04446188070728, "Agent": "c51"}, {"env_step": 4000000, "rew": 382.57000122070315, "rew_std": 14.872595676225728, "Agent": "c51"}, {"env_step": 4100000, "rew": 359.1599945068359, "rew_std": 31.658272094999887, "Agent": "c51"}, {"env_step": 4200000, "rew": 360.13999938964844, "rew_std": 25.854099915610277, "Agent": "c51"}, {"env_step": 4300000, "rew": 358.4100006103516, "rew_std": 45.640715079962746, "Agent": "c51"}, {"env_step": 4400000, "rew": 375.90000305175784, "rew_std": 31.782793945259574, "Agent": "c51"}, {"env_step": 4500000, "rew": 357.9, "rew_std": 39.46456467194559, "Agent": "c51"}, {"env_step": 4600000, "rew": 403.4100036621094, "rew_std": 37.36884707172226, "Agent": "c51"}, {"env_step": 4700000, "rew": 375.38999938964844, "rew_std": 24.63223304182013, "Agent": "c51"}, {"env_step": 4800000, "rew": 345.60999908447263, "rew_std": 64.29045939613836, "Agent": "c51"}, {"env_step": 4900000, "rew": 369.19000244140625, "rew_std": 40.53828808279498, "Agent": "c51"}, {"env_step": 5000000, "rew": 328.8799976348877, "rew_std": 98.52224821427203, "Agent": "c51"}, {"env_step": 5100000, "rew": 385.2899993896484, "rew_std": 33.74096429736962, "Agent": "c51"}, {"env_step": 5200000, "rew": 378.63999938964844, "rew_std": 23.966530681765192, "Agent": "c51"}, {"env_step": 5300000, "rew": 358.99000244140626, "rew_std": 35.26937456390392, "Agent": "c51"}, {"env_step": 5400000, "rew": 367.1299987792969, "rew_std": 37.816190250907496, "Agent": "c51"}, {"env_step": 5500000, "rew": 374.85, "rew_std": 48.78137438800481, "Agent": "c51"}, {"env_step": 5600000, "rew": 396.31000366210935, "rew_std": 16.84918405865486, "Agent": "c51"}, {"env_step": 5700000, "rew": 392.25, "rew_std": 17.89766911339113, "Agent": "c51"}, {"env_step": 5800000, "rew": 371.0399993896484, "rew_std": 39.75309508083556, "Agent": "c51"}, {"env_step": 5900000, "rew": 361.20999908447266, "rew_std": 66.4414985994371, "Agent": "c51"}, {"env_step": 6000000, "rew": 379.6600006103516, "rew_std": 33.6160148677817, "Agent": "c51"}, {"env_step": 6100000, "rew": 376.65, "rew_std": 38.38656729834399, "Agent": "c51"}, {"env_step": 6200000, "rew": 401.14000244140624, "rew_std": 25.221350146221273, "Agent": "c51"}, {"env_step": 6300000, "rew": 373.94000244140625, "rew_std": 43.70732540398474, "Agent": "c51"}, {"env_step": 6400000, "rew": 383.6600006103516, "rew_std": 21.5665598368943, "Agent": "c51"}, {"env_step": 6500000, "rew": 396.2099945068359, "rew_std": 23.735648538855735, "Agent": "c51"}, {"env_step": 6600000, "rew": 379.5899993896484, "rew_std": 37.21383152538017, "Agent": "c51"}, {"env_step": 6700000, "rew": 369.11000366210936, "rew_std": 33.04576961471482, "Agent": "c51"}, {"env_step": 6800000, "rew": 384.3999969482422, "rew_std": 43.737378807281985, "Agent": "c51"}, {"env_step": 6900000, "rew": 392.86000366210936, "rew_std": 25.008686655391916, "Agent": "c51"}, {"env_step": 7000000, "rew": 388.18999938964845, "rew_std": 41.67885269592273, "Agent": "c51"}, {"env_step": 7100000, "rew": 400.7399963378906, "rew_std": 31.629359514939143, "Agent": "c51"}, {"env_step": 7200000, "rew": 392.60999755859376, "rew_std": 31.733938484043435, "Agent": "c51"}, {"env_step": 7300000, "rew": 381.43999633789065, "rew_std": 28.448867547263603, "Agent": "c51"}, {"env_step": 7400000, "rew": 383.7099975585937, "rew_std": 27.319865345659487, "Agent": "c51"}, {"env_step": 7500000, "rew": 400.85, "rew_std": 24.355008972204978, "Agent": "c51"}, {"env_step": 7600000, "rew": 370.6299987792969, "rew_std": 61.18848259333839, "Agent": "c51"}, {"env_step": 7700000, "rew": 377.75999755859374, "rew_std": 29.30734371334747, "Agent": "c51"}, {"env_step": 7800000, "rew": 366.9, "rew_std": 61.976462247217256, "Agent": "c51"}, {"env_step": 7900000, "rew": 381.92999877929685, "rew_std": 42.68440563855683, "Agent": "c51"}, {"env_step": 8000000, "rew": 389.1, "rew_std": 30.273154962392713, "Agent": "c51"}, {"env_step": 8100000, "rew": 377.89000244140624, "rew_std": 64.2143809894212, "Agent": "c51"}, {"env_step": 8200000, "rew": 369.98999786376953, "rew_std": 51.384270079498556, "Agent": "c51"}, {"env_step": 8300000, "rew": 363.1800018310547, "rew_std": 53.85413212986565, "Agent": "c51"}, {"env_step": 8400000, "rew": 402.32000122070315, "rew_std": 47.67640870874529, "Agent": "c51"}, {"env_step": 8500000, "rew": 412.0899993896484, "rew_std": 49.33683150503912, "Agent": "c51"}, {"env_step": 8600000, "rew": 362.84000396728516, "rew_std": 95.5870313016572, "Agent": "c51"}, {"env_step": 8700000, "rew": 374.8699951171875, "rew_std": 35.3107884710375, "Agent": "c51"}, {"env_step": 8800000, "rew": 387.94000244140625, "rew_std": 45.46937780145519, "Agent": "c51"}, {"env_step": 8900000, "rew": 390.63999938964844, "rew_std": 27.526135712106345, "Agent": "c51"}, {"env_step": 9000000, "rew": 389.9, "rew_std": 36.79899479363974, "Agent": "c51"}, {"env_step": 9100000, "rew": 401.82000122070315, "rew_std": 28.145932045294533, "Agent": "c51"}, {"env_step": 9200000, "rew": 378.2200042724609, "rew_std": 44.36847920124076, "Agent": "c51"}, {"env_step": 9300000, "rew": 378.5300048828125, "rew_std": 20.175735548110744, "Agent": "c51"}, {"env_step": 9400000, "rew": 411.37000427246096, "rew_std": 26.821631968299695, "Agent": "c51"}, {"env_step": 9500000, "rew": 398.6599945068359, "rew_std": 36.35720540569888, "Agent": "c51"}, {"env_step": 9600000, "rew": 386.3699981689453, "rew_std": 28.54824021627022, "Agent": "c51"}, {"env_step": 9700000, "rew": 389.52000122070314, "rew_std": 61.006069637114855, "Agent": "c51"}, {"env_step": 9800000, "rew": 412.8700012207031, "rew_std": 35.838668839394245, "Agent": "c51"}, {"env_step": 9900000, "rew": 399.7899993896484, "rew_std": 36.742630957118074, "Agent": "c51"}, {"env_step": 10000000, "rew": 393.1800048828125, "rew_std": 20.823774222066966, "Agent": "c51"}, {"env_step": 0, "rew": 2.3299999952316286, "rew_std": 1.0705605633034625, "Agent": "dqn"}, {"env_step": 100000, "rew": 7.849999904632568, "rew_std": 1.8200273963417377, "Agent": "dqn"}, {"env_step": 200000, "rew": 17.30000009536743, "rew_std": 9.143740794241733, "Agent": "dqn"}, {"env_step": 300000, "rew": 20.85, "rew_std": 4.622391089254499, "Agent": "dqn"}, {"env_step": 400000, "rew": 20.7, "rew_std": 5.0768098447216925, "Agent": "dqn"}, {"env_step": 500000, "rew": 25.080000114440917, "rew_std": 3.1577840761532077, "Agent": "dqn"}, {"env_step": 600000, "rew": 28.130000114440918, "rew_std": 3.998262178859403, "Agent": "dqn"}, {"env_step": 700000, "rew": 35.89000053405762, "rew_std": 6.575477441314717, "Agent": "dqn"}, {"env_step": 800000, "rew": 40.44000015258789, "rew_std": 3.872260440437905, "Agent": "dqn"}, {"env_step": 900000, "rew": 39.329999923706055, "rew_std": 8.570536398642876, "Agent": "dqn"}, {"env_step": 1000000, "rew": 41.73000030517578, "rew_std": 9.01854193615441, "Agent": "dqn"}, {"env_step": 1100000, "rew": 46.03999996185303, "rew_std": 13.705852687158178, "Agent": "dqn"}, {"env_step": 1200000, "rew": 46.45000019073486, "rew_std": 8.782511298663483, "Agent": "dqn"}, {"env_step": 1300000, "rew": 47.709999084472656, "rew_std": 8.820708473452349, "Agent": "dqn"}, {"env_step": 1400000, "rew": 53.69000015258789, "rew_std": 8.472597260377047, "Agent": "dqn"}, {"env_step": 1500000, "rew": 56.78999996185303, "rew_std": 19.832672991347415, "Agent": "dqn"}, {"env_step": 1600000, "rew": 47.09000072479248, "rew_std": 14.559289729405599, "Agent": "dqn"}, {"env_step": 1700000, "rew": 51.7899995803833, "rew_std": 15.683395606454836, "Agent": "dqn"}, {"env_step": 1800000, "rew": 49.360000419616696, "rew_std": 14.638525024332282, "Agent": "dqn"}, {"env_step": 1900000, "rew": 52.28000049591064, "rew_std": 13.878459272042756, "Agent": "dqn"}, {"env_step": 2000000, "rew": 50.32000026702881, "rew_std": 12.656760859312767, "Agent": "dqn"}, {"env_step": 2100000, "rew": 50.69000015258789, "rew_std": 7.424345019289965, "Agent": "dqn"}, {"env_step": 2200000, "rew": 57.699999237060545, "rew_std": 26.776631520034286, "Agent": "dqn"}, {"env_step": 2300000, "rew": 51.079999923706055, "rew_std": 16.490165999706548, "Agent": "dqn"}, {"env_step": 2400000, "rew": 56.36000061035156, "rew_std": 10.570827964178985, "Agent": "dqn"}, {"env_step": 2500000, "rew": 61.59000091552734, "rew_std": 20.03838606299226, "Agent": "dqn"}, {"env_step": 2600000, "rew": 49.81999969482422, "rew_std": 11.181932063887603, "Agent": "dqn"}, {"env_step": 2700000, "rew": 50.91000061035156, "rew_std": 6.640550189836024, "Agent": "dqn"}, {"env_step": 2800000, "rew": 51.87000007629395, "rew_std": 16.15952039351572, "Agent": "dqn"}, {"env_step": 2900000, "rew": 55.97000026702881, "rew_std": 12.618800305474606, "Agent": "dqn"}, {"env_step": 3000000, "rew": 62.70000076293945, "rew_std": 15.349006905504705, "Agent": "dqn"}, {"env_step": 3100000, "rew": 62.3, "rew_std": 7.967809614396711, "Agent": "dqn"}, {"env_step": 3200000, "rew": 57.64999961853027, "rew_std": 14.362815684542023, "Agent": "dqn"}, {"env_step": 3300000, "rew": 63.35, "rew_std": 17.445471857828533, "Agent": "dqn"}, {"env_step": 3400000, "rew": 61.999999618530275, "rew_std": 9.367175853731641, "Agent": "dqn"}, {"env_step": 3500000, "rew": 58.58999938964844, "rew_std": 7.702006216494004, "Agent": "dqn"}, {"env_step": 3600000, "rew": 59.83000030517578, "rew_std": 11.262597633065775, "Agent": "dqn"}, {"env_step": 3700000, "rew": 66.31999969482422, "rew_std": 12.887497638750386, "Agent": "dqn"}, {"env_step": 3800000, "rew": 60.06000022888183, "rew_std": 8.369014666496854, "Agent": "dqn"}, {"env_step": 3900000, "rew": 68.73999938964843, "rew_std": 16.99924625009274, "Agent": "dqn"}, {"env_step": 4000000, "rew": 65.21999893188476, "rew_std": 13.805780604536238, "Agent": "dqn"}, {"env_step": 4100000, "rew": 65.03999938964844, "rew_std": 24.91546420245774, "Agent": "dqn"}, {"env_step": 4200000, "rew": 57.69999961853027, "rew_std": 19.0262977849217, "Agent": "dqn"}, {"env_step": 4300000, "rew": 72.17000045776368, "rew_std": 17.75004520954237, "Agent": "dqn"}, {"env_step": 4400000, "rew": 69.8600009918213, "rew_std": 6.844588638105477, "Agent": "dqn"}, {"env_step": 4500000, "rew": 61.260000228881836, "rew_std": 11.948741149739522, "Agent": "dqn"}, {"env_step": 4600000, "rew": 67.55, "rew_std": 8.807752424830234, "Agent": "dqn"}, {"env_step": 4700000, "rew": 70.23999977111816, "rew_std": 8.630087095950666, "Agent": "dqn"}, {"env_step": 4800000, "rew": 72.41999969482421, "rew_std": 12.884859861619276, "Agent": "dqn"}, {"env_step": 4900000, "rew": 73.97000045776367, "rew_std": 13.834816048918906, "Agent": "dqn"}, {"env_step": 5000000, "rew": 74.23000030517578, "rew_std": 13.696208341395574, "Agent": "dqn"}, {"env_step": 5100000, "rew": 67.39999885559082, "rew_std": 15.599165755242288, "Agent": "dqn"}, {"env_step": 5200000, "rew": 85.09999961853028, "rew_std": 31.04148759266113, "Agent": "dqn"}, {"env_step": 5300000, "rew": 69.8799991607666, "rew_std": 17.921539788764512, "Agent": "dqn"}, {"env_step": 5400000, "rew": 73.52999992370606, "rew_std": 21.51474045621979, "Agent": "dqn"}, {"env_step": 5500000, "rew": 77.47999992370606, "rew_std": 13.142054243069717, "Agent": "dqn"}, {"env_step": 5600000, "rew": 81.1799991607666, "rew_std": 20.257827947382573, "Agent": "dqn"}, {"env_step": 5700000, "rew": 91.23000030517578, "rew_std": 32.801493962015556, "Agent": "dqn"}, {"env_step": 5800000, "rew": 82.73000068664551, "rew_std": 19.65411187086091, "Agent": "dqn"}, {"env_step": 5900000, "rew": 81.49000053405761, "rew_std": 18.301501103980517, "Agent": "dqn"}, {"env_step": 6000000, "rew": 81.15999946594238, "rew_std": 17.353743105571674, "Agent": "dqn"}, {"env_step": 6100000, "rew": 78.85, "rew_std": 23.848828094928958, "Agent": "dqn"}, {"env_step": 6200000, "rew": 73.11000022888183, "rew_std": 16.69673268597132, "Agent": "dqn"}, {"env_step": 6300000, "rew": 91.60000190734863, "rew_std": 27.26793083658477, "Agent": "dqn"}, {"env_step": 6400000, "rew": 91.17999992370605, "rew_std": 17.885123036862367, "Agent": "dqn"}, {"env_step": 6500000, "rew": 85.3, "rew_std": 27.91558722418007, "Agent": "dqn"}, {"env_step": 6600000, "rew": 78.09999961853028, "rew_std": 18.799307603869114, "Agent": "dqn"}, {"env_step": 6700000, "rew": 73.22999992370606, "rew_std": 15.534029981853278, "Agent": "dqn"}, {"env_step": 6800000, "rew": 98.13000106811523, "rew_std": 20.634877163905355, "Agent": "dqn"}, {"env_step": 6900000, "rew": 89.0, "rew_std": 24.171967172300295, "Agent": "dqn"}, {"env_step": 7000000, "rew": 94.03000106811524, "rew_std": 22.807151580126355, "Agent": "dqn"}, {"env_step": 7100000, "rew": 91.46000061035156, "rew_std": 23.31502638921496, "Agent": "dqn"}, {"env_step": 7200000, "rew": 83.65999984741211, "rew_std": 16.474659802642254, "Agent": "dqn"}, {"env_step": 7300000, "rew": 80.12000045776367, "rew_std": 11.930952073355787, "Agent": "dqn"}, {"env_step": 7400000, "rew": 77.42999877929688, "rew_std": 19.180929987122642, "Agent": "dqn"}, {"env_step": 7500000, "rew": 86.84999923706054, "rew_std": 17.592342521566607, "Agent": "dqn"}, {"env_step": 7600000, "rew": 82.52999992370606, "rew_std": 20.004302258249783, "Agent": "dqn"}, {"env_step": 7700000, "rew": 107.37000045776367, "rew_std": 34.55555067760397, "Agent": "dqn"}, {"env_step": 7800000, "rew": 96.06000061035157, "rew_std": 22.622474586994528, "Agent": "dqn"}, {"env_step": 7900000, "rew": 94.13999977111817, "rew_std": 28.41982322868775, "Agent": "dqn"}, {"env_step": 8000000, "rew": 101.21000061035156, "rew_std": 26.587306822196613, "Agent": "dqn"}, {"env_step": 8100000, "rew": 85.82999992370605, "rew_std": 25.36777673896879, "Agent": "dqn"}, {"env_step": 8200000, "rew": 87.62999954223633, "rew_std": 39.89198041691922, "Agent": "dqn"}, {"env_step": 8300000, "rew": 101.57999839782715, "rew_std": 41.77749993495092, "Agent": "dqn"}, {"env_step": 8400000, "rew": 93.03000068664551, "rew_std": 27.115569981755712, "Agent": "dqn"}, {"env_step": 8500000, "rew": 87.7099998474121, "rew_std": 36.714669130069105, "Agent": "dqn"}, {"env_step": 8600000, "rew": 90.95000076293945, "rew_std": 12.810327317331756, "Agent": "dqn"}, {"env_step": 8700000, "rew": 104.0099998474121, "rew_std": 32.22671128294261, "Agent": "dqn"}, {"env_step": 8800000, "rew": 103.99000091552735, "rew_std": 27.8962892258018, "Agent": "dqn"}, {"env_step": 8900000, "rew": 114.25000076293945, "rew_std": 32.67464640396138, "Agent": "dqn"}, {"env_step": 9000000, "rew": 106.80000038146973, "rew_std": 32.973262202331064, "Agent": "dqn"}, {"env_step": 9100000, "rew": 98.43000030517578, "rew_std": 20.662141740244365, "Agent": "dqn"}, {"env_step": 9200000, "rew": 88.96000099182129, "rew_std": 33.323092362700145, "Agent": "dqn"}, {"env_step": 9300000, "rew": 121.35000076293946, "rew_std": 25.42248087718444, "Agent": "dqn"}, {"env_step": 9400000, "rew": 114.03000106811524, "rew_std": 31.284407594353972, "Agent": "dqn"}, {"env_step": 9500000, "rew": 125.76000061035157, "rew_std": 36.260922820967124, "Agent": "dqn"}, {"env_step": 9600000, "rew": 100.2, "rew_std": 41.19708629230755, "Agent": "dqn"}, {"env_step": 9700000, "rew": 122.76999969482422, "rew_std": 33.774755897887985, "Agent": "dqn"}, {"env_step": 9800000, "rew": 133.53999938964844, "rew_std": 44.59944213785166, "Agent": "dqn"}, {"env_step": 9900000, "rew": 111.62000198364258, "rew_std": 32.61686090929321, "Agent": "dqn"}, {"env_step": 10000000, "rew": 119.93999862670898, "rew_std": 32.37928701114132, "Agent": "dqn"}, {"env_step": 0, "rew": 1.8899999886751175, "rew_std": 1.2739309645395656, "Agent": "fqf"}, {"env_step": 100000, "rew": 6.579999995231629, "rew_std": 2.0439177558947796, "Agent": "fqf"}, {"env_step": 200000, "rew": 15.449999904632568, "rew_std": 1.902235310873203, "Agent": "fqf"}, {"env_step": 300000, "rew": 15.630000019073487, "rew_std": 1.6285271252770628, "Agent": "fqf"}, {"env_step": 400000, "rew": 20.410000228881835, "rew_std": 2.727068191039453, "Agent": "fqf"}, {"env_step": 500000, "rew": 27.5, "rew_std": 5.404812646912962, "Agent": "fqf"}, {"env_step": 600000, "rew": 34.10999984741211, "rew_std": 5.110469271319042, "Agent": "fqf"}, {"env_step": 700000, "rew": 44.479999732971194, "rew_std": 9.641866944004914, "Agent": "fqf"}, {"env_step": 800000, "rew": 58.929999923706056, "rew_std": 10.773119278904277, "Agent": "fqf"}, {"env_step": 900000, "rew": 74.28000030517578, "rew_std": 18.03883545662945, "Agent": "fqf"}, {"env_step": 1000000, "rew": 91.27000007629394, "rew_std": 19.16142200039165, "Agent": "fqf"}, {"env_step": 1100000, "rew": 89.1100009918213, "rew_std": 13.826457342888988, "Agent": "fqf"}, {"env_step": 1200000, "rew": 94.35999984741211, "rew_std": 42.61833485770056, "Agent": "fqf"}, {"env_step": 1300000, "rew": 111.60999984741211, "rew_std": 28.842728288197964, "Agent": "fqf"}, {"env_step": 1400000, "rew": 137.2, "rew_std": 25.806123286033692, "Agent": "fqf"}, {"env_step": 1500000, "rew": 157.3999984741211, "rew_std": 31.331581823972737, "Agent": "fqf"}, {"env_step": 1600000, "rew": 166.1099998474121, "rew_std": 31.462182753954036, "Agent": "fqf"}, {"env_step": 1700000, "rew": 189.7300018310547, "rew_std": 38.91149203014107, "Agent": "fqf"}, {"env_step": 1800000, "rew": 206.3300003051758, "rew_std": 38.15114780212248, "Agent": "fqf"}, {"env_step": 1900000, "rew": 224.5, "rew_std": 38.52728870047049, "Agent": "fqf"}, {"env_step": 2000000, "rew": 222.76000061035157, "rew_std": 46.865021102153406, "Agent": "fqf"}, {"env_step": 2100000, "rew": 245.28999938964844, "rew_std": 49.371034931773835, "Agent": "fqf"}, {"env_step": 2200000, "rew": 267.70999908447266, "rew_std": 28.133131370013544, "Agent": "fqf"}, {"env_step": 2300000, "rew": 268.58999786376955, "rew_std": 49.59553152130905, "Agent": "fqf"}, {"env_step": 2400000, "rew": 247.30999908447265, "rew_std": 63.79005209586264, "Agent": "fqf"}, {"env_step": 2500000, "rew": 281.91000213623045, "rew_std": 36.61752006054675, "Agent": "fqf"}, {"env_step": 2600000, "rew": 273.11999969482423, "rew_std": 53.78060736276747, "Agent": "fqf"}, {"env_step": 2700000, "rew": 299.9100006103516, "rew_std": 30.088116602832, "Agent": "fqf"}, {"env_step": 2800000, "rew": 297.63999938964844, "rew_std": 55.8203918208197, "Agent": "fqf"}, {"env_step": 2900000, "rew": 309.13000335693357, "rew_std": 49.09570374572412, "Agent": "fqf"}, {"env_step": 3000000, "rew": 315.32999725341796, "rew_std": 43.39456033965058, "Agent": "fqf"}, {"env_step": 3100000, "rew": 279.22000274658205, "rew_std": 85.23476924161254, "Agent": "fqf"}, {"env_step": 3200000, "rew": 297.58000030517576, "rew_std": 63.087017417518, "Agent": "fqf"}, {"env_step": 3300000, "rew": 301.73999938964846, "rew_std": 49.87208136848178, "Agent": "fqf"}, {"env_step": 3400000, "rew": 275.0300010681152, "rew_std": 68.53272323238663, "Agent": "fqf"}, {"env_step": 3500000, "rew": 309.43999938964845, "rew_std": 32.276252757870395, "Agent": "fqf"}, {"env_step": 3600000, "rew": 319.67999572753905, "rew_std": 42.78061813129124, "Agent": "fqf"}, {"env_step": 3700000, "rew": 332.6600006103516, "rew_std": 33.96071915762684, "Agent": "fqf"}, {"env_step": 3800000, "rew": 355.36000061035156, "rew_std": 28.662765200015865, "Agent": "fqf"}, {"env_step": 3900000, "rew": 316.99999542236327, "rew_std": 53.55531395626551, "Agent": "fqf"}, {"env_step": 4000000, "rew": 319.78999786376954, "rew_std": 80.64893371138278, "Agent": "fqf"}, {"env_step": 4100000, "rew": 345.6599975585938, "rew_std": 25.589495375720983, "Agent": "fqf"}, {"env_step": 4200000, "rew": 338.1300048828125, "rew_std": 25.35192511248875, "Agent": "fqf"}, {"env_step": 4300000, "rew": 331.38999633789064, "rew_std": 38.176389861042445, "Agent": "fqf"}, {"env_step": 4400000, "rew": 328.5199996948242, "rew_std": 88.22566393672108, "Agent": "fqf"}, {"env_step": 4500000, "rew": 356.0900024414062, "rew_std": 26.407973243051238, "Agent": "fqf"}, {"env_step": 4600000, "rew": 330.85999755859376, "rew_std": 52.67645135396039, "Agent": "fqf"}, {"env_step": 4700000, "rew": 363.3799987792969, "rew_std": 35.14901906852587, "Agent": "fqf"}, {"env_step": 4800000, "rew": 364.2799987792969, "rew_std": 22.464898788730974, "Agent": "fqf"}, {"env_step": 4900000, "rew": 342.62999572753904, "rew_std": 31.664115177564884, "Agent": "fqf"}, {"env_step": 5000000, "rew": 326.9600006103516, "rew_std": 44.123470427909474, "Agent": "fqf"}, {"env_step": 5100000, "rew": 342.51000061035154, "rew_std": 42.72719409460211, "Agent": "fqf"}, {"env_step": 5200000, "rew": 368.5100036621094, "rew_std": 36.07728802793028, "Agent": "fqf"}, {"env_step": 5300000, "rew": 339.4, "rew_std": 37.085738197603874, "Agent": "fqf"}, {"env_step": 5400000, "rew": 339.8399963378906, "rew_std": 29.956508084411002, "Agent": "fqf"}, {"env_step": 5500000, "rew": 329.1000015258789, "rew_std": 52.50864780548441, "Agent": "fqf"}, {"env_step": 5600000, "rew": 345.49000244140626, "rew_std": 25.85855984648126, "Agent": "fqf"}, {"env_step": 5700000, "rew": 348.35999908447263, "rew_std": 53.21148820407242, "Agent": "fqf"}, {"env_step": 5800000, "rew": 344.5499984741211, "rew_std": 46.83556422879634, "Agent": "fqf"}, {"env_step": 5900000, "rew": 350.65999908447264, "rew_std": 54.664820479976136, "Agent": "fqf"}, {"env_step": 6000000, "rew": 346.4800033569336, "rew_std": 62.894860468597145, "Agent": "fqf"}, {"env_step": 6100000, "rew": 350.48999938964846, "rew_std": 26.15692816124583, "Agent": "fqf"}, {"env_step": 6200000, "rew": 362.8300048828125, "rew_std": 36.7557307025397, "Agent": "fqf"}, {"env_step": 6300000, "rew": 328.7800018310547, "rew_std": 47.65588972046255, "Agent": "fqf"}, {"env_step": 6400000, "rew": 364.5799987792969, "rew_std": 26.335103106220885, "Agent": "fqf"}, {"env_step": 6500000, "rew": 318.6900009155273, "rew_std": 56.799413057921996, "Agent": "fqf"}, {"env_step": 6600000, "rew": 371.51999816894534, "rew_std": 26.211210500163315, "Agent": "fqf"}, {"env_step": 6700000, "rew": 347.8500030517578, "rew_std": 32.235581327971936, "Agent": "fqf"}, {"env_step": 6800000, "rew": 372.7200042724609, "rew_std": 28.695146937057064, "Agent": "fqf"}, {"env_step": 6900000, "rew": 361.5699981689453, "rew_std": 43.78193476682266, "Agent": "fqf"}, {"env_step": 7000000, "rew": 317.13000030517577, "rew_std": 49.348357840104256, "Agent": "fqf"}, {"env_step": 7100000, "rew": 340.74000091552733, "rew_std": 77.68987471874023, "Agent": "fqf"}, {"env_step": 7200000, "rew": 344.6399978637695, "rew_std": 59.30083036122553, "Agent": "fqf"}, {"env_step": 7300000, "rew": 341.8500015258789, "rew_std": 40.51899094909766, "Agent": "fqf"}, {"env_step": 7400000, "rew": 359.8500030517578, "rew_std": 20.46920835454293, "Agent": "fqf"}, {"env_step": 7500000, "rew": 342.1299987792969, "rew_std": 52.97516510033074, "Agent": "fqf"}, {"env_step": 7600000, "rew": 348.57000122070315, "rew_std": 27.585034799201082, "Agent": "fqf"}, {"env_step": 7700000, "rew": 347.2500030517578, "rew_std": 27.34297686518728, "Agent": "fqf"}, {"env_step": 7800000, "rew": 345.8099990844727, "rew_std": 71.28503787650662, "Agent": "fqf"}, {"env_step": 7900000, "rew": 355.4199981689453, "rew_std": 48.30798976082001, "Agent": "fqf"}, {"env_step": 8000000, "rew": 373.85, "rew_std": 25.45906797131143, "Agent": "fqf"}, {"env_step": 8100000, "rew": 346.7200012207031, "rew_std": 34.270798637584605, "Agent": "fqf"}, {"env_step": 8200000, "rew": 365.01000213623047, "rew_std": 59.017802669324645, "Agent": "fqf"}, {"env_step": 8300000, "rew": 334.4899932861328, "rew_std": 60.103334841706335, "Agent": "fqf"}, {"env_step": 8400000, "rew": 355.2200012207031, "rew_std": 30.91270427542967, "Agent": "fqf"}, {"env_step": 8500000, "rew": 359.00999755859374, "rew_std": 34.8320641579841, "Agent": "fqf"}, {"env_step": 8600000, "rew": 336.2000045776367, "rew_std": 45.92332986368791, "Agent": "fqf"}, {"env_step": 8700000, "rew": 371.00999755859374, "rew_std": 35.20410344429364, "Agent": "fqf"}, {"env_step": 8800000, "rew": 345.88999938964844, "rew_std": 27.24296297805744, "Agent": "fqf"}, {"env_step": 8900000, "rew": 327.00999603271487, "rew_std": 62.46383398874547, "Agent": "fqf"}, {"env_step": 9000000, "rew": 367.0299957275391, "rew_std": 24.968425234757614, "Agent": "fqf"}, {"env_step": 9100000, "rew": 357.7699951171875, "rew_std": 31.722642179225197, "Agent": "fqf"}, {"env_step": 9200000, "rew": 351.0800018310547, "rew_std": 40.11283828329421, "Agent": "fqf"}, {"env_step": 9300000, "rew": 363.8500030517578, "rew_std": 21.079715798651307, "Agent": "fqf"}, {"env_step": 9400000, "rew": 342.8400054931641, "rew_std": 63.49006749721425, "Agent": "fqf"}, {"env_step": 9500000, "rew": 373.99000091552733, "rew_std": 45.288134172835484, "Agent": "fqf"}, {"env_step": 9600000, "rew": 356.8399993896484, "rew_std": 47.543644666957135, "Agent": "fqf"}, {"env_step": 9700000, "rew": 364.5300018310547, "rew_std": 23.580712727396694, "Agent": "fqf"}, {"env_step": 9800000, "rew": 382.63999633789064, "rew_std": 29.47945522804052, "Agent": "fqf"}, {"env_step": 9900000, "rew": 353.19000244140625, "rew_std": 41.2007373443112, "Agent": "fqf"}, {"env_step": 10000000, "rew": 335.73000183105466, "rew_std": 36.178617059142844, "Agent": "fqf"}, {"env_step": 0, "rew": 2.0200000025331972, "rew_std": 1.062826409813908, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 11.1, "rew_std": 1.8363006019761408, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 15.950000190734864, "rew_std": 2.2743131208480416, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 21.6100004196167, "rew_std": 1.6908279939018895, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 26.039999961853027, "rew_std": 3.166764513719337, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 31.70999984741211, "rew_std": 4.500988535661596, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 34.890000343322754, "rew_std": 8.884306606312624, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 39.35000057220459, "rew_std": 11.433481420905531, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 45.01999969482422, "rew_std": 7.258622758189306, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 51.72000007629394, "rew_std": 12.04224138466468, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 48.96999988555908, "rew_std": 9.053513212898372, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 66.27000007629394, "rew_std": 17.327149763903382, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 67.5099998474121, "rew_std": 15.202332343099394, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 47.89999961853027, "rew_std": 13.158266496317525, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 54.50000057220459, "rew_std": 12.41821272111614, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 71.68000030517578, "rew_std": 12.78567937628033, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 65.53000030517578, "rew_std": 15.931104640556512, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 65.3899990081787, "rew_std": 14.402253328610442, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 69.67999954223633, "rew_std": 13.667245828132831, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 104.74000091552735, "rew_std": 41.49964546688277, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 64.65, "rew_std": 15.356839508305148, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 67.09999961853028, "rew_std": 20.951228029225863, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 81.0700008392334, "rew_std": 28.43526185117888, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 69.75000076293945, "rew_std": 15.399562151245634, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 93.77000045776367, "rew_std": 48.462461876453574, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 90.25000076293945, "rew_std": 37.74602613741299, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 90.18000106811523, "rew_std": 29.855881757158723, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 99.36000061035156, "rew_std": 40.36459324093467, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 81.06999969482422, "rew_std": 39.89363303080445, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 95.2400001525879, "rew_std": 43.06056686630658, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 104.05000076293945, "rew_std": 28.336240349879567, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 93.90999908447266, "rew_std": 27.109681802005888, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 107.66000022888184, "rew_std": 40.67018922208847, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 93.79000053405761, "rew_std": 30.64237221598378, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 108.4900001525879, "rew_std": 41.321239097052164, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 124.85, "rew_std": 42.0317792485268, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 116.13000106811523, "rew_std": 43.9727670450532, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 111.63999977111817, "rew_std": 43.274708584109035, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 106.15, "rew_std": 45.770651300224905, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 129.54000015258788, "rew_std": 46.98308583368676, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 115.51000137329102, "rew_std": 36.304806385435626, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 129.35999908447266, "rew_std": 31.217724397411512, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 135.28999938964844, "rew_std": 26.868697494551604, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 126.12999877929687, "rew_std": 41.017608258673214, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 136.70000076293945, "rew_std": 50.228299617735615, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 120.93000183105468, "rew_std": 41.47946862067106, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 138.7300003051758, "rew_std": 50.09087919140305, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 111.62000122070313, "rew_std": 28.04349582228607, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 139.99000091552733, "rew_std": 46.49149126588381, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 141.19000167846679, "rew_std": 55.482997939665566, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 141.16000061035157, "rew_std": 29.674102239383583, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 149.54000015258788, "rew_std": 40.483557547800565, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 138.81000061035155, "rew_std": 25.27221522764106, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 154.86000289916993, "rew_std": 47.20214481743621, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 152.83000259399415, "rew_std": 35.65692378910702, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 165.04999923706055, "rew_std": 52.75731800579599, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 159.33999938964843, "rew_std": 39.30949528911902, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 157.33999938964843, "rew_std": 31.022483741005583, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 133.2099983215332, "rew_std": 30.196568926146423, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 154.22000122070312, "rew_std": 54.375359375832986, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 184.93000030517578, "rew_std": 30.234021002954563, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 163.85000305175782, "rew_std": 37.09256658071057, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 174.16000061035157, "rew_std": 45.05503855203985, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 134.93999862670898, "rew_std": 28.63627883914366, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 158.54000244140624, "rew_std": 58.80484980319214, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 163.03000259399414, "rew_std": 43.68508069770034, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 171.29000091552734, "rew_std": 25.585327282680602, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 175.55999755859375, "rew_std": 40.4673989589574, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 170.24999923706054, "rew_std": 40.89010527420232, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 174.58000106811522, "rew_std": 34.85977017255225, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 197.0900016784668, "rew_std": 40.22520027724406, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 185.90000076293944, "rew_std": 40.68073380527696, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 163.37999954223633, "rew_std": 29.362010642178937, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 175.2400001525879, "rew_std": 33.284537997701975, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 173.48999938964843, "rew_std": 38.9055120846502, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 180.91999893188478, "rew_std": 32.606096613717376, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 182.53000030517578, "rew_std": 39.06146447307148, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 202.53999938964844, "rew_std": 34.642085489481985, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 198.09000091552736, "rew_std": 37.14933188731783, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 173.42000045776368, "rew_std": 46.51472327478004, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 187.71000137329102, "rew_std": 42.45332867238581, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 178.81999816894532, "rew_std": 25.60713985608123, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 186.19999923706055, "rew_std": 58.60175754971055, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 183.31999893188475, "rew_std": 40.961731898305466, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 189.95, "rew_std": 19.00927386779873, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 192.83999938964843, "rew_std": 33.04204192587639, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 202.9000015258789, "rew_std": 23.599364986605206, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 186.10999908447266, "rew_std": 46.4904581707004, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 213.19000015258788, "rew_std": 44.943285014544436, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 202.45999603271486, "rew_std": 54.62318213575417, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 163.0799997329712, "rew_std": 66.0252791544666, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 189.61999969482423, "rew_std": 31.533055330348382, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 190.22999954223633, "rew_std": 44.21936226238718, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 206.0199996948242, "rew_std": 34.16480026287263, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 194.15, "rew_std": 31.170764052493578, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 198.09000091552736, "rew_std": 34.949348176785655, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 184.69000167846679, "rew_std": 36.43675343515362, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 177.53000259399414, "rew_std": 49.71995694653478, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 188.76999893188477, "rew_std": 54.15346713496224, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 228.30999908447265, "rew_std": 27.33559443989839, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 208.64000244140624, "rew_std": 42.412903043388575, "Agent": "qrdqn"}, {"env_step": 0, "rew": 2.0299999952316283, "rew_std": 0.6356886257408865, "Agent": "iqn"}, {"env_step": 100000, "rew": 10.880000019073487, "rew_std": 1.0235234666900987, "Agent": "iqn"}, {"env_step": 200000, "rew": 16.200000095367432, "rew_std": 2.41453951471406, "Agent": "iqn"}, {"env_step": 300000, "rew": 19.000000286102296, "rew_std": 3.212164382918219, "Agent": "iqn"}, {"env_step": 400000, "rew": 24.710000038146973, "rew_std": 4.045108260414139, "Agent": "iqn"}, {"env_step": 500000, "rew": 36.970000457763675, "rew_std": 6.761220184785156, "Agent": "iqn"}, {"env_step": 600000, "rew": 57.630000305175784, "rew_std": 17.247496577908297, "Agent": "iqn"}, {"env_step": 700000, "rew": 59.85, "rew_std": 15.685677915496768, "Agent": "iqn"}, {"env_step": 800000, "rew": 79.85, "rew_std": 15.545884075479117, "Agent": "iqn"}, {"env_step": 900000, "rew": 85.95, "rew_std": 18.034815034946483, "Agent": "iqn"}, {"env_step": 1000000, "rew": 105.31999969482422, "rew_std": 23.10228556713175, "Agent": "iqn"}, {"env_step": 1100000, "rew": 114.6, "rew_std": 42.868006897695565, "Agent": "iqn"}, {"env_step": 1200000, "rew": 100.68000030517578, "rew_std": 21.099801867092722, "Agent": "iqn"}, {"env_step": 1300000, "rew": 115.17000045776368, "rew_std": 24.481870429507214, "Agent": "iqn"}, {"env_step": 1400000, "rew": 148.81999969482422, "rew_std": 46.95697798485056, "Agent": "iqn"}, {"env_step": 1500000, "rew": 174.43000259399415, "rew_std": 65.91861982472467, "Agent": "iqn"}, {"env_step": 1600000, "rew": 177.42999954223632, "rew_std": 37.79439115810842, "Agent": "iqn"}, {"env_step": 1700000, "rew": 212.91999893188478, "rew_std": 38.73584462706583, "Agent": "iqn"}, {"env_step": 1800000, "rew": 239.47000274658203, "rew_std": 44.23055960487321, "Agent": "iqn"}, {"env_step": 1900000, "rew": 224.89999542236328, "rew_std": 35.47142441734377, "Agent": "iqn"}, {"env_step": 2000000, "rew": 255.11000366210936, "rew_std": 70.83536414074327, "Agent": "iqn"}, {"env_step": 2100000, "rew": 268.1800018310547, "rew_std": 46.30323741929793, "Agent": "iqn"}, {"env_step": 2200000, "rew": 251.55999755859375, "rew_std": 84.66489362401488, "Agent": "iqn"}, {"env_step": 2300000, "rew": 272.47999420166013, "rew_std": 42.157886622987164, "Agent": "iqn"}, {"env_step": 2400000, "rew": 315.0400024414063, "rew_std": 35.556779061887944, "Agent": "iqn"}, {"env_step": 2500000, "rew": 288.16000213623045, "rew_std": 75.40411670056966, "Agent": "iqn"}, {"env_step": 2600000, "rew": 282.24999847412107, "rew_std": 67.52896065218202, "Agent": "iqn"}, {"env_step": 2700000, "rew": 314.6600006103516, "rew_std": 33.30751400267159, "Agent": "iqn"}, {"env_step": 2800000, "rew": 292.0699981689453, "rew_std": 70.06501237480857, "Agent": "iqn"}, {"env_step": 2900000, "rew": 280.75, "rew_std": 53.51295587493006, "Agent": "iqn"}, {"env_step": 3000000, "rew": 320.45, "rew_std": 25.30736054112851, "Agent": "iqn"}, {"env_step": 3100000, "rew": 314.0599990844727, "rew_std": 44.75654636439621, "Agent": "iqn"}, {"env_step": 3200000, "rew": 331.3699981689453, "rew_std": 23.177711488651255, "Agent": "iqn"}, {"env_step": 3300000, "rew": 330.7899993896484, "rew_std": 30.686655193589775, "Agent": "iqn"}, {"env_step": 3400000, "rew": 302.63000030517577, "rew_std": 62.505184496442915, "Agent": "iqn"}, {"env_step": 3500000, "rew": 312.2699996948242, "rew_std": 60.86172947653031, "Agent": "iqn"}, {"env_step": 3600000, "rew": 337.6700012207031, "rew_std": 35.29467556366819, "Agent": "iqn"}, {"env_step": 3700000, "rew": 299.9600006103516, "rew_std": 71.5931756482553, "Agent": "iqn"}, {"env_step": 3800000, "rew": 246.19000167846679, "rew_std": 87.48656258153838, "Agent": "iqn"}, {"env_step": 3900000, "rew": 326.85999755859376, "rew_std": 51.01209852522548, "Agent": "iqn"}, {"env_step": 4000000, "rew": 307.7100006103516, "rew_std": 58.77869107819418, "Agent": "iqn"}, {"env_step": 4100000, "rew": 311.3300033569336, "rew_std": 66.51625456766375, "Agent": "iqn"}, {"env_step": 4200000, "rew": 300.1900009155273, "rew_std": 35.21126152649786, "Agent": "iqn"}, {"env_step": 4300000, "rew": 307.98000183105466, "rew_std": 31.851334098626857, "Agent": "iqn"}, {"env_step": 4400000, "rew": 318.60999755859376, "rew_std": 43.45476757896472, "Agent": "iqn"}, {"env_step": 4500000, "rew": 327.53999786376954, "rew_std": 62.97847529940396, "Agent": "iqn"}, {"env_step": 4600000, "rew": 282.2199996948242, "rew_std": 65.37763576262309, "Agent": "iqn"}, {"env_step": 4700000, "rew": 298.72000274658205, "rew_std": 53.23556836698092, "Agent": "iqn"}, {"env_step": 4800000, "rew": 338.88000030517577, "rew_std": 64.96912888006219, "Agent": "iqn"}, {"env_step": 4900000, "rew": 320.7, "rew_std": 66.17025120314409, "Agent": "iqn"}, {"env_step": 5000000, "rew": 318.7500061035156, "rew_std": 40.19410702152574, "Agent": "iqn"}, {"env_step": 5100000, "rew": 295.86999664306643, "rew_std": 70.69885222375017, "Agent": "iqn"}, {"env_step": 5200000, "rew": 344.55999755859375, "rew_std": 31.723278369793565, "Agent": "iqn"}, {"env_step": 5300000, "rew": 328.7099975585937, "rew_std": 42.69288989467297, "Agent": "iqn"}, {"env_step": 5400000, "rew": 296.60999755859376, "rew_std": 66.42924294236374, "Agent": "iqn"}, {"env_step": 5500000, "rew": 283.00999755859374, "rew_std": 70.532708487894, "Agent": "iqn"}, {"env_step": 5600000, "rew": 355.9200042724609, "rew_std": 22.674958525127415, "Agent": "iqn"}, {"env_step": 5700000, "rew": 301.33000030517576, "rew_std": 88.94783620229133, "Agent": "iqn"}, {"env_step": 5800000, "rew": 293.93999633789065, "rew_std": 52.81626973902586, "Agent": "iqn"}, {"env_step": 5900000, "rew": 353.3300018310547, "rew_std": 36.446288269528395, "Agent": "iqn"}, {"env_step": 6000000, "rew": 305.2799987792969, "rew_std": 54.018343190981945, "Agent": "iqn"}, {"env_step": 6100000, "rew": 349.9500030517578, "rew_std": 24.089635436458245, "Agent": "iqn"}, {"env_step": 6200000, "rew": 328.2199966430664, "rew_std": 48.67830877960062, "Agent": "iqn"}, {"env_step": 6300000, "rew": 343.49000244140626, "rew_std": 31.285020475109025, "Agent": "iqn"}, {"env_step": 6400000, "rew": 303.22000274658205, "rew_std": 55.57735070139985, "Agent": "iqn"}, {"env_step": 6500000, "rew": 321.5300003051758, "rew_std": 54.123212058813415, "Agent": "iqn"}, {"env_step": 6600000, "rew": 348.51000061035154, "rew_std": 38.049976345782774, "Agent": "iqn"}, {"env_step": 6700000, "rew": 352.5299987792969, "rew_std": 29.52311476032704, "Agent": "iqn"}, {"env_step": 6800000, "rew": 352.8199981689453, "rew_std": 27.302040489543003, "Agent": "iqn"}, {"env_step": 6900000, "rew": 325.95, "rew_std": 32.27061521262411, "Agent": "iqn"}, {"env_step": 7000000, "rew": 337.38000335693357, "rew_std": 57.94110508353129, "Agent": "iqn"}, {"env_step": 7100000, "rew": 337.1800064086914, "rew_std": 57.54656752151562, "Agent": "iqn"}, {"env_step": 7200000, "rew": 347.05, "rew_std": 29.28273921056375, "Agent": "iqn"}, {"env_step": 7300000, "rew": 336.5800018310547, "rew_std": 25.209833569339764, "Agent": "iqn"}, {"env_step": 7400000, "rew": 314.8700004577637, "rew_std": 83.15007163125841, "Agent": "iqn"}, {"env_step": 7500000, "rew": 346.7200012207031, "rew_std": 32.34303330425867, "Agent": "iqn"}, {"env_step": 7600000, "rew": 314.9699996948242, "rew_std": 51.35753429441995, "Agent": "iqn"}, {"env_step": 7700000, "rew": 312.4199966430664, "rew_std": 58.537693420573355, "Agent": "iqn"}, {"env_step": 7800000, "rew": 328.15, "rew_std": 45.2648705332799, "Agent": "iqn"}, {"env_step": 7900000, "rew": 346.00999755859374, "rew_std": 24.54332676008246, "Agent": "iqn"}, {"env_step": 8000000, "rew": 321.4400039672852, "rew_std": 50.142358701938754, "Agent": "iqn"}, {"env_step": 8100000, "rew": 337.76999816894534, "rew_std": 42.3190257331327, "Agent": "iqn"}, {"env_step": 8200000, "rew": 333.6700012207031, "rew_std": 29.37312182285308, "Agent": "iqn"}, {"env_step": 8300000, "rew": 324.7100006103516, "rew_std": 52.949946115785885, "Agent": "iqn"}, {"env_step": 8400000, "rew": 333.55999755859375, "rew_std": 33.45080520039474, "Agent": "iqn"}, {"env_step": 8500000, "rew": 331.4600036621094, "rew_std": 48.38483477275051, "Agent": "iqn"}, {"env_step": 8600000, "rew": 324.1599975585938, "rew_std": 49.630536861003044, "Agent": "iqn"}, {"env_step": 8700000, "rew": 351.7799987792969, "rew_std": 27.03962312243994, "Agent": "iqn"}, {"env_step": 8800000, "rew": 339.1300018310547, "rew_std": 53.111113054337935, "Agent": "iqn"}, {"env_step": 8900000, "rew": 329.3400024414062, "rew_std": 39.404931065916315, "Agent": "iqn"}, {"env_step": 9000000, "rew": 337.5, "rew_std": 31.20205217899507, "Agent": "iqn"}, {"env_step": 9100000, "rew": 312.82000122070315, "rew_std": 81.47756719359116, "Agent": "iqn"}, {"env_step": 9200000, "rew": 318.81000366210935, "rew_std": 61.65786917648312, "Agent": "iqn"}, {"env_step": 9300000, "rew": 355.5400024414063, "rew_std": 16.46543217809965, "Agent": "iqn"}, {"env_step": 9400000, "rew": 316.15000305175784, "rew_std": 69.99261936144228, "Agent": "iqn"}, {"env_step": 9500000, "rew": 346.1699981689453, "rew_std": 31.56960876454528, "Agent": "iqn"}, {"env_step": 9600000, "rew": 338.1199951171875, "rew_std": 45.98025387262979, "Agent": "iqn"}, {"env_step": 9700000, "rew": 329.63000335693357, "rew_std": 42.38771307072964, "Agent": "iqn"}, {"env_step": 9800000, "rew": 331.4, "rew_std": 39.38928853624626, "Agent": "iqn"}, {"env_step": 9900000, "rew": 318.9999969482422, "rew_std": 43.779264475855875, "Agent": "iqn"}, {"env_step": 10000000, "rew": 345.3199981689453, "rew_std": 30.032006070982476, "Agent": "iqn"}, {"env_step": 0, "rew": 1.7999999798834323, "rew_std": 1.461506037350442, "Agent": "rainbow"}, {"env_step": 100000, "rew": 2.789999971538782, "rew_std": 2.4865437409115354, "Agent": "rainbow"}, {"env_step": 200000, "rew": 12.420000076293945, "rew_std": 1.9046260138234519, "Agent": "rainbow"}, {"env_step": 300000, "rew": 17.679999923706056, "rew_std": 3.491647063886927, "Agent": "rainbow"}, {"env_step": 400000, "rew": 22.370000076293945, "rew_std": 3.6133226874735795, "Agent": "rainbow"}, {"env_step": 500000, "rew": 25.05, "rew_std": 3.6381997573897396, "Agent": "rainbow"}, {"env_step": 600000, "rew": 35.28999977111816, "rew_std": 4.300104297171605, "Agent": "rainbow"}, {"env_step": 700000, "rew": 38.70999984741211, "rew_std": 5.35918838448342, "Agent": "rainbow"}, {"env_step": 800000, "rew": 50.54999961853027, "rew_std": 8.483189257414512, "Agent": "rainbow"}, {"env_step": 900000, "rew": 60.01000061035156, "rew_std": 10.841259439227493, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 72.13000030517578, "rew_std": 14.579921126080473, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 105.4900016784668, "rew_std": 41.347393284288735, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 99.45000076293945, "rew_std": 25.770341675180582, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 104.1, "rew_std": 24.05194318506914, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 122.69000091552735, "rew_std": 33.97927298843038, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 188.78999786376954, "rew_std": 47.31898888179236, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 230.06000213623048, "rew_std": 45.668113003632385, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 222.32000122070312, "rew_std": 69.96254538894237, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 264.9599975585937, "rew_std": 44.13764946857046, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 304.4, "rew_std": 44.836877219962034, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 327.15000305175784, "rew_std": 42.61066349224782, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 329.89000091552737, "rew_std": 47.86103795081456, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 332.67000274658204, "rew_std": 49.45685362258107, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 291.48999786376953, "rew_std": 72.64021500933792, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 334.86000061035156, "rew_std": 78.4941559533148, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 333.99000091552733, "rew_std": 75.35539320141508, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 353.07000122070315, "rew_std": 51.661630785667796, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 335.8000061035156, "rew_std": 65.27762192648794, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 381.63999938964844, "rew_std": 33.01331023409123, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 370.3, "rew_std": 29.175224311445085, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 396.6999969482422, "rew_std": 40.15956167187139, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 378.6699981689453, "rew_std": 44.56986018654734, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 367.72999877929686, "rew_std": 48.201724085448, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 373.5100036621094, "rew_std": 50.91597587464675, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 373.94000549316405, "rew_std": 45.228182826120296, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 386.4099945068359, "rew_std": 24.17674431981728, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 405.77000732421874, "rew_std": 42.80668625101679, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 407.6, "rew_std": 48.41737864076781, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 408.2899993896484, "rew_std": 31.628448022764232, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 390.32000122070315, "rew_std": 28.6771582193927, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 371.5400054931641, "rew_std": 32.82566550832653, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 374.39000244140624, "rew_std": 44.559746097958346, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 373.72999877929686, "rew_std": 42.524114470487525, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 405.72999877929686, "rew_std": 21.966842238579567, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 382.3500061035156, "rew_std": 30.38684579249488, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 411.3499984741211, "rew_std": 69.50523878087984, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 417.1599975585938, "rew_std": 63.06370162906102, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 386.0800048828125, "rew_std": 28.676079172356957, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 398.8399993896484, "rew_std": 30.87983841532746, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 396.72999877929686, "rew_std": 33.71180556312966, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 384.89000244140624, "rew_std": 33.94638292724067, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 400.55, "rew_std": 46.40784802725254, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 419.52000122070314, "rew_std": 28.008704651064, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 407.02000122070314, "rew_std": 16.72254065818173, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 414.0499969482422, "rew_std": 41.30225599948548, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 398.7799987792969, "rew_std": 47.40503931200679, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 403.820002746582, "rew_std": 64.9688057624937, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 389.6999984741211, "rew_std": 72.28918253740537, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 403.6700012207031, "rew_std": 38.4149988299815, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 409.89000244140624, "rew_std": 24.034117466481515, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 399.0400024414063, "rew_std": 39.877192287649464, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 384.40000305175784, "rew_std": 56.328160747865354, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 403.8999969482422, "rew_std": 33.781714504496996, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 397.63999938964844, "rew_std": 26.051031347673337, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 409.3799987792969, "rew_std": 15.132536949771454, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 408.31000061035155, "rew_std": 22.57203611858315, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 415.3700012207031, "rew_std": 38.56120137444495, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 431.77000122070314, "rew_std": 47.137184174849416, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 404.22999877929686, "rew_std": 34.66502740832278, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 401.00999755859374, "rew_std": 22.66051127275429, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 393.8199981689453, "rew_std": 48.31937448033659, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 417.7, "rew_std": 50.47389404778245, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 395.7499969482422, "rew_std": 40.349476442782, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 417.0899963378906, "rew_std": 18.112780812448758, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 383.18999633789065, "rew_std": 47.911194905935396, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 410.9200073242188, "rew_std": 70.87141742592017, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 420.8400024414062, "rew_std": 34.12468989742961, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 422.22999572753906, "rew_std": 21.98477505605195, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 423.4200042724609, "rew_std": 43.2258487041201, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 418.1700012207031, "rew_std": 35.33822585932713, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 396.6499938964844, "rew_std": 39.98475122704287, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 431.2100006103516, "rew_std": 43.29839137758222, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 388.6700042724609, "rew_std": 42.25809445722602, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 371.5899963378906, "rew_std": 76.53331656114038, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 408.69000244140625, "rew_std": 24.624358338524335, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 409.0399993896484, "rew_std": 41.573793217544875, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 401.95, "rew_std": 37.11682649365457, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 420.77000122070314, "rew_std": 44.74215708867204, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 405.2499969482422, "rew_std": 31.691043996566787, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 398.4700012207031, "rew_std": 40.46342211972141, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 440.4, "rew_std": 50.116695811843044, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 422.5, "rew_std": 35.31455535189779, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 428.8199981689453, "rew_std": 33.58162360678032, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 425.3400024414062, "rew_std": 46.15141555774316, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 440.2799987792969, "rew_std": 42.420672496482084, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 410.85, "rew_std": 6.367617048401184, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 399.57000122070315, "rew_std": 53.69724380529421, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 431.38999938964844, "rew_std": 40.52948488877201, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 422.23999938964846, "rew_std": 37.25512766393269, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 413.8299987792969, "rew_std": 36.612840411302244, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 392.0399993896484, "rew_std": 48.50192720302268, "Agent": "rainbow"}, {"env_step": 0, "rew": 2.0299999833106996, "rew_std": 0.8764131095183902, "Agent": "ppo"}, {"env_step": 100000, "rew": 2.680000030994415, "rew_std": 1.5315352171604617, "Agent": "ppo"}, {"env_step": 200000, "rew": 6.869999933242798, "rew_std": 2.2427883234590684, "Agent": "ppo"}, {"env_step": 300000, "rew": 8.350000023841858, "rew_std": 2.62154539898698, "Agent": "ppo"}, {"env_step": 400000, "rew": 10.77000002861023, "rew_std": 3.155328811734828, "Agent": "ppo"}, {"env_step": 500000, "rew": 11.309999942779541, "rew_std": 2.5762180106126547, "Agent": "ppo"}, {"env_step": 600000, "rew": 13.859999895095825, "rew_std": 4.651494279703967, "Agent": "ppo"}, {"env_step": 700000, "rew": 14.749999761581421, "rew_std": 4.220485482312834, "Agent": "ppo"}, {"env_step": 800000, "rew": 15.349999904632568, "rew_std": 4.1898090655449005, "Agent": "ppo"}, {"env_step": 900000, "rew": 18.020000171661376, "rew_std": 4.536915203735637, "Agent": "ppo"}, {"env_step": 1000000, "rew": 17.020000171661376, "rew_std": 4.455962464888489, "Agent": "ppo"}, {"env_step": 1100000, "rew": 20.690000343322755, "rew_std": 8.05238462382638, "Agent": "ppo"}, {"env_step": 1200000, "rew": 22.689999961853026, "rew_std": 12.304588638832776, "Agent": "ppo"}, {"env_step": 1300000, "rew": 20.55999975204468, "rew_std": 4.387299621179701, "Agent": "ppo"}, {"env_step": 1400000, "rew": 19.94000005722046, "rew_std": 4.290501381090037, "Agent": "ppo"}, {"env_step": 1500000, "rew": 26.379999923706055, "rew_std": 10.657748376402598, "Agent": "ppo"}, {"env_step": 1600000, "rew": 23.750000190734863, "rew_std": 4.385715448611054, "Agent": "ppo"}, {"env_step": 1700000, "rew": 23.659999656677247, "rew_std": 4.599826003557162, "Agent": "ppo"}, {"env_step": 1800000, "rew": 24.960000133514406, "rew_std": 4.907586145252241, "Agent": "ppo"}, {"env_step": 1900000, "rew": 27.629999732971193, "rew_std": 5.699657718554115, "Agent": "ppo"}, {"env_step": 2000000, "rew": 25.119999885559082, "rew_std": 2.981207745714502, "Agent": "ppo"}, {"env_step": 2100000, "rew": 24.629999923706055, "rew_std": 3.647204546502502, "Agent": "ppo"}, {"env_step": 2200000, "rew": 27.63999996185303, "rew_std": 3.726714114078771, "Agent": "ppo"}, {"env_step": 2300000, "rew": 28.329999923706055, "rew_std": 4.171102659408543, "Agent": "ppo"}, {"env_step": 2400000, "rew": 28.530000305175783, "rew_std": 3.5877709920260523, "Agent": "ppo"}, {"env_step": 2500000, "rew": 32.079999923706055, "rew_std": 4.9793168787475475, "Agent": "ppo"}, {"env_step": 2600000, "rew": 35.150000190734865, "rew_std": 6.757550860011463, "Agent": "ppo"}, {"env_step": 2700000, "rew": 35.24000015258789, "rew_std": 13.677953506506757, "Agent": "ppo"}, {"env_step": 2800000, "rew": 37.55, "rew_std": 9.215123739752018, "Agent": "ppo"}, {"env_step": 2900000, "rew": 36.089999771118165, "rew_std": 4.728942780362954, "Agent": "ppo"}, {"env_step": 3000000, "rew": 42.98000030517578, "rew_std": 19.57303269533935, "Agent": "ppo"}, {"env_step": 3100000, "rew": 37.360000419616696, "rew_std": 12.54338152629255, "Agent": "ppo"}, {"env_step": 3200000, "rew": 40.380000305175784, "rew_std": 10.776437119519981, "Agent": "ppo"}, {"env_step": 3300000, "rew": 38.110000419616696, "rew_std": 12.645825732034167, "Agent": "ppo"}, {"env_step": 3400000, "rew": 42.21999931335449, "rew_std": 9.1218199543614, "Agent": "ppo"}, {"env_step": 3500000, "rew": 50.119999694824216, "rew_std": 14.80836362588282, "Agent": "ppo"}, {"env_step": 3600000, "rew": 47.400000190734865, "rew_std": 10.068664307564164, "Agent": "ppo"}, {"env_step": 3700000, "rew": 45.4399995803833, "rew_std": 9.41564705130973, "Agent": "ppo"}, {"env_step": 3800000, "rew": 53.88000068664551, "rew_std": 16.57653842254833, "Agent": "ppo"}, {"env_step": 3900000, "rew": 61.64000015258789, "rew_std": 24.900129246081427, "Agent": "ppo"}, {"env_step": 4000000, "rew": 56.04999923706055, "rew_std": 14.419240647637906, "Agent": "ppo"}, {"env_step": 4100000, "rew": 55.7, "rew_std": 20.825513362350105, "Agent": "ppo"}, {"env_step": 4200000, "rew": 54.29000072479248, "rew_std": 21.086083955047158, "Agent": "ppo"}, {"env_step": 4300000, "rew": 60.97000007629394, "rew_std": 23.419352948854787, "Agent": "ppo"}, {"env_step": 4400000, "rew": 61.32000160217285, "rew_std": 24.429810367430697, "Agent": "ppo"}, {"env_step": 4500000, "rew": 62.31000022888183, "rew_std": 21.309597897936026, "Agent": "ppo"}, {"env_step": 4600000, "rew": 67.86999893188477, "rew_std": 26.248467597744845, "Agent": "ppo"}, {"env_step": 4700000, "rew": 66.7, "rew_std": 24.40237644035704, "Agent": "ppo"}, {"env_step": 4800000, "rew": 82.43000106811523, "rew_std": 39.014153045648264, "Agent": "ppo"}, {"env_step": 4900000, "rew": 82.50999946594239, "rew_std": 29.639110602215194, "Agent": "ppo"}, {"env_step": 5000000, "rew": 89.46999969482422, "rew_std": 36.290717341380685, "Agent": "ppo"}, {"env_step": 5100000, "rew": 75.40999946594238, "rew_std": 19.553385764445366, "Agent": "ppo"}, {"env_step": 5200000, "rew": 91.71999969482422, "rew_std": 33.941354984622286, "Agent": "ppo"}, {"env_step": 5300000, "rew": 95.90999984741211, "rew_std": 34.3326784841907, "Agent": "ppo"}, {"env_step": 5400000, "rew": 101.17000045776368, "rew_std": 48.307889695724214, "Agent": "ppo"}, {"env_step": 5500000, "rew": 93.73999977111816, "rew_std": 32.80829688751657, "Agent": "ppo"}, {"env_step": 5600000, "rew": 101.56000099182128, "rew_std": 38.65323253336432, "Agent": "ppo"}, {"env_step": 5700000, "rew": 119.71000213623047, "rew_std": 58.63711387604412, "Agent": "ppo"}, {"env_step": 5800000, "rew": 121.56000022888183, "rew_std": 52.67867263607598, "Agent": "ppo"}, {"env_step": 5900000, "rew": 128.3799991607666, "rew_std": 58.80482705685627, "Agent": "ppo"}, {"env_step": 6000000, "rew": 120.53999824523926, "rew_std": 48.01154252771422, "Agent": "ppo"}, {"env_step": 6100000, "rew": 122.3899990081787, "rew_std": 49.0965679103651, "Agent": "ppo"}, {"env_step": 6200000, "rew": 133.99999961853027, "rew_std": 60.90436501831146, "Agent": "ppo"}, {"env_step": 6300000, "rew": 140.52000198364257, "rew_std": 69.07889716111299, "Agent": "ppo"}, {"env_step": 6400000, "rew": 137.21999893188476, "rew_std": 62.32881643967556, "Agent": "ppo"}, {"env_step": 6500000, "rew": 146.8299991607666, "rew_std": 55.37363915857669, "Agent": "ppo"}, {"env_step": 6600000, "rew": 139.81000213623048, "rew_std": 74.04937024552305, "Agent": "ppo"}, {"env_step": 6700000, "rew": 149.6099994659424, "rew_std": 71.83785305550174, "Agent": "ppo"}, {"env_step": 6800000, "rew": 135.49000091552733, "rew_std": 55.006754667730945, "Agent": "ppo"}, {"env_step": 6900000, "rew": 147.45999984741212, "rew_std": 59.91933138185291, "Agent": "ppo"}, {"env_step": 7000000, "rew": 165.1099994659424, "rew_std": 73.1342120883567, "Agent": "ppo"}, {"env_step": 7100000, "rew": 174.0099983215332, "rew_std": 66.24739028991273, "Agent": "ppo"}, {"env_step": 7200000, "rew": 177.29999847412108, "rew_std": 73.95540152011542, "Agent": "ppo"}, {"env_step": 7300000, "rew": 175.92999992370605, "rew_std": 76.0113898211075, "Agent": "ppo"}, {"env_step": 7400000, "rew": 164.42999877929688, "rew_std": 77.33506176445988, "Agent": "ppo"}, {"env_step": 7500000, "rew": 173.9599983215332, "rew_std": 84.44470542302061, "Agent": "ppo"}, {"env_step": 7600000, "rew": 171.43999900817872, "rew_std": 83.88048894373154, "Agent": "ppo"}, {"env_step": 7700000, "rew": 199.14999923706054, "rew_std": 94.75587743328266, "Agent": "ppo"}, {"env_step": 7800000, "rew": 186.2400001525879, "rew_std": 77.16537397952645, "Agent": "ppo"}, {"env_step": 7900000, "rew": 199.35, "rew_std": 79.58159406938299, "Agent": "ppo"}, {"env_step": 8000000, "rew": 210.05000190734864, "rew_std": 90.49879749595148, "Agent": "ppo"}, {"env_step": 8100000, "rew": 212.7500015258789, "rew_std": 88.85424210708028, "Agent": "ppo"}, {"env_step": 8200000, "rew": 210.8900001525879, "rew_std": 73.44615975377866, "Agent": "ppo"}, {"env_step": 8300000, "rew": 219.910001373291, "rew_std": 100.7312432120665, "Agent": "ppo"}, {"env_step": 8400000, "rew": 237.1999984741211, "rew_std": 88.27977955944947, "Agent": "ppo"}, {"env_step": 8500000, "rew": 235.44000015258788, "rew_std": 82.60257787044871, "Agent": "ppo"}, {"env_step": 8600000, "rew": 217.410001373291, "rew_std": 82.26707245141274, "Agent": "ppo"}, {"env_step": 8700000, "rew": 239.08999938964843, "rew_std": 80.68150053430362, "Agent": "ppo"}, {"env_step": 8800000, "rew": 228.78000259399414, "rew_std": 78.50268738950463, "Agent": "ppo"}, {"env_step": 8900000, "rew": 242.50999908447267, "rew_std": 88.02333190391393, "Agent": "ppo"}, {"env_step": 9000000, "rew": 230.4200012207031, "rew_std": 98.88399222725009, "Agent": "ppo"}, {"env_step": 9100000, "rew": 254.71000213623046, "rew_std": 74.41610668817124, "Agent": "ppo"}, {"env_step": 9200000, "rew": 258.9599975585937, "rew_std": 88.94478371137306, "Agent": "ppo"}, {"env_step": 9300000, "rew": 248.64999694824218, "rew_std": 86.56067064571964, "Agent": "ppo"}, {"env_step": 9400000, "rew": 247.660001373291, "rew_std": 92.0610693574401, "Agent": "ppo"}, {"env_step": 9500000, "rew": 276.51000289916993, "rew_std": 81.18026107244279, "Agent": "ppo"}, {"env_step": 9600000, "rew": 258.3400054931641, "rew_std": 82.19079470003253, "Agent": "ppo"}, {"env_step": 9700000, "rew": 265.7800018310547, "rew_std": 71.35941141595737, "Agent": "ppo"}, {"env_step": 9800000, "rew": 279.3699981689453, "rew_std": 81.73140051743914, "Agent": "ppo"}, {"env_step": 9900000, "rew": 283.01000061035154, "rew_std": 74.29673322328118, "Agent": "ppo"}, {"env_step": 10000000, "rew": 272.84999923706056, "rew_std": 87.10014073751415, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/EnduroNoFrameskip-v4/result.json b/examples/atari/benchmark/EnduroNoFrameskip-v4/result.json new file mode 100644 index 000000000..0694a7694 --- /dev/null +++ b/examples/atari/benchmark/EnduroNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 0.0800000011920929, "rew_std": 0.24000000357627865, "Agent": "c51"}, {"env_step": 100000, "rew": 0.0, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 200000, "rew": 0.0, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 300000, "rew": 0.1, "rew_std": 0.30000000000000004, "Agent": "c51"}, {"env_step": 400000, "rew": 0.21000000238418579, "rew_std": 0.35623026856774925, "Agent": "c51"}, {"env_step": 500000, "rew": 0.05000000074505806, "rew_std": 0.12041594758226036, "Agent": "c51"}, {"env_step": 600000, "rew": 0.31999999061226847, "rew_std": 0.927146130289149, "Agent": "c51"}, {"env_step": 700000, "rew": 0.7299999989569187, "rew_std": 1.0354226172474177, "Agent": "c51"}, {"env_step": 800000, "rew": 29.999999809265137, "rew_std": 22.8517390602112, "Agent": "c51"}, {"env_step": 900000, "rew": 84.33000020980835, "rew_std": 38.11215200504169, "Agent": "c51"}, {"env_step": 1000000, "rew": 134.27000045776367, "rew_std": 33.76175580023914, "Agent": "c51"}, {"env_step": 1100000, "rew": 195.3500015258789, "rew_std": 55.070539310018276, "Agent": "c51"}, {"env_step": 1200000, "rew": 305.8000015258789, "rew_std": 63.623845163113806, "Agent": "c51"}, {"env_step": 1300000, "rew": 341.6900039672852, "rew_std": 75.15398169731095, "Agent": "c51"}, {"env_step": 1400000, "rew": 439.62000427246096, "rew_std": 35.53360923105612, "Agent": "c51"}, {"env_step": 1500000, "rew": 448.17999877929685, "rew_std": 63.31653151381171, "Agent": "c51"}, {"env_step": 1600000, "rew": 483.0900024414062, "rew_std": 63.598508175034475, "Agent": "c51"}, {"env_step": 1700000, "rew": 479.4499938964844, "rew_std": 60.719817637295435, "Agent": "c51"}, {"env_step": 1800000, "rew": 477.8299987792969, "rew_std": 88.50112258719895, "Agent": "c51"}, {"env_step": 1900000, "rew": 516.6200012207031, "rew_std": 90.65022983110897, "Agent": "c51"}, {"env_step": 2000000, "rew": 500.8199981689453, "rew_std": 56.8060386594065, "Agent": "c51"}, {"env_step": 2100000, "rew": 539.5200012207031, "rew_std": 80.30648599564611, "Agent": "c51"}, {"env_step": 2200000, "rew": 592.730014038086, "rew_std": 96.93099005249192, "Agent": "c51"}, {"env_step": 2300000, "rew": 573.3399963378906, "rew_std": 91.49156422648889, "Agent": "c51"}, {"env_step": 2400000, "rew": 606.1099975585937, "rew_std": 68.63315724977679, "Agent": "c51"}, {"env_step": 2500000, "rew": 652.9599975585937, "rew_std": 85.58606896755197, "Agent": "c51"}, {"env_step": 2600000, "rew": 655.4, "rew_std": 81.90140506345105, "Agent": "c51"}, {"env_step": 2700000, "rew": 625.2999969482422, "rew_std": 85.18681205945472, "Agent": "c51"}, {"env_step": 2800000, "rew": 637.7900024414063, "rew_std": 122.54666760609061, "Agent": "c51"}, {"env_step": 2900000, "rew": 644.1, "rew_std": 85.42630507564513, "Agent": "c51"}, {"env_step": 3000000, "rew": 710.5900024414062, "rew_std": 75.28909772977295, "Agent": "c51"}, {"env_step": 3100000, "rew": 671.3799987792969, "rew_std": 56.7536538058374, "Agent": "c51"}, {"env_step": 3200000, "rew": 668.2599975585938, "rew_std": 65.81738352088684, "Agent": "c51"}, {"env_step": 3300000, "rew": 690.7899993896484, "rew_std": 84.55681861003309, "Agent": "c51"}, {"env_step": 3400000, "rew": 738.3400024414062, "rew_std": 101.42283074745313, "Agent": "c51"}, {"env_step": 3500000, "rew": 730.4300048828125, "rew_std": 90.93792521834833, "Agent": "c51"}, {"env_step": 3600000, "rew": 742.3700012207031, "rew_std": 98.71111614905327, "Agent": "c51"}, {"env_step": 3700000, "rew": 708.8199981689453, "rew_std": 130.55409140026177, "Agent": "c51"}, {"env_step": 3800000, "rew": 705.9700012207031, "rew_std": 75.86588955018891, "Agent": "c51"}, {"env_step": 3900000, "rew": 755.3899963378906, "rew_std": 111.82682749974384, "Agent": "c51"}, {"env_step": 4000000, "rew": 792.8599975585937, "rew_std": 100.65659388596904, "Agent": "c51"}, {"env_step": 4100000, "rew": 780.4700012207031, "rew_std": 89.4066144108773, "Agent": "c51"}, {"env_step": 4200000, "rew": 749.0600036621094, "rew_std": 89.14610115546856, "Agent": "c51"}, {"env_step": 4300000, "rew": 735.3100067138672, "rew_std": 105.2854315881353, "Agent": "c51"}, {"env_step": 4400000, "rew": 794.9, "rew_std": 94.90966229691644, "Agent": "c51"}, {"env_step": 4500000, "rew": 775.8700012207031, "rew_std": 86.57670898287867, "Agent": "c51"}, {"env_step": 4600000, "rew": 764.4599975585937, "rew_std": 121.75587907672723, "Agent": "c51"}, {"env_step": 4700000, "rew": 761.55, "rew_std": 62.056058351897406, "Agent": "c51"}, {"env_step": 4800000, "rew": 746.5799987792968, "rew_std": 130.65757158616265, "Agent": "c51"}, {"env_step": 4900000, "rew": 792.0400085449219, "rew_std": 92.14410963183664, "Agent": "c51"}, {"env_step": 5000000, "rew": 784.8700012207031, "rew_std": 76.30846325078628, "Agent": "c51"}, {"env_step": 5100000, "rew": 806.9400024414062, "rew_std": 89.7122211065443, "Agent": "c51"}, {"env_step": 5200000, "rew": 809.7999938964844, "rew_std": 96.43909531778648, "Agent": "c51"}, {"env_step": 5300000, "rew": 801.8500061035156, "rew_std": 71.23311713783924, "Agent": "c51"}, {"env_step": 5400000, "rew": 865.3399963378906, "rew_std": 87.65904211044649, "Agent": "c51"}, {"env_step": 5500000, "rew": 800.1799987792969, "rew_std": 120.17872453215695, "Agent": "c51"}, {"env_step": 5600000, "rew": 808.1899963378906, "rew_std": 114.39077140355394, "Agent": "c51"}, {"env_step": 5700000, "rew": 787.6900024414062, "rew_std": 137.37429836391115, "Agent": "c51"}, {"env_step": 5800000, "rew": 817.6800048828125, "rew_std": 75.91765398683945, "Agent": "c51"}, {"env_step": 5900000, "rew": 788.95, "rew_std": 112.15058353811531, "Agent": "c51"}, {"env_step": 6000000, "rew": 824.4900024414062, "rew_std": 83.1460697372063, "Agent": "c51"}, {"env_step": 6100000, "rew": 791.3400024414062, "rew_std": 71.07509644467352, "Agent": "c51"}, {"env_step": 6200000, "rew": 852.5599975585938, "rew_std": 102.26750645543113, "Agent": "c51"}, {"env_step": 6300000, "rew": 791.0799957275391, "rew_std": 148.64477463928537, "Agent": "c51"}, {"env_step": 6400000, "rew": 799.7700012207031, "rew_std": 94.79903258127105, "Agent": "c51"}, {"env_step": 6500000, "rew": 856.9799987792969, "rew_std": 98.21994199980757, "Agent": "c51"}, {"env_step": 6600000, "rew": 830.3799987792969, "rew_std": 92.69931723386792, "Agent": "c51"}, {"env_step": 6700000, "rew": 828.5700012207031, "rew_std": 117.4840294040638, "Agent": "c51"}, {"env_step": 6800000, "rew": 836.3399963378906, "rew_std": 107.67462291584121, "Agent": "c51"}, {"env_step": 6900000, "rew": 809.05, "rew_std": 86.39843789136866, "Agent": "c51"}, {"env_step": 7000000, "rew": 802.610009765625, "rew_std": 85.19054082178417, "Agent": "c51"}, {"env_step": 7100000, "rew": 821.9500061035156, "rew_std": 84.06559770155239, "Agent": "c51"}, {"env_step": 7200000, "rew": 846.0100036621094, "rew_std": 109.6511176842256, "Agent": "c51"}, {"env_step": 7300000, "rew": 753.2699981689453, "rew_std": 118.18144461063531, "Agent": "c51"}, {"env_step": 7400000, "rew": 862.4699951171875, "rew_std": 94.61919535944561, "Agent": "c51"}, {"env_step": 7500000, "rew": 855.6, "rew_std": 83.0109175169287, "Agent": "c51"}, {"env_step": 7600000, "rew": 804.8099975585938, "rew_std": 87.84749020213859, "Agent": "c51"}, {"env_step": 7700000, "rew": 879.1099975585937, "rew_std": 124.99047443353965, "Agent": "c51"}, {"env_step": 7800000, "rew": 861.0999938964844, "rew_std": 149.99051826966058, "Agent": "c51"}, {"env_step": 7900000, "rew": 840.1100158691406, "rew_std": 74.45142853212236, "Agent": "c51"}, {"env_step": 8000000, "rew": 838.1, "rew_std": 81.488879742754, "Agent": "c51"}, {"env_step": 8100000, "rew": 853.1600036621094, "rew_std": 125.11934723061991, "Agent": "c51"}, {"env_step": 8200000, "rew": 883.8700012207031, "rew_std": 110.8634912939346, "Agent": "c51"}, {"env_step": 8300000, "rew": 843.6199951171875, "rew_std": 110.07341220660334, "Agent": "c51"}, {"env_step": 8400000, "rew": 833.9500122070312, "rew_std": 166.85491541704317, "Agent": "c51"}, {"env_step": 8500000, "rew": 883.5900085449218, "rew_std": 120.01639086371644, "Agent": "c51"}, {"env_step": 8600000, "rew": 816.3799987792969, "rew_std": 93.30947260374052, "Agent": "c51"}, {"env_step": 8700000, "rew": 816.5599975585938, "rew_std": 90.72039308816316, "Agent": "c51"}, {"env_step": 8800000, "rew": 885.2699951171875, "rew_std": 84.88027385527451, "Agent": "c51"}, {"env_step": 8900000, "rew": 940.8200012207031, "rew_std": 133.91121568644473, "Agent": "c51"}, {"env_step": 9000000, "rew": 858.2299926757812, "rew_std": 106.44362694927028, "Agent": "c51"}, {"env_step": 9100000, "rew": 843.5200012207031, "rew_std": 68.82380650364031, "Agent": "c51"}, {"env_step": 9200000, "rew": 847.75, "rew_std": 129.47580625363784, "Agent": "c51"}, {"env_step": 9300000, "rew": 898.089990234375, "rew_std": 74.57461814213535, "Agent": "c51"}, {"env_step": 9400000, "rew": 837.9999938964844, "rew_std": 75.13513732170806, "Agent": "c51"}, {"env_step": 9500000, "rew": 900.9, "rew_std": 78.32506786062443, "Agent": "c51"}, {"env_step": 9600000, "rew": 832.4200134277344, "rew_std": 69.69465721794408, "Agent": "c51"}, {"env_step": 9700000, "rew": 889.0700012207031, "rew_std": 126.08315874519296, "Agent": "c51"}, {"env_step": 9800000, "rew": 873.6100036621094, "rew_std": 72.68277945780702, "Agent": "c51"}, {"env_step": 9900000, "rew": 796.860009765625, "rew_std": 83.10054074269745, "Agent": "c51"}, {"env_step": 10000000, "rew": 821.8199951171875, "rew_std": 135.73986691667577, "Agent": "c51"}, {"env_step": 0, "rew": 0.010000000149011612, "rew_std": 0.03000000044703483, "Agent": "dqn"}, {"env_step": 100000, "rew": 0.28999999687075617, "rew_std": 0.6774215679654139, "Agent": "dqn"}, {"env_step": 200000, "rew": 0.44000001028180125, "rew_std": 0.8392854380207859, "Agent": "dqn"}, {"env_step": 300000, "rew": 0.3599999964237213, "rew_std": 0.8284925931025058, "Agent": "dqn"}, {"env_step": 400000, "rew": 0.33999999538064, "rew_std": 0.6873135967539007, "Agent": "dqn"}, {"env_step": 500000, "rew": 0.11000000089406967, "rew_std": 0.18138357257301754, "Agent": "dqn"}, {"env_step": 600000, "rew": 0.2100000001490116, "rew_std": 0.4548626165857307, "Agent": "dqn"}, {"env_step": 700000, "rew": 8.389999697357416, "rew_std": 23.108285476400564, "Agent": "dqn"}, {"env_step": 800000, "rew": 98.94999904632569, "rew_std": 35.660067729885725, "Agent": "dqn"}, {"env_step": 900000, "rew": 164.40999908447264, "rew_std": 59.0228520750357, "Agent": "dqn"}, {"env_step": 1000000, "rew": 210.4000030517578, "rew_std": 57.88502705780608, "Agent": "dqn"}, {"env_step": 1100000, "rew": 300.38000030517577, "rew_std": 82.23668084181749, "Agent": "dqn"}, {"env_step": 1200000, "rew": 302.7600036621094, "rew_std": 103.46174434569636, "Agent": "dqn"}, {"env_step": 1300000, "rew": 433.91000213623045, "rew_std": 126.5024948103054, "Agent": "dqn"}, {"env_step": 1400000, "rew": 416.14000244140624, "rew_std": 145.09603673682304, "Agent": "dqn"}, {"env_step": 1500000, "rew": 472.1600006103516, "rew_std": 86.80930065353702, "Agent": "dqn"}, {"env_step": 1600000, "rew": 536.65, "rew_std": 132.84745000480228, "Agent": "dqn"}, {"env_step": 1700000, "rew": 511.6300048828125, "rew_std": 113.56259400514695, "Agent": "dqn"}, {"env_step": 1800000, "rew": 559.5200012207031, "rew_std": 95.26979029881092, "Agent": "dqn"}, {"env_step": 1900000, "rew": 504.64000244140624, "rew_std": 183.2878214612098, "Agent": "dqn"}, {"env_step": 2000000, "rew": 574.7700103759765, "rew_std": 78.04244399982899, "Agent": "dqn"}, {"env_step": 2100000, "rew": 531.539998626709, "rew_std": 230.03735295552605, "Agent": "dqn"}, {"env_step": 2200000, "rew": 584.3100006103516, "rew_std": 116.97556069856971, "Agent": "dqn"}, {"env_step": 2300000, "rew": 609.7900024414063, "rew_std": 76.25380786006397, "Agent": "dqn"}, {"env_step": 2400000, "rew": 601.6499938964844, "rew_std": 156.2863846625289, "Agent": "dqn"}, {"env_step": 2500000, "rew": 614.8899978637695, "rew_std": 188.88530877823078, "Agent": "dqn"}, {"env_step": 2600000, "rew": 585.7100036621093, "rew_std": 183.29359497607433, "Agent": "dqn"}, {"env_step": 2700000, "rew": 681.8800048828125, "rew_std": 179.32764210720728, "Agent": "dqn"}, {"env_step": 2800000, "rew": 593.8799987792969, "rew_std": 178.6578949602182, "Agent": "dqn"}, {"env_step": 2900000, "rew": 685.2, "rew_std": 118.27089032922618, "Agent": "dqn"}, {"env_step": 3000000, "rew": 683.2299926757812, "rew_std": 131.34903655399373, "Agent": "dqn"}, {"env_step": 3100000, "rew": 662.1999938964843, "rew_std": 109.7032239820281, "Agent": "dqn"}, {"env_step": 3200000, "rew": 701.2099975585937, "rew_std": 88.04874320833147, "Agent": "dqn"}, {"env_step": 3300000, "rew": 688.9199981689453, "rew_std": 126.02541709175058, "Agent": "dqn"}, {"env_step": 3400000, "rew": 636.0799987792968, "rew_std": 172.2193654656943, "Agent": "dqn"}, {"env_step": 3500000, "rew": 653.7300018310547, "rew_std": 166.93894277813533, "Agent": "dqn"}, {"env_step": 3600000, "rew": 684.3899963378906, "rew_std": 172.87680391908185, "Agent": "dqn"}, {"env_step": 3700000, "rew": 643.3400039672852, "rew_std": 180.69860945189737, "Agent": "dqn"}, {"env_step": 3800000, "rew": 601.6399993896484, "rew_std": 220.07335285006258, "Agent": "dqn"}, {"env_step": 3900000, "rew": 787.8099914550781, "rew_std": 150.5371983171373, "Agent": "dqn"}, {"env_step": 4000000, "rew": 709.3800048828125, "rew_std": 144.69985159836313, "Agent": "dqn"}, {"env_step": 4100000, "rew": 764.1300018310546, "rew_std": 195.3602195608862, "Agent": "dqn"}, {"env_step": 4200000, "rew": 680.2700012207031, "rew_std": 210.1577440975007, "Agent": "dqn"}, {"env_step": 4300000, "rew": 705.5600036621094, "rew_std": 216.64282568222822, "Agent": "dqn"}, {"env_step": 4400000, "rew": 808.1700073242188, "rew_std": 171.82676781938977, "Agent": "dqn"}, {"env_step": 4500000, "rew": 715.6900006294251, "rew_std": 325.7469276625226, "Agent": "dqn"}, {"env_step": 4600000, "rew": 732.2800018310547, "rew_std": 201.57531656345432, "Agent": "dqn"}, {"env_step": 4700000, "rew": 786.0399963378907, "rew_std": 166.10157244455863, "Agent": "dqn"}, {"env_step": 4800000, "rew": 786.3699920654296, "rew_std": 178.73539138167627, "Agent": "dqn"}, {"env_step": 4900000, "rew": 775.7399993896485, "rew_std": 224.3126871078825, "Agent": "dqn"}, {"env_step": 5000000, "rew": 837.7899932861328, "rew_std": 153.09056362847045, "Agent": "dqn"}, {"env_step": 5100000, "rew": 830.0400085449219, "rew_std": 160.10900182067942, "Agent": "dqn"}, {"env_step": 5200000, "rew": 823.5699981689453, "rew_std": 194.98995547995364, "Agent": "dqn"}, {"env_step": 5300000, "rew": 855.3900024414063, "rew_std": 140.50763881053481, "Agent": "dqn"}, {"env_step": 5400000, "rew": 894.0799865722656, "rew_std": 140.23513752874317, "Agent": "dqn"}, {"env_step": 5500000, "rew": 833.1599899291992, "rew_std": 252.01737545461143, "Agent": "dqn"}, {"env_step": 5600000, "rew": 810.3499969482422, "rew_std": 203.2235554729935, "Agent": "dqn"}, {"env_step": 5700000, "rew": 725.3200134277344, "rew_std": 319.200193375417, "Agent": "dqn"}, {"env_step": 5800000, "rew": 766.3399963378906, "rew_std": 245.59766336856708, "Agent": "dqn"}, {"env_step": 5900000, "rew": 824.45, "rew_std": 157.8227175018482, "Agent": "dqn"}, {"env_step": 6000000, "rew": 839.1499938964844, "rew_std": 267.6931744720739, "Agent": "dqn"}, {"env_step": 6100000, "rew": 911.7200012207031, "rew_std": 149.13539534554963, "Agent": "dqn"}, {"env_step": 6200000, "rew": 865.1299987792969, "rew_std": 151.98633776803706, "Agent": "dqn"}, {"env_step": 6300000, "rew": 701.3800109863281, "rew_std": 231.76907968297863, "Agent": "dqn"}, {"env_step": 6400000, "rew": 848.5299987792969, "rew_std": 142.20331551456655, "Agent": "dqn"}, {"env_step": 6500000, "rew": 857.1699829101562, "rew_std": 245.273054002329, "Agent": "dqn"}, {"env_step": 6600000, "rew": 872.0099975585938, "rew_std": 275.1938175427823, "Agent": "dqn"}, {"env_step": 6700000, "rew": 780.0400024414063, "rew_std": 218.67946501129768, "Agent": "dqn"}, {"env_step": 6800000, "rew": 972.5299926757813, "rew_std": 84.68238747454869, "Agent": "dqn"}, {"env_step": 6900000, "rew": 839.6300048828125, "rew_std": 172.06233073457074, "Agent": "dqn"}, {"env_step": 7000000, "rew": 765.7000030517578, "rew_std": 228.73327046919016, "Agent": "dqn"}, {"env_step": 7100000, "rew": 803.6699981689453, "rew_std": 223.20593976154984, "Agent": "dqn"}, {"env_step": 7200000, "rew": 869.5399948120117, "rew_std": 296.05559318233026, "Agent": "dqn"}, {"env_step": 7300000, "rew": 899.0700073242188, "rew_std": 223.90129458785196, "Agent": "dqn"}, {"env_step": 7400000, "rew": 894.3500122070312, "rew_std": 124.86718242625085, "Agent": "dqn"}, {"env_step": 7500000, "rew": 844.4800048828125, "rew_std": 178.28963708114927, "Agent": "dqn"}, {"env_step": 7600000, "rew": 832.0400024414063, "rew_std": 169.4274077668312, "Agent": "dqn"}, {"env_step": 7700000, "rew": 792.3100036621094, "rew_std": 230.68153832883345, "Agent": "dqn"}, {"env_step": 7800000, "rew": 803.5799963474274, "rew_std": 309.8821414828576, "Agent": "dqn"}, {"env_step": 7900000, "rew": 673.1000030517578, "rew_std": 227.6657908497509, "Agent": "dqn"}, {"env_step": 8000000, "rew": 902.8799987792969, "rew_std": 131.25283923863736, "Agent": "dqn"}, {"env_step": 8100000, "rew": 724.4699996948242, "rew_std": 295.4643426314042, "Agent": "dqn"}, {"env_step": 8200000, "rew": 927.2100036621093, "rew_std": 143.6894016940865, "Agent": "dqn"}, {"env_step": 8300000, "rew": 942.3600006103516, "rew_std": 285.8560329981964, "Agent": "dqn"}, {"env_step": 8400000, "rew": 851.1799987792969, "rew_std": 200.8229014095921, "Agent": "dqn"}, {"env_step": 8500000, "rew": 901.9700012207031, "rew_std": 160.8610738450723, "Agent": "dqn"}, {"env_step": 8600000, "rew": 871.3400024414062, "rew_std": 190.1946167222594, "Agent": "dqn"}, {"env_step": 8700000, "rew": 833.9000122070313, "rew_std": 240.40292224599622, "Agent": "dqn"}, {"env_step": 8800000, "rew": 869.95, "rew_std": 184.55665785734556, "Agent": "dqn"}, {"env_step": 8900000, "rew": 875.4000030517578, "rew_std": 285.9085977204755, "Agent": "dqn"}, {"env_step": 9000000, "rew": 867.3599975585937, "rew_std": 361.56061577070335, "Agent": "dqn"}, {"env_step": 9100000, "rew": 856.3100036621094, "rew_std": 315.8472236982946, "Agent": "dqn"}, {"env_step": 9200000, "rew": 856.9499938964843, "rew_std": 170.14471559957494, "Agent": "dqn"}, {"env_step": 9300000, "rew": 888.9199951171875, "rew_std": 168.72139042881585, "Agent": "dqn"}, {"env_step": 9400000, "rew": 866.0400131225585, "rew_std": 299.502088920062, "Agent": "dqn"}, {"env_step": 9500000, "rew": 840.8400024414062, "rew_std": 331.5126113915152, "Agent": "dqn"}, {"env_step": 9600000, "rew": 807.6199981689454, "rew_std": 295.85304518327024, "Agent": "dqn"}, {"env_step": 9700000, "rew": 997.8700073242187, "rew_std": 180.62872163215707, "Agent": "dqn"}, {"env_step": 9800000, "rew": 902.3699951171875, "rew_std": 191.78846507427704, "Agent": "dqn"}, {"env_step": 9900000, "rew": 832.2099884033203, "rew_std": 279.22019714027266, "Agent": "dqn"}, {"env_step": 10000000, "rew": 833.1200012207031, "rew_std": 180.39020450524953, "Agent": "dqn"}, {"env_step": 0, "rew": 0.010000000149011612, "rew_std": 0.03000000044703483, "Agent": "fqf"}, {"env_step": 100000, "rew": 0.4000000074505806, "rew_std": 0.5949790043492437, "Agent": "fqf"}, {"env_step": 200000, "rew": 0.5199999868869781, "rew_std": 0.9031057265445962, "Agent": "fqf"}, {"env_step": 300000, "rew": 0.020000000298023225, "rew_std": 0.04000000059604644, "Agent": "fqf"}, {"env_step": 400000, "rew": 0.1600000001490116, "rew_std": 0.4476605856920158, "Agent": "fqf"}, {"env_step": 500000, "rew": 0.06999999880790711, "rew_std": 0.2099999964237213, "Agent": "fqf"}, {"env_step": 600000, "rew": 3.8100000239908693, "rew_std": 5.602936729313963, "Agent": "fqf"}, {"env_step": 700000, "rew": 12.430000038444996, "rew_std": 19.787372405641634, "Agent": "fqf"}, {"env_step": 800000, "rew": 85.2499984741211, "rew_std": 63.42670047163025, "Agent": "fqf"}, {"env_step": 900000, "rew": 133.19000046253205, "rew_std": 70.73937261722692, "Agent": "fqf"}, {"env_step": 1000000, "rew": 305.75999908447267, "rew_std": 103.32499176000272, "Agent": "fqf"}, {"env_step": 1100000, "rew": 413.0800033569336, "rew_std": 109.4271524578977, "Agent": "fqf"}, {"env_step": 1200000, "rew": 447.47999572753906, "rew_std": 130.462502495816, "Agent": "fqf"}, {"env_step": 1300000, "rew": 518.3400054931641, "rew_std": 135.58270493310644, "Agent": "fqf"}, {"env_step": 1400000, "rew": 657.4699951171875, "rew_std": 146.84401743315414, "Agent": "fqf"}, {"env_step": 1500000, "rew": 748.0899963378906, "rew_std": 115.51613589716597, "Agent": "fqf"}, {"env_step": 1600000, "rew": 675.2199920654297, "rew_std": 152.8333391660496, "Agent": "fqf"}, {"env_step": 1700000, "rew": 711.7800109863281, "rew_std": 140.070698003054, "Agent": "fqf"}, {"env_step": 1800000, "rew": 768.7699981689453, "rew_std": 205.88203217918607, "Agent": "fqf"}, {"env_step": 1900000, "rew": 830.1599975585938, "rew_std": 164.96536198083228, "Agent": "fqf"}, {"env_step": 2000000, "rew": 838.0, "rew_std": 134.02208935127933, "Agent": "fqf"}, {"env_step": 2100000, "rew": 860.7899963378907, "rew_std": 130.38507918675546, "Agent": "fqf"}, {"env_step": 2200000, "rew": 977.0700073242188, "rew_std": 126.20982209871863, "Agent": "fqf"}, {"env_step": 2300000, "rew": 950.0299987792969, "rew_std": 156.14618566531715, "Agent": "fqf"}, {"env_step": 2400000, "rew": 846.3499877929687, "rew_std": 248.7892251417476, "Agent": "fqf"}, {"env_step": 2500000, "rew": 992.1199951171875, "rew_std": 115.97767285528869, "Agent": "fqf"}, {"env_step": 2600000, "rew": 987.1100036621094, "rew_std": 102.14894278448398, "Agent": "fqf"}, {"env_step": 2700000, "rew": 1004.62001953125, "rew_std": 195.0578605917069, "Agent": "fqf"}, {"env_step": 2800000, "rew": 972.389990234375, "rew_std": 155.29393383794988, "Agent": "fqf"}, {"env_step": 2900000, "rew": 948.7399932861329, "rew_std": 274.68796913449233, "Agent": "fqf"}, {"env_step": 3000000, "rew": 1058.3299926757813, "rew_std": 170.51883401478082, "Agent": "fqf"}, {"env_step": 3100000, "rew": 1085.8400024414063, "rew_std": 143.12279720739653, "Agent": "fqf"}, {"env_step": 3200000, "rew": 1149.7299865722657, "rew_std": 218.88763506679157, "Agent": "fqf"}, {"env_step": 3300000, "rew": 1151.3599914550782, "rew_std": 190.10523364130052, "Agent": "fqf"}, {"env_step": 3400000, "rew": 1080.9000122070313, "rew_std": 332.21089689623733, "Agent": "fqf"}, {"env_step": 3500000, "rew": 1113.7200073242188, "rew_std": 122.5017752266977, "Agent": "fqf"}, {"env_step": 3600000, "rew": 1153.9199951171875, "rew_std": 110.683608376239, "Agent": "fqf"}, {"env_step": 3700000, "rew": 1151.8500061035156, "rew_std": 253.38377103265688, "Agent": "fqf"}, {"env_step": 3800000, "rew": 1277.9900146484374, "rew_std": 112.66564272737654, "Agent": "fqf"}, {"env_step": 3900000, "rew": 1282.3099731445313, "rew_std": 217.32348002992126, "Agent": "fqf"}, {"env_step": 4000000, "rew": 1248.0900024414063, "rew_std": 170.67968176451825, "Agent": "fqf"}, {"env_step": 4100000, "rew": 1322.8300170898438, "rew_std": 153.41429245269322, "Agent": "fqf"}, {"env_step": 4200000, "rew": 1236.4299896240234, "rew_std": 308.0954582465107, "Agent": "fqf"}, {"env_step": 4300000, "rew": 1342.439990234375, "rew_std": 193.51426337682267, "Agent": "fqf"}, {"env_step": 4400000, "rew": 1149.9899963378907, "rew_std": 244.50325562855912, "Agent": "fqf"}, {"env_step": 4500000, "rew": 1353.7800048828126, "rew_std": 228.50535375228858, "Agent": "fqf"}, {"env_step": 4600000, "rew": 1196.4300048828125, "rew_std": 221.77920221529982, "Agent": "fqf"}, {"env_step": 4700000, "rew": 1338.169989013672, "rew_std": 258.7844697757098, "Agent": "fqf"}, {"env_step": 4800000, "rew": 1455.7900146484376, "rew_std": 222.74215426809056, "Agent": "fqf"}, {"env_step": 4900000, "rew": 1465.7900024414062, "rew_std": 211.17771615384086, "Agent": "fqf"}, {"env_step": 5000000, "rew": 1360.9300048828125, "rew_std": 158.9558026017405, "Agent": "fqf"}, {"env_step": 5100000, "rew": 1326.210009765625, "rew_std": 153.008085562372, "Agent": "fqf"}, {"env_step": 5200000, "rew": 1324.9800048828124, "rew_std": 192.30021302076855, "Agent": "fqf"}, {"env_step": 5300000, "rew": 1373.3199951171875, "rew_std": 190.05878674516413, "Agent": "fqf"}, {"env_step": 5400000, "rew": 1444.8299926757813, "rew_std": 176.63967297772865, "Agent": "fqf"}, {"env_step": 5500000, "rew": 1380.8700012207032, "rew_std": 275.76877411799353, "Agent": "fqf"}, {"env_step": 5600000, "rew": 1449.3299926757813, "rew_std": 189.39536052457436, "Agent": "fqf"}, {"env_step": 5700000, "rew": 1399.7899780273438, "rew_std": 186.23228867562835, "Agent": "fqf"}, {"env_step": 5800000, "rew": 1526.0900024414063, "rew_std": 226.097034699169, "Agent": "fqf"}, {"env_step": 5900000, "rew": 1323.17001953125, "rew_std": 214.75273220122753, "Agent": "fqf"}, {"env_step": 6000000, "rew": 1335.5700073242188, "rew_std": 199.16455799287937, "Agent": "fqf"}, {"env_step": 6100000, "rew": 1455.260009765625, "rew_std": 188.3336061850183, "Agent": "fqf"}, {"env_step": 6200000, "rew": 1460.6299926757813, "rew_std": 168.61568012736888, "Agent": "fqf"}, {"env_step": 6300000, "rew": 1531.5299926757812, "rew_std": 223.6121634917823, "Agent": "fqf"}, {"env_step": 6400000, "rew": 1473.3, "rew_std": 157.68532141529403, "Agent": "fqf"}, {"env_step": 6500000, "rew": 1348.3100036621095, "rew_std": 336.5419653083397, "Agent": "fqf"}, {"env_step": 6600000, "rew": 1360.3900024414063, "rew_std": 385.11999323091857, "Agent": "fqf"}, {"env_step": 6700000, "rew": 1525.3900024414063, "rew_std": 223.73438160213453, "Agent": "fqf"}, {"env_step": 6800000, "rew": 1424.3700134277344, "rew_std": 227.2740165319224, "Agent": "fqf"}, {"env_step": 6900000, "rew": 1444.5199951171876, "rew_std": 206.8632128076105, "Agent": "fqf"}, {"env_step": 7000000, "rew": 1550.7000244140625, "rew_std": 243.50839787358856, "Agent": "fqf"}, {"env_step": 7100000, "rew": 1510.7899963378907, "rew_std": 258.7483723817995, "Agent": "fqf"}, {"env_step": 7200000, "rew": 1483.280010986328, "rew_std": 264.7287475532349, "Agent": "fqf"}, {"env_step": 7300000, "rew": 1499.6600219726563, "rew_std": 341.719842324931, "Agent": "fqf"}, {"env_step": 7400000, "rew": 1687.2500244140624, "rew_std": 256.1505463645012, "Agent": "fqf"}, {"env_step": 7500000, "rew": 1454.0300048828126, "rew_std": 280.16069877794627, "Agent": "fqf"}, {"env_step": 7600000, "rew": 1593.1700012207032, "rew_std": 356.6653348908056, "Agent": "fqf"}, {"env_step": 7700000, "rew": 1752.35, "rew_std": 272.67251651423953, "Agent": "fqf"}, {"env_step": 7800000, "rew": 1424.1700073242187, "rew_std": 240.21965983357364, "Agent": "fqf"}, {"env_step": 7900000, "rew": 1545.0499877929688, "rew_std": 274.2309684007817, "Agent": "fqf"}, {"env_step": 8000000, "rew": 1491.2900024414062, "rew_std": 221.5089150627939, "Agent": "fqf"}, {"env_step": 8100000, "rew": 1686.5300170898438, "rew_std": 233.44947282580907, "Agent": "fqf"}, {"env_step": 8200000, "rew": 1654.559991455078, "rew_std": 257.67832128859897, "Agent": "fqf"}, {"env_step": 8300000, "rew": 1608.6599975585937, "rew_std": 238.0655354689683, "Agent": "fqf"}, {"env_step": 8400000, "rew": 1575.3399780273437, "rew_std": 203.41885145877984, "Agent": "fqf"}, {"env_step": 8500000, "rew": 1501.899984741211, "rew_std": 443.3008682851743, "Agent": "fqf"}, {"env_step": 8600000, "rew": 1344.8300048828125, "rew_std": 226.3636211692771, "Agent": "fqf"}, {"env_step": 8700000, "rew": 1358.25, "rew_std": 207.60759860147468, "Agent": "fqf"}, {"env_step": 8800000, "rew": 1577.8999877929687, "rew_std": 218.78633687041156, "Agent": "fqf"}, {"env_step": 8900000, "rew": 1816.8199951171875, "rew_std": 314.3398063009122, "Agent": "fqf"}, {"env_step": 9000000, "rew": 1508.2200073242188, "rew_std": 202.8977505176873, "Agent": "fqf"}, {"env_step": 9100000, "rew": 1388.3, "rew_std": 358.01253786434296, "Agent": "fqf"}, {"env_step": 9200000, "rew": 1657.6999877929688, "rew_std": 162.50743736286006, "Agent": "fqf"}, {"env_step": 9300000, "rew": 1769.5699829101563, "rew_std": 430.9407204209698, "Agent": "fqf"}, {"env_step": 9400000, "rew": 1644.0599975585938, "rew_std": 363.31351881469755, "Agent": "fqf"}, {"env_step": 9500000, "rew": 1774.7999755859375, "rew_std": 458.10963716513834, "Agent": "fqf"}, {"env_step": 9600000, "rew": 1574.6399780273437, "rew_std": 286.1478292951951, "Agent": "fqf"}, {"env_step": 9700000, "rew": 1621.3900024414063, "rew_std": 203.88568091812692, "Agent": "fqf"}, {"env_step": 9800000, "rew": 1800.6699829101562, "rew_std": 246.23150505646822, "Agent": "fqf"}, {"env_step": 9900000, "rew": 1717.560009765625, "rew_std": 272.92596987574973, "Agent": "fqf"}, {"env_step": 10000000, "rew": 1663.030029296875, "rew_std": 215.58594858353038, "Agent": "fqf"}, {"env_step": 0, "rew": 0.2, "rew_std": 0.43817804165122526, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 2.950000001490116, "rew_std": 8.683806768461812, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 2.750000011920929, "rew_std": 7.12281545355883, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 2.139999923855066, "rew_std": 6.060560801476709, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 8.719999969005585, "rew_std": 12.750513633943633, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 0.020000000298023225, "rew_std": 0.06000000089406966, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 4.539999961853027, "rew_std": 8.518591324669725, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 20.8, "rew_std": 19.17268910037082, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 64.31000022888183, "rew_std": 55.11154952769602, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 117.36000137329101, "rew_std": 81.42853758823472, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 212.5300022125244, "rew_std": 134.6447147733004, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 311.71999740600586, "rew_std": 143.0127312672216, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 427.21999702453616, "rew_std": 166.6607249218663, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 450.81999626159666, "rew_std": 170.6163965376507, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 446.6700017929077, "rew_std": 171.28357388934182, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 501.95000114440916, "rew_std": 214.17296736360868, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 515.3500011444091, "rew_std": 228.24397876121898, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 532.7900005340576, "rew_std": 260.70330697040697, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 535.5499984741211, "rew_std": 226.46023524425055, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 614.3999969482422, "rew_std": 229.86442537632706, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 495.1, "rew_std": 277.79406604885946, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 585.6600044250488, "rew_std": 230.43919543285637, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 716.0299999237061, "rew_std": 264.0099569711277, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 542.9899975776673, "rew_std": 303.6674555033, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 715.6400062561036, "rew_std": 286.50699130558786, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 648.0000051498413, "rew_std": 301.31887025376795, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 593.8800014495849, "rew_std": 302.4725858413253, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 662.1199962615967, "rew_std": 292.98960962786776, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 695.9800054550171, "rew_std": 284.20259753123815, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 729.7400060653687, "rew_std": 261.0564239167806, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 765.3200073242188, "rew_std": 267.8584904904683, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 763.0400096893311, "rew_std": 257.2424218386392, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 775.7299938201904, "rew_std": 273.62065502831194, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 768.5900030136108, "rew_std": 293.28401432770056, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 736.4700023651124, "rew_std": 251.00099161324306, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 704.0100011825562, "rew_std": 279.16315078624314, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 711.050004196167, "rew_std": 264.62492121177553, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 801.9700037002564, "rew_std": 277.7941106570264, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 844.069990158081, "rew_std": 287.56283848408725, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 759.6999963760376, "rew_std": 279.6283181481931, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 583.4499931335449, "rew_std": 287.06731842027597, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 749.8800132751464, "rew_std": 264.1112287832134, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 793.8099964141845, "rew_std": 302.25798478353556, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 721.4700023651124, "rew_std": 280.748223525854, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 782.9300025939941, "rew_std": 341.9947531259377, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 861.8200061798095, "rew_std": 300.90433581636256, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 699.4100095748902, "rew_std": 358.53734373918525, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 763.3199853897095, "rew_std": 321.5669115617899, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 875.8500049591064, "rew_std": 322.19139996909126, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 798.370009803772, "rew_std": 320.01471740842925, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 916.0799865722656, "rew_std": 321.69201590196326, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 854.7900035858154, "rew_std": 282.8008511766018, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 778.5300037384034, "rew_std": 300.45106950066236, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 824.4299976348877, "rew_std": 302.3329753994756, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 888.6600048065186, "rew_std": 338.1730635095935, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 839.840009689331, "rew_std": 347.04786183662765, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 743.8000047683715, "rew_std": 372.26147487134074, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 867.8499877929687, "rew_std": 316.0468936380672, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 823.3300037384033, "rew_std": 323.5871449731984, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 840.5399921417236, "rew_std": 379.45472835781385, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 795.1999963760376, "rew_std": 305.4413360252164, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 837.2100086212158, "rew_std": 294.2474416713455, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 832.8199975967407, "rew_std": 315.05369700324695, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 758.1000026702881, "rew_std": 356.9235426531571, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 869.2500061035156, "rew_std": 302.04547033603006, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 785.2299983978271, "rew_std": 393.64854338638054, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 790.1000085830689, "rew_std": 365.117793324928, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 871.6399927139282, "rew_std": 307.94262149553043, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 769.5600109100342, "rew_std": 397.7108398542242, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 897.1599975585938, "rew_std": 326.12778476504053, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 826.01999874115, "rew_std": 303.25010067918225, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 899.7099914550781, "rew_std": 354.635686696347, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 839.5300022125244, "rew_std": 366.1003253391808, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 789.2700035095215, "rew_std": 325.517405634325, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 791.4800006866456, "rew_std": 308.0200619677834, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 753.9000038146972, "rew_std": 353.6681404822802, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 760.5899974822999, "rew_std": 373.76654972757194, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 895.6800060272217, "rew_std": 332.0611307126876, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 797.7900001525879, "rew_std": 337.71737028991475, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 863.1199945449829, "rew_std": 383.8510796441181, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 936.8600036621094, "rew_std": 335.0957512819982, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 873.0900012969971, "rew_std": 323.48754155145383, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 897.2599962234497, "rew_std": 430.1072599184845, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 925.4600048065186, "rew_std": 328.0253425434283, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 800.1099956512451, "rew_std": 369.4526365613206, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 764.4199901580811, "rew_std": 386.03387542422104, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 951.6600109100342, "rew_std": 333.5321850552157, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 746.5100072860718, "rew_std": 286.61728504504305, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 849.2099956512451, "rew_std": 376.9793778487278, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 804.9700115203857, "rew_std": 377.45671631618694, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 855.3400024414062, "rew_std": 335.099863589258, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 660.5900043487549, "rew_std": 356.5631885015981, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 878.2999950408936, "rew_std": 312.5758680927236, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 826.950011062622, "rew_std": 350.83283915590056, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 790.7599872589111, "rew_std": 401.66813659775227, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 849.3099939346314, "rew_std": 313.7882372406271, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 854.3600103378296, "rew_std": 367.7412676045596, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 803.1500019073486, "rew_std": 384.89482159028836, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 655.2900049209595, "rew_std": 378.5388990350636, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 778.3899938583374, "rew_std": 332.5220751161268, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 805.2999959945679, "rew_std": 376.93931456836924, "Agent": "qrdqn"}, {"env_step": 0, "rew": 0.020000000298023225, "rew_std": 0.06000000089406966, "Agent": "iqn"}, {"env_step": 100000, "rew": 1.2300000190734863, "rew_std": 3.52648555976251, "Agent": "iqn"}, {"env_step": 200000, "rew": 0.17000000029802323, "rew_std": 0.2193171198611889, "Agent": "iqn"}, {"env_step": 300000, "rew": 2.0799999237060547, "rew_std": 5.910634254899296, "Agent": "iqn"}, {"env_step": 400000, "rew": 0.04000000059604645, "rew_std": 0.08000000119209288, "Agent": "iqn"}, {"env_step": 500000, "rew": 3.5900000773370264, "rew_std": 10.53740503238059, "Agent": "iqn"}, {"env_step": 600000, "rew": 4.530000066757202, "rew_std": 9.554166769060705, "Agent": "iqn"}, {"env_step": 700000, "rew": 3.480000114440918, "rew_std": 6.673799742209458, "Agent": "iqn"}, {"env_step": 800000, "rew": 37.689999313652514, "rew_std": 42.65694315548521, "Agent": "iqn"}, {"env_step": 900000, "rew": 123.90999913215637, "rew_std": 116.8702046746665, "Agent": "iqn"}, {"env_step": 1000000, "rew": 214.27999999523163, "rew_std": 131.19766379013453, "Agent": "iqn"}, {"env_step": 1100000, "rew": 314.01000213623047, "rew_std": 130.61631856241644, "Agent": "iqn"}, {"env_step": 1200000, "rew": 447.6299987792969, "rew_std": 132.88649299306232, "Agent": "iqn"}, {"env_step": 1300000, "rew": 488.24000244140626, "rew_std": 144.3410893300805, "Agent": "iqn"}, {"env_step": 1400000, "rew": 562.2800018310547, "rew_std": 126.35490427347918, "Agent": "iqn"}, {"env_step": 1500000, "rew": 503.0600067138672, "rew_std": 126.1369021393955, "Agent": "iqn"}, {"env_step": 1600000, "rew": 590.9699981689453, "rew_std": 106.22815802626981, "Agent": "iqn"}, {"env_step": 1700000, "rew": 656.8100067138672, "rew_std": 176.85540361563625, "Agent": "iqn"}, {"env_step": 1800000, "rew": 639.1500061035156, "rew_std": 159.90553612644817, "Agent": "iqn"}, {"env_step": 1900000, "rew": 654.3699951171875, "rew_std": 166.7387170420838, "Agent": "iqn"}, {"env_step": 2000000, "rew": 633.2700103759765, "rew_std": 194.57762929404822, "Agent": "iqn"}, {"env_step": 2100000, "rew": 700.1900115966797, "rew_std": 157.40320450762798, "Agent": "iqn"}, {"env_step": 2200000, "rew": 628.6800003051758, "rew_std": 207.51145605282667, "Agent": "iqn"}, {"env_step": 2300000, "rew": 684.490007019043, "rew_std": 224.21249061996116, "Agent": "iqn"}, {"env_step": 2400000, "rew": 756.5900001525879, "rew_std": 288.4319216808326, "Agent": "iqn"}, {"env_step": 2500000, "rew": 675.5500030517578, "rew_std": 244.21607763740568, "Agent": "iqn"}, {"env_step": 2600000, "rew": 779.7999938964844, "rew_std": 256.5563681757168, "Agent": "iqn"}, {"env_step": 2700000, "rew": 727.7399963378906, "rew_std": 269.84431788518737, "Agent": "iqn"}, {"env_step": 2800000, "rew": 792.0200012207031, "rew_std": 116.56821154467826, "Agent": "iqn"}, {"env_step": 2900000, "rew": 859.7300109863281, "rew_std": 185.18119041013455, "Agent": "iqn"}, {"env_step": 3000000, "rew": 899.7199981689453, "rew_std": 216.57974461966018, "Agent": "iqn"}, {"env_step": 3100000, "rew": 915.3699890136719, "rew_std": 114.51627047111124, "Agent": "iqn"}, {"env_step": 3200000, "rew": 795.7599945068359, "rew_std": 240.49648753795014, "Agent": "iqn"}, {"env_step": 3300000, "rew": 880.1699981689453, "rew_std": 189.51477550814192, "Agent": "iqn"}, {"env_step": 3400000, "rew": 945.1100036621094, "rew_std": 128.7564537028809, "Agent": "iqn"}, {"env_step": 3500000, "rew": 919.9100036621094, "rew_std": 244.82328680147785, "Agent": "iqn"}, {"env_step": 3600000, "rew": 982.8000061035157, "rew_std": 159.50998642265364, "Agent": "iqn"}, {"env_step": 3700000, "rew": 837.7000122070312, "rew_std": 188.50218141170882, "Agent": "iqn"}, {"env_step": 3800000, "rew": 1006.9300048828125, "rew_std": 142.2613367175323, "Agent": "iqn"}, {"env_step": 3900000, "rew": 913.0099868774414, "rew_std": 267.489982408041, "Agent": "iqn"}, {"env_step": 4000000, "rew": 874.3000061035157, "rew_std": 173.92007373390783, "Agent": "iqn"}, {"env_step": 4100000, "rew": 910.5500030517578, "rew_std": 194.92890230647552, "Agent": "iqn"}, {"env_step": 4200000, "rew": 983.5, "rew_std": 116.83092046232777, "Agent": "iqn"}, {"env_step": 4300000, "rew": 901.1400039672851, "rew_std": 305.8871257170003, "Agent": "iqn"}, {"env_step": 4400000, "rew": 813.9199890136719, "rew_std": 259.7093781051844, "Agent": "iqn"}, {"env_step": 4500000, "rew": 975.1299987792969, "rew_std": 249.7706832098956, "Agent": "iqn"}, {"env_step": 4600000, "rew": 964.7699890136719, "rew_std": 288.6829312458577, "Agent": "iqn"}, {"env_step": 4700000, "rew": 990.8800170898437, "rew_std": 227.1040665924821, "Agent": "iqn"}, {"env_step": 4800000, "rew": 1069.3499877929687, "rew_std": 184.13221489797237, "Agent": "iqn"}, {"env_step": 4900000, "rew": 985.4000122070313, "rew_std": 185.19558967958181, "Agent": "iqn"}, {"env_step": 5000000, "rew": 888.0499984741211, "rew_std": 383.0892119253023, "Agent": "iqn"}, {"env_step": 5100000, "rew": 1122.0600036621095, "rew_std": 252.77394487644332, "Agent": "iqn"}, {"env_step": 5200000, "rew": 972.6900054931641, "rew_std": 222.1775487183736, "Agent": "iqn"}, {"env_step": 5300000, "rew": 966.9400115966797, "rew_std": 369.08832261651287, "Agent": "iqn"}, {"env_step": 5400000, "rew": 789.2899993896484, "rew_std": 320.53568647830184, "Agent": "iqn"}, {"env_step": 5500000, "rew": 1027.3899841308594, "rew_std": 133.49564343614747, "Agent": "iqn"}, {"env_step": 5600000, "rew": 872.7399963378906, "rew_std": 283.1106543105209, "Agent": "iqn"}, {"env_step": 5700000, "rew": 1003.5799987792968, "rew_std": 303.12510600006334, "Agent": "iqn"}, {"env_step": 5800000, "rew": 898.3699935913086, "rew_std": 299.9163407129428, "Agent": "iqn"}, {"env_step": 5900000, "rew": 928.5400024414063, "rew_std": 183.30899650150636, "Agent": "iqn"}, {"env_step": 6000000, "rew": 1099.45, "rew_std": 215.64728660357196, "Agent": "iqn"}, {"env_step": 6100000, "rew": 1008.9999969482421, "rew_std": 270.1578310856458, "Agent": "iqn"}, {"env_step": 6200000, "rew": 1065.940008544922, "rew_std": 255.40183052553036, "Agent": "iqn"}, {"env_step": 6300000, "rew": 811.1000024795533, "rew_std": 373.20585603601734, "Agent": "iqn"}, {"env_step": 6400000, "rew": 940.3700012207031, "rew_std": 246.35399546539406, "Agent": "iqn"}, {"env_step": 6500000, "rew": 1068.6700012207032, "rew_std": 97.1969648010114, "Agent": "iqn"}, {"env_step": 6600000, "rew": 1245.320001220703, "rew_std": 287.68207875342046, "Agent": "iqn"}, {"env_step": 6700000, "rew": 1029.4099975585937, "rew_std": 181.585287367347, "Agent": "iqn"}, {"env_step": 6800000, "rew": 1042.259991455078, "rew_std": 164.0986750263718, "Agent": "iqn"}, {"env_step": 6900000, "rew": 838.8700035095214, "rew_std": 355.00632184818426, "Agent": "iqn"}, {"env_step": 7000000, "rew": 1098.1199951171875, "rew_std": 197.77309679595174, "Agent": "iqn"}, {"env_step": 7100000, "rew": 929.949984741211, "rew_std": 290.7787575853067, "Agent": "iqn"}, {"env_step": 7200000, "rew": 1002.5799926757812, "rew_std": 238.4512457320423, "Agent": "iqn"}, {"env_step": 7300000, "rew": 936.2500061035156, "rew_std": 200.61891005074025, "Agent": "iqn"}, {"env_step": 7400000, "rew": 1090.2499938964843, "rew_std": 137.09873398122215, "Agent": "iqn"}, {"env_step": 7500000, "rew": 1079.7300170898438, "rew_std": 129.4222508666326, "Agent": "iqn"}, {"env_step": 7600000, "rew": 968.8100051879883, "rew_std": 469.84580201774713, "Agent": "iqn"}, {"env_step": 7700000, "rew": 1022.8900024414063, "rew_std": 251.64726234338931, "Agent": "iqn"}, {"env_step": 7800000, "rew": 1021.4299987792969, "rew_std": 243.66798220474894, "Agent": "iqn"}, {"env_step": 7900000, "rew": 1113.2900024414062, "rew_std": 199.72603151675196, "Agent": "iqn"}, {"env_step": 8000000, "rew": 1132.0199890136719, "rew_std": 263.47352587686873, "Agent": "iqn"}, {"env_step": 8100000, "rew": 1050.8499877929687, "rew_std": 191.7771377236277, "Agent": "iqn"}, {"env_step": 8200000, "rew": 1099.139990234375, "rew_std": 223.08476706246242, "Agent": "iqn"}, {"env_step": 8300000, "rew": 1095.5199951171876, "rew_std": 152.96869354522246, "Agent": "iqn"}, {"env_step": 8400000, "rew": 1059.9700012207031, "rew_std": 121.60402177574996, "Agent": "iqn"}, {"env_step": 8500000, "rew": 1119.9500122070312, "rew_std": 173.45015933529174, "Agent": "iqn"}, {"env_step": 8600000, "rew": 940.7099975585937, "rew_std": 184.9244564548404, "Agent": "iqn"}, {"env_step": 8700000, "rew": 930.7999961853027, "rew_std": 366.8234875758687, "Agent": "iqn"}, {"env_step": 8800000, "rew": 1097.2800170898438, "rew_std": 296.206762846177, "Agent": "iqn"}, {"env_step": 8900000, "rew": 1139.8899780273437, "rew_std": 255.91239554199356, "Agent": "iqn"}, {"env_step": 9000000, "rew": 1043.5500061035157, "rew_std": 173.89118497858877, "Agent": "iqn"}, {"env_step": 9100000, "rew": 929.5200164794921, "rew_std": 373.30865054928415, "Agent": "iqn"}, {"env_step": 9200000, "rew": 1205.3200134277345, "rew_std": 275.42816935716706, "Agent": "iqn"}, {"env_step": 9300000, "rew": 1150.1200012207032, "rew_std": 260.06818848705825, "Agent": "iqn"}, {"env_step": 9400000, "rew": 1100.200018310547, "rew_std": 185.52076935234098, "Agent": "iqn"}, {"env_step": 9500000, "rew": 1058.1600158691406, "rew_std": 311.87799312292907, "Agent": "iqn"}, {"env_step": 9600000, "rew": 1252.6800048828125, "rew_std": 118.09878836211058, "Agent": "iqn"}, {"env_step": 9700000, "rew": 1132.0099853515626, "rew_std": 200.64719895414822, "Agent": "iqn"}, {"env_step": 9800000, "rew": 1039.539990234375, "rew_std": 270.93414588943654, "Agent": "iqn"}, {"env_step": 9900000, "rew": 1111.9599914550781, "rew_std": 303.33757722581527, "Agent": "iqn"}, {"env_step": 10000000, "rew": 1095.0599853515625, "rew_std": 200.86304116683058, "Agent": "iqn"}, {"env_step": 0, "rew": 0.2100000001490116, "rew_std": 0.5974110812223167, "Agent": "rainbow"}, {"env_step": 100000, "rew": 0.12999999523162842, "rew_std": 0.38999998569488525, "Agent": "rainbow"}, {"env_step": 200000, "rew": 2.7599999859929083, "rew_std": 6.376864428026797, "Agent": "rainbow"}, {"env_step": 300000, "rew": 0.7399999916553497, "rew_std": 1.967841428665537, "Agent": "rainbow"}, {"env_step": 400000, "rew": 0.7299999989569187, "rew_std": 1.9344508264320834, "Agent": "rainbow"}, {"env_step": 500000, "rew": 2.250000037252903, "rew_std": 6.453410065907903, "Agent": "rainbow"}, {"env_step": 600000, "rew": 0.3300000071525574, "rew_std": 0.7043436813838512, "Agent": "rainbow"}, {"env_step": 700000, "rew": 11.450000222027302, "rew_std": 19.350775633693363, "Agent": "rainbow"}, {"env_step": 800000, "rew": 51.87000031471253, "rew_std": 41.72313644425024, "Agent": "rainbow"}, {"env_step": 900000, "rew": 134.95999908447266, "rew_std": 26.553200308986938, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 273.26000061035154, "rew_std": 40.46751980619983, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 394.9699981689453, "rew_std": 35.29900920102157, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 475.4699951171875, "rew_std": 51.0648386902766, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 537.4499969482422, "rew_std": 87.05237149623139, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 528.3800109863281, "rew_std": 74.70653568610189, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 602.5700042724609, "rew_std": 63.9815013284615, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 672.6400024414063, "rew_std": 75.62920855186832, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 670.960009765625, "rew_std": 59.331076612532364, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 704.7300048828125, "rew_std": 67.48957648360094, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 787.0799987792968, "rew_std": 112.42707564022125, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 823.6899963378906, "rew_std": 77.87041479137376, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 840.9600036621093, "rew_std": 68.54743565383826, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 822.8200012207031, "rew_std": 101.75918406873306, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 846.6400024414063, "rew_std": 56.10774301137517, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 935.4899963378906, "rew_std": 81.81529716155883, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 871.6499938964844, "rew_std": 105.67288003470732, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 935.3400085449218, "rew_std": 93.00937834754181, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 962.9700134277343, "rew_std": 60.47081018959421, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 939.1, "rew_std": 76.38223487303658, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 983.4500122070312, "rew_std": 67.66671891975996, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 1005.25, "rew_std": 46.68377918260524, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 1027.85, "rew_std": 100.20803948410037, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 1019.7700134277344, "rew_std": 74.38652294354544, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 1025.939990234375, "rew_std": 67.48715328162088, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 1048.9500061035155, "rew_std": 63.75370223721345, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 1024.8799865722656, "rew_std": 81.16544192265837, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 1057.9299865722655, "rew_std": 79.86718486180474, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 1059.6200012207032, "rew_std": 100.3108670590954, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 1100.7599975585938, "rew_std": 81.71528182411633, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 1076.8199890136718, "rew_std": 65.37815728364572, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 1191.0, "rew_std": 100.77746153732592, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 1085.950018310547, "rew_std": 93.44744071480993, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 1124.4300048828125, "rew_std": 98.69067996332086, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 1204.660009765625, "rew_std": 81.11235149073514, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 1136.6400024414063, "rew_std": 78.94447133335663, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 1154.5200073242188, "rew_std": 74.92851522386881, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 1206.0400085449219, "rew_std": 103.3929078135147, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 1204.1800170898437, "rew_std": 82.69720477051608, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 1142.9900146484374, "rew_std": 100.03756445774546, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 1199.2599853515626, "rew_std": 43.66213881744983, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 1174.4100036621094, "rew_std": 135.42985480511723, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 1206.4500244140625, "rew_std": 65.40353311217433, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 1213.0400024414062, "rew_std": 56.73084174140543, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 1279.0799926757813, "rew_std": 122.6794261050074, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 1260.5200073242188, "rew_std": 78.9505194850195, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 1181.0700073242188, "rew_std": 114.83173344170228, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 1176.05, "rew_std": 83.41206986065441, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 1270.2599853515626, "rew_std": 124.96829424226486, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 1261.5499755859375, "rew_std": 105.05167725943326, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 1254.1099853515625, "rew_std": 103.52183258934855, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 1285.210009765625, "rew_std": 135.08428673916382, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 1321.8599975585937, "rew_std": 98.54867262115465, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 1270.4499877929688, "rew_std": 134.84840828335157, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 1291.8700073242187, "rew_std": 128.573159656795, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 1372.1099975585937, "rew_std": 88.26145690808981, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 1354.3300170898438, "rew_std": 76.23653593249794, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 1337.8300048828125, "rew_std": 111.20302612183444, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 1287.5800048828125, "rew_std": 156.0572077287139, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 1319.3700073242187, "rew_std": 129.23841474784112, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 1279.7999877929688, "rew_std": 117.75878546918071, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 1328.610009765625, "rew_std": 100.9171629081728, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 1364.7, "rew_std": 163.70892187079815, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 1308.8900024414063, "rew_std": 88.94055366414823, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 1322.25, "rew_std": 94.6752858690983, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 1309.5300170898438, "rew_std": 130.62605278751548, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 1346.460009765625, "rew_std": 117.62017984362635, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 1307.6800170898437, "rew_std": 135.51715895844544, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 1370.15, "rew_std": 121.40495533214569, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 1366.02001953125, "rew_std": 155.8914434634503, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 1383.0500122070312, "rew_std": 119.51592283983616, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 1347.489990234375, "rew_std": 107.93389821410152, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 1382.2799926757812, "rew_std": 81.35011185204777, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 1357.7900024414062, "rew_std": 102.5295829744403, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 1308.2999877929688, "rew_std": 108.36144846385606, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 1368.2300048828124, "rew_std": 109.5325932250981, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 1311.7599975585938, "rew_std": 113.36432112272027, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 1384.7000122070312, "rew_std": 129.2364554734506, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 1377.9300170898437, "rew_std": 130.36785628181076, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 1420.160009765625, "rew_std": 126.74235879373302, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 1345.9299926757812, "rew_std": 110.19251868290497, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 1361.6299926757813, "rew_std": 146.04748540296958, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 1334.089990234375, "rew_std": 85.54697028191892, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 1292.2299926757812, "rew_std": 143.56093407787503, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 1363.2300048828124, "rew_std": 162.6994478889228, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 1438.1799926757812, "rew_std": 130.79961009153894, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 1496.1199951171875, "rew_std": 112.32410367854669, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 1472.02001953125, "rew_std": 126.8561263598282, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 1391.2999877929688, "rew_std": 85.84510612212074, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 1311.4199951171875, "rew_std": 129.5012392428379, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 1416.0599975585938, "rew_std": 92.06283588597819, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 1416.15, "rew_std": 73.5937659368437, "Agent": "rainbow"}, {"env_step": 0, "rew": 0.010000000149011612, "rew_std": 0.03000000044703483, "Agent": "ppo"}, {"env_step": 100000, "rew": 5.800000095367432, "rew_std": 9.745665904076512, "Agent": "ppo"}, {"env_step": 200000, "rew": 17.870000410079957, "rew_std": 24.34313324422257, "Agent": "ppo"}, {"env_step": 300000, "rew": 33.790000438690186, "rew_std": 34.83846926788018, "Agent": "ppo"}, {"env_step": 400000, "rew": 49.810000157356264, "rew_std": 45.02722450198439, "Agent": "ppo"}, {"env_step": 500000, "rew": 63.84000015258789, "rew_std": 55.360387449231766, "Agent": "ppo"}, {"env_step": 600000, "rew": 70.23000016212464, "rew_std": 58.73603829366222, "Agent": "ppo"}, {"env_step": 700000, "rew": 75.51999950408936, "rew_std": 67.29662320233204, "Agent": "ppo"}, {"env_step": 800000, "rew": 81.71000061035156, "rew_std": 56.81521740785272, "Agent": "ppo"}, {"env_step": 900000, "rew": 113.76000213623047, "rew_std": 79.55546964125922, "Agent": "ppo"}, {"env_step": 1000000, "rew": 116.16000061035156, "rew_std": 84.3558915187514, "Agent": "ppo"}, {"env_step": 1100000, "rew": 122.9199995458126, "rew_std": 82.33155847187241, "Agent": "ppo"}, {"env_step": 1200000, "rew": 150.4199990928173, "rew_std": 104.54179755010438, "Agent": "ppo"}, {"env_step": 1300000, "rew": 168.3199987411499, "rew_std": 108.28887045300536, "Agent": "ppo"}, {"env_step": 1400000, "rew": 176.67999801635742, "rew_std": 94.50735937346175, "Agent": "ppo"}, {"env_step": 1500000, "rew": 210.8900005340576, "rew_std": 108.90844271319088, "Agent": "ppo"}, {"env_step": 1600000, "rew": 211.0199996948242, "rew_std": 101.37994700391509, "Agent": "ppo"}, {"env_step": 1700000, "rew": 214.6699966430664, "rew_std": 100.4095196324463, "Agent": "ppo"}, {"env_step": 1800000, "rew": 247.6599998474121, "rew_std": 104.51677601247573, "Agent": "ppo"}, {"env_step": 1900000, "rew": 279.729997253418, "rew_std": 113.7720723989544, "Agent": "ppo"}, {"env_step": 2000000, "rew": 280.9099998474121, "rew_std": 106.76945620737145, "Agent": "ppo"}, {"env_step": 2100000, "rew": 288.3299987792969, "rew_std": 102.17095623218948, "Agent": "ppo"}, {"env_step": 2200000, "rew": 271.02000427246094, "rew_std": 118.16367469140917, "Agent": "ppo"}, {"env_step": 2300000, "rew": 269.90000305175784, "rew_std": 85.66159506214764, "Agent": "ppo"}, {"env_step": 2400000, "rew": 296.75999755859374, "rew_std": 95.57390780369239, "Agent": "ppo"}, {"env_step": 2500000, "rew": 300.6899978637695, "rew_std": 87.79065128890048, "Agent": "ppo"}, {"env_step": 2600000, "rew": 320.3000015258789, "rew_std": 91.139115860422, "Agent": "ppo"}, {"env_step": 2700000, "rew": 333.9300018310547, "rew_std": 89.31125875672396, "Agent": "ppo"}, {"env_step": 2800000, "rew": 327.020002746582, "rew_std": 120.26429493395794, "Agent": "ppo"}, {"env_step": 2900000, "rew": 361.1499954223633, "rew_std": 109.55767628353465, "Agent": "ppo"}, {"env_step": 3000000, "rew": 302.6900039672852, "rew_std": 98.16769631029796, "Agent": "ppo"}, {"env_step": 3100000, "rew": 315.95, "rew_std": 70.34762657993309, "Agent": "ppo"}, {"env_step": 3200000, "rew": 318.9499984741211, "rew_std": 115.132872934207, "Agent": "ppo"}, {"env_step": 3300000, "rew": 363.1899978637695, "rew_std": 85.86564602287181, "Agent": "ppo"}, {"env_step": 3400000, "rew": 368.1300018310547, "rew_std": 95.21212558703517, "Agent": "ppo"}, {"env_step": 3500000, "rew": 350.01000518798827, "rew_std": 93.16288451590842, "Agent": "ppo"}, {"env_step": 3600000, "rew": 388.5899993896484, "rew_std": 123.07756326920718, "Agent": "ppo"}, {"env_step": 3700000, "rew": 417.2999969482422, "rew_std": 100.34292919570994, "Agent": "ppo"}, {"env_step": 3800000, "rew": 461.9800048828125, "rew_std": 110.07789422926527, "Agent": "ppo"}, {"env_step": 3900000, "rew": 426.2000030517578, "rew_std": 88.50425199374192, "Agent": "ppo"}, {"env_step": 4000000, "rew": 449.4999969482422, "rew_std": 82.22106733939164, "Agent": "ppo"}, {"env_step": 4100000, "rew": 459.7000030517578, "rew_std": 107.17836845612624, "Agent": "ppo"}, {"env_step": 4200000, "rew": 465.42999572753905, "rew_std": 70.88704020848354, "Agent": "ppo"}, {"env_step": 4300000, "rew": 477.6600067138672, "rew_std": 132.27509463627436, "Agent": "ppo"}, {"env_step": 4400000, "rew": 410.0800048828125, "rew_std": 95.43147426617367, "Agent": "ppo"}, {"env_step": 4500000, "rew": 447.7100006103516, "rew_std": 70.30009378544847, "Agent": "ppo"}, {"env_step": 4600000, "rew": 462.73999786376953, "rew_std": 135.12483044104556, "Agent": "ppo"}, {"env_step": 4700000, "rew": 506.6499908447266, "rew_std": 102.90543516850502, "Agent": "ppo"}, {"env_step": 4800000, "rew": 504.0899993896484, "rew_std": 128.18980369342842, "Agent": "ppo"}, {"env_step": 4900000, "rew": 534.0000030517579, "rew_std": 116.97765592191337, "Agent": "ppo"}, {"env_step": 5000000, "rew": 513.1700057983398, "rew_std": 134.31567368090884, "Agent": "ppo"}, {"env_step": 5100000, "rew": 599.9900024414062, "rew_std": 114.45719219959994, "Agent": "ppo"}, {"env_step": 5200000, "rew": 602.4800048828125, "rew_std": 115.42681306636841, "Agent": "ppo"}, {"env_step": 5300000, "rew": 560.45, "rew_std": 147.17203595366996, "Agent": "ppo"}, {"env_step": 5400000, "rew": 542.2500030517579, "rew_std": 112.07122589244243, "Agent": "ppo"}, {"env_step": 5500000, "rew": 658.7099975585937, "rew_std": 119.60214061911367, "Agent": "ppo"}, {"env_step": 5600000, "rew": 624.2800048828125, "rew_std": 68.26668122502235, "Agent": "ppo"}, {"env_step": 5700000, "rew": 587.1499908447265, "rew_std": 79.0157166299757, "Agent": "ppo"}, {"env_step": 5800000, "rew": 649.9000061035156, "rew_std": 150.5787790102997, "Agent": "ppo"}, {"env_step": 5900000, "rew": 665.9100036621094, "rew_std": 119.23486176362321, "Agent": "ppo"}, {"env_step": 6000000, "rew": 706.7900024414063, "rew_std": 129.37492925213294, "Agent": "ppo"}, {"env_step": 6100000, "rew": 643.3500030517578, "rew_std": 116.35478540380245, "Agent": "ppo"}, {"env_step": 6200000, "rew": 721.2799926757813, "rew_std": 105.70935856689015, "Agent": "ppo"}, {"env_step": 6300000, "rew": 650.6100036621094, "rew_std": 148.55013326415474, "Agent": "ppo"}, {"env_step": 6400000, "rew": 768.1000030517578, "rew_std": 139.68046925775155, "Agent": "ppo"}, {"env_step": 6500000, "rew": 764.2999877929688, "rew_std": 118.32171828460929, "Agent": "ppo"}, {"env_step": 6600000, "rew": 782.5200073242188, "rew_std": 120.42663578622158, "Agent": "ppo"}, {"env_step": 6700000, "rew": 727.1499938964844, "rew_std": 130.45287574227336, "Agent": "ppo"}, {"env_step": 6800000, "rew": 783.6400024414063, "rew_std": 90.19995201850675, "Agent": "ppo"}, {"env_step": 6900000, "rew": 819.2, "rew_std": 132.53455239250277, "Agent": "ppo"}, {"env_step": 7000000, "rew": 794.2299987792969, "rew_std": 115.94847255070289, "Agent": "ppo"}, {"env_step": 7100000, "rew": 844.1199890136719, "rew_std": 122.43119457526758, "Agent": "ppo"}, {"env_step": 7200000, "rew": 889.6299987792969, "rew_std": 118.17887362331, "Agent": "ppo"}, {"env_step": 7300000, "rew": 861.8200012207031, "rew_std": 80.9622334545407, "Agent": "ppo"}, {"env_step": 7400000, "rew": 857.1600036621094, "rew_std": 95.34967659902838, "Agent": "ppo"}, {"env_step": 7500000, "rew": 892.6200073242187, "rew_std": 123.67628608131649, "Agent": "ppo"}, {"env_step": 7600000, "rew": 841.9999877929688, "rew_std": 86.62423578644787, "Agent": "ppo"}, {"env_step": 7700000, "rew": 890.85, "rew_std": 97.07490413687609, "Agent": "ppo"}, {"env_step": 7800000, "rew": 909.2900024414063, "rew_std": 86.85939542942558, "Agent": "ppo"}, {"env_step": 7900000, "rew": 906.0800048828125, "rew_std": 88.32103888799158, "Agent": "ppo"}, {"env_step": 8000000, "rew": 931.8700073242187, "rew_std": 80.47352350435204, "Agent": "ppo"}, {"env_step": 8100000, "rew": 938.1000061035156, "rew_std": 122.04440568291714, "Agent": "ppo"}, {"env_step": 8200000, "rew": 945.4200073242188, "rew_std": 66.3337244036705, "Agent": "ppo"}, {"env_step": 8300000, "rew": 971.860009765625, "rew_std": 91.97996093457455, "Agent": "ppo"}, {"env_step": 8400000, "rew": 1005.7700073242188, "rew_std": 129.41220377608226, "Agent": "ppo"}, {"env_step": 8500000, "rew": 972.6299926757813, "rew_std": 93.78562067872805, "Agent": "ppo"}, {"env_step": 8600000, "rew": 1000.3700012207031, "rew_std": 41.05399464776146, "Agent": "ppo"}, {"env_step": 8700000, "rew": 992.8999938964844, "rew_std": 132.0640325185449, "Agent": "ppo"}, {"env_step": 8800000, "rew": 1002.5400024414063, "rew_std": 93.22239772526292, "Agent": "ppo"}, {"env_step": 8900000, "rew": 979.8400085449218, "rew_std": 81.5561815195113, "Agent": "ppo"}, {"env_step": 9000000, "rew": 999.1100036621094, "rew_std": 134.88361081259976, "Agent": "ppo"}, {"env_step": 9100000, "rew": 1019.3699890136719, "rew_std": 110.85209895729604, "Agent": "ppo"}, {"env_step": 9200000, "rew": 1059.209979248047, "rew_std": 97.60941217671626, "Agent": "ppo"}, {"env_step": 9300000, "rew": 1088.9700012207031, "rew_std": 108.06601150231093, "Agent": "ppo"}, {"env_step": 9400000, "rew": 1053.210009765625, "rew_std": 92.88492116582314, "Agent": "ppo"}, {"env_step": 9500000, "rew": 1086.1199890136718, "rew_std": 105.10582835713497, "Agent": "ppo"}, {"env_step": 9600000, "rew": 1088.6500183105468, "rew_std": 111.11191848457115, "Agent": "ppo"}, {"env_step": 9700000, "rew": 1098.8700073242187, "rew_std": 110.51410372623518, "Agent": "ppo"}, {"env_step": 9800000, "rew": 1096.7400024414062, "rew_std": 105.4631692708768, "Agent": "ppo"}, {"env_step": 9900000, "rew": 1075.4200134277344, "rew_std": 89.31879559577925, "Agent": "ppo"}, {"env_step": 10000000, "rew": 1081.520001220703, "rew_std": 84.75678447189097, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/MsPacmanNoFrameskip-v4/result.json b/examples/atari/benchmark/MsPacmanNoFrameskip-v4/result.json new file mode 100644 index 000000000..924d28d06 --- /dev/null +++ b/examples/atari/benchmark/MsPacmanNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 232.0, "rew_std": 98.97373388935065, "Agent": "c51"}, {"env_step": 100000, "rew": 471.9, "rew_std": 188.48206811259263, "Agent": "c51"}, {"env_step": 200000, "rew": 674.3, "rew_std": 146.9837065800152, "Agent": "c51"}, {"env_step": 300000, "rew": 971.9, "rew_std": 232.55900326583787, "Agent": "c51"}, {"env_step": 400000, "rew": 1213.2, "rew_std": 339.9396417012879, "Agent": "c51"}, {"env_step": 500000, "rew": 1105.6, "rew_std": 205.68480741172888, "Agent": "c51"}, {"env_step": 600000, "rew": 1321.9, "rew_std": 232.04717192846803, "Agent": "c51"}, {"env_step": 700000, "rew": 1380.7, "rew_std": 526.1245194818429, "Agent": "c51"}, {"env_step": 800000, "rew": 1383.7, "rew_std": 241.8123445980374, "Agent": "c51"}, {"env_step": 900000, "rew": 1527.4, "rew_std": 273.0213178489914, "Agent": "c51"}, {"env_step": 1000000, "rew": 1433.2, "rew_std": 211.11788176277253, "Agent": "c51"}, {"env_step": 1100000, "rew": 1540.9, "rew_std": 213.74632160577642, "Agent": "c51"}, {"env_step": 1200000, "rew": 1537.3, "rew_std": 244.24375119949335, "Agent": "c51"}, {"env_step": 1300000, "rew": 1540.3, "rew_std": 281.00250888559697, "Agent": "c51"}, {"env_step": 1400000, "rew": 1688.0, "rew_std": 280.55480747975076, "Agent": "c51"}, {"env_step": 1500000, "rew": 1538.1, "rew_std": 241.28466590316094, "Agent": "c51"}, {"env_step": 1600000, "rew": 1563.0, "rew_std": 274.25572008619986, "Agent": "c51"}, {"env_step": 1700000, "rew": 1590.1, "rew_std": 294.4925975300568, "Agent": "c51"}, {"env_step": 1800000, "rew": 1855.9, "rew_std": 304.23755520974066, "Agent": "c51"}, {"env_step": 1900000, "rew": 1742.9, "rew_std": 189.30052826128087, "Agent": "c51"}, {"env_step": 2000000, "rew": 1842.5, "rew_std": 387.4669663339057, "Agent": "c51"}, {"env_step": 2100000, "rew": 1696.0, "rew_std": 306.7631007797385, "Agent": "c51"}, {"env_step": 2200000, "rew": 1946.0, "rew_std": 377.3793847045702, "Agent": "c51"}, {"env_step": 2300000, "rew": 1633.2, "rew_std": 193.38914137045026, "Agent": "c51"}, {"env_step": 2400000, "rew": 1732.7, "rew_std": 415.1855127530343, "Agent": "c51"}, {"env_step": 2500000, "rew": 2071.9, "rew_std": 396.92983007075696, "Agent": "c51"}, {"env_step": 2600000, "rew": 1844.4, "rew_std": 247.90207744188027, "Agent": "c51"}, {"env_step": 2700000, "rew": 1785.0, "rew_std": 315.5059428917306, "Agent": "c51"}, {"env_step": 2800000, "rew": 2009.1, "rew_std": 355.064627920045, "Agent": "c51"}, {"env_step": 2900000, "rew": 1977.9, "rew_std": 321.0471772185515, "Agent": "c51"}, {"env_step": 3000000, "rew": 1903.5, "rew_std": 249.7784017884653, "Agent": "c51"}, {"env_step": 3100000, "rew": 1831.5, "rew_std": 293.79082695005985, "Agent": "c51"}, {"env_step": 3200000, "rew": 2088.6, "rew_std": 283.78238141223636, "Agent": "c51"}, {"env_step": 3300000, "rew": 2027.6, "rew_std": 295.14003455986784, "Agent": "c51"}, {"env_step": 3400000, "rew": 2003.4, "rew_std": 174.97668416106185, "Agent": "c51"}, {"env_step": 3500000, "rew": 2107.5, "rew_std": 332.1888769962053, "Agent": "c51"}, {"env_step": 3600000, "rew": 1979.6, "rew_std": 317.34372532003846, "Agent": "c51"}, {"env_step": 3700000, "rew": 1993.1, "rew_std": 282.6320753205481, "Agent": "c51"}, {"env_step": 3800000, "rew": 1860.6, "rew_std": 249.90246097227612, "Agent": "c51"}, {"env_step": 3900000, "rew": 2034.8, "rew_std": 301.3057583253264, "Agent": "c51"}, {"env_step": 4000000, "rew": 2045.1, "rew_std": 451.0275933909144, "Agent": "c51"}, {"env_step": 4100000, "rew": 2082.3, "rew_std": 434.06291018699125, "Agent": "c51"}, {"env_step": 4200000, "rew": 2143.4, "rew_std": 325.0452891521426, "Agent": "c51"}, {"env_step": 4300000, "rew": 2178.5, "rew_std": 244.46441458829955, "Agent": "c51"}, {"env_step": 4400000, "rew": 2125.9, "rew_std": 343.1540324693854, "Agent": "c51"}, {"env_step": 4500000, "rew": 1984.6, "rew_std": 215.0196270111173, "Agent": "c51"}, {"env_step": 4600000, "rew": 2114.5, "rew_std": 265.95535339601645, "Agent": "c51"}, {"env_step": 4700000, "rew": 1941.8, "rew_std": 327.6485312037886, "Agent": "c51"}, {"env_step": 4800000, "rew": 2072.2, "rew_std": 302.6386624342633, "Agent": "c51"}, {"env_step": 4900000, "rew": 1997.1, "rew_std": 483.2809638295306, "Agent": "c51"}, {"env_step": 5000000, "rew": 2116.6, "rew_std": 315.6698275096941, "Agent": "c51"}, {"env_step": 5100000, "rew": 2136.5, "rew_std": 296.60318609212544, "Agent": "c51"}, {"env_step": 5200000, "rew": 1947.6, "rew_std": 303.33222710420995, "Agent": "c51"}, {"env_step": 5300000, "rew": 2043.2, "rew_std": 348.6327007037636, "Agent": "c51"}, {"env_step": 5400000, "rew": 2003.5, "rew_std": 181.4779600943321, "Agent": "c51"}, {"env_step": 5500000, "rew": 2042.7, "rew_std": 349.1080205323275, "Agent": "c51"}, {"env_step": 5600000, "rew": 2124.6, "rew_std": 246.09843559031415, "Agent": "c51"}, {"env_step": 5700000, "rew": 1958.8, "rew_std": 204.2428946132521, "Agent": "c51"}, {"env_step": 5800000, "rew": 2104.0, "rew_std": 256.8260111437313, "Agent": "c51"}, {"env_step": 5900000, "rew": 2023.0, "rew_std": 217.54447821077878, "Agent": "c51"}, {"env_step": 6000000, "rew": 1912.1, "rew_std": 324.066490091154, "Agent": "c51"}, {"env_step": 6100000, "rew": 2112.9, "rew_std": 196.80114328936202, "Agent": "c51"}, {"env_step": 6200000, "rew": 2013.2, "rew_std": 245.47211654279596, "Agent": "c51"}, {"env_step": 6300000, "rew": 2207.9, "rew_std": 279.84583255785674, "Agent": "c51"}, {"env_step": 6400000, "rew": 2062.1, "rew_std": 293.391700632448, "Agent": "c51"}, {"env_step": 6500000, "rew": 2121.7, "rew_std": 276.0326248833641, "Agent": "c51"}, {"env_step": 6600000, "rew": 2086.0, "rew_std": 265.9657872734762, "Agent": "c51"}, {"env_step": 6700000, "rew": 1945.4, "rew_std": 268.4459722178748, "Agent": "c51"}, {"env_step": 6800000, "rew": 2025.5, "rew_std": 188.10648579993196, "Agent": "c51"}, {"env_step": 6900000, "rew": 2222.5, "rew_std": 192.25828980826807, "Agent": "c51"}, {"env_step": 7000000, "rew": 1962.0, "rew_std": 251.00756960697422, "Agent": "c51"}, {"env_step": 7100000, "rew": 2028.0, "rew_std": 182.15323219751002, "Agent": "c51"}, {"env_step": 7200000, "rew": 2155.4, "rew_std": 353.8415464582982, "Agent": "c51"}, {"env_step": 7300000, "rew": 2094.3, "rew_std": 366.438821633298, "Agent": "c51"}, {"env_step": 7400000, "rew": 2234.5, "rew_std": 312.953111503944, "Agent": "c51"}, {"env_step": 7500000, "rew": 2193.4, "rew_std": 310.7629965102023, "Agent": "c51"}, {"env_step": 7600000, "rew": 2107.7, "rew_std": 326.7916920608601, "Agent": "c51"}, {"env_step": 7700000, "rew": 2056.6, "rew_std": 275.43790588806036, "Agent": "c51"}, {"env_step": 7800000, "rew": 2155.4, "rew_std": 317.36546756066576, "Agent": "c51"}, {"env_step": 7900000, "rew": 2004.5, "rew_std": 340.1814956754703, "Agent": "c51"}, {"env_step": 8000000, "rew": 2161.7, "rew_std": 239.97793648583612, "Agent": "c51"}, {"env_step": 8100000, "rew": 1823.4, "rew_std": 288.0486764420208, "Agent": "c51"}, {"env_step": 8200000, "rew": 2090.5, "rew_std": 331.0233375458594, "Agent": "c51"}, {"env_step": 8300000, "rew": 1968.3, "rew_std": 320.45063582399086, "Agent": "c51"}, {"env_step": 8400000, "rew": 2106.9, "rew_std": 403.024428540008, "Agent": "c51"}, {"env_step": 8500000, "rew": 2226.4, "rew_std": 361.9058441086577, "Agent": "c51"}, {"env_step": 8600000, "rew": 1958.6, "rew_std": 128.12353413795609, "Agent": "c51"}, {"env_step": 8700000, "rew": 1775.2, "rew_std": 258.49982591870344, "Agent": "c51"}, {"env_step": 8800000, "rew": 2074.7, "rew_std": 342.712138682014, "Agent": "c51"}, {"env_step": 8900000, "rew": 1892.9, "rew_std": 167.9615729862042, "Agent": "c51"}, {"env_step": 9000000, "rew": 2107.6, "rew_std": 225.7517220310844, "Agent": "c51"}, {"env_step": 9100000, "rew": 1941.5, "rew_std": 392.5196173441526, "Agent": "c51"}, {"env_step": 9200000, "rew": 2188.9, "rew_std": 298.97974847805324, "Agent": "c51"}, {"env_step": 9300000, "rew": 2027.5, "rew_std": 442.07267502074814, "Agent": "c51"}, {"env_step": 9400000, "rew": 2137.9, "rew_std": 365.06340545171054, "Agent": "c51"}, {"env_step": 9500000, "rew": 2254.9, "rew_std": 201.1842190630269, "Agent": "c51"}, {"env_step": 9600000, "rew": 1965.5, "rew_std": 197.30040547348096, "Agent": "c51"}, {"env_step": 9700000, "rew": 2237.9, "rew_std": 387.8250765486935, "Agent": "c51"}, {"env_step": 9800000, "rew": 2177.9, "rew_std": 237.57838706414353, "Agent": "c51"}, {"env_step": 9900000, "rew": 2144.3, "rew_std": 298.6901571863392, "Agent": "c51"}, {"env_step": 10000000, "rew": 2196.7, "rew_std": 370.68991084193266, "Agent": "c51"}, {"env_step": 0, "rew": 131.5, "rew_std": 68.65020029104068, "Agent": "dqn"}, {"env_step": 100000, "rew": 614.7, "rew_std": 204.22930739734684, "Agent": "dqn"}, {"env_step": 200000, "rew": 701.0, "rew_std": 207.84417239845817, "Agent": "dqn"}, {"env_step": 300000, "rew": 810.8, "rew_std": 271.50977882941896, "Agent": "dqn"}, {"env_step": 400000, "rew": 834.8, "rew_std": 215.7822050123689, "Agent": "dqn"}, {"env_step": 500000, "rew": 909.7, "rew_std": 287.6004346311041, "Agent": "dqn"}, {"env_step": 600000, "rew": 1064.1, "rew_std": 212.43608450543425, "Agent": "dqn"}, {"env_step": 700000, "rew": 1294.5, "rew_std": 225.1289630411867, "Agent": "dqn"}, {"env_step": 800000, "rew": 1285.4, "rew_std": 259.38820327840665, "Agent": "dqn"}, {"env_step": 900000, "rew": 1304.9, "rew_std": 298.1504485993607, "Agent": "dqn"}, {"env_step": 1000000, "rew": 1251.2, "rew_std": 232.5570037646684, "Agent": "dqn"}, {"env_step": 1100000, "rew": 1391.9, "rew_std": 193.24205028926804, "Agent": "dqn"}, {"env_step": 1200000, "rew": 1458.9, "rew_std": 220.16468835851038, "Agent": "dqn"}, {"env_step": 1300000, "rew": 1373.2, "rew_std": 253.95267275616533, "Agent": "dqn"}, {"env_step": 1400000, "rew": 1561.5, "rew_std": 382.30334814123717, "Agent": "dqn"}, {"env_step": 1500000, "rew": 1512.3, "rew_std": 150.26180486071635, "Agent": "dqn"}, {"env_step": 1600000, "rew": 1592.5, "rew_std": 247.11060276726292, "Agent": "dqn"}, {"env_step": 1700000, "rew": 1433.2, "rew_std": 348.8689725384016, "Agent": "dqn"}, {"env_step": 1800000, "rew": 1603.8, "rew_std": 354.88640436060666, "Agent": "dqn"}, {"env_step": 1900000, "rew": 1709.6, "rew_std": 354.1762837909958, "Agent": "dqn"}, {"env_step": 2000000, "rew": 1364.8, "rew_std": 449.32745297833736, "Agent": "dqn"}, {"env_step": 2100000, "rew": 1460.0, "rew_std": 327.8566760034024, "Agent": "dqn"}, {"env_step": 2200000, "rew": 1597.0, "rew_std": 265.5627985995026, "Agent": "dqn"}, {"env_step": 2300000, "rew": 1751.1, "rew_std": 489.0773865146496, "Agent": "dqn"}, {"env_step": 2400000, "rew": 1606.6, "rew_std": 194.81129330713864, "Agent": "dqn"}, {"env_step": 2500000, "rew": 1659.0, "rew_std": 233.647169895122, "Agent": "dqn"}, {"env_step": 2600000, "rew": 1689.7, "rew_std": 161.25510844621326, "Agent": "dqn"}, {"env_step": 2700000, "rew": 1622.3, "rew_std": 451.706552974384, "Agent": "dqn"}, {"env_step": 2800000, "rew": 1908.7, "rew_std": 397.6817949064302, "Agent": "dqn"}, {"env_step": 2900000, "rew": 1810.7, "rew_std": 342.4213924391991, "Agent": "dqn"}, {"env_step": 3000000, "rew": 1618.5, "rew_std": 344.36412414768176, "Agent": "dqn"}, {"env_step": 3100000, "rew": 1750.4, "rew_std": 284.15425388334415, "Agent": "dqn"}, {"env_step": 3200000, "rew": 1895.3, "rew_std": 299.36167089325244, "Agent": "dqn"}, {"env_step": 3300000, "rew": 1750.6, "rew_std": 258.5123594724244, "Agent": "dqn"}, {"env_step": 3400000, "rew": 1768.8, "rew_std": 519.2761885547998, "Agent": "dqn"}, {"env_step": 3500000, "rew": 1923.8, "rew_std": 338.9373983496067, "Agent": "dqn"}, {"env_step": 3600000, "rew": 1848.1, "rew_std": 409.1123195407344, "Agent": "dqn"}, {"env_step": 3700000, "rew": 1954.5, "rew_std": 319.1367261848752, "Agent": "dqn"}, {"env_step": 3800000, "rew": 1761.1, "rew_std": 322.0672134819066, "Agent": "dqn"}, {"env_step": 3900000, "rew": 1843.7, "rew_std": 310.8404896405872, "Agent": "dqn"}, {"env_step": 4000000, "rew": 2049.1, "rew_std": 425.3754694384715, "Agent": "dqn"}, {"env_step": 4100000, "rew": 1596.5, "rew_std": 433.0591760949074, "Agent": "dqn"}, {"env_step": 4200000, "rew": 1982.2, "rew_std": 302.4684446351388, "Agent": "dqn"}, {"env_step": 4300000, "rew": 1967.3, "rew_std": 453.393217858406, "Agent": "dqn"}, {"env_step": 4400000, "rew": 1863.3, "rew_std": 420.0681016216299, "Agent": "dqn"}, {"env_step": 4500000, "rew": 2167.2, "rew_std": 428.3346355362825, "Agent": "dqn"}, {"env_step": 4600000, "rew": 1978.7, "rew_std": 467.56562106296906, "Agent": "dqn"}, {"env_step": 4700000, "rew": 2055.6, "rew_std": 222.23060095315407, "Agent": "dqn"}, {"env_step": 4800000, "rew": 1964.6, "rew_std": 371.6714140205028, "Agent": "dqn"}, {"env_step": 4900000, "rew": 1900.1, "rew_std": 293.1492623221147, "Agent": "dqn"}, {"env_step": 5000000, "rew": 1980.9, "rew_std": 444.9308822727413, "Agent": "dqn"}, {"env_step": 5100000, "rew": 1902.8, "rew_std": 498.980921478968, "Agent": "dqn"}, {"env_step": 5200000, "rew": 2109.0, "rew_std": 436.7092854520041, "Agent": "dqn"}, {"env_step": 5300000, "rew": 1968.1, "rew_std": 310.17428971466995, "Agent": "dqn"}, {"env_step": 5400000, "rew": 1976.0, "rew_std": 482.8349614516331, "Agent": "dqn"}, {"env_step": 5500000, "rew": 1849.4, "rew_std": 398.51930944434804, "Agent": "dqn"}, {"env_step": 5600000, "rew": 1880.3, "rew_std": 403.730863323576, "Agent": "dqn"}, {"env_step": 5700000, "rew": 2198.5, "rew_std": 510.2962374934779, "Agent": "dqn"}, {"env_step": 5800000, "rew": 2004.4, "rew_std": 301.12960664803455, "Agent": "dqn"}, {"env_step": 5900000, "rew": 2048.1, "rew_std": 450.4685227626898, "Agent": "dqn"}, {"env_step": 6000000, "rew": 2285.8, "rew_std": 433.295003432996, "Agent": "dqn"}, {"env_step": 6100000, "rew": 2123.8, "rew_std": 344.2341644869085, "Agent": "dqn"}, {"env_step": 6200000, "rew": 2220.9, "rew_std": 532.900825670218, "Agent": "dqn"}, {"env_step": 6300000, "rew": 2083.9, "rew_std": 434.93619072227136, "Agent": "dqn"}, {"env_step": 6400000, "rew": 2324.8, "rew_std": 359.76959293414444, "Agent": "dqn"}, {"env_step": 6500000, "rew": 1959.3, "rew_std": 218.1110038489576, "Agent": "dqn"}, {"env_step": 6600000, "rew": 2100.8, "rew_std": 346.50073592995443, "Agent": "dqn"}, {"env_step": 6700000, "rew": 1936.2, "rew_std": 392.79404272468287, "Agent": "dqn"}, {"env_step": 6800000, "rew": 2225.4, "rew_std": 382.2230239009681, "Agent": "dqn"}, {"env_step": 6900000, "rew": 2039.2, "rew_std": 316.61895079101, "Agent": "dqn"}, {"env_step": 7000000, "rew": 2102.3, "rew_std": 456.89212074624356, "Agent": "dqn"}, {"env_step": 7100000, "rew": 2108.4, "rew_std": 328.34195589354704, "Agent": "dqn"}, {"env_step": 7200000, "rew": 1930.3, "rew_std": 574.398824859522, "Agent": "dqn"}, {"env_step": 7300000, "rew": 1915.3, "rew_std": 206.36184240309544, "Agent": "dqn"}, {"env_step": 7400000, "rew": 2049.0, "rew_std": 228.25950144517535, "Agent": "dqn"}, {"env_step": 7500000, "rew": 1851.8, "rew_std": 267.78043244419484, "Agent": "dqn"}, {"env_step": 7600000, "rew": 1897.6, "rew_std": 284.4177209668905, "Agent": "dqn"}, {"env_step": 7700000, "rew": 2028.1, "rew_std": 348.8350469777943, "Agent": "dqn"}, {"env_step": 7800000, "rew": 1792.0, "rew_std": 491.49120032814426, "Agent": "dqn"}, {"env_step": 7900000, "rew": 1943.1, "rew_std": 397.7744209976303, "Agent": "dqn"}, {"env_step": 8000000, "rew": 1958.2, "rew_std": 320.44587686534527, "Agent": "dqn"}, {"env_step": 8100000, "rew": 1928.8, "rew_std": 440.1206198305187, "Agent": "dqn"}, {"env_step": 8200000, "rew": 1939.0, "rew_std": 313.2452713130719, "Agent": "dqn"}, {"env_step": 8300000, "rew": 1952.0, "rew_std": 200.15993605114886, "Agent": "dqn"}, {"env_step": 8400000, "rew": 2045.5, "rew_std": 214.5685205243304, "Agent": "dqn"}, {"env_step": 8500000, "rew": 1957.4, "rew_std": 295.4894921989613, "Agent": "dqn"}, {"env_step": 8600000, "rew": 1757.6, "rew_std": 440.1148032048002, "Agent": "dqn"}, {"env_step": 8700000, "rew": 1913.0, "rew_std": 399.30990471061443, "Agent": "dqn"}, {"env_step": 8800000, "rew": 1883.1, "rew_std": 390.40759470071794, "Agent": "dqn"}, {"env_step": 8900000, "rew": 2099.2, "rew_std": 247.28234874329385, "Agent": "dqn"}, {"env_step": 9000000, "rew": 1986.4, "rew_std": 552.3334500100459, "Agent": "dqn"}, {"env_step": 9100000, "rew": 1933.1, "rew_std": 483.2095715111612, "Agent": "dqn"}, {"env_step": 9200000, "rew": 1978.8, "rew_std": 328.87955242003113, "Agent": "dqn"}, {"env_step": 9300000, "rew": 2072.5, "rew_std": 331.83045369585955, "Agent": "dqn"}, {"env_step": 9400000, "rew": 2054.7, "rew_std": 349.56088167871417, "Agent": "dqn"}, {"env_step": 9500000, "rew": 1718.4, "rew_std": 509.64207047691815, "Agent": "dqn"}, {"env_step": 9600000, "rew": 1724.2, "rew_std": 495.79507863632534, "Agent": "dqn"}, {"env_step": 9700000, "rew": 1770.2, "rew_std": 291.362591970898, "Agent": "dqn"}, {"env_step": 9800000, "rew": 1836.1, "rew_std": 500.204048364265, "Agent": "dqn"}, {"env_step": 9900000, "rew": 2061.6, "rew_std": 311.6386368857366, "Agent": "dqn"}, {"env_step": 10000000, "rew": 1889.7, "rew_std": 482.98779487684783, "Agent": "dqn"}, {"env_step": 0, "rew": 209.6, "rew_std": 147.36770338171112, "Agent": "fqf"}, {"env_step": 100000, "rew": 564.9, "rew_std": 161.8928349248354, "Agent": "fqf"}, {"env_step": 200000, "rew": 767.5, "rew_std": 204.61732575713134, "Agent": "fqf"}, {"env_step": 300000, "rew": 1075.9, "rew_std": 288.21535351191824, "Agent": "fqf"}, {"env_step": 400000, "rew": 1022.0, "rew_std": 265.35787156216037, "Agent": "fqf"}, {"env_step": 500000, "rew": 1071.1, "rew_std": 377.931329741264, "Agent": "fqf"}, {"env_step": 600000, "rew": 1151.7, "rew_std": 300.1049982922644, "Agent": "fqf"}, {"env_step": 700000, "rew": 1196.7, "rew_std": 103.24538730616491, "Agent": "fqf"}, {"env_step": 800000, "rew": 1514.1, "rew_std": 486.713149606624, "Agent": "fqf"}, {"env_step": 900000, "rew": 1626.9, "rew_std": 316.3809254680187, "Agent": "fqf"}, {"env_step": 1000000, "rew": 1582.2, "rew_std": 369.04926500400995, "Agent": "fqf"}, {"env_step": 1100000, "rew": 1562.1, "rew_std": 180.65572230073423, "Agent": "fqf"}, {"env_step": 1200000, "rew": 1479.4, "rew_std": 133.2525421896333, "Agent": "fqf"}, {"env_step": 1300000, "rew": 1791.1, "rew_std": 167.81623878516643, "Agent": "fqf"}, {"env_step": 1400000, "rew": 1891.5, "rew_std": 251.22788459882395, "Agent": "fqf"}, {"env_step": 1500000, "rew": 1736.2, "rew_std": 316.84216891064233, "Agent": "fqf"}, {"env_step": 1600000, "rew": 2012.1, "rew_std": 421.7516923498944, "Agent": "fqf"}, {"env_step": 1700000, "rew": 1790.0, "rew_std": 352.4060158396845, "Agent": "fqf"}, {"env_step": 1800000, "rew": 1927.9, "rew_std": 216.36147993577785, "Agent": "fqf"}, {"env_step": 1900000, "rew": 2056.4, "rew_std": 326.7314493586438, "Agent": "fqf"}, {"env_step": 2000000, "rew": 2039.8, "rew_std": 309.31789472967773, "Agent": "fqf"}, {"env_step": 2100000, "rew": 2133.9, "rew_std": 337.53442787366146, "Agent": "fqf"}, {"env_step": 2200000, "rew": 2087.1, "rew_std": 346.3381151418365, "Agent": "fqf"}, {"env_step": 2300000, "rew": 2096.6, "rew_std": 242.30361119884284, "Agent": "fqf"}, {"env_step": 2400000, "rew": 2233.8, "rew_std": 185.708804314712, "Agent": "fqf"}, {"env_step": 2500000, "rew": 1932.5, "rew_std": 284.03248053699775, "Agent": "fqf"}, {"env_step": 2600000, "rew": 1983.8, "rew_std": 354.9137359979182, "Agent": "fqf"}, {"env_step": 2700000, "rew": 2270.3, "rew_std": 424.8583410973592, "Agent": "fqf"}, {"env_step": 2800000, "rew": 2289.4, "rew_std": 383.8, "Agent": "fqf"}, {"env_step": 2900000, "rew": 2172.8, "rew_std": 362.5851072506978, "Agent": "fqf"}, {"env_step": 3000000, "rew": 2144.2, "rew_std": 308.21057736554076, "Agent": "fqf"}, {"env_step": 3100000, "rew": 2074.5, "rew_std": 176.32711079127907, "Agent": "fqf"}, {"env_step": 3200000, "rew": 2291.0, "rew_std": 323.1361941968123, "Agent": "fqf"}, {"env_step": 3300000, "rew": 2121.9, "rew_std": 152.47062012073016, "Agent": "fqf"}, {"env_step": 3400000, "rew": 2160.7, "rew_std": 297.12726229681454, "Agent": "fqf"}, {"env_step": 3500000, "rew": 1965.6, "rew_std": 434.0376020577019, "Agent": "fqf"}, {"env_step": 3600000, "rew": 2088.7, "rew_std": 263.4023728063208, "Agent": "fqf"}, {"env_step": 3700000, "rew": 2288.5, "rew_std": 494.5837138442793, "Agent": "fqf"}, {"env_step": 3800000, "rew": 2077.7, "rew_std": 488.92699864090133, "Agent": "fqf"}, {"env_step": 3900000, "rew": 2320.0, "rew_std": 402.8208038321755, "Agent": "fqf"}, {"env_step": 4000000, "rew": 2162.4, "rew_std": 318.08275652729117, "Agent": "fqf"}, {"env_step": 4100000, "rew": 2152.5, "rew_std": 415.441271421124, "Agent": "fqf"}, {"env_step": 4200000, "rew": 2323.0, "rew_std": 441.1031625368379, "Agent": "fqf"}, {"env_step": 4300000, "rew": 2254.9, "rew_std": 369.04347982317745, "Agent": "fqf"}, {"env_step": 4400000, "rew": 2266.5, "rew_std": 468.3191753494619, "Agent": "fqf"}, {"env_step": 4500000, "rew": 2189.8, "rew_std": 463.9204242108769, "Agent": "fqf"}, {"env_step": 4600000, "rew": 2164.3, "rew_std": 272.80764285481445, "Agent": "fqf"}, {"env_step": 4700000, "rew": 2167.5, "rew_std": 151.73611962878186, "Agent": "fqf"}, {"env_step": 4800000, "rew": 2223.9, "rew_std": 334.81470995163875, "Agent": "fqf"}, {"env_step": 4900000, "rew": 2216.2, "rew_std": 302.2647184174825, "Agent": "fqf"}, {"env_step": 5000000, "rew": 2307.7, "rew_std": 463.2478926017905, "Agent": "fqf"}, {"env_step": 5100000, "rew": 2229.6, "rew_std": 334.5005829591333, "Agent": "fqf"}, {"env_step": 5200000, "rew": 2097.1, "rew_std": 257.26540770185176, "Agent": "fqf"}, {"env_step": 5300000, "rew": 2246.4, "rew_std": 323.79691165914477, "Agent": "fqf"}, {"env_step": 5400000, "rew": 2412.3, "rew_std": 271.80399187649914, "Agent": "fqf"}, {"env_step": 5500000, "rew": 2289.4, "rew_std": 326.94929270454156, "Agent": "fqf"}, {"env_step": 5600000, "rew": 2213.5, "rew_std": 387.96320701839755, "Agent": "fqf"}, {"env_step": 5700000, "rew": 2212.0, "rew_std": 371.89353315162657, "Agent": "fqf"}, {"env_step": 5800000, "rew": 2119.3, "rew_std": 379.4562030063549, "Agent": "fqf"}, {"env_step": 5900000, "rew": 2086.9, "rew_std": 480.4985848054081, "Agent": "fqf"}, {"env_step": 6000000, "rew": 2082.4, "rew_std": 193.79483997258544, "Agent": "fqf"}, {"env_step": 6100000, "rew": 2167.7, "rew_std": 307.71611917480044, "Agent": "fqf"}, {"env_step": 6200000, "rew": 2257.0, "rew_std": 330.79963724284823, "Agent": "fqf"}, {"env_step": 6300000, "rew": 2369.5, "rew_std": 511.182990718588, "Agent": "fqf"}, {"env_step": 6400000, "rew": 2233.4, "rew_std": 333.7532621563421, "Agent": "fqf"}, {"env_step": 6500000, "rew": 2179.4, "rew_std": 211.5184152739425, "Agent": "fqf"}, {"env_step": 6600000, "rew": 2365.5, "rew_std": 349.8263140474141, "Agent": "fqf"}, {"env_step": 6700000, "rew": 2255.2, "rew_std": 228.93309066187874, "Agent": "fqf"}, {"env_step": 6800000, "rew": 2354.2, "rew_std": 476.53138406614937, "Agent": "fqf"}, {"env_step": 6900000, "rew": 2295.9, "rew_std": 328.7827398146077, "Agent": "fqf"}, {"env_step": 7000000, "rew": 2294.0, "rew_std": 350.9675198647305, "Agent": "fqf"}, {"env_step": 7100000, "rew": 2279.9, "rew_std": 249.64392642321585, "Agent": "fqf"}, {"env_step": 7200000, "rew": 2247.8, "rew_std": 342.9891543474808, "Agent": "fqf"}, {"env_step": 7300000, "rew": 2430.6, "rew_std": 378.38821334708615, "Agent": "fqf"}, {"env_step": 7400000, "rew": 2458.8, "rew_std": 619.2716366829665, "Agent": "fqf"}, {"env_step": 7500000, "rew": 2126.3, "rew_std": 379.9394820231243, "Agent": "fqf"}, {"env_step": 7600000, "rew": 2294.9, "rew_std": 231.97821018362907, "Agent": "fqf"}, {"env_step": 7700000, "rew": 2384.8, "rew_std": 322.39317610644304, "Agent": "fqf"}, {"env_step": 7800000, "rew": 2327.4, "rew_std": 316.6234988120749, "Agent": "fqf"}, {"env_step": 7900000, "rew": 2369.9, "rew_std": 376.6129179940593, "Agent": "fqf"}, {"env_step": 8000000, "rew": 2459.9, "rew_std": 387.55888584833144, "Agent": "fqf"}, {"env_step": 8100000, "rew": 2432.6, "rew_std": 335.16748052279775, "Agent": "fqf"}, {"env_step": 8200000, "rew": 2405.6, "rew_std": 405.6466935647325, "Agent": "fqf"}, {"env_step": 8300000, "rew": 2475.6, "rew_std": 527.2349002105228, "Agent": "fqf"}, {"env_step": 8400000, "rew": 2371.0, "rew_std": 221.4050586594624, "Agent": "fqf"}, {"env_step": 8500000, "rew": 2384.4, "rew_std": 362.2496928915192, "Agent": "fqf"}, {"env_step": 8600000, "rew": 2201.5, "rew_std": 263.163162315701, "Agent": "fqf"}, {"env_step": 8700000, "rew": 2120.5, "rew_std": 442.54948875803706, "Agent": "fqf"}, {"env_step": 8800000, "rew": 2236.1, "rew_std": 213.28546598397182, "Agent": "fqf"}, {"env_step": 8900000, "rew": 2335.3, "rew_std": 308.52230065264325, "Agent": "fqf"}, {"env_step": 9000000, "rew": 2441.1, "rew_std": 316.18394962426544, "Agent": "fqf"}, {"env_step": 9100000, "rew": 2425.4, "rew_std": 412.7859493732799, "Agent": "fqf"}, {"env_step": 9200000, "rew": 2400.9, "rew_std": 393.80869721223786, "Agent": "fqf"}, {"env_step": 9300000, "rew": 2478.2, "rew_std": 338.00852060266175, "Agent": "fqf"}, {"env_step": 9400000, "rew": 2325.9, "rew_std": 250.8499352202428, "Agent": "fqf"}, {"env_step": 9500000, "rew": 2419.5, "rew_std": 283.8465254323188, "Agent": "fqf"}, {"env_step": 9600000, "rew": 2506.6, "rew_std": 402.5186206872919, "Agent": "fqf"}, {"env_step": 9700000, "rew": 2327.1, "rew_std": 375.1155688584519, "Agent": "fqf"}, {"env_step": 9800000, "rew": 2354.1, "rew_std": 263.84557983790444, "Agent": "fqf"}, {"env_step": 9900000, "rew": 2433.2, "rew_std": 550.9763697292291, "Agent": "fqf"}, {"env_step": 10000000, "rew": 2478.0, "rew_std": 184.68892765945662, "Agent": "fqf"}, {"env_step": 0, "rew": 147.9, "rew_std": 65.50030534279973, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 658.8, "rew_std": 173.94355406280508, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 901.9, "rew_std": 225.8364231030947, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 947.9, "rew_std": 176.00366473457305, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 984.4, "rew_std": 298.15405413980204, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 1047.1, "rew_std": 262.9248752020242, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 1181.9, "rew_std": 363.3566980255077, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 1294.7, "rew_std": 404.93630363305283, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 1202.4, "rew_std": 548.8827197134193, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 1376.5, "rew_std": 180.5803145417573, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 1537.5, "rew_std": 396.10762426391136, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 1516.6, "rew_std": 246.3169502896624, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 1514.0, "rew_std": 284.75779181613274, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 1366.4, "rew_std": 237.443551186382, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 1548.5, "rew_std": 338.3723540716647, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 1512.0, "rew_std": 236.26468208346333, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 1628.0, "rew_std": 213.3972820820359, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 1573.0, "rew_std": 335.270338682085, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 1587.9, "rew_std": 292.99059711874713, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 1870.7, "rew_std": 401.1979685890745, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 1629.4, "rew_std": 364.31859683524254, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 1756.7, "rew_std": 314.8085291093619, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 1695.5, "rew_std": 151.9527887207076, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 1751.0, "rew_std": 158.11894257172352, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 1726.3, "rew_std": 512.4833753401177, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 1908.5, "rew_std": 349.27532120091166, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 1737.8, "rew_std": 288.164813952016, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 1928.7, "rew_std": 390.23686396853896, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 1859.6, "rew_std": 433.55949995358196, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 1784.5, "rew_std": 345.3847854205509, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 1677.1, "rew_std": 354.96688577950476, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 1964.8, "rew_std": 299.83221974964596, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 1798.1, "rew_std": 198.37159574898823, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 1783.1, "rew_std": 387.8730333498322, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 1856.4, "rew_std": 299.4779457656273, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 2008.8, "rew_std": 300.43894554468136, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 2021.3, "rew_std": 332.70619170673694, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 1957.0, "rew_std": 290.85013323015687, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 1850.0, "rew_std": 178.16116299575506, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 1878.4, "rew_std": 399.1170755555317, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 2028.5, "rew_std": 457.8126800340943, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 1910.1, "rew_std": 372.1944249985483, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 1774.8, "rew_std": 338.8928444213598, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 1837.0, "rew_std": 452.25545878408144, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 2068.4, "rew_std": 295.75131445185497, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 1876.6, "rew_std": 202.19851631503136, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 1891.1, "rew_std": 480.94541270293865, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 1814.4, "rew_std": 474.1063593751934, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 2115.4, "rew_std": 403.2094244930294, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 2100.4, "rew_std": 376.1237030552581, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 1879.5, "rew_std": 195.04525115982702, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 1979.9, "rew_std": 212.22226556136846, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 1924.1, "rew_std": 592.8174170855643, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 2100.4, "rew_std": 348.4285292567186, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 1820.9, "rew_std": 254.82796157407844, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 1936.0, "rew_std": 332.0704744478196, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 1994.6, "rew_std": 341.4827082005764, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 1998.0, "rew_std": 395.96893817571095, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 2020.0, "rew_std": 326.8748996175754, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 1926.1, "rew_std": 247.97235733040887, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 2020.8, "rew_std": 313.74059348449, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 1995.5, "rew_std": 454.48965884825145, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 2165.4, "rew_std": 601.1125019495103, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 2024.4, "rew_std": 388.68424202686685, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 1701.7, "rew_std": 395.4142258442405, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 1837.4, "rew_std": 457.4256660923171, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 2029.2, "rew_std": 292.2097876526384, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 2231.2, "rew_std": 258.9786863817175, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 1961.0, "rew_std": 310.98295773241335, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 2151.2, "rew_std": 517.7655453967558, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 2058.0, "rew_std": 143.03985458605584, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 1998.7, "rew_std": 416.9923380591063, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 2028.3, "rew_std": 338.8569167067422, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 1894.4, "rew_std": 426.75219976000125, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 2052.4, "rew_std": 381.0210492873064, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 2102.5, "rew_std": 231.69905049438592, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 2112.5, "rew_std": 287.3075877870266, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 2069.4, "rew_std": 393.8327563827062, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 2143.4, "rew_std": 293.58174330158886, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 2049.1, "rew_std": 565.8735636164672, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 1993.5, "rew_std": 267.2022642119636, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 1891.7, "rew_std": 279.16018698947744, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 2026.0, "rew_std": 382.7017115195593, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 1835.2, "rew_std": 455.81439205009747, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 1992.0, "rew_std": 213.05257567088927, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 2126.1, "rew_std": 186.0109942987242, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 2112.9, "rew_std": 253.74532508008892, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 2143.2, "rew_std": 242.88507570453973, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 1859.2, "rew_std": 253.84436176523596, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 1909.5, "rew_std": 577.5562743144602, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 2166.2, "rew_std": 251.24044260429093, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 2221.9, "rew_std": 475.83493986885827, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 2060.8, "rew_std": 244.7904409898393, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 2114.2, "rew_std": 240.22980664355538, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 2168.0, "rew_std": 323.3663557020118, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 2012.4, "rew_std": 346.8542056830218, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 1901.9, "rew_std": 406.43263894525006, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 2197.4, "rew_std": 377.0950012927777, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 2095.6, "rew_std": 300.4899998336051, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 2027.9, "rew_std": 359.36790340819255, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 2259.3, "rew_std": 269.21108818174633, "Agent": "qrdqn"}, {"env_step": 0, "rew": 203.5, "rew_std": 125.49442218680478, "Agent": "iqn"}, {"env_step": 100000, "rew": 497.4, "rew_std": 171.87914358641655, "Agent": "iqn"}, {"env_step": 200000, "rew": 719.6, "rew_std": 175.82332041000703, "Agent": "iqn"}, {"env_step": 300000, "rew": 808.8, "rew_std": 230.12640005005943, "Agent": "iqn"}, {"env_step": 400000, "rew": 841.3, "rew_std": 215.85182417575254, "Agent": "iqn"}, {"env_step": 500000, "rew": 917.6, "rew_std": 177.8264322309819, "Agent": "iqn"}, {"env_step": 600000, "rew": 896.3, "rew_std": 348.6686249148323, "Agent": "iqn"}, {"env_step": 700000, "rew": 1141.9, "rew_std": 364.5055417960062, "Agent": "iqn"}, {"env_step": 800000, "rew": 1323.0, "rew_std": 291.3722704719857, "Agent": "iqn"}, {"env_step": 900000, "rew": 1274.1, "rew_std": 234.52439105559998, "Agent": "iqn"}, {"env_step": 1000000, "rew": 1553.1, "rew_std": 408.0204529187232, "Agent": "iqn"}, {"env_step": 1100000, "rew": 1436.4, "rew_std": 345.38245467886753, "Agent": "iqn"}, {"env_step": 1200000, "rew": 1649.8, "rew_std": 456.99295399382254, "Agent": "iqn"}, {"env_step": 1300000, "rew": 1489.3, "rew_std": 167.85592036028996, "Agent": "iqn"}, {"env_step": 1400000, "rew": 1645.2, "rew_std": 115.38006760268429, "Agent": "iqn"}, {"env_step": 1500000, "rew": 1641.9, "rew_std": 186.58534240395198, "Agent": "iqn"}, {"env_step": 1600000, "rew": 1599.5, "rew_std": 387.8569968429086, "Agent": "iqn"}, {"env_step": 1700000, "rew": 1690.2, "rew_std": 161.43902873840636, "Agent": "iqn"}, {"env_step": 1800000, "rew": 1613.6, "rew_std": 344.5162405460735, "Agent": "iqn"}, {"env_step": 1900000, "rew": 1773.5, "rew_std": 319.91131583612355, "Agent": "iqn"}, {"env_step": 2000000, "rew": 1738.7, "rew_std": 435.27900248001856, "Agent": "iqn"}, {"env_step": 2100000, "rew": 1719.0, "rew_std": 253.0829903411132, "Agent": "iqn"}, {"env_step": 2200000, "rew": 1831.4, "rew_std": 298.3257280222408, "Agent": "iqn"}, {"env_step": 2300000, "rew": 1982.3, "rew_std": 322.387980545181, "Agent": "iqn"}, {"env_step": 2400000, "rew": 1801.0, "rew_std": 123.33045041675636, "Agent": "iqn"}, {"env_step": 2500000, "rew": 1800.4, "rew_std": 263.40888367706964, "Agent": "iqn"}, {"env_step": 2600000, "rew": 1744.0, "rew_std": 312.34083946868043, "Agent": "iqn"}, {"env_step": 2700000, "rew": 2024.6, "rew_std": 493.24663202093933, "Agent": "iqn"}, {"env_step": 2800000, "rew": 1913.7, "rew_std": 184.7598711841941, "Agent": "iqn"}, {"env_step": 2900000, "rew": 1956.7, "rew_std": 347.0703242860156, "Agent": "iqn"}, {"env_step": 3000000, "rew": 1950.4, "rew_std": 288.921165718263, "Agent": "iqn"}, {"env_step": 3100000, "rew": 1983.4, "rew_std": 243.26002548713177, "Agent": "iqn"}, {"env_step": 3200000, "rew": 2040.2, "rew_std": 305.4157166879269, "Agent": "iqn"}, {"env_step": 3300000, "rew": 2148.3, "rew_std": 352.78890288669794, "Agent": "iqn"}, {"env_step": 3400000, "rew": 1893.3, "rew_std": 572.8401260386705, "Agent": "iqn"}, {"env_step": 3500000, "rew": 2011.7, "rew_std": 243.61323855652836, "Agent": "iqn"}, {"env_step": 3600000, "rew": 1999.7, "rew_std": 199.95301948207737, "Agent": "iqn"}, {"env_step": 3700000, "rew": 2145.6, "rew_std": 185.3392565000734, "Agent": "iqn"}, {"env_step": 3800000, "rew": 2101.3, "rew_std": 386.0235873622233, "Agent": "iqn"}, {"env_step": 3900000, "rew": 1885.6, "rew_std": 300.85850494875496, "Agent": "iqn"}, {"env_step": 4000000, "rew": 2040.6, "rew_std": 263.6210158541993, "Agent": "iqn"}, {"env_step": 4100000, "rew": 2034.7, "rew_std": 204.19894710796137, "Agent": "iqn"}, {"env_step": 4200000, "rew": 2011.4, "rew_std": 203.3834801551001, "Agent": "iqn"}, {"env_step": 4300000, "rew": 1990.5, "rew_std": 242.6170851362286, "Agent": "iqn"}, {"env_step": 4400000, "rew": 1978.7, "rew_std": 212.20275681526854, "Agent": "iqn"}, {"env_step": 4500000, "rew": 1977.7, "rew_std": 178.95030036297788, "Agent": "iqn"}, {"env_step": 4600000, "rew": 1849.0, "rew_std": 308.38774294708924, "Agent": "iqn"}, {"env_step": 4700000, "rew": 1953.0, "rew_std": 273.4209209259599, "Agent": "iqn"}, {"env_step": 4800000, "rew": 2019.8, "rew_std": 216.3579441573616, "Agent": "iqn"}, {"env_step": 4900000, "rew": 1956.9, "rew_std": 152.99048990051637, "Agent": "iqn"}, {"env_step": 5000000, "rew": 2045.9, "rew_std": 282.905090092066, "Agent": "iqn"}, {"env_step": 5100000, "rew": 1971.6, "rew_std": 380.651336527274, "Agent": "iqn"}, {"env_step": 5200000, "rew": 2039.4, "rew_std": 223.29630538815462, "Agent": "iqn"}, {"env_step": 5300000, "rew": 1975.8, "rew_std": 201.08694636897744, "Agent": "iqn"}, {"env_step": 5400000, "rew": 2064.5, "rew_std": 254.50432216369134, "Agent": "iqn"}, {"env_step": 5500000, "rew": 2134.7, "rew_std": 428.5522255221643, "Agent": "iqn"}, {"env_step": 5600000, "rew": 1948.5, "rew_std": 272.5880591662078, "Agent": "iqn"}, {"env_step": 5700000, "rew": 2002.2, "rew_std": 340.7244634598461, "Agent": "iqn"}, {"env_step": 5800000, "rew": 2045.1, "rew_std": 164.70364294696094, "Agent": "iqn"}, {"env_step": 5900000, "rew": 1886.4, "rew_std": 163.4730558838367, "Agent": "iqn"}, {"env_step": 6000000, "rew": 1919.7, "rew_std": 219.83268637761765, "Agent": "iqn"}, {"env_step": 6100000, "rew": 2004.6, "rew_std": 165.23207920981932, "Agent": "iqn"}, {"env_step": 6200000, "rew": 1947.4, "rew_std": 389.1902362598528, "Agent": "iqn"}, {"env_step": 6300000, "rew": 2121.2, "rew_std": 371.044148316612, "Agent": "iqn"}, {"env_step": 6400000, "rew": 2047.5, "rew_std": 190.7633350515764, "Agent": "iqn"}, {"env_step": 6500000, "rew": 2032.7, "rew_std": 139.8721201669582, "Agent": "iqn"}, {"env_step": 6600000, "rew": 2159.6, "rew_std": 173.13416762730577, "Agent": "iqn"}, {"env_step": 6700000, "rew": 1899.0, "rew_std": 313.5557366721266, "Agent": "iqn"}, {"env_step": 6800000, "rew": 2104.5, "rew_std": 332.75554090052356, "Agent": "iqn"}, {"env_step": 6900000, "rew": 2212.5, "rew_std": 400.02956140765394, "Agent": "iqn"}, {"env_step": 7000000, "rew": 1910.5, "rew_std": 262.7969748684334, "Agent": "iqn"}, {"env_step": 7100000, "rew": 2110.5, "rew_std": 244.04640952081226, "Agent": "iqn"}, {"env_step": 7200000, "rew": 2069.4, "rew_std": 252.60095011697797, "Agent": "iqn"}, {"env_step": 7300000, "rew": 1997.3, "rew_std": 178.55478150976523, "Agent": "iqn"}, {"env_step": 7400000, "rew": 2102.1, "rew_std": 270.0775629333173, "Agent": "iqn"}, {"env_step": 7500000, "rew": 1930.6, "rew_std": 381.8453089930528, "Agent": "iqn"}, {"env_step": 7600000, "rew": 2114.2, "rew_std": 166.0757658419795, "Agent": "iqn"}, {"env_step": 7700000, "rew": 2000.9, "rew_std": 236.48909065747623, "Agent": "iqn"}, {"env_step": 7800000, "rew": 2138.6, "rew_std": 264.63189528097325, "Agent": "iqn"}, {"env_step": 7900000, "rew": 2128.6, "rew_std": 213.55570701809867, "Agent": "iqn"}, {"env_step": 8000000, "rew": 2109.3, "rew_std": 174.64652873733274, "Agent": "iqn"}, {"env_step": 8100000, "rew": 2009.0, "rew_std": 247.61986996200446, "Agent": "iqn"}, {"env_step": 8200000, "rew": 1983.7, "rew_std": 389.60288756630126, "Agent": "iqn"}, {"env_step": 8300000, "rew": 1994.3, "rew_std": 114.65692303563705, "Agent": "iqn"}, {"env_step": 8400000, "rew": 2095.6, "rew_std": 306.54630971518804, "Agent": "iqn"}, {"env_step": 8500000, "rew": 2008.5, "rew_std": 301.76555469436863, "Agent": "iqn"}, {"env_step": 8600000, "rew": 2129.8, "rew_std": 119.71365836862559, "Agent": "iqn"}, {"env_step": 8700000, "rew": 1975.8, "rew_std": 117.61700557317381, "Agent": "iqn"}, {"env_step": 8800000, "rew": 2123.2, "rew_std": 291.63051966486637, "Agent": "iqn"}, {"env_step": 8900000, "rew": 2044.2, "rew_std": 255.55109078225433, "Agent": "iqn"}, {"env_step": 9000000, "rew": 2228.6, "rew_std": 253.11902338623227, "Agent": "iqn"}, {"env_step": 9100000, "rew": 2149.0, "rew_std": 178.49201662819544, "Agent": "iqn"}, {"env_step": 9200000, "rew": 2148.9, "rew_std": 300.1541104166325, "Agent": "iqn"}, {"env_step": 9300000, "rew": 2022.7, "rew_std": 154.7081445819838, "Agent": "iqn"}, {"env_step": 9400000, "rew": 2217.1, "rew_std": 328.33350423007397, "Agent": "iqn"}, {"env_step": 9500000, "rew": 1985.3, "rew_std": 223.17842637674457, "Agent": "iqn"}, {"env_step": 9600000, "rew": 2110.1, "rew_std": 211.15892119444067, "Agent": "iqn"}, {"env_step": 9700000, "rew": 2162.6, "rew_std": 227.4173256372522, "Agent": "iqn"}, {"env_step": 9800000, "rew": 2212.4, "rew_std": 328.63329107076174, "Agent": "iqn"}, {"env_step": 9900000, "rew": 2094.4, "rew_std": 378.75142243957316, "Agent": "iqn"}, {"env_step": 10000000, "rew": 2151.1, "rew_std": 407.2558041329798, "Agent": "iqn"}, {"env_step": 0, "rew": 218.6, "rew_std": 99.78997945685728, "Agent": "rainbow"}, {"env_step": 100000, "rew": 395.4, "rew_std": 217.94045058226342, "Agent": "rainbow"}, {"env_step": 200000, "rew": 716.4, "rew_std": 209.39923591073583, "Agent": "rainbow"}, {"env_step": 300000, "rew": 943.7, "rew_std": 255.72096120576424, "Agent": "rainbow"}, {"env_step": 400000, "rew": 1031.6, "rew_std": 220.23632761195415, "Agent": "rainbow"}, {"env_step": 500000, "rew": 1255.4, "rew_std": 227.50701088098361, "Agent": "rainbow"}, {"env_step": 600000, "rew": 1306.0, "rew_std": 232.00991358129505, "Agent": "rainbow"}, {"env_step": 700000, "rew": 1406.3, "rew_std": 257.8658759898254, "Agent": "rainbow"}, {"env_step": 800000, "rew": 1297.9, "rew_std": 324.35488280585514, "Agent": "rainbow"}, {"env_step": 900000, "rew": 1442.4, "rew_std": 252.78734145522398, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 1444.5, "rew_std": 303.269269791715, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 1614.9, "rew_std": 246.82117008068815, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 1609.4, "rew_std": 298.84952735448655, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 1685.1, "rew_std": 399.2817175879707, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 1548.6, "rew_std": 186.0033333034653, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 1715.5, "rew_std": 250.8785562777337, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 1737.4, "rew_std": 276.36541028138817, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 2035.6, "rew_std": 429.08791639942507, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 1743.6, "rew_std": 354.16470744556125, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 1857.3, "rew_std": 287.29046277243526, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 1836.8, "rew_std": 371.6750731485769, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 1950.2, "rew_std": 312.3401351091467, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 2048.7, "rew_std": 436.6781537929279, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 1939.5, "rew_std": 278.96782968650706, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 1835.0, "rew_std": 308.29239367846884, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 1861.0, "rew_std": 219.7257381373425, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 1996.7, "rew_std": 346.1849361251873, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 2101.1, "rew_std": 340.95056826466794, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 2038.1, "rew_std": 255.98728484047797, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 1941.0, "rew_std": 302.7953103996163, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 2099.1, "rew_std": 384.3590638972886, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 2072.2, "rew_std": 272.6069698301934, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 1995.5, "rew_std": 265.344021979015, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 2059.7, "rew_std": 355.7518938811148, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 1939.6, "rew_std": 301.1342557730688, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 1921.4, "rew_std": 263.6744963017849, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 2222.2, "rew_std": 170.95309298167143, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 2048.7, "rew_std": 211.11515814834328, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 2072.6, "rew_std": 327.48288504897477, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 2167.4, "rew_std": 428.5650942389032, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 2107.1, "rew_std": 285.2712568766787, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 1802.2, "rew_std": 228.4192636359727, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 1961.4, "rew_std": 254.83100282343983, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 2048.1, "rew_std": 245.7040699703609, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 2136.8, "rew_std": 292.6403253141986, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 2099.8, "rew_std": 350.09107386507304, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 2179.6, "rew_std": 253.28489887871328, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 2250.3, "rew_std": 184.54974939023896, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 1950.7, "rew_std": 262.8326653975871, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 2161.1, "rew_std": 393.27940449507395, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 2120.8, "rew_std": 218.70198901701832, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 2207.4, "rew_std": 232.03973797606307, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 2217.3, "rew_std": 359.2347561136032, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 2141.2, "rew_std": 243.542521954586, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 2160.4, "rew_std": 287.35072646506393, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 2235.1, "rew_std": 212.19493396403223, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 2280.4, "rew_std": 318.04597151984177, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 2358.9, "rew_std": 310.13430961439917, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 2267.6, "rew_std": 273.4484229246898, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 2193.4, "rew_std": 181.35997353330202, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 2366.9, "rew_std": 578.7907134707674, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 2292.2, "rew_std": 293.46372859350095, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 2048.0, "rew_std": 355.46139030842716, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 2311.8, "rew_std": 276.04304012236935, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 2211.3, "rew_std": 304.2528718023874, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 2256.9, "rew_std": 187.56622830349818, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 2262.1, "rew_std": 290.55342021735004, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 2175.7, "rew_std": 346.9455432773276, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 2179.1, "rew_std": 243.099341833745, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 2338.0, "rew_std": 367.66288907095316, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 2354.4, "rew_std": 258.2797707912875, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 2320.4, "rew_std": 294.2781677257081, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 2389.3, "rew_std": 247.6655204100886, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 2187.6, "rew_std": 325.17201601613874, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 2160.5, "rew_std": 205.99866504421817, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 2400.5, "rew_std": 389.60268222896, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 2228.4, "rew_std": 339.70051516004503, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 2230.1, "rew_std": 383.68019234774164, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 2358.0, "rew_std": 292.9624549323684, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 2243.1, "rew_std": 245.06833740816052, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 2271.8, "rew_std": 182.58466529257052, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 2178.2, "rew_std": 284.79389038390553, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 2151.4, "rew_std": 386.34937556569184, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 2225.5, "rew_std": 272.64161457855255, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 2378.0, "rew_std": 335.8109587252923, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 2290.5, "rew_std": 365.62802135503784, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 2313.5, "rew_std": 400.5274647262033, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 2258.8, "rew_std": 245.23898548150945, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 2345.8, "rew_std": 273.3780532522682, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 2222.2, "rew_std": 320.44181999233496, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 2361.9, "rew_std": 291.36212863033523, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 2401.0, "rew_std": 308.2463300673667, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 2296.9, "rew_std": 327.37759544599265, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 2196.2, "rew_std": 414.1250535768151, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 2343.8, "rew_std": 295.55195820701306, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 2109.8, "rew_std": 314.5847421602008, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 2524.2, "rew_std": 338.81463958925974, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 2397.1, "rew_std": 202.06011481734836, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 2485.8, "rew_std": 377.7405988241137, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 2244.9, "rew_std": 120.4271148869722, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 2214.0, "rew_std": 176.29690865128634, "Agent": "rainbow"}, {"env_step": 0, "rew": 370.7, "rew_std": 113.11502994739469, "Agent": "ppo"}, {"env_step": 100000, "rew": 505.9, "rew_std": 129.42986517801833, "Agent": "ppo"}, {"env_step": 200000, "rew": 421.8, "rew_std": 102.49858535609162, "Agent": "ppo"}, {"env_step": 300000, "rew": 479.5, "rew_std": 92.63719555340609, "Agent": "ppo"}, {"env_step": 400000, "rew": 508.4, "rew_std": 132.38595091625092, "Agent": "ppo"}, {"env_step": 500000, "rew": 560.6, "rew_std": 100.25088528287418, "Agent": "ppo"}, {"env_step": 600000, "rew": 664.6, "rew_std": 175.08866325379265, "Agent": "ppo"}, {"env_step": 700000, "rew": 588.6, "rew_std": 162.83746497658333, "Agent": "ppo"}, {"env_step": 800000, "rew": 610.4, "rew_std": 181.44982777616517, "Agent": "ppo"}, {"env_step": 900000, "rew": 633.7, "rew_std": 107.41233634922946, "Agent": "ppo"}, {"env_step": 1000000, "rew": 697.1, "rew_std": 94.16204118433288, "Agent": "ppo"}, {"env_step": 1100000, "rew": 631.9, "rew_std": 98.8275771229873, "Agent": "ppo"}, {"env_step": 1200000, "rew": 712.6, "rew_std": 130.972668904623, "Agent": "ppo"}, {"env_step": 1300000, "rew": 727.2, "rew_std": 129.8936488054747, "Agent": "ppo"}, {"env_step": 1400000, "rew": 664.1, "rew_std": 156.49054284524672, "Agent": "ppo"}, {"env_step": 1500000, "rew": 628.1, "rew_std": 184.3379776389011, "Agent": "ppo"}, {"env_step": 1600000, "rew": 641.9, "rew_std": 127.15065866915515, "Agent": "ppo"}, {"env_step": 1700000, "rew": 647.3, "rew_std": 92.44355034289846, "Agent": "ppo"}, {"env_step": 1800000, "rew": 647.3, "rew_std": 125.52294610946637, "Agent": "ppo"}, {"env_step": 1900000, "rew": 613.0, "rew_std": 117.30387887874808, "Agent": "ppo"}, {"env_step": 2000000, "rew": 757.2, "rew_std": 211.36262678155757, "Agent": "ppo"}, {"env_step": 2100000, "rew": 698.0, "rew_std": 88.34591105421914, "Agent": "ppo"}, {"env_step": 2200000, "rew": 756.7, "rew_std": 118.22609694986974, "Agent": "ppo"}, {"env_step": 2300000, "rew": 694.6, "rew_std": 142.86441124366837, "Agent": "ppo"}, {"env_step": 2400000, "rew": 795.3, "rew_std": 180.00836091693074, "Agent": "ppo"}, {"env_step": 2500000, "rew": 637.0, "rew_std": 111.93748255164576, "Agent": "ppo"}, {"env_step": 2600000, "rew": 731.4, "rew_std": 201.773239058107, "Agent": "ppo"}, {"env_step": 2700000, "rew": 709.3, "rew_std": 171.81679196167062, "Agent": "ppo"}, {"env_step": 2800000, "rew": 643.3, "rew_std": 124.15880959480886, "Agent": "ppo"}, {"env_step": 2900000, "rew": 841.8, "rew_std": 230.30275725661647, "Agent": "ppo"}, {"env_step": 3000000, "rew": 771.9, "rew_std": 201.02659028098745, "Agent": "ppo"}, {"env_step": 3100000, "rew": 803.4, "rew_std": 195.58128744846732, "Agent": "ppo"}, {"env_step": 3200000, "rew": 756.8, "rew_std": 186.79657384438292, "Agent": "ppo"}, {"env_step": 3300000, "rew": 761.7, "rew_std": 183.00986312218257, "Agent": "ppo"}, {"env_step": 3400000, "rew": 884.0, "rew_std": 177.51788642274894, "Agent": "ppo"}, {"env_step": 3500000, "rew": 882.3, "rew_std": 235.03235947417963, "Agent": "ppo"}, {"env_step": 3600000, "rew": 886.8, "rew_std": 165.33166665826604, "Agent": "ppo"}, {"env_step": 3700000, "rew": 887.6, "rew_std": 155.86545479996522, "Agent": "ppo"}, {"env_step": 3800000, "rew": 870.0, "rew_std": 140.03142504452347, "Agent": "ppo"}, {"env_step": 3900000, "rew": 963.2, "rew_std": 163.08267841803433, "Agent": "ppo"}, {"env_step": 4000000, "rew": 915.2, "rew_std": 198.6211469103932, "Agent": "ppo"}, {"env_step": 4100000, "rew": 954.3, "rew_std": 224.29135070260733, "Agent": "ppo"}, {"env_step": 4200000, "rew": 1005.9, "rew_std": 185.8673989703412, "Agent": "ppo"}, {"env_step": 4300000, "rew": 1021.8, "rew_std": 173.70768549491413, "Agent": "ppo"}, {"env_step": 4400000, "rew": 969.5, "rew_std": 176.3333490863257, "Agent": "ppo"}, {"env_step": 4500000, "rew": 1041.1, "rew_std": 177.89291722831462, "Agent": "ppo"}, {"env_step": 4600000, "rew": 977.5, "rew_std": 200.08660624839436, "Agent": "ppo"}, {"env_step": 4700000, "rew": 1033.2, "rew_std": 133.5520872169357, "Agent": "ppo"}, {"env_step": 4800000, "rew": 1085.6, "rew_std": 141.09018392503427, "Agent": "ppo"}, {"env_step": 4900000, "rew": 1077.5, "rew_std": 248.93543339589084, "Agent": "ppo"}, {"env_step": 5000000, "rew": 1067.3, "rew_std": 158.23656341061002, "Agent": "ppo"}, {"env_step": 5100000, "rew": 1198.8, "rew_std": 166.84831434569546, "Agent": "ppo"}, {"env_step": 5200000, "rew": 1088.0, "rew_std": 144.770853420155, "Agent": "ppo"}, {"env_step": 5300000, "rew": 1108.4, "rew_std": 154.99238690980923, "Agent": "ppo"}, {"env_step": 5400000, "rew": 1203.5, "rew_std": 257.2929264476581, "Agent": "ppo"}, {"env_step": 5500000, "rew": 1092.1, "rew_std": 100.34286222746488, "Agent": "ppo"}, {"env_step": 5600000, "rew": 1198.8, "rew_std": 151.49838282965268, "Agent": "ppo"}, {"env_step": 5700000, "rew": 1137.5, "rew_std": 123.52024125624108, "Agent": "ppo"}, {"env_step": 5800000, "rew": 1118.2, "rew_std": 153.89463928285483, "Agent": "ppo"}, {"env_step": 5900000, "rew": 1187.0, "rew_std": 157.57855184002676, "Agent": "ppo"}, {"env_step": 6000000, "rew": 1200.2, "rew_std": 167.1201962660408, "Agent": "ppo"}, {"env_step": 6100000, "rew": 1207.1, "rew_std": 205.2556698364262, "Agent": "ppo"}, {"env_step": 6200000, "rew": 1304.3, "rew_std": 198.32904477156137, "Agent": "ppo"}, {"env_step": 6300000, "rew": 1280.2, "rew_std": 114.50310039470546, "Agent": "ppo"}, {"env_step": 6400000, "rew": 1224.8, "rew_std": 189.02105702804647, "Agent": "ppo"}, {"env_step": 6500000, "rew": 1325.9, "rew_std": 179.55859767774976, "Agent": "ppo"}, {"env_step": 6600000, "rew": 1417.9, "rew_std": 262.43606840524035, "Agent": "ppo"}, {"env_step": 6700000, "rew": 1329.9, "rew_std": 153.3286992053347, "Agent": "ppo"}, {"env_step": 6800000, "rew": 1324.8, "rew_std": 237.16230729186287, "Agent": "ppo"}, {"env_step": 6900000, "rew": 1362.0, "rew_std": 162.35947770302786, "Agent": "ppo"}, {"env_step": 7000000, "rew": 1291.7, "rew_std": 179.75597347515324, "Agent": "ppo"}, {"env_step": 7100000, "rew": 1315.4, "rew_std": 236.61200307676702, "Agent": "ppo"}, {"env_step": 7200000, "rew": 1400.3, "rew_std": 257.7530019223831, "Agent": "ppo"}, {"env_step": 7300000, "rew": 1361.2, "rew_std": 186.70286553773084, "Agent": "ppo"}, {"env_step": 7400000, "rew": 1465.6, "rew_std": 229.4812410634037, "Agent": "ppo"}, {"env_step": 7500000, "rew": 1450.6, "rew_std": 163.0295678703713, "Agent": "ppo"}, {"env_step": 7600000, "rew": 1490.6, "rew_std": 267.5194198558303, "Agent": "ppo"}, {"env_step": 7700000, "rew": 1461.2, "rew_std": 199.32877363792716, "Agent": "ppo"}, {"env_step": 7800000, "rew": 1510.4, "rew_std": 212.96769708103622, "Agent": "ppo"}, {"env_step": 7900000, "rew": 1515.6, "rew_std": 344.78027785823247, "Agent": "ppo"}, {"env_step": 8000000, "rew": 1401.0, "rew_std": 341.4229049141255, "Agent": "ppo"}, {"env_step": 8100000, "rew": 1480.9, "rew_std": 253.02982037696665, "Agent": "ppo"}, {"env_step": 8200000, "rew": 1490.2, "rew_std": 273.54590108426044, "Agent": "ppo"}, {"env_step": 8300000, "rew": 1565.9, "rew_std": 238.09512804759362, "Agent": "ppo"}, {"env_step": 8400000, "rew": 1507.5, "rew_std": 310.9798224965729, "Agent": "ppo"}, {"env_step": 8500000, "rew": 1463.0, "rew_std": 203.8013738913455, "Agent": "ppo"}, {"env_step": 8600000, "rew": 1554.6, "rew_std": 261.8802016189846, "Agent": "ppo"}, {"env_step": 8700000, "rew": 1525.2, "rew_std": 198.0645349374794, "Agent": "ppo"}, {"env_step": 8800000, "rew": 1599.1, "rew_std": 190.6459808126046, "Agent": "ppo"}, {"env_step": 8900000, "rew": 1544.1, "rew_std": 207.58297136325993, "Agent": "ppo"}, {"env_step": 9000000, "rew": 1524.5, "rew_std": 192.14382633850093, "Agent": "ppo"}, {"env_step": 9100000, "rew": 1563.0, "rew_std": 273.20761336390314, "Agent": "ppo"}, {"env_step": 9200000, "rew": 1699.4, "rew_std": 248.01701554530484, "Agent": "ppo"}, {"env_step": 9300000, "rew": 1534.9, "rew_std": 245.79888120168488, "Agent": "ppo"}, {"env_step": 9400000, "rew": 1526.9, "rew_std": 157.2097007184989, "Agent": "ppo"}, {"env_step": 9500000, "rew": 1573.5, "rew_std": 227.85620465548, "Agent": "ppo"}, {"env_step": 9600000, "rew": 1482.6, "rew_std": 161.7721854955295, "Agent": "ppo"}, {"env_step": 9700000, "rew": 1633.9, "rew_std": 182.42667019928857, "Agent": "ppo"}, {"env_step": 9800000, "rew": 1514.0, "rew_std": 231.70110055845657, "Agent": "ppo"}, {"env_step": 9900000, "rew": 1624.4, "rew_std": 227.23696882329688, "Agent": "ppo"}, {"env_step": 10000000, "rew": 1531.6, "rew_std": 227.96455864892684, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/PongNoFrameskip-v4/result.json b/examples/atari/benchmark/PongNoFrameskip-v4/result.json new file mode 100644 index 000000000..ee5aa5478 --- /dev/null +++ b/examples/atari/benchmark/PongNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": -20.979999923706053, "rew_std": 0.04000015258789063, "Agent": "c51"}, {"env_step": 100000, "rew": -20.869999885559082, "rew_std": 0.15524167570244413, "Agent": "c51"}, {"env_step": 200000, "rew": -20.560000038146974, "rew_std": 0.40298883737879937, "Agent": "c51"}, {"env_step": 300000, "rew": -18.95999994277954, "rew_std": 2.2632720366854833, "Agent": "c51"}, {"env_step": 400000, "rew": -16.210000228881835, "rew_std": 2.7750494802377017, "Agent": "c51"}, {"env_step": 500000, "rew": -15.040000057220459, "rew_std": 3.022648038181074, "Agent": "c51"}, {"env_step": 600000, "rew": -12.759999966621399, "rew_std": 5.666603835995492, "Agent": "c51"}, {"env_step": 700000, "rew": -8.17000013589859, "rew_std": 6.876634371998414, "Agent": "c51"}, {"env_step": 800000, "rew": -5.910000105202198, "rew_std": 5.658347880641881, "Agent": "c51"}, {"env_step": 900000, "rew": -2.0299999713897705, "rew_std": 7.5090678214603175, "Agent": "c51"}, {"env_step": 1000000, "rew": -1.05, "rew_std": 8.06576073888153, "Agent": "c51"}, {"env_step": 1100000, "rew": 5.750000011920929, "rew_std": 8.470448577145289, "Agent": "c51"}, {"env_step": 1200000, "rew": 11.85, "rew_std": 6.486486065226738, "Agent": "c51"}, {"env_step": 1300000, "rew": 11.839999842643739, "rew_std": 9.283232047765221, "Agent": "c51"}, {"env_step": 1400000, "rew": 10.289999675750732, "rew_std": 13.408239764024396, "Agent": "c51"}, {"env_step": 1500000, "rew": 15.300000054495674, "rew_std": 7.003264581462973, "Agent": "c51"}, {"env_step": 1600000, "rew": 15.419999885559083, "rew_std": 5.896914245313163, "Agent": "c51"}, {"env_step": 1700000, "rew": 16.47999973297119, "rew_std": 6.142116861407374, "Agent": "c51"}, {"env_step": 1800000, "rew": 18.700000381469728, "rew_std": 1.2743627474105064, "Agent": "c51"}, {"env_step": 1900000, "rew": 13.000000283122063, "rew_std": 8.335466556491935, "Agent": "c51"}, {"env_step": 2000000, "rew": 17.47499966621399, "rew_std": 3.660174086617874, "Agent": "c51"}, {"env_step": 2100000, "rew": 13.566666801770529, "rew_std": 8.47833851940157, "Agent": "c51"}, {"env_step": 2200000, "rew": 19.75, "rew_std": 0.5499992370605469, "Agent": "c51"}, {"env_step": 2300000, "rew": 14.0, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2400000, "rew": 19.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2500000, "rew": 15.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2600000, "rew": 18.200000762939453, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2700000, "rew": 19.0, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 2900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 3900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 4900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 5900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 6900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 7900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 8900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9100000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9200000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9300000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9400000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9500000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9600000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9700000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9800000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 9900000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 10000000, "rew": 20.600000381469727, "rew_std": 0.0, "Agent": "c51"}, {"env_step": 0, "rew": -20.979999923706053, "rew_std": 0.04000015258789063, "Agent": "dqn"}, {"env_step": 100000, "rew": -20.689999961853026, "rew_std": 0.5281095979692643, "Agent": "dqn"}, {"env_step": 200000, "rew": -18.38000020980835, "rew_std": 2.5906757312772744, "Agent": "dqn"}, {"env_step": 300000, "rew": -18.030000019073487, "rew_std": 1.7245580854624265, "Agent": "dqn"}, {"env_step": 400000, "rew": -13.899999952316284, "rew_std": 3.808936970212056, "Agent": "dqn"}, {"env_step": 500000, "rew": -5.709999942779541, "rew_std": 9.006936246078585, "Agent": "dqn"}, {"env_step": 600000, "rew": -1.0700000286102296, "rew_std": 8.908540906843577, "Agent": "dqn"}, {"env_step": 700000, "rew": 6.160000026226044, "rew_std": 7.3988107178341656, "Agent": "dqn"}, {"env_step": 800000, "rew": 15.04000015258789, "rew_std": 5.2547504042740645, "Agent": "dqn"}, {"env_step": 900000, "rew": 19.755555470784504, "rew_std": 0.4374447957623508, "Agent": "dqn"}, {"env_step": 1000000, "rew": 19.983332951863606, "rew_std": 0.5814256919850659, "Agent": "dqn"}, {"env_step": 1100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 1900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 2900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 3900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 4900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 5900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 6900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 7900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 8900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9100000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9200000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9300000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9400000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9500000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9600000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9700000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9800000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 9900000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 10000000, "rew": 20.25, "rew_std": 0.25, "Agent": "dqn"}, {"env_step": 0, "rew": -20.979999923706053, "rew_std": 0.04000015258789063, "Agent": "fqf"}, {"env_step": 100000, "rew": -20.879999923706055, "rew_std": 0.15999994277996732, "Agent": "fqf"}, {"env_step": 200000, "rew": -19.329999923706055, "rew_std": 1.1883183401767072, "Agent": "fqf"}, {"env_step": 300000, "rew": -18.410000228881835, "rew_std": 2.3947650818103883, "Agent": "fqf"}, {"env_step": 400000, "rew": -15.789999866485596, "rew_std": 1.8124292335112842, "Agent": "fqf"}, {"env_step": 500000, "rew": -12.899999952316284, "rew_std": 3.9191835397861126, "Agent": "fqf"}, {"env_step": 600000, "rew": -7.259999930858612, "rew_std": 6.181294202818166, "Agent": "fqf"}, {"env_step": 700000, "rew": -0.2800000667572021, "rew_std": 5.578135949422739, "Agent": "fqf"}, {"env_step": 800000, "rew": 5.889999827742576, "rew_std": 6.357428520171511, "Agent": "fqf"}, {"env_step": 900000, "rew": 12.8555555873447, "rew_std": 5.842585252592779, "Agent": "fqf"}, {"env_step": 1000000, "rew": 18.875, "rew_std": 2.6085196695608577, "Agent": "fqf"}, {"env_step": 1100000, "rew": 18.749999682108562, "rew_std": 2.6196374340932294, "Agent": "fqf"}, {"env_step": 1200000, "rew": 19.65999984741211, "rew_std": 1.051855243717263, "Agent": "fqf"}, {"env_step": 1300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 1900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 2900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 3900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 4900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 5900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 6900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 7900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 8900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9100000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9200000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9300000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9400000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9500000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9600000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9700000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9800000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 9900000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 10000000, "rew": 20.399999618530273, "rew_std": 0.39999961853027344, "Agent": "fqf"}, {"env_step": 0, "rew": -21.0, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 100000, "rew": -20.870000076293945, "rew_std": 0.27221299202092436, "Agent": "qrdqn"}, {"env_step": 200000, "rew": -19.48000011444092, "rew_std": 1.2023307411527404, "Agent": "qrdqn"}, {"env_step": 300000, "rew": -16.780000019073487, "rew_std": 2.1613883342785347, "Agent": "qrdqn"}, {"env_step": 400000, "rew": -12.920000219345093, "rew_std": 3.473845164617662, "Agent": "qrdqn"}, {"env_step": 500000, "rew": -7.060000002384186, "rew_std": 6.094456461922503, "Agent": "qrdqn"}, {"env_step": 600000, "rew": -3.779999941587448, "rew_std": 6.045295632144355, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 9.749999952316283, "rew_std": 6.640368991575429, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 15.269999933242797, "rew_std": 4.12966090763813, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 19.622222052680122, "rew_std": 1.2916639583656102, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 20.09999990463257, "rew_std": 0.3162274644388989, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 19.899999618530273, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 19.899999618530273, "rew_std": 0.10000038146972656, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "qrdqn"}, {"env_step": 0, "rew": -20.969999885559083, "rew_std": 0.06403148663413369, "Agent": "iqn"}, {"env_step": 100000, "rew": -19.1300000667572, "rew_std": 5.345100609195572, "Agent": "iqn"}, {"env_step": 200000, "rew": -19.34000015258789, "rew_std": 1.09380072496787, "Agent": "iqn"}, {"env_step": 300000, "rew": -18.3, "rew_std": 1.1471704685545094, "Agent": "iqn"}, {"env_step": 400000, "rew": -14.660000038146972, "rew_std": 2.7383207958984883, "Agent": "iqn"}, {"env_step": 500000, "rew": -9.659999978542327, "rew_std": 5.29871682181189, "Agent": "iqn"}, {"env_step": 600000, "rew": -8.680000057816505, "rew_std": 4.040495106986447, "Agent": "iqn"}, {"env_step": 700000, "rew": 2.8499999545514583, "rew_std": 6.374519581488704, "Agent": "iqn"}, {"env_step": 800000, "rew": 7.970000147819519, "rew_std": 8.160275826601659, "Agent": "iqn"}, {"env_step": 900000, "rew": 17.166666507720947, "rew_std": 4.651164654639624, "Agent": "iqn"}, {"env_step": 1000000, "rew": 17.849999984105427, "rew_std": 4.5853935091484725, "Agent": "iqn"}, {"env_step": 1100000, "rew": 18.260000038146973, "rew_std": 1.9652988864635694, "Agent": "iqn"}, {"env_step": 1200000, "rew": 18.68000030517578, "rew_std": 2.9047550585330666, "Agent": "iqn"}, {"env_step": 1300000, "rew": 19.600000381469727, "rew_std": 0.39999961853027344, "Agent": "iqn"}, {"env_step": 1400000, "rew": 18.799999237060547, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 1500000, "rew": 17.0, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 1600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 1700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 1800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 1900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 2900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 3900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 4900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 5900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 6900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 7900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 8900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9100000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9200000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9300000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9400000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9500000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9600000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9700000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9800000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 9900000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 10000000, "rew": 20.700000762939453, "rew_std": 0.0, "Agent": "iqn"}, {"env_step": 0, "rew": -21.0, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 100000, "rew": -20.979999923706053, "rew_std": 0.04000015258789063, "Agent": "rainbow"}, {"env_step": 200000, "rew": -20.439999961853026, "rew_std": 0.611882543624649, "Agent": "rainbow"}, {"env_step": 300000, "rew": -20.05, "rew_std": 1.0984076053899456, "Agent": "rainbow"}, {"env_step": 400000, "rew": -18.579999923706055, "rew_std": 1.1417527594487265, "Agent": "rainbow"}, {"env_step": 500000, "rew": -16.669999980926512, "rew_std": 2.142918529337897, "Agent": "rainbow"}, {"env_step": 600000, "rew": -14.539999961853027, "rew_std": 3.4153184124021854, "Agent": "rainbow"}, {"env_step": 700000, "rew": -11.319999885559081, "rew_std": 2.876734170162213, "Agent": "rainbow"}, {"env_step": 800000, "rew": -10.470000064373016, "rew_std": 4.46520999148195, "Agent": "rainbow"}, {"env_step": 900000, "rew": -2.170000058412552, "rew_std": 4.194055360234164, "Agent": "rainbow"}, {"env_step": 1000000, "rew": -1.1700000524520875, "rew_std": 7.9131599288409395, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 4.420000007003546, "rew_std": 8.925671038750298, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 4.199999978972806, "rew_std": 7.79358685682886, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 4.3666667805777655, "rew_std": 9.006787650672438, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 8.224999904632568, "rew_std": 5.813507857159169, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 10.48749989271164, "rew_std": 5.611915177475383, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 10.325000084936619, "rew_std": 7.195441264466608, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 5.216666638851166, "rew_std": 8.010496691447514, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 7.8833333651224775, "rew_std": 8.73506665798113, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 10.416666527589163, "rew_std": 7.064799091845216, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 14.739999961853027, "rew_std": 3.559550394534507, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 16.82000026702881, "rew_std": 2.790985522657408, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 14.699999809265137, "rew_std": 3.199374665910315, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 16.800000190734863, "rew_std": 1.987460835388907, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 16.649999856948853, "rew_std": 3.9150350231246187, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 18.700000127156574, "rew_std": 1.8384774512584698, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 9.5, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 16.100000381469727, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 15.5, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 15.600000381469727, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3000000, "rew": -4.300000190734863, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 17.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 17.799999237060547, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 19.100000381469727, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 19.5, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 20.200000762939453, "rew_std": 0.0, "Agent": "rainbow"}, {"env_step": 0, "rew": -20.75, "rew_std": 0.34132100802270626, "Agent": "ppo"}, {"env_step": 100000, "rew": -20.61000003814697, "rew_std": 0.32695557164785227, "Agent": "ppo"}, {"env_step": 200000, "rew": -19.98000011444092, "rew_std": 0.5793098790055098, "Agent": "ppo"}, {"env_step": 300000, "rew": -17.55, "rew_std": 2.648112510163754, "Agent": "ppo"}, {"env_step": 400000, "rew": -13.260000038146973, "rew_std": 4.553284472142394, "Agent": "ppo"}, {"env_step": 500000, "rew": -9.600000047683716, "rew_std": 5.175519361004068, "Agent": "ppo"}, {"env_step": 600000, "rew": -8.650000131130218, "rew_std": 5.414471552623239, "Agent": "ppo"}, {"env_step": 700000, "rew": -4.4400000154972075, "rew_std": 5.544041881025165, "Agent": "ppo"}, {"env_step": 800000, "rew": 0.6799999058246613, "rew_std": 7.877410761852243, "Agent": "ppo"}, {"env_step": 900000, "rew": 5.640000033378601, "rew_std": 6.771735266186935, "Agent": "ppo"}, {"env_step": 1000000, "rew": 5.6600001603364944, "rew_std": 7.132489235026172, "Agent": "ppo"}, {"env_step": 1100000, "rew": 6.7699999690055845, "rew_std": 6.8543488111854005, "Agent": "ppo"}, {"env_step": 1200000, "rew": 11.959999895095825, "rew_std": 4.759663803505452, "Agent": "ppo"}, {"env_step": 1300000, "rew": 13.499999952316283, "rew_std": 4.599999950243093, "Agent": "ppo"}, {"env_step": 1400000, "rew": 13.460000038146973, "rew_std": 4.538986609617991, "Agent": "ppo"}, {"env_step": 1500000, "rew": 13.359999942779542, "rew_std": 4.740295478528203, "Agent": "ppo"}, {"env_step": 1600000, "rew": 15.47999997138977, "rew_std": 3.309924420995019, "Agent": "ppo"}, {"env_step": 1700000, "rew": 13.88000020980835, "rew_std": 3.9776378782724717, "Agent": "ppo"}, {"env_step": 1800000, "rew": 16.680000019073486, "rew_std": 2.098475869175282, "Agent": "ppo"}, {"env_step": 1900000, "rew": 15.039999866485596, "rew_std": 3.2720634721834996, "Agent": "ppo"}, {"env_step": 2000000, "rew": 16.200000190734862, "rew_std": 2.0079841339730997, "Agent": "ppo"}, {"env_step": 2100000, "rew": 16.709999752044677, "rew_std": 2.592083999305904, "Agent": "ppo"}, {"env_step": 2200000, "rew": 17.93000011444092, "rew_std": 1.5020321173047337, "Agent": "ppo"}, {"env_step": 2300000, "rew": 16.13333299424913, "rew_std": 4.134945780702597, "Agent": "ppo"}, {"env_step": 2400000, "rew": 16.46666653951009, "rew_std": 2.9988884554980983, "Agent": "ppo"}, {"env_step": 2500000, "rew": 17.266666624281143, "rew_std": 1.7549928259554646, "Agent": "ppo"}, {"env_step": 2600000, "rew": 17.63333363003201, "rew_std": 1.300427226972741, "Agent": "ppo"}, {"env_step": 2700000, "rew": 16.8111113442315, "rew_std": 2.6534861585374485, "Agent": "ppo"}, {"env_step": 2800000, "rew": 17.000000211927627, "rew_std": 2.82999802642146, "Agent": "ppo"}, {"env_step": 2900000, "rew": 16.97777779897054, "rew_std": 2.5494127247858547, "Agent": "ppo"}, {"env_step": 3000000, "rew": 17.81250011920929, "rew_std": 1.6593954848338575, "Agent": "ppo"}, {"env_step": 3100000, "rew": 17.06250011920929, "rew_std": 2.284697851779331, "Agent": "ppo"}, {"env_step": 3200000, "rew": 16.975000381469727, "rew_std": 2.1057958062253594, "Agent": "ppo"}, {"env_step": 3300000, "rew": 16.824999809265137, "rew_std": 2.9625790227338165, "Agent": "ppo"}, {"env_step": 3400000, "rew": 18.1875, "rew_std": 2.531519990815377, "Agent": "ppo"}, {"env_step": 3500000, "rew": 16.71666669845581, "rew_std": 2.412755415928967, "Agent": "ppo"}, {"env_step": 3600000, "rew": 16.46666669845581, "rew_std": 3.901566607031345, "Agent": "ppo"}, {"env_step": 3700000, "rew": 16.166666666666668, "rew_std": 2.739626889190835, "Agent": "ppo"}, {"env_step": 3800000, "rew": 17.300000190734863, "rew_std": 2.78926494928614, "Agent": "ppo"}, {"env_step": 3900000, "rew": 18.09999990463257, "rew_std": 2.077658824212887, "Agent": "ppo"}, {"env_step": 4000000, "rew": 17.019999504089355, "rew_std": 1.4483091764261082, "Agent": "ppo"}, {"env_step": 4100000, "rew": 18.620000076293945, "rew_std": 1.2253983415940415, "Agent": "ppo"}, {"env_step": 4200000, "rew": 18.35999984741211, "rew_std": 2.2526428387365733, "Agent": "ppo"}, {"env_step": 4300000, "rew": 19.0, "rew_std": 0.6519197285159748, "Agent": "ppo"}, {"env_step": 4400000, "rew": 18.975000381469727, "rew_std": 1.3141059206073868, "Agent": "ppo"}, {"env_step": 4500000, "rew": 19.625, "rew_std": 0.3897113582892007, "Agent": "ppo"}, {"env_step": 4600000, "rew": 19.566666920979817, "rew_std": 0.684754539003982, "Agent": "ppo"}, {"env_step": 4700000, "rew": 15.199999809265137, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 4800000, "rew": 17.200000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 4900000, "rew": 16.799999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5000000, "rew": 18.700000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5100000, "rew": 16.100000381469727, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5200000, "rew": 17.700000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5300000, "rew": 17.700000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5400000, "rew": 17.600000381469727, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5500000, "rew": 16.700000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5600000, "rew": 19.399999618530273, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5700000, "rew": 19.100000381469727, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5800000, "rew": 18.5, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 5900000, "rew": 18.700000762939453, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6000000, "rew": 19.600000381469727, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6100000, "rew": 19.0, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6200000, "rew": 19.0, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6300000, "rew": 19.100000381469727, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6400000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6500000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6600000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6700000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6800000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 6900000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7000000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7100000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7200000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7300000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7400000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7500000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7600000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7700000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7800000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 7900000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8000000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8100000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8200000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8300000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8400000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8500000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8600000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8700000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8800000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 8900000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9000000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9100000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9200000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9300000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9400000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9500000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9600000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9700000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9800000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 9900000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}, {"env_step": 10000000, "rew": 20.299999237060547, "rew_std": 0.0, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/QbertNoFrameskip-v4/result.json b/examples/atari/benchmark/QbertNoFrameskip-v4/result.json new file mode 100644 index 000000000..f4add1d09 --- /dev/null +++ b/examples/atari/benchmark/QbertNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 95.0, "rew_std": 75.92759709091287, "Agent": "c51"}, {"env_step": 100000, "rew": 251.5, "rew_std": 82.12186067059123, "Agent": "c51"}, {"env_step": 200000, "rew": 255.5, "rew_std": 117.85478352616833, "Agent": "c51"}, {"env_step": 300000, "rew": 320.0, "rew_std": 42.175229697062704, "Agent": "c51"}, {"env_step": 400000, "rew": 332.5, "rew_std": 83.60621986431393, "Agent": "c51"}, {"env_step": 500000, "rew": 430.25, "rew_std": 135.99839153460601, "Agent": "c51"}, {"env_step": 600000, "rew": 523.75, "rew_std": 108.9681719586045, "Agent": "c51"}, {"env_step": 700000, "rew": 1121.0, "rew_std": 516.2099863427673, "Agent": "c51"}, {"env_step": 800000, "rew": 1754.75, "rew_std": 1004.4398003364861, "Agent": "c51"}, {"env_step": 900000, "rew": 2517.0, "rew_std": 1108.9954914245593, "Agent": "c51"}, {"env_step": 1000000, "rew": 2285.0, "rew_std": 1031.815753901829, "Agent": "c51"}, {"env_step": 1100000, "rew": 2877.75, "rew_std": 1017.4357780715203, "Agent": "c51"}, {"env_step": 1200000, "rew": 3304.5, "rew_std": 804.6146593245738, "Agent": "c51"}, {"env_step": 1300000, "rew": 3511.25, "rew_std": 1172.84443235239, "Agent": "c51"}, {"env_step": 1400000, "rew": 3495.0, "rew_std": 713.4371030441296, "Agent": "c51"}, {"env_step": 1500000, "rew": 3199.0, "rew_std": 1272.923897960911, "Agent": "c51"}, {"env_step": 1600000, "rew": 3992.0, "rew_std": 1011.4944389367645, "Agent": "c51"}, {"env_step": 1700000, "rew": 4453.75, "rew_std": 1278.8536126156114, "Agent": "c51"}, {"env_step": 1800000, "rew": 3931.5, "rew_std": 1001.7822867270114, "Agent": "c51"}, {"env_step": 1900000, "rew": 4928.25, "rew_std": 1331.802842953866, "Agent": "c51"}, {"env_step": 2000000, "rew": 4457.0, "rew_std": 1296.9019816470325, "Agent": "c51"}, {"env_step": 2100000, "rew": 5236.75, "rew_std": 1800.0354336790151, "Agent": "c51"}, {"env_step": 2200000, "rew": 4757.25, "rew_std": 1431.1256277839482, "Agent": "c51"}, {"env_step": 2300000, "rew": 4738.25, "rew_std": 1369.4538373015719, "Agent": "c51"}, {"env_step": 2400000, "rew": 6592.0, "rew_std": 1420.6903251588644, "Agent": "c51"}, {"env_step": 2500000, "rew": 5894.25, "rew_std": 1735.2507203571477, "Agent": "c51"}, {"env_step": 2600000, "rew": 7282.25, "rew_std": 2613.5424833929906, "Agent": "c51"}, {"env_step": 2700000, "rew": 7078.25, "rew_std": 2062.308188050467, "Agent": "c51"}, {"env_step": 2800000, "rew": 6066.25, "rew_std": 1512.1017037554054, "Agent": "c51"}, {"env_step": 2900000, "rew": 7065.5, "rew_std": 2015.3544353289324, "Agent": "c51"}, {"env_step": 3000000, "rew": 6861.0, "rew_std": 1669.891538394036, "Agent": "c51"}, {"env_step": 3100000, "rew": 7762.75, "rew_std": 2067.515553145852, "Agent": "c51"}, {"env_step": 3200000, "rew": 7553.5, "rew_std": 2434.32644688423, "Agent": "c51"}, {"env_step": 3300000, "rew": 6468.25, "rew_std": 1466.2916873869265, "Agent": "c51"}, {"env_step": 3400000, "rew": 7396.25, "rew_std": 2111.3411762431956, "Agent": "c51"}, {"env_step": 3500000, "rew": 7398.75, "rew_std": 2466.653413534216, "Agent": "c51"}, {"env_step": 3600000, "rew": 7548.75, "rew_std": 2775.422546658436, "Agent": "c51"}, {"env_step": 3700000, "rew": 8335.5, "rew_std": 2109.992239322221, "Agent": "c51"}, {"env_step": 3800000, "rew": 6925.0, "rew_std": 1951.7191140120547, "Agent": "c51"}, {"env_step": 3900000, "rew": 7580.5, "rew_std": 2267.1120947143304, "Agent": "c51"}, {"env_step": 4000000, "rew": 8586.75, "rew_std": 2490.3042108344916, "Agent": "c51"}, {"env_step": 4100000, "rew": 8712.75, "rew_std": 2641.0264221510547, "Agent": "c51"}, {"env_step": 4200000, "rew": 9052.75, "rew_std": 1451.2083112013934, "Agent": "c51"}, {"env_step": 4300000, "rew": 7919.75, "rew_std": 1486.0133116833106, "Agent": "c51"}, {"env_step": 4400000, "rew": 9568.25, "rew_std": 2890.1516071825713, "Agent": "c51"}, {"env_step": 4500000, "rew": 8489.0, "rew_std": 1878.7070687044322, "Agent": "c51"}, {"env_step": 4600000, "rew": 8453.75, "rew_std": 2539.73577611924, "Agent": "c51"}, {"env_step": 4700000, "rew": 8407.0, "rew_std": 2617.2267765709566, "Agent": "c51"}, {"env_step": 4800000, "rew": 8893.25, "rew_std": 2978.127568204559, "Agent": "c51"}, {"env_step": 4900000, "rew": 10263.75, "rew_std": 2290.572322040935, "Agent": "c51"}, {"env_step": 5000000, "rew": 8514.5, "rew_std": 1787.0897431298743, "Agent": "c51"}, {"env_step": 5100000, "rew": 8638.75, "rew_std": 2969.4349736102995, "Agent": "c51"}, {"env_step": 5200000, "rew": 10585.75, "rew_std": 3481.069708078251, "Agent": "c51"}, {"env_step": 5300000, "rew": 9607.5, "rew_std": 2606.770032051159, "Agent": "c51"}, {"env_step": 5400000, "rew": 9306.5, "rew_std": 2684.2033734424817, "Agent": "c51"}, {"env_step": 5500000, "rew": 9660.75, "rew_std": 2237.9474552589477, "Agent": "c51"}, {"env_step": 5600000, "rew": 9766.25, "rew_std": 2911.0542012302003, "Agent": "c51"}, {"env_step": 5700000, "rew": 10415.5, "rew_std": 1625.4448621838885, "Agent": "c51"}, {"env_step": 5800000, "rew": 9485.5, "rew_std": 3670.640407340387, "Agent": "c51"}, {"env_step": 5900000, "rew": 10269.0, "rew_std": 2380.1436931412354, "Agent": "c51"}, {"env_step": 6000000, "rew": 10933.5, "rew_std": 2768.2542332668795, "Agent": "c51"}, {"env_step": 6100000, "rew": 10309.25, "rew_std": 2190.8112224698866, "Agent": "c51"}, {"env_step": 6200000, "rew": 10257.0, "rew_std": 3413.4135773445328, "Agent": "c51"}, {"env_step": 6300000, "rew": 9958.0, "rew_std": 2849.388925717232, "Agent": "c51"}, {"env_step": 6400000, "rew": 11790.0, "rew_std": 1323.6403401226482, "Agent": "c51"}, {"env_step": 6500000, "rew": 10310.75, "rew_std": 2311.68581613073, "Agent": "c51"}, {"env_step": 6600000, "rew": 9120.75, "rew_std": 2925.0596254606503, "Agent": "c51"}, {"env_step": 6700000, "rew": 10305.5, "rew_std": 2839.6374768621436, "Agent": "c51"}, {"env_step": 6800000, "rew": 10348.75, "rew_std": 3006.7963121069574, "Agent": "c51"}, {"env_step": 6900000, "rew": 10654.25, "rew_std": 1407.1265268269233, "Agent": "c51"}, {"env_step": 7000000, "rew": 11493.75, "rew_std": 1194.8479244238574, "Agent": "c51"}, {"env_step": 7100000, "rew": 11250.5, "rew_std": 1915.5099843122719, "Agent": "c51"}, {"env_step": 7200000, "rew": 10615.75, "rew_std": 2852.864141963301, "Agent": "c51"}, {"env_step": 7300000, "rew": 10428.75, "rew_std": 1486.1473892249046, "Agent": "c51"}, {"env_step": 7400000, "rew": 11293.0, "rew_std": 2100.1969550496924, "Agent": "c51"}, {"env_step": 7500000, "rew": 10405.0, "rew_std": 2845.91066268778, "Agent": "c51"}, {"env_step": 7600000, "rew": 11912.75, "rew_std": 1889.1385106709354, "Agent": "c51"}, {"env_step": 7700000, "rew": 10792.75, "rew_std": 2319.9715650197095, "Agent": "c51"}, {"env_step": 7800000, "rew": 11481.75, "rew_std": 2059.718442530435, "Agent": "c51"}, {"env_step": 7900000, "rew": 11188.0, "rew_std": 1572.3460973971348, "Agent": "c51"}, {"env_step": 8000000, "rew": 11333.25, "rew_std": 2443.5376634093445, "Agent": "c51"}, {"env_step": 8100000, "rew": 11388.75, "rew_std": 1806.7637677626813, "Agent": "c51"}, {"env_step": 8200000, "rew": 11084.25, "rew_std": 2011.5637729139983, "Agent": "c51"}, {"env_step": 8300000, "rew": 11189.25, "rew_std": 1837.155767075835, "Agent": "c51"}, {"env_step": 8400000, "rew": 12201.5, "rew_std": 1443.038547648676, "Agent": "c51"}, {"env_step": 8500000, "rew": 12172.0, "rew_std": 2153.40886735427, "Agent": "c51"}, {"env_step": 8600000, "rew": 10667.0, "rew_std": 2920.304093754621, "Agent": "c51"}, {"env_step": 8700000, "rew": 12087.25, "rew_std": 1455.5503469478479, "Agent": "c51"}, {"env_step": 8800000, "rew": 11311.0, "rew_std": 2612.836868233453, "Agent": "c51"}, {"env_step": 8900000, "rew": 12494.75, "rew_std": 2119.100767424711, "Agent": "c51"}, {"env_step": 9000000, "rew": 12513.25, "rew_std": 1274.6416408151745, "Agent": "c51"}, {"env_step": 9100000, "rew": 12241.0, "rew_std": 1972.8945106112492, "Agent": "c51"}, {"env_step": 9200000, "rew": 10962.25, "rew_std": 1657.8398784261403, "Agent": "c51"}, {"env_step": 9300000, "rew": 11570.25, "rew_std": 2591.904813549294, "Agent": "c51"}, {"env_step": 9400000, "rew": 11239.25, "rew_std": 2040.6086867648094, "Agent": "c51"}, {"env_step": 9500000, "rew": 11834.25, "rew_std": 1834.925083620582, "Agent": "c51"}, {"env_step": 9600000, "rew": 11510.5, "rew_std": 1754.8346788230508, "Agent": "c51"}, {"env_step": 9700000, "rew": 10276.75, "rew_std": 2304.5601668214263, "Agent": "c51"}, {"env_step": 9800000, "rew": 12446.75, "rew_std": 1572.9002074194027, "Agent": "c51"}, {"env_step": 9900000, "rew": 10765.0, "rew_std": 2277.32930205537, "Agent": "c51"}, {"env_step": 10000000, "rew": 11854.5, "rew_std": 2126.8074078298673, "Agent": "c51"}, {"env_step": 0, "rew": 79.5, "rew_std": 76.44278906476399, "Agent": "dqn"}, {"env_step": 100000, "rew": 306.5, "rew_std": 140.31749712705113, "Agent": "dqn"}, {"env_step": 200000, "rew": 409.5, "rew_std": 96.2925230742242, "Agent": "dqn"}, {"env_step": 300000, "rew": 537.25, "rew_std": 147.0180686174322, "Agent": "dqn"}, {"env_step": 400000, "rew": 534.25, "rew_std": 124.05165254844451, "Agent": "dqn"}, {"env_step": 500000, "rew": 725.25, "rew_std": 251.90883767744236, "Agent": "dqn"}, {"env_step": 600000, "rew": 669.5, "rew_std": 160.39326669159152, "Agent": "dqn"}, {"env_step": 700000, "rew": 958.5, "rew_std": 439.7985334218385, "Agent": "dqn"}, {"env_step": 800000, "rew": 818.5, "rew_std": 111.63668751803773, "Agent": "dqn"}, {"env_step": 900000, "rew": 778.75, "rew_std": 199.5408792703891, "Agent": "dqn"}, {"env_step": 1000000, "rew": 850.0, "rew_std": 283.47618947629445, "Agent": "dqn"}, {"env_step": 1100000, "rew": 1346.0, "rew_std": 645.7797612189469, "Agent": "dqn"}, {"env_step": 1200000, "rew": 1157.5, "rew_std": 768.8619837135922, "Agent": "dqn"}, {"env_step": 1300000, "rew": 1414.5, "rew_std": 999.8636156996613, "Agent": "dqn"}, {"env_step": 1400000, "rew": 1861.25, "rew_std": 1166.1422779832656, "Agent": "dqn"}, {"env_step": 1500000, "rew": 2099.75, "rew_std": 986.7018609995625, "Agent": "dqn"}, {"env_step": 1600000, "rew": 2019.0, "rew_std": 728.7679671884598, "Agent": "dqn"}, {"env_step": 1700000, "rew": 3189.0, "rew_std": 1119.5803901462368, "Agent": "dqn"}, {"env_step": 1800000, "rew": 3215.5, "rew_std": 1019.3391241387726, "Agent": "dqn"}, {"env_step": 1900000, "rew": 4062.5, "rew_std": 644.8352502771542, "Agent": "dqn"}, {"env_step": 2000000, "rew": 3697.75, "rew_std": 775.0285881823974, "Agent": "dqn"}, {"env_step": 2100000, "rew": 4084.75, "rew_std": 369.5460898183067, "Agent": "dqn"}, {"env_step": 2200000, "rew": 4364.5, "rew_std": 82.35441700358275, "Agent": "dqn"}, {"env_step": 2300000, "rew": 3960.5, "rew_std": 493.58357954859076, "Agent": "dqn"}, {"env_step": 2400000, "rew": 4298.5, "rew_std": 337.0908631215032, "Agent": "dqn"}, {"env_step": 2500000, "rew": 3868.5, "rew_std": 810.0564795123856, "Agent": "dqn"}, {"env_step": 2600000, "rew": 3593.0, "rew_std": 1069.2274079913964, "Agent": "dqn"}, {"env_step": 2700000, "rew": 3861.5, "rew_std": 863.5603626846244, "Agent": "dqn"}, {"env_step": 2800000, "rew": 4479.75, "rew_std": 226.15108334916283, "Agent": "dqn"}, {"env_step": 2900000, "rew": 4399.25, "rew_std": 278.67106505699513, "Agent": "dqn"}, {"env_step": 3000000, "rew": 4731.0, "rew_std": 975.6428649869787, "Agent": "dqn"}, {"env_step": 3100000, "rew": 4451.0, "rew_std": 1066.7041529871344, "Agent": "dqn"}, {"env_step": 3200000, "rew": 4260.0, "rew_std": 1112.3870729202133, "Agent": "dqn"}, {"env_step": 3300000, "rew": 4400.75, "rew_std": 758.1804287239285, "Agent": "dqn"}, {"env_step": 3400000, "rew": 4580.5, "rew_std": 901.3668786903588, "Agent": "dqn"}, {"env_step": 3500000, "rew": 4537.0, "rew_std": 1127.5176273566635, "Agent": "dqn"}, {"env_step": 3600000, "rew": 5060.75, "rew_std": 1816.7983686969778, "Agent": "dqn"}, {"env_step": 3700000, "rew": 5504.0, "rew_std": 1962.111808740776, "Agent": "dqn"}, {"env_step": 3800000, "rew": 5938.25, "rew_std": 1861.7293875587827, "Agent": "dqn"}, {"env_step": 3900000, "rew": 5781.75, "rew_std": 1370.2176150159507, "Agent": "dqn"}, {"env_step": 4000000, "rew": 5990.25, "rew_std": 3394.9163189245182, "Agent": "dqn"}, {"env_step": 4100000, "rew": 6092.75, "rew_std": 2065.6846473990167, "Agent": "dqn"}, {"env_step": 4200000, "rew": 6176.0, "rew_std": 1842.3508080710362, "Agent": "dqn"}, {"env_step": 4300000, "rew": 6576.5, "rew_std": 2726.7487966440913, "Agent": "dqn"}, {"env_step": 4400000, "rew": 6971.25, "rew_std": 3082.8676281183402, "Agent": "dqn"}, {"env_step": 4500000, "rew": 6908.25, "rew_std": 2762.2427595162594, "Agent": "dqn"}, {"env_step": 4600000, "rew": 7546.0, "rew_std": 2864.2300885229174, "Agent": "dqn"}, {"env_step": 4700000, "rew": 7737.75, "rew_std": 3928.65680767613, "Agent": "dqn"}, {"env_step": 4800000, "rew": 8261.75, "rew_std": 3556.5873829416873, "Agent": "dqn"}, {"env_step": 4900000, "rew": 8120.5, "rew_std": 2792.5308413695275, "Agent": "dqn"}, {"env_step": 5000000, "rew": 7459.25, "rew_std": 3016.322481516192, "Agent": "dqn"}, {"env_step": 5100000, "rew": 8186.25, "rew_std": 3262.4464076058016, "Agent": "dqn"}, {"env_step": 5200000, "rew": 8457.75, "rew_std": 3065.806062441002, "Agent": "dqn"}, {"env_step": 5300000, "rew": 7461.25, "rew_std": 2633.543062586978, "Agent": "dqn"}, {"env_step": 5400000, "rew": 8212.25, "rew_std": 2857.8948655435174, "Agent": "dqn"}, {"env_step": 5500000, "rew": 8331.0, "rew_std": 2962.497088606164, "Agent": "dqn"}, {"env_step": 5600000, "rew": 8116.0, "rew_std": 3106.8304186099376, "Agent": "dqn"}, {"env_step": 5700000, "rew": 8354.0, "rew_std": 2939.679446810485, "Agent": "dqn"}, {"env_step": 5800000, "rew": 8698.25, "rew_std": 2624.4728161099324, "Agent": "dqn"}, {"env_step": 5900000, "rew": 9697.25, "rew_std": 2572.896337301602, "Agent": "dqn"}, {"env_step": 6000000, "rew": 8455.0, "rew_std": 1774.5978417658464, "Agent": "dqn"}, {"env_step": 6100000, "rew": 9885.75, "rew_std": 3028.3760190075473, "Agent": "dqn"}, {"env_step": 6200000, "rew": 8983.5, "rew_std": 2107.2515274641514, "Agent": "dqn"}, {"env_step": 6300000, "rew": 9419.75, "rew_std": 2727.142838668338, "Agent": "dqn"}, {"env_step": 6400000, "rew": 8409.25, "rew_std": 3007.3811385489535, "Agent": "dqn"}, {"env_step": 6500000, "rew": 9823.75, "rew_std": 2742.98269453163, "Agent": "dqn"}, {"env_step": 6600000, "rew": 9702.25, "rew_std": 2529.285336315379, "Agent": "dqn"}, {"env_step": 6700000, "rew": 10412.5, "rew_std": 2968.082925054487, "Agent": "dqn"}, {"env_step": 6800000, "rew": 9085.25, "rew_std": 2521.6067422379724, "Agent": "dqn"}, {"env_step": 6900000, "rew": 9624.25, "rew_std": 2870.277654252285, "Agent": "dqn"}, {"env_step": 7000000, "rew": 10178.25, "rew_std": 2328.1741907554942, "Agent": "dqn"}, {"env_step": 7100000, "rew": 9411.75, "rew_std": 3466.6296762850225, "Agent": "dqn"}, {"env_step": 7200000, "rew": 10059.0, "rew_std": 2418.3835510522313, "Agent": "dqn"}, {"env_step": 7300000, "rew": 9972.25, "rew_std": 3165.8356815381308, "Agent": "dqn"}, {"env_step": 7400000, "rew": 9769.25, "rew_std": 3534.1402861940837, "Agent": "dqn"}, {"env_step": 7500000, "rew": 9630.75, "rew_std": 3561.6785105480812, "Agent": "dqn"}, {"env_step": 7600000, "rew": 10130.5, "rew_std": 2504.094846446516, "Agent": "dqn"}, {"env_step": 7700000, "rew": 9689.75, "rew_std": 2412.3324941848296, "Agent": "dqn"}, {"env_step": 7800000, "rew": 9682.5, "rew_std": 2696.419848614084, "Agent": "dqn"}, {"env_step": 7900000, "rew": 8600.25, "rew_std": 4069.30498519096, "Agent": "dqn"}, {"env_step": 8000000, "rew": 10808.25, "rew_std": 1838.3657994262187, "Agent": "dqn"}, {"env_step": 8100000, "rew": 10105.5, "rew_std": 3078.21819402069, "Agent": "dqn"}, {"env_step": 8200000, "rew": 9794.25, "rew_std": 3020.5171432223324, "Agent": "dqn"}, {"env_step": 8300000, "rew": 10248.5, "rew_std": 2272.298450908243, "Agent": "dqn"}, {"env_step": 8400000, "rew": 9916.5, "rew_std": 3159.7433044473723, "Agent": "dqn"}, {"env_step": 8500000, "rew": 10325.5, "rew_std": 2780.830316650047, "Agent": "dqn"}, {"env_step": 8600000, "rew": 10778.0, "rew_std": 1940.7523669958514, "Agent": "dqn"}, {"env_step": 8700000, "rew": 10993.0, "rew_std": 2580.0946688057784, "Agent": "dqn"}, {"env_step": 8800000, "rew": 10329.75, "rew_std": 2510.3706026202585, "Agent": "dqn"}, {"env_step": 8900000, "rew": 9983.0, "rew_std": 3615.9431342320636, "Agent": "dqn"}, {"env_step": 9000000, "rew": 11148.0, "rew_std": 1932.5183698997535, "Agent": "dqn"}, {"env_step": 9100000, "rew": 10034.75, "rew_std": 2345.046494741629, "Agent": "dqn"}, {"env_step": 9200000, "rew": 10810.75, "rew_std": 2402.0418527785896, "Agent": "dqn"}, {"env_step": 9300000, "rew": 10502.5, "rew_std": 2058.038811587381, "Agent": "dqn"}, {"env_step": 9400000, "rew": 10956.0, "rew_std": 1991.7147762669233, "Agent": "dqn"}, {"env_step": 9500000, "rew": 11620.25, "rew_std": 786.060947064539, "Agent": "dqn"}, {"env_step": 9600000, "rew": 10733.5, "rew_std": 2011.6753589980665, "Agent": "dqn"}, {"env_step": 9700000, "rew": 11486.25, "rew_std": 2341.8905957580514, "Agent": "dqn"}, {"env_step": 9800000, "rew": 11012.5, "rew_std": 2049.413025722243, "Agent": "dqn"}, {"env_step": 9900000, "rew": 10990.5, "rew_std": 1687.970601047305, "Agent": "dqn"}, {"env_step": 10000000, "rew": 11396.5, "rew_std": 1123.2326117060527, "Agent": "dqn"}, {"env_step": 0, "rew": 62.25, "rew_std": 64.61859252568102, "Agent": "fqf"}, {"env_step": 100000, "rew": 282.5, "rew_std": 133.41195598596101, "Agent": "fqf"}, {"env_step": 200000, "rew": 334.25, "rew_std": 97.66684442532174, "Agent": "fqf"}, {"env_step": 300000, "rew": 478.0, "rew_std": 103.5, "Agent": "fqf"}, {"env_step": 400000, "rew": 497.75, "rew_std": 127.49730389306278, "Agent": "fqf"}, {"env_step": 500000, "rew": 761.75, "rew_std": 323.0790344482291, "Agent": "fqf"}, {"env_step": 600000, "rew": 723.25, "rew_std": 85.77623505377233, "Agent": "fqf"}, {"env_step": 700000, "rew": 1184.75, "rew_std": 753.0441969101149, "Agent": "fqf"}, {"env_step": 800000, "rew": 1227.25, "rew_std": 684.0965301037567, "Agent": "fqf"}, {"env_step": 900000, "rew": 1899.75, "rew_std": 957.4160864013096, "Agent": "fqf"}, {"env_step": 1000000, "rew": 1912.5, "rew_std": 1270.665180132044, "Agent": "fqf"}, {"env_step": 1100000, "rew": 2567.5, "rew_std": 1188.7546004117082, "Agent": "fqf"}, {"env_step": 1200000, "rew": 3371.0, "rew_std": 1017.2175283586103, "Agent": "fqf"}, {"env_step": 1300000, "rew": 3156.25, "rew_std": 890.8782534667686, "Agent": "fqf"}, {"env_step": 1400000, "rew": 3885.0, "rew_std": 888.4551198569346, "Agent": "fqf"}, {"env_step": 1500000, "rew": 3952.75, "rew_std": 590.0110698114062, "Agent": "fqf"}, {"env_step": 1600000, "rew": 3700.0, "rew_std": 1213.4516883667022, "Agent": "fqf"}, {"env_step": 1700000, "rew": 4309.75, "rew_std": 1129.6019486969735, "Agent": "fqf"}, {"env_step": 1800000, "rew": 4612.75, "rew_std": 1088.452714866383, "Agent": "fqf"}, {"env_step": 1900000, "rew": 5602.25, "rew_std": 1122.1271374046703, "Agent": "fqf"}, {"env_step": 2000000, "rew": 6148.5, "rew_std": 2185.0435350354005, "Agent": "fqf"}, {"env_step": 2100000, "rew": 6673.75, "rew_std": 1807.6529153850304, "Agent": "fqf"}, {"env_step": 2200000, "rew": 6371.75, "rew_std": 2170.01153510759, "Agent": "fqf"}, {"env_step": 2300000, "rew": 6601.0, "rew_std": 2183.5877014674725, "Agent": "fqf"}, {"env_step": 2400000, "rew": 7732.0, "rew_std": 1939.5839760113508, "Agent": "fqf"}, {"env_step": 2500000, "rew": 8078.25, "rew_std": 2086.995762453772, "Agent": "fqf"}, {"env_step": 2600000, "rew": 9642.5, "rew_std": 2714.1858816227013, "Agent": "fqf"}, {"env_step": 2700000, "rew": 10048.5, "rew_std": 2313.9531110201865, "Agent": "fqf"}, {"env_step": 2800000, "rew": 9025.75, "rew_std": 3670.8754150066165, "Agent": "fqf"}, {"env_step": 2900000, "rew": 9993.5, "rew_std": 3190.4126300527337, "Agent": "fqf"}, {"env_step": 3000000, "rew": 10725.75, "rew_std": 1486.178846067996, "Agent": "fqf"}, {"env_step": 3100000, "rew": 12443.0, "rew_std": 1860.8062096843937, "Agent": "fqf"}, {"env_step": 3200000, "rew": 11651.5, "rew_std": 1916.6462245286687, "Agent": "fqf"}, {"env_step": 3300000, "rew": 11780.25, "rew_std": 2378.499645259591, "Agent": "fqf"}, {"env_step": 3400000, "rew": 12591.25, "rew_std": 1730.6852869600527, "Agent": "fqf"}, {"env_step": 3500000, "rew": 13177.25, "rew_std": 1040.0303180676995, "Agent": "fqf"}, {"env_step": 3600000, "rew": 12289.75, "rew_std": 3415.4978498748906, "Agent": "fqf"}, {"env_step": 3700000, "rew": 12660.0, "rew_std": 1981.2193215290426, "Agent": "fqf"}, {"env_step": 3800000, "rew": 12749.0, "rew_std": 2114.099453668157, "Agent": "fqf"}, {"env_step": 3900000, "rew": 13807.25, "rew_std": 1109.9293051811903, "Agent": "fqf"}, {"env_step": 4000000, "rew": 14015.25, "rew_std": 1171.8481396921702, "Agent": "fqf"}, {"env_step": 4100000, "rew": 13752.25, "rew_std": 1630.1025466209173, "Agent": "fqf"}, {"env_step": 4200000, "rew": 14020.5, "rew_std": 1309.8782386160938, "Agent": "fqf"}, {"env_step": 4300000, "rew": 13418.75, "rew_std": 1649.8266007371806, "Agent": "fqf"}, {"env_step": 4400000, "rew": 14221.5, "rew_std": 1284.3087634988715, "Agent": "fqf"}, {"env_step": 4500000, "rew": 14305.75, "rew_std": 859.7587234218679, "Agent": "fqf"}, {"env_step": 4600000, "rew": 14158.0, "rew_std": 1344.8414404679831, "Agent": "fqf"}, {"env_step": 4700000, "rew": 12771.5, "rew_std": 1663.6489263062685, "Agent": "fqf"}, {"env_step": 4800000, "rew": 14314.0, "rew_std": 1097.285970018755, "Agent": "fqf"}, {"env_step": 4900000, "rew": 14935.25, "rew_std": 337.25074128902963, "Agent": "fqf"}, {"env_step": 5000000, "rew": 14672.0, "rew_std": 807.711117912834, "Agent": "fqf"}, {"env_step": 5100000, "rew": 14673.0, "rew_std": 571.9405563517943, "Agent": "fqf"}, {"env_step": 5200000, "rew": 14309.75, "rew_std": 1108.4434187183394, "Agent": "fqf"}, {"env_step": 5300000, "rew": 14757.25, "rew_std": 947.0417427442151, "Agent": "fqf"}, {"env_step": 5400000, "rew": 14685.0, "rew_std": 655.1602857316674, "Agent": "fqf"}, {"env_step": 5500000, "rew": 14524.25, "rew_std": 979.248468214273, "Agent": "fqf"}, {"env_step": 5600000, "rew": 14862.5, "rew_std": 499.7686964986903, "Agent": "fqf"}, {"env_step": 5700000, "rew": 14338.0, "rew_std": 1270.7752555035056, "Agent": "fqf"}, {"env_step": 5800000, "rew": 14777.75, "rew_std": 538.4253081904676, "Agent": "fqf"}, {"env_step": 5900000, "rew": 14932.0, "rew_std": 720.0848908288522, "Agent": "fqf"}, {"env_step": 6000000, "rew": 15026.25, "rew_std": 556.9619039934419, "Agent": "fqf"}, {"env_step": 6100000, "rew": 15113.75, "rew_std": 255.20151351432068, "Agent": "fqf"}, {"env_step": 6200000, "rew": 14408.5, "rew_std": 1393.7912325739462, "Agent": "fqf"}, {"env_step": 6300000, "rew": 15156.5, "rew_std": 590.047879413188, "Agent": "fqf"}, {"env_step": 6400000, "rew": 14545.5, "rew_std": 1392.182100157878, "Agent": "fqf"}, {"env_step": 6500000, "rew": 14554.75, "rew_std": 1060.3109508535692, "Agent": "fqf"}, {"env_step": 6600000, "rew": 13926.25, "rew_std": 1543.7536437203962, "Agent": "fqf"}, {"env_step": 6700000, "rew": 14911.25, "rew_std": 508.5976430342555, "Agent": "fqf"}, {"env_step": 6800000, "rew": 14964.0, "rew_std": 1249.9880999433556, "Agent": "fqf"}, {"env_step": 6900000, "rew": 15271.75, "rew_std": 499.26827708157066, "Agent": "fqf"}, {"env_step": 7000000, "rew": 14915.25, "rew_std": 710.6022533738548, "Agent": "fqf"}, {"env_step": 7100000, "rew": 14988.5, "rew_std": 568.0396112948463, "Agent": "fqf"}, {"env_step": 7200000, "rew": 14881.25, "rew_std": 963.4282861220133, "Agent": "fqf"}, {"env_step": 7300000, "rew": 15227.75, "rew_std": 746.1756244343553, "Agent": "fqf"}, {"env_step": 7400000, "rew": 15052.0, "rew_std": 1012.3807337163228, "Agent": "fqf"}, {"env_step": 7500000, "rew": 15262.75, "rew_std": 626.2052878250071, "Agent": "fqf"}, {"env_step": 7600000, "rew": 14771.75, "rew_std": 516.1831675868557, "Agent": "fqf"}, {"env_step": 7700000, "rew": 14902.25, "rew_std": 1191.0822022429854, "Agent": "fqf"}, {"env_step": 7800000, "rew": 15195.0, "rew_std": 983.0596370515881, "Agent": "fqf"}, {"env_step": 7900000, "rew": 15172.75, "rew_std": 897.3812247311619, "Agent": "fqf"}, {"env_step": 8000000, "rew": 14729.5, "rew_std": 1125.9345007592583, "Agent": "fqf"}, {"env_step": 8100000, "rew": 14950.75, "rew_std": 407.5706227146407, "Agent": "fqf"}, {"env_step": 8200000, "rew": 14679.25, "rew_std": 1469.804004791115, "Agent": "fqf"}, {"env_step": 8300000, "rew": 14879.75, "rew_std": 1249.1259193932372, "Agent": "fqf"}, {"env_step": 8400000, "rew": 14759.25, "rew_std": 824.2845761628687, "Agent": "fqf"}, {"env_step": 8500000, "rew": 14181.25, "rew_std": 1934.2803086678, "Agent": "fqf"}, {"env_step": 8600000, "rew": 15150.75, "rew_std": 606.5559022052296, "Agent": "fqf"}, {"env_step": 8700000, "rew": 15301.25, "rew_std": 684.131977399098, "Agent": "fqf"}, {"env_step": 8800000, "rew": 15258.75, "rew_std": 178.02826320559328, "Agent": "fqf"}, {"env_step": 8900000, "rew": 14306.75, "rew_std": 2652.5966169962594, "Agent": "fqf"}, {"env_step": 9000000, "rew": 14469.5, "rew_std": 1781.5501676910476, "Agent": "fqf"}, {"env_step": 9100000, "rew": 14648.25, "rew_std": 983.8413553515628, "Agent": "fqf"}, {"env_step": 9200000, "rew": 15119.25, "rew_std": 669.5624037384417, "Agent": "fqf"}, {"env_step": 9300000, "rew": 14687.75, "rew_std": 914.5568940749395, "Agent": "fqf"}, {"env_step": 9400000, "rew": 14220.0, "rew_std": 3311.433790671346, "Agent": "fqf"}, {"env_step": 9500000, "rew": 15234.75, "rew_std": 382.4288332487497, "Agent": "fqf"}, {"env_step": 9600000, "rew": 14718.75, "rew_std": 632.6375838503432, "Agent": "fqf"}, {"env_step": 9700000, "rew": 14343.5, "rew_std": 1404.7336046382602, "Agent": "fqf"}, {"env_step": 9800000, "rew": 15267.5, "rew_std": 387.3209263646879, "Agent": "fqf"}, {"env_step": 9900000, "rew": 15137.75, "rew_std": 331.75, "Agent": "fqf"}, {"env_step": 10000000, "rew": 14602.75, "rew_std": 1270.1847552620052, "Agent": "fqf"}, {"env_step": 0, "rew": 63.5, "rew_std": 62.13091018164791, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 270.75, "rew_std": 151.2119786921658, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 330.0, "rew_std": 140.30324301312496, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 482.5, "rew_std": 145.48625364617786, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 655.25, "rew_std": 164.68701375639793, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 624.5, "rew_std": 130.56033088193365, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 676.5, "rew_std": 131.37351331223505, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 628.25, "rew_std": 158.0587311729409, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 1161.25, "rew_std": 710.1436914456116, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 1550.25, "rew_std": 826.7983808039297, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 1962.5, "rew_std": 961.0228925473108, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 2176.0, "rew_std": 1403.9837071704214, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 2638.5, "rew_std": 1025.882668729714, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 3701.0, "rew_std": 630.7289433663243, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 3190.25, "rew_std": 947.5115104841735, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 3946.75, "rew_std": 637.7578400145309, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 4426.5, "rew_std": 815.5735711755256, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 4326.25, "rew_std": 986.4046139896143, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 4494.5, "rew_std": 949.5484453149297, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 4857.5, "rew_std": 1134.8067016016428, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 4661.0, "rew_std": 2612.279225121235, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 6238.5, "rew_std": 2523.3789846156683, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 6793.5, "rew_std": 2207.1540499022717, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 8352.75, "rew_std": 2463.5217296585797, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 10017.0, "rew_std": 1099.753836092423, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 9378.25, "rew_std": 2206.291869291096, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 9277.75, "rew_std": 2164.6920826066694, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 9680.25, "rew_std": 1852.4255889238843, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 9750.0, "rew_std": 3101.0985956592867, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 11197.0, "rew_std": 2089.198650200598, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 10168.5, "rew_std": 1820.62976741566, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 10809.0, "rew_std": 1863.6564195151423, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 11434.75, "rew_std": 1928.14951767232, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 12635.0, "rew_std": 2041.877812211103, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 11676.0, "rew_std": 3368.622715591641, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 11960.0, "rew_std": 1950.4877595104256, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 11736.0, "rew_std": 2031.8129835198908, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 12507.25, "rew_std": 1577.2018141315968, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 12923.5, "rew_std": 4095.112208474879, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 13316.75, "rew_std": 1166.7872824555468, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 13060.0, "rew_std": 2080.1246957814815, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 12532.75, "rew_std": 1183.963919424912, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 12320.25, "rew_std": 2122.9921249265153, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 12833.5, "rew_std": 1463.2879074194525, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 12643.5, "rew_std": 1230.7717091321201, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 12753.5, "rew_std": 2467.2244526998347, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 14206.0, "rew_std": 934.261874422798, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 13566.0, "rew_std": 1616.8879058240248, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 13339.0, "rew_std": 2508.4644705476694, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 13325.5, "rew_std": 1697.8286868821601, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 13318.25, "rew_std": 1575.3479972691748, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 12695.25, "rew_std": 1818.0165875205869, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 13957.5, "rew_std": 1218.8980679285696, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 13959.75, "rew_std": 1010.0305997839868, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 13414.0, "rew_std": 1498.4079884997943, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 12775.5, "rew_std": 1296.2314608124584, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 14213.75, "rew_std": 1282.7033220897185, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 12620.5, "rew_std": 2257.2158735929534, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 12587.5, "rew_std": 1430.5497195134462, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 13289.5, "rew_std": 1792.5658286378216, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 13572.75, "rew_std": 2379.9851496385436, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 12327.75, "rew_std": 2985.5888133666363, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 13057.75, "rew_std": 2234.581182794664, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 13167.75, "rew_std": 2580.7533904850343, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 14265.0, "rew_std": 1022.666856801373, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 13314.5, "rew_std": 1621.0269892879637, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 14761.5, "rew_std": 862.8928091020344, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 12912.5, "rew_std": 2490.064005201473, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 13582.25, "rew_std": 1415.470085342675, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 14093.0, "rew_std": 1151.0564712471755, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 13608.75, "rew_std": 1454.381419195116, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 14457.25, "rew_std": 1426.2934699773396, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 14363.5, "rew_std": 1147.3579432766394, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 14335.75, "rew_std": 1048.029132467223, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 14255.0, "rew_std": 996.4361494847525, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 13165.0, "rew_std": 2007.4355531373853, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 13882.25, "rew_std": 1050.5673764685444, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 14029.25, "rew_std": 1288.9787866757156, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 13062.75, "rew_std": 2194.7472662017376, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 13878.75, "rew_std": 1196.7911524154915, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 14246.25, "rew_std": 1554.0568884374857, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 14211.5, "rew_std": 1194.981276003938, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 14197.0, "rew_std": 1123.807034147767, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 13508.0, "rew_std": 1345.116073058381, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 11739.5, "rew_std": 2172.110954808709, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 13295.5, "rew_std": 1875.5738455203516, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 14682.0, "rew_std": 657.4094994750228, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 13262.75, "rew_std": 2101.4068055709727, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 13034.25, "rew_std": 2962.464567298654, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 13833.25, "rew_std": 1593.2596500570771, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 13900.75, "rew_std": 1380.3591244672525, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 13849.5, "rew_std": 1837.9743605393412, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 12643.25, "rew_std": 2829.352631345199, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 13530.75, "rew_std": 1416.5393790855233, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 13982.5, "rew_std": 1845.6198145880423, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 13809.25, "rew_std": 1238.4738844642627, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 12931.5, "rew_std": 1797.4736437567033, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 14342.75, "rew_std": 649.1700951984773, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 14729.75, "rew_std": 626.4367984880837, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 13490.75, "rew_std": 1119.1950511416676, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 14191.5, "rew_std": 1683.4767595663445, "Agent": "qrdqn"}, {"env_step": 0, "rew": 74.75, "rew_std": 68.97871048374273, "Agent": "iqn"}, {"env_step": 100000, "rew": 305.25, "rew_std": 107.32223674523374, "Agent": "iqn"}, {"env_step": 200000, "rew": 278.5, "rew_std": 60.28266749240614, "Agent": "iqn"}, {"env_step": 300000, "rew": 480.75, "rew_std": 128.17980535170116, "Agent": "iqn"}, {"env_step": 400000, "rew": 580.5, "rew_std": 164.20566372692508, "Agent": "iqn"}, {"env_step": 500000, "rew": 603.5, "rew_std": 163.69254717304634, "Agent": "iqn"}, {"env_step": 600000, "rew": 681.5, "rew_std": 165.10299815569672, "Agent": "iqn"}, {"env_step": 700000, "rew": 779.5, "rew_std": 202.94642150084834, "Agent": "iqn"}, {"env_step": 800000, "rew": 1212.0, "rew_std": 518.2033867122059, "Agent": "iqn"}, {"env_step": 900000, "rew": 1937.0, "rew_std": 1077.2446333122296, "Agent": "iqn"}, {"env_step": 1000000, "rew": 2055.75, "rew_std": 1114.4051384034444, "Agent": "iqn"}, {"env_step": 1100000, "rew": 2164.0, "rew_std": 763.3292212407435, "Agent": "iqn"}, {"env_step": 1200000, "rew": 2717.0, "rew_std": 926.5607103692666, "Agent": "iqn"}, {"env_step": 1300000, "rew": 3349.25, "rew_std": 801.4120740917247, "Agent": "iqn"}, {"env_step": 1400000, "rew": 3172.25, "rew_std": 848.1453663730057, "Agent": "iqn"}, {"env_step": 1500000, "rew": 3463.5, "rew_std": 827.8875225536377, "Agent": "iqn"}, {"env_step": 1600000, "rew": 4035.75, "rew_std": 911.0859248720726, "Agent": "iqn"}, {"env_step": 1700000, "rew": 4497.0, "rew_std": 543.007596631944, "Agent": "iqn"}, {"env_step": 1800000, "rew": 4461.25, "rew_std": 499.12705045909905, "Agent": "iqn"}, {"env_step": 1900000, "rew": 4384.25, "rew_std": 471.4711682595236, "Agent": "iqn"}, {"env_step": 2000000, "rew": 5132.0, "rew_std": 1111.9947167140679, "Agent": "iqn"}, {"env_step": 2100000, "rew": 4575.75, "rew_std": 2275.0469912729277, "Agent": "iqn"}, {"env_step": 2200000, "rew": 5614.5, "rew_std": 1350.1304566596518, "Agent": "iqn"}, {"env_step": 2300000, "rew": 5378.75, "rew_std": 2386.0001178751018, "Agent": "iqn"}, {"env_step": 2400000, "rew": 6720.5, "rew_std": 2223.6897265580915, "Agent": "iqn"}, {"env_step": 2500000, "rew": 7193.75, "rew_std": 1491.2818521325873, "Agent": "iqn"}, {"env_step": 2600000, "rew": 8060.25, "rew_std": 2501.7125259509735, "Agent": "iqn"}, {"env_step": 2700000, "rew": 8047.0, "rew_std": 1672.755511125281, "Agent": "iqn"}, {"env_step": 2800000, "rew": 8176.0, "rew_std": 3218.092447397992, "Agent": "iqn"}, {"env_step": 2900000, "rew": 9079.25, "rew_std": 2817.5170917848927, "Agent": "iqn"}, {"env_step": 3000000, "rew": 9333.5, "rew_std": 1586.5446731813133, "Agent": "iqn"}, {"env_step": 3100000, "rew": 11244.75, "rew_std": 1804.940944324772, "Agent": "iqn"}, {"env_step": 3200000, "rew": 9774.75, "rew_std": 2385.623988079429, "Agent": "iqn"}, {"env_step": 3300000, "rew": 10427.5, "rew_std": 2821.736167681167, "Agent": "iqn"}, {"env_step": 3400000, "rew": 9773.25, "rew_std": 2530.4006723244443, "Agent": "iqn"}, {"env_step": 3500000, "rew": 10958.5, "rew_std": 1914.0373559572968, "Agent": "iqn"}, {"env_step": 3600000, "rew": 11481.25, "rew_std": 2320.765027420915, "Agent": "iqn"}, {"env_step": 3700000, "rew": 10402.0, "rew_std": 2840.605525235773, "Agent": "iqn"}, {"env_step": 3800000, "rew": 11571.25, "rew_std": 1838.5531845720427, "Agent": "iqn"}, {"env_step": 3900000, "rew": 12558.75, "rew_std": 1597.0246749815733, "Agent": "iqn"}, {"env_step": 4000000, "rew": 12249.5, "rew_std": 1836.1981102266716, "Agent": "iqn"}, {"env_step": 4100000, "rew": 12411.5, "rew_std": 1798.764228574718, "Agent": "iqn"}, {"env_step": 4200000, "rew": 12926.75, "rew_std": 1323.884459648953, "Agent": "iqn"}, {"env_step": 4300000, "rew": 11794.75, "rew_std": 2639.6958750015124, "Agent": "iqn"}, {"env_step": 4400000, "rew": 12201.0, "rew_std": 1702.2159087495334, "Agent": "iqn"}, {"env_step": 4500000, "rew": 12271.25, "rew_std": 1584.632548100663, "Agent": "iqn"}, {"env_step": 4600000, "rew": 12395.25, "rew_std": 1911.1424757196937, "Agent": "iqn"}, {"env_step": 4700000, "rew": 12780.0, "rew_std": 1188.934396844502, "Agent": "iqn"}, {"env_step": 4800000, "rew": 12680.5, "rew_std": 1798.4388368804762, "Agent": "iqn"}, {"env_step": 4900000, "rew": 11659.0, "rew_std": 1524.3105818697186, "Agent": "iqn"}, {"env_step": 5000000, "rew": 12834.25, "rew_std": 1934.9157119885094, "Agent": "iqn"}, {"env_step": 5100000, "rew": 13496.0, "rew_std": 1634.7783488901484, "Agent": "iqn"}, {"env_step": 5200000, "rew": 13142.75, "rew_std": 1530.6499640675527, "Agent": "iqn"}, {"env_step": 5300000, "rew": 12664.75, "rew_std": 2404.7719356521106, "Agent": "iqn"}, {"env_step": 5400000, "rew": 12944.25, "rew_std": 2205.103186361128, "Agent": "iqn"}, {"env_step": 5500000, "rew": 13810.25, "rew_std": 2059.245750875791, "Agent": "iqn"}, {"env_step": 5600000, "rew": 13504.0, "rew_std": 849.1313208214616, "Agent": "iqn"}, {"env_step": 5700000, "rew": 13502.25, "rew_std": 1435.742599667503, "Agent": "iqn"}, {"env_step": 5800000, "rew": 14175.25, "rew_std": 1070.7231493247916, "Agent": "iqn"}, {"env_step": 5900000, "rew": 13746.0, "rew_std": 1353.6211619208677, "Agent": "iqn"}, {"env_step": 6000000, "rew": 14359.75, "rew_std": 987.1046360442241, "Agent": "iqn"}, {"env_step": 6100000, "rew": 13638.25, "rew_std": 2135.9354069119227, "Agent": "iqn"}, {"env_step": 6200000, "rew": 14398.0, "rew_std": 724.5531381479208, "Agent": "iqn"}, {"env_step": 6300000, "rew": 13681.25, "rew_std": 1508.860600751441, "Agent": "iqn"}, {"env_step": 6400000, "rew": 12862.0, "rew_std": 2345.081501781974, "Agent": "iqn"}, {"env_step": 6500000, "rew": 12578.5, "rew_std": 3452.268855405094, "Agent": "iqn"}, {"env_step": 6600000, "rew": 13525.25, "rew_std": 1754.864115109771, "Agent": "iqn"}, {"env_step": 6700000, "rew": 14026.75, "rew_std": 1140.708688710663, "Agent": "iqn"}, {"env_step": 6800000, "rew": 14103.75, "rew_std": 1377.3363106010092, "Agent": "iqn"}, {"env_step": 6900000, "rew": 13723.5, "rew_std": 1402.6114928945933, "Agent": "iqn"}, {"env_step": 7000000, "rew": 13494.25, "rew_std": 997.4141880382492, "Agent": "iqn"}, {"env_step": 7100000, "rew": 14152.25, "rew_std": 709.2394253705867, "Agent": "iqn"}, {"env_step": 7200000, "rew": 13685.25, "rew_std": 1417.7761856160514, "Agent": "iqn"}, {"env_step": 7300000, "rew": 13408.25, "rew_std": 2077.5096419752185, "Agent": "iqn"}, {"env_step": 7400000, "rew": 14233.0, "rew_std": 909.7477672410084, "Agent": "iqn"}, {"env_step": 7500000, "rew": 14091.5, "rew_std": 743.8003764451857, "Agent": "iqn"}, {"env_step": 7600000, "rew": 13211.75, "rew_std": 1589.0996074821742, "Agent": "iqn"}, {"env_step": 7700000, "rew": 13444.5, "rew_std": 1892.1039215645635, "Agent": "iqn"}, {"env_step": 7800000, "rew": 13603.25, "rew_std": 2529.7435764322045, "Agent": "iqn"}, {"env_step": 7900000, "rew": 13292.25, "rew_std": 3160.3117824828614, "Agent": "iqn"}, {"env_step": 8000000, "rew": 14121.75, "rew_std": 818.3054518332382, "Agent": "iqn"}, {"env_step": 8100000, "rew": 14027.0, "rew_std": 721.3241296393737, "Agent": "iqn"}, {"env_step": 8200000, "rew": 14095.25, "rew_std": 599.5054732861078, "Agent": "iqn"}, {"env_step": 8300000, "rew": 14409.25, "rew_std": 808.6462839214684, "Agent": "iqn"}, {"env_step": 8400000, "rew": 13536.75, "rew_std": 753.1708388539747, "Agent": "iqn"}, {"env_step": 8500000, "rew": 13976.5, "rew_std": 988.6829623291786, "Agent": "iqn"}, {"env_step": 8600000, "rew": 13914.5, "rew_std": 1239.5683724587361, "Agent": "iqn"}, {"env_step": 8700000, "rew": 14257.0, "rew_std": 1150.6013645046662, "Agent": "iqn"}, {"env_step": 8800000, "rew": 13446.5, "rew_std": 1551.8111193054392, "Agent": "iqn"}, {"env_step": 8900000, "rew": 14032.5, "rew_std": 1186.8413963120768, "Agent": "iqn"}, {"env_step": 9000000, "rew": 14378.5, "rew_std": 943.7049326987753, "Agent": "iqn"}, {"env_step": 9100000, "rew": 14320.75, "rew_std": 647.3224177332344, "Agent": "iqn"}, {"env_step": 9200000, "rew": 13960.25, "rew_std": 1017.343630490701, "Agent": "iqn"}, {"env_step": 9300000, "rew": 13514.25, "rew_std": 1402.1367845185434, "Agent": "iqn"}, {"env_step": 9400000, "rew": 13712.25, "rew_std": 1607.3042065831844, "Agent": "iqn"}, {"env_step": 9500000, "rew": 14267.75, "rew_std": 724.1317645981289, "Agent": "iqn"}, {"env_step": 9600000, "rew": 14351.75, "rew_std": 780.0296869350551, "Agent": "iqn"}, {"env_step": 9700000, "rew": 13220.25, "rew_std": 1425.2001833075942, "Agent": "iqn"}, {"env_step": 9800000, "rew": 14156.5, "rew_std": 853.8107225843443, "Agent": "iqn"}, {"env_step": 9900000, "rew": 14273.75, "rew_std": 895.3443820675931, "Agent": "iqn"}, {"env_step": 10000000, "rew": 13774.75, "rew_std": 1513.8219223211163, "Agent": "iqn"}, {"env_step": 0, "rew": 45.5, "rew_std": 47.75981574503821, "Agent": "rainbow"}, {"env_step": 100000, "rew": 284.5, "rew_std": 61.47967143698801, "Agent": "rainbow"}, {"env_step": 200000, "rew": 285.0, "rew_std": 74.47314952383846, "Agent": "rainbow"}, {"env_step": 300000, "rew": 377.75, "rew_std": 92.13746523537534, "Agent": "rainbow"}, {"env_step": 400000, "rew": 395.75, "rew_std": 96.40442157909564, "Agent": "rainbow"}, {"env_step": 500000, "rew": 446.5, "rew_std": 135.95587519485872, "Agent": "rainbow"}, {"env_step": 600000, "rew": 509.0, "rew_std": 112.18400064180275, "Agent": "rainbow"}, {"env_step": 700000, "rew": 842.0, "rew_std": 379.03957577012983, "Agent": "rainbow"}, {"env_step": 800000, "rew": 841.25, "rew_std": 334.61031439571616, "Agent": "rainbow"}, {"env_step": 900000, "rew": 1965.0, "rew_std": 1128.5698914998575, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 2198.25, "rew_std": 836.4859906178943, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 3015.75, "rew_std": 848.7866707836546, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 2877.0, "rew_std": 996.3312702108672, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 3242.0, "rew_std": 876.3666470148211, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 3739.5, "rew_std": 779.8091112573641, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 3878.5, "rew_std": 610.4621200369438, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 3686.75, "rew_std": 1020.1911891895558, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 3802.5, "rew_std": 775.4450335130144, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 4826.75, "rew_std": 1208.2508276430024, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 5678.25, "rew_std": 1521.4220527191, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 5642.5, "rew_std": 2018.9904655545058, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 7018.0, "rew_std": 2637.9750283124363, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 6920.25, "rew_std": 1881.316178237991, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 7435.0, "rew_std": 1537.6528379318916, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 7692.5, "rew_std": 1343.7070923382075, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 8006.25, "rew_std": 1876.4488568836616, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 9979.75, "rew_std": 2021.7954427933603, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 9089.75, "rew_std": 1605.1473647301048, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 8764.75, "rew_std": 1827.6663569973596, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 9663.0, "rew_std": 2015.3541252097607, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 9934.5, "rew_std": 2286.617261371041, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 10924.25, "rew_std": 2628.7715881186787, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 9174.75, "rew_std": 1997.3590219337134, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 10324.25, "rew_std": 1182.9740328933683, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 10506.5, "rew_std": 1664.2221155843351, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 10675.0, "rew_std": 2079.8194032175006, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 10794.25, "rew_std": 2335.775848085599, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 10830.25, "rew_std": 2143.70282746933, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 11664.75, "rew_std": 1526.7708775386043, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 10242.5, "rew_std": 2334.839662589275, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 11877.25, "rew_std": 1986.8088263594966, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 11280.25, "rew_std": 2765.102721871287, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 12994.5, "rew_std": 1754.1610530393154, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 10860.25, "rew_std": 1974.6045331913933, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 10636.25, "rew_std": 2674.058537597859, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 12535.5, "rew_std": 1929.7117012652434, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 12290.5, "rew_std": 1829.934015203827, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 12177.5, "rew_std": 946.7675269040442, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 13175.75, "rew_std": 1413.9178945398492, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 12883.5, "rew_std": 1610.216677966043, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 12284.5, "rew_std": 1809.4221453270654, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 12318.0, "rew_std": 2168.0633062712905, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 12730.25, "rew_std": 1575.0005753967203, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 11980.25, "rew_std": 1916.1492798057254, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 12032.75, "rew_std": 2195.3403637021756, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 12618.0, "rew_std": 2118.3926099757805, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 13014.25, "rew_std": 1486.7145195026515, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 12690.0, "rew_std": 1458.9743829142444, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 12033.5, "rew_std": 1977.8407418192194, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 12640.25, "rew_std": 2624.1961745456456, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 13131.25, "rew_std": 1906.204097807997, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 13501.75, "rew_std": 1226.5200008560805, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 13880.0, "rew_std": 1096.272662251504, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 12978.75, "rew_std": 1734.9788363262533, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 12417.0, "rew_std": 1276.8250663266288, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 13424.5, "rew_std": 1740.133543725883, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 13237.0, "rew_std": 1644.9296337533713, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 13351.75, "rew_std": 1120.8969901378093, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 12263.0, "rew_std": 2282.7893573433357, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 12439.0, "rew_std": 2598.2990108915487, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 14034.5, "rew_std": 744.4837137238128, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 13683.25, "rew_std": 901.8238810876545, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 14111.25, "rew_std": 1060.766379793402, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 13421.75, "rew_std": 1568.2095881928537, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 14206.5, "rew_std": 607.6617068731582, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 13354.25, "rew_std": 1601.6690708445362, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 13701.75, "rew_std": 1030.2663793893305, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 13039.0, "rew_std": 2426.61317477673, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 13988.25, "rew_std": 1832.0964937742772, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 13303.0, "rew_std": 1248.9764809635128, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 13551.25, "rew_std": 1319.6809510256637, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 13257.25, "rew_std": 1674.4097654098891, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 13652.5, "rew_std": 1983.858613913804, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 13802.5, "rew_std": 1365.1304882684292, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 13834.5, "rew_std": 1055.2753195256678, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 14132.75, "rew_std": 759.6795788357089, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 13816.5, "rew_std": 838.3877384599563, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 13764.0, "rew_std": 1449.42367857021, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 13053.75, "rew_std": 1003.1601629351118, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 13302.75, "rew_std": 1787.7211226866455, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 13252.75, "rew_std": 1108.8256456720326, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 13711.75, "rew_std": 1272.3845969281458, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 13983.5, "rew_std": 1598.7660085203213, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 13033.25, "rew_std": 1330.3514808124958, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 14224.75, "rew_std": 1230.1089636694792, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 13983.25, "rew_std": 1469.7389436563217, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 12979.5, "rew_std": 1610.91891478125, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 13711.25, "rew_std": 1179.091413970944, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 13414.0, "rew_std": 2159.0412223947924, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 13838.75, "rew_std": 1349.4764030912138, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 14035.0, "rew_std": 1246.866572653225, "Agent": "rainbow"}, {"env_step": 0, "rew": 120.5, "rew_std": 101.5, "Agent": "ppo"}, {"env_step": 100000, "rew": 273.0, "rew_std": 28.956864471140516, "Agent": "ppo"}, {"env_step": 200000, "rew": 355.0, "rew_std": 89.81230427953622, "Agent": "ppo"}, {"env_step": 300000, "rew": 391.5, "rew_std": 92.91931984253867, "Agent": "ppo"}, {"env_step": 400000, "rew": 474.0, "rew_std": 108.15035829806575, "Agent": "ppo"}, {"env_step": 500000, "rew": 542.75, "rew_std": 105.84452040611266, "Agent": "ppo"}, {"env_step": 600000, "rew": 621.75, "rew_std": 77.6695725493581, "Agent": "ppo"}, {"env_step": 700000, "rew": 641.75, "rew_std": 85.77623505377233, "Agent": "ppo"}, {"env_step": 800000, "rew": 672.25, "rew_std": 64.53148456373835, "Agent": "ppo"}, {"env_step": 900000, "rew": 744.75, "rew_std": 134.25465541276398, "Agent": "ppo"}, {"env_step": 1000000, "rew": 791.25, "rew_std": 143.7891251103504, "Agent": "ppo"}, {"env_step": 1100000, "rew": 995.0, "rew_std": 389.2460661329797, "Agent": "ppo"}, {"env_step": 1200000, "rew": 817.25, "rew_std": 168.63588734311568, "Agent": "ppo"}, {"env_step": 1300000, "rew": 1099.0, "rew_std": 655.2797112684018, "Agent": "ppo"}, {"env_step": 1400000, "rew": 1188.0, "rew_std": 663.5, "Agent": "ppo"}, {"env_step": 1500000, "rew": 1322.0, "rew_std": 450.0927682156202, "Agent": "ppo"}, {"env_step": 1600000, "rew": 1452.75, "rew_std": 704.6368302182337, "Agent": "ppo"}, {"env_step": 1700000, "rew": 1558.5, "rew_std": 423.40170051618827, "Agent": "ppo"}, {"env_step": 1800000, "rew": 1552.75, "rew_std": 663.306537356598, "Agent": "ppo"}, {"env_step": 1900000, "rew": 1814.25, "rew_std": 756.1093257591788, "Agent": "ppo"}, {"env_step": 2000000, "rew": 1824.0, "rew_std": 703.5785315087435, "Agent": "ppo"}, {"env_step": 2100000, "rew": 1752.25, "rew_std": 750.6567541160207, "Agent": "ppo"}, {"env_step": 2200000, "rew": 2510.75, "rew_std": 872.3481601402045, "Agent": "ppo"}, {"env_step": 2300000, "rew": 2298.25, "rew_std": 906.4326022931876, "Agent": "ppo"}, {"env_step": 2400000, "rew": 2231.0, "rew_std": 897.2521942018309, "Agent": "ppo"}, {"env_step": 2500000, "rew": 2028.0, "rew_std": 938.4780231843471, "Agent": "ppo"}, {"env_step": 2600000, "rew": 2503.25, "rew_std": 949.5203065232465, "Agent": "ppo"}, {"env_step": 2700000, "rew": 2804.5, "rew_std": 959.1681291619317, "Agent": "ppo"}, {"env_step": 2800000, "rew": 2946.25, "rew_std": 708.6265324555665, "Agent": "ppo"}, {"env_step": 2900000, "rew": 3231.75, "rew_std": 616.26298160769, "Agent": "ppo"}, {"env_step": 3000000, "rew": 2883.25, "rew_std": 727.0738012746712, "Agent": "ppo"}, {"env_step": 3100000, "rew": 3300.5, "rew_std": 795.6183130119617, "Agent": "ppo"}, {"env_step": 3200000, "rew": 3390.5, "rew_std": 828.5211222413102, "Agent": "ppo"}, {"env_step": 3300000, "rew": 3235.5, "rew_std": 996.1192197724126, "Agent": "ppo"}, {"env_step": 3400000, "rew": 3114.0, "rew_std": 1074.6076028020648, "Agent": "ppo"}, {"env_step": 3500000, "rew": 3412.75, "rew_std": 1089.8081539885816, "Agent": "ppo"}, {"env_step": 3600000, "rew": 3153.75, "rew_std": 1106.7566636347847, "Agent": "ppo"}, {"env_step": 3700000, "rew": 3294.75, "rew_std": 694.6846856668138, "Agent": "ppo"}, {"env_step": 3800000, "rew": 3217.0, "rew_std": 1153.753548206895, "Agent": "ppo"}, {"env_step": 3900000, "rew": 3735.5, "rew_std": 868.4992803681532, "Agent": "ppo"}, {"env_step": 4000000, "rew": 3744.0, "rew_std": 798.573885122723, "Agent": "ppo"}, {"env_step": 4100000, "rew": 3626.75, "rew_std": 879.9460565852886, "Agent": "ppo"}, {"env_step": 4200000, "rew": 3621.5, "rew_std": 977.4035758068414, "Agent": "ppo"}, {"env_step": 4300000, "rew": 3884.5, "rew_std": 623.5030072100695, "Agent": "ppo"}, {"env_step": 4400000, "rew": 3692.25, "rew_std": 711.3521016346265, "Agent": "ppo"}, {"env_step": 4500000, "rew": 3992.75, "rew_std": 715.286175247362, "Agent": "ppo"}, {"env_step": 4600000, "rew": 4163.0, "rew_std": 830.2919667201412, "Agent": "ppo"}, {"env_step": 4700000, "rew": 4100.75, "rew_std": 683.023654422012, "Agent": "ppo"}, {"env_step": 4800000, "rew": 4077.5, "rew_std": 490.6844709179209, "Agent": "ppo"}, {"env_step": 4900000, "rew": 4007.25, "rew_std": 496.95126773155533, "Agent": "ppo"}, {"env_step": 5000000, "rew": 4787.5, "rew_std": 1021.3936557468918, "Agent": "ppo"}, {"env_step": 5100000, "rew": 4553.0, "rew_std": 615.2263810988602, "Agent": "ppo"}, {"env_step": 5200000, "rew": 4548.75, "rew_std": 416.08029573629176, "Agent": "ppo"}, {"env_step": 5300000, "rew": 4595.0, "rew_std": 509.9178855462907, "Agent": "ppo"}, {"env_step": 5400000, "rew": 5037.5, "rew_std": 584.2281232532374, "Agent": "ppo"}, {"env_step": 5500000, "rew": 5001.75, "rew_std": 1064.1552107188124, "Agent": "ppo"}, {"env_step": 5600000, "rew": 5132.75, "rew_std": 1378.285370487549, "Agent": "ppo"}, {"env_step": 5700000, "rew": 5175.5, "rew_std": 1010.7384676561984, "Agent": "ppo"}, {"env_step": 5800000, "rew": 4833.5, "rew_std": 789.5474969879899, "Agent": "ppo"}, {"env_step": 5900000, "rew": 5724.0, "rew_std": 707.8031152799484, "Agent": "ppo"}, {"env_step": 6000000, "rew": 6142.5, "rew_std": 1675.208569104158, "Agent": "ppo"}, {"env_step": 6100000, "rew": 6317.0, "rew_std": 1503.244324785562, "Agent": "ppo"}, {"env_step": 6200000, "rew": 6381.75, "rew_std": 1400.6998473977214, "Agent": "ppo"}, {"env_step": 6300000, "rew": 6283.0, "rew_std": 1507.1785726980065, "Agent": "ppo"}, {"env_step": 6400000, "rew": 6748.0, "rew_std": 1430.778983630945, "Agent": "ppo"}, {"env_step": 6500000, "rew": 7201.75, "rew_std": 1294.4265380854952, "Agent": "ppo"}, {"env_step": 6600000, "rew": 6559.0, "rew_std": 1157.9767916499882, "Agent": "ppo"}, {"env_step": 6700000, "rew": 7433.5, "rew_std": 1716.4509896877335, "Agent": "ppo"}, {"env_step": 6800000, "rew": 7610.5, "rew_std": 1812.574412265604, "Agent": "ppo"}, {"env_step": 6900000, "rew": 8195.0, "rew_std": 1976.1841386874858, "Agent": "ppo"}, {"env_step": 7000000, "rew": 8271.5, "rew_std": 1789.7011622055788, "Agent": "ppo"}, {"env_step": 7100000, "rew": 7825.5, "rew_std": 1272.6767067877058, "Agent": "ppo"}, {"env_step": 7200000, "rew": 8352.75, "rew_std": 1310.4419340436264, "Agent": "ppo"}, {"env_step": 7300000, "rew": 8443.0, "rew_std": 1754.0131841009634, "Agent": "ppo"}, {"env_step": 7400000, "rew": 8361.25, "rew_std": 1613.0232678111001, "Agent": "ppo"}, {"env_step": 7500000, "rew": 8785.5, "rew_std": 1928.0082987373264, "Agent": "ppo"}, {"env_step": 7600000, "rew": 9088.0, "rew_std": 1135.7738551313814, "Agent": "ppo"}, {"env_step": 7700000, "rew": 8585.25, "rew_std": 1348.3320483100592, "Agent": "ppo"}, {"env_step": 7800000, "rew": 8759.25, "rew_std": 1379.0055520192802, "Agent": "ppo"}, {"env_step": 7900000, "rew": 9218.5, "rew_std": 1970.6262329523577, "Agent": "ppo"}, {"env_step": 8000000, "rew": 9573.25, "rew_std": 1635.5530601298144, "Agent": "ppo"}, {"env_step": 8100000, "rew": 10431.25, "rew_std": 1564.9469839262927, "Agent": "ppo"}, {"env_step": 8200000, "rew": 9307.5, "rew_std": 1389.4486316521384, "Agent": "ppo"}, {"env_step": 8300000, "rew": 9908.75, "rew_std": 1632.5357002222033, "Agent": "ppo"}, {"env_step": 8400000, "rew": 10750.5, "rew_std": 2245.378531562106, "Agent": "ppo"}, {"env_step": 8500000, "rew": 10358.5, "rew_std": 2260.2992611599025, "Agent": "ppo"}, {"env_step": 8600000, "rew": 10700.25, "rew_std": 1594.5439982954374, "Agent": "ppo"}, {"env_step": 8700000, "rew": 10038.25, "rew_std": 1889.7635599460584, "Agent": "ppo"}, {"env_step": 8800000, "rew": 9823.0, "rew_std": 1878.6184418343178, "Agent": "ppo"}, {"env_step": 8900000, "rew": 10836.5, "rew_std": 1715.2179890614486, "Agent": "ppo"}, {"env_step": 9000000, "rew": 10589.0, "rew_std": 1656.9747282321478, "Agent": "ppo"}, {"env_step": 9100000, "rew": 10209.75, "rew_std": 1596.2845336906576, "Agent": "ppo"}, {"env_step": 9200000, "rew": 11638.75, "rew_std": 2334.8370526655603, "Agent": "ppo"}, {"env_step": 9300000, "rew": 11236.5, "rew_std": 1308.257046608196, "Agent": "ppo"}, {"env_step": 9400000, "rew": 12341.75, "rew_std": 1760.6944830094742, "Agent": "ppo"}, {"env_step": 9500000, "rew": 11866.0, "rew_std": 1635.246617486182, "Agent": "ppo"}, {"env_step": 9600000, "rew": 11265.5, "rew_std": 1304.1528859761804, "Agent": "ppo"}, {"env_step": 9700000, "rew": 11678.5, "rew_std": 1495.5292541438298, "Agent": "ppo"}, {"env_step": 9800000, "rew": 11504.25, "rew_std": 1666.65422703691, "Agent": "ppo"}, {"env_step": 9900000, "rew": 11494.0, "rew_std": 1494.6768881601133, "Agent": "ppo"}, {"env_step": 10000000, "rew": 12188.5, "rew_std": 1292.4967117946567, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/SeaquestNoFrameskip-v4/result.json b/examples/atari/benchmark/SeaquestNoFrameskip-v4/result.json new file mode 100644 index 000000000..9d225cf2b --- /dev/null +++ b/examples/atari/benchmark/SeaquestNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 32.2, "rew_std": 46.315872009495834, "Agent": "c51"}, {"env_step": 100000, "rew": 150.4, "rew_std": 44.16152171291203, "Agent": "c51"}, {"env_step": 200000, "rew": 128.6, "rew_std": 49.11252386102755, "Agent": "c51"}, {"env_step": 300000, "rew": 247.0, "rew_std": 99.90095094642493, "Agent": "c51"}, {"env_step": 400000, "rew": 316.8, "rew_std": 101.15809409038903, "Agent": "c51"}, {"env_step": 500000, "rew": 294.4, "rew_std": 154.54138604270378, "Agent": "c51"}, {"env_step": 600000, "rew": 319.4, "rew_std": 168.48513287527777, "Agent": "c51"}, {"env_step": 700000, "rew": 447.6, "rew_std": 228.1434636363707, "Agent": "c51"}, {"env_step": 800000, "rew": 584.0, "rew_std": 225.6138293633615, "Agent": "c51"}, {"env_step": 900000, "rew": 728.2, "rew_std": 275.2329195427029, "Agent": "c51"}, {"env_step": 1000000, "rew": 972.4, "rew_std": 346.5323072961596, "Agent": "c51"}, {"env_step": 1100000, "rew": 1153.0, "rew_std": 393.3764100705582, "Agent": "c51"}, {"env_step": 1200000, "rew": 1589.2, "rew_std": 267.4624459620453, "Agent": "c51"}, {"env_step": 1300000, "rew": 1583.4, "rew_std": 262.64508371564847, "Agent": "c51"}, {"env_step": 1400000, "rew": 1678.6, "rew_std": 221.38482332806828, "Agent": "c51"}, {"env_step": 1500000, "rew": 1636.2, "rew_std": 262.5969535238366, "Agent": "c51"}, {"env_step": 1600000, "rew": 1672.2, "rew_std": 191.08835652650322, "Agent": "c51"}, {"env_step": 1700000, "rew": 1610.6, "rew_std": 330.96591969566896, "Agent": "c51"}, {"env_step": 1800000, "rew": 1730.3, "rew_std": 421.8265164733009, "Agent": "c51"}, {"env_step": 1900000, "rew": 1915.1, "rew_std": 466.08463823644735, "Agent": "c51"}, {"env_step": 2000000, "rew": 1765.0, "rew_std": 223.29218526406157, "Agent": "c51"}, {"env_step": 2100000, "rew": 1774.2, "rew_std": 280.23483009790203, "Agent": "c51"}, {"env_step": 2200000, "rew": 1940.0, "rew_std": 288.7337874236405, "Agent": "c51"}, {"env_step": 2300000, "rew": 1953.0, "rew_std": 183.59793027155834, "Agent": "c51"}, {"env_step": 2400000, "rew": 1960.0, "rew_std": 160.45186193996005, "Agent": "c51"}, {"env_step": 2500000, "rew": 1876.8, "rew_std": 178.058866670548, "Agent": "c51"}, {"env_step": 2600000, "rew": 1938.3, "rew_std": 339.1395140646398, "Agent": "c51"}, {"env_step": 2700000, "rew": 2020.2, "rew_std": 316.60505365518094, "Agent": "c51"}, {"env_step": 2800000, "rew": 1987.6, "rew_std": 300.36351309704713, "Agent": "c51"}, {"env_step": 2900000, "rew": 1866.7, "rew_std": 246.95750646619348, "Agent": "c51"}, {"env_step": 3000000, "rew": 1934.9, "rew_std": 380.61383316952634, "Agent": "c51"}, {"env_step": 3100000, "rew": 2063.6, "rew_std": 397.0740988782824, "Agent": "c51"}, {"env_step": 3200000, "rew": 2049.0, "rew_std": 507.7331976540435, "Agent": "c51"}, {"env_step": 3300000, "rew": 2166.0, "rew_std": 523.4004203284518, "Agent": "c51"}, {"env_step": 3400000, "rew": 2154.2, "rew_std": 581.4135877325194, "Agent": "c51"}, {"env_step": 3500000, "rew": 2041.9, "rew_std": 658.6993927430024, "Agent": "c51"}, {"env_step": 3600000, "rew": 2267.9, "rew_std": 511.7625328216203, "Agent": "c51"}, {"env_step": 3700000, "rew": 2240.1, "rew_std": 415.064440779983, "Agent": "c51"}, {"env_step": 3800000, "rew": 2300.7, "rew_std": 460.17693336367915, "Agent": "c51"}, {"env_step": 3900000, "rew": 2148.5, "rew_std": 605.8113980439787, "Agent": "c51"}, {"env_step": 4000000, "rew": 2083.7, "rew_std": 491.9182960614496, "Agent": "c51"}, {"env_step": 4100000, "rew": 2218.3, "rew_std": 504.38795584351533, "Agent": "c51"}, {"env_step": 4200000, "rew": 2268.6, "rew_std": 484.98725756456736, "Agent": "c51"}, {"env_step": 4300000, "rew": 2227.8, "rew_std": 526.6742446712199, "Agent": "c51"}, {"env_step": 4400000, "rew": 2411.4, "rew_std": 649.1550200067777, "Agent": "c51"}, {"env_step": 4500000, "rew": 2175.5, "rew_std": 458.5758933917046, "Agent": "c51"}, {"env_step": 4600000, "rew": 2318.9, "rew_std": 604.9889998999981, "Agent": "c51"}, {"env_step": 4700000, "rew": 2327.4, "rew_std": 395.89195495741006, "Agent": "c51"}, {"env_step": 4800000, "rew": 2369.6, "rew_std": 508.4897639087733, "Agent": "c51"}, {"env_step": 4900000, "rew": 2172.9, "rew_std": 587.6421445063313, "Agent": "c51"}, {"env_step": 5000000, "rew": 2279.5, "rew_std": 422.98540163934734, "Agent": "c51"}, {"env_step": 5100000, "rew": 2513.7, "rew_std": 757.7894232568834, "Agent": "c51"}, {"env_step": 5200000, "rew": 2347.0, "rew_std": 447.44988546204814, "Agent": "c51"}, {"env_step": 5300000, "rew": 2241.3, "rew_std": 527.0457380531599, "Agent": "c51"}, {"env_step": 5400000, "rew": 2434.3, "rew_std": 574.2675421787305, "Agent": "c51"}, {"env_step": 5500000, "rew": 2543.6, "rew_std": 672.8527624971157, "Agent": "c51"}, {"env_step": 5600000, "rew": 2479.0, "rew_std": 647.793794351258, "Agent": "c51"}, {"env_step": 5700000, "rew": 2461.7, "rew_std": 558.4800891705988, "Agent": "c51"}, {"env_step": 5800000, "rew": 2491.6, "rew_std": 587.2570476375741, "Agent": "c51"}, {"env_step": 5900000, "rew": 2470.1, "rew_std": 801.6780463502789, "Agent": "c51"}, {"env_step": 6000000, "rew": 2324.7, "rew_std": 429.707353904957, "Agent": "c51"}, {"env_step": 6100000, "rew": 2391.7, "rew_std": 472.14575080159307, "Agent": "c51"}, {"env_step": 6200000, "rew": 2537.3, "rew_std": 751.1694948545235, "Agent": "c51"}, {"env_step": 6300000, "rew": 2379.9, "rew_std": 653.9957874482068, "Agent": "c51"}, {"env_step": 6400000, "rew": 2658.8, "rew_std": 892.9185629160143, "Agent": "c51"}, {"env_step": 6500000, "rew": 2667.7, "rew_std": 955.2983879396008, "Agent": "c51"}, {"env_step": 6600000, "rew": 2439.5, "rew_std": 665.1733984458489, "Agent": "c51"}, {"env_step": 6700000, "rew": 2414.2, "rew_std": 540.237318222279, "Agent": "c51"}, {"env_step": 6800000, "rew": 2644.7, "rew_std": 830.3852178356741, "Agent": "c51"}, {"env_step": 6900000, "rew": 2430.4, "rew_std": 685.8056867655736, "Agent": "c51"}, {"env_step": 7000000, "rew": 2793.1, "rew_std": 1111.4479250059358, "Agent": "c51"}, {"env_step": 7100000, "rew": 2576.3, "rew_std": 875.817338261809, "Agent": "c51"}, {"env_step": 7200000, "rew": 2954.8, "rew_std": 1122.580758787536, "Agent": "c51"}, {"env_step": 7300000, "rew": 2826.6, "rew_std": 955.3017533742938, "Agent": "c51"}, {"env_step": 7400000, "rew": 2654.4, "rew_std": 863.3571914335341, "Agent": "c51"}, {"env_step": 7500000, "rew": 2642.0, "rew_std": 993.2044099781273, "Agent": "c51"}, {"env_step": 7600000, "rew": 2686.2, "rew_std": 1022.8722109823885, "Agent": "c51"}, {"env_step": 7700000, "rew": 2804.2, "rew_std": 1017.5520428951043, "Agent": "c51"}, {"env_step": 7800000, "rew": 2618.4, "rew_std": 754.956846448855, "Agent": "c51"}, {"env_step": 7900000, "rew": 2661.4, "rew_std": 895.5007761023996, "Agent": "c51"}, {"env_step": 8000000, "rew": 2549.6, "rew_std": 666.4779366190602, "Agent": "c51"}, {"env_step": 8100000, "rew": 2469.4, "rew_std": 947.9606742898145, "Agent": "c51"}, {"env_step": 8200000, "rew": 2505.2, "rew_std": 674.0418087923033, "Agent": "c51"}, {"env_step": 8300000, "rew": 2662.4, "rew_std": 742.0776509234057, "Agent": "c51"}, {"env_step": 8400000, "rew": 2667.8, "rew_std": 823.5222887086907, "Agent": "c51"}, {"env_step": 8500000, "rew": 2946.4, "rew_std": 1133.8231960936414, "Agent": "c51"}, {"env_step": 8600000, "rew": 2712.2, "rew_std": 895.4735953672783, "Agent": "c51"}, {"env_step": 8700000, "rew": 2573.9, "rew_std": 830.3705739005928, "Agent": "c51"}, {"env_step": 8800000, "rew": 2695.3, "rew_std": 1011.963146562166, "Agent": "c51"}, {"env_step": 8900000, "rew": 2988.3, "rew_std": 1189.3779929021725, "Agent": "c51"}, {"env_step": 9000000, "rew": 3090.7, "rew_std": 1242.8095630465675, "Agent": "c51"}, {"env_step": 9100000, "rew": 2933.6, "rew_std": 1181.3922464617751, "Agent": "c51"}, {"env_step": 9200000, "rew": 2749.2, "rew_std": 1097.8828534957636, "Agent": "c51"}, {"env_step": 9300000, "rew": 2900.2, "rew_std": 1171.506961140223, "Agent": "c51"}, {"env_step": 9400000, "rew": 2628.8, "rew_std": 762.4866949658859, "Agent": "c51"}, {"env_step": 9500000, "rew": 2926.8, "rew_std": 1080.2360667928099, "Agent": "c51"}, {"env_step": 9600000, "rew": 2832.0, "rew_std": 1037.878316567024, "Agent": "c51"}, {"env_step": 9700000, "rew": 3305.4, "rew_std": 1524.3043790529503, "Agent": "c51"}, {"env_step": 9800000, "rew": 2810.2, "rew_std": 1373.4536613952434, "Agent": "c51"}, {"env_step": 9900000, "rew": 2678.6, "rew_std": 794.8096879127733, "Agent": "c51"}, {"env_step": 10000000, "rew": 2879.0, "rew_std": 1374.2044243852513, "Agent": "c51"}, {"env_step": 0, "rew": 67.6, "rew_std": 52.75452587219413, "Agent": "dqn"}, {"env_step": 100000, "rew": 221.0, "rew_std": 43.148580509676094, "Agent": "dqn"}, {"env_step": 200000, "rew": 284.2, "rew_std": 53.54960317313286, "Agent": "dqn"}, {"env_step": 300000, "rew": 255.8, "rew_std": 84.65671857566888, "Agent": "dqn"}, {"env_step": 400000, "rew": 283.4, "rew_std": 66.36294146585125, "Agent": "dqn"}, {"env_step": 500000, "rew": 266.6, "rew_std": 59.49151199961218, "Agent": "dqn"}, {"env_step": 600000, "rew": 290.4, "rew_std": 82.25715774326268, "Agent": "dqn"}, {"env_step": 700000, "rew": 346.2, "rew_std": 104.86353036208536, "Agent": "dqn"}, {"env_step": 800000, "rew": 407.4, "rew_std": 125.18801859603019, "Agent": "dqn"}, {"env_step": 900000, "rew": 519.8, "rew_std": 125.2436026310326, "Agent": "dqn"}, {"env_step": 1000000, "rew": 500.8, "rew_std": 113.11304080432106, "Agent": "dqn"}, {"env_step": 1100000, "rew": 857.6, "rew_std": 217.36200219909645, "Agent": "dqn"}, {"env_step": 1200000, "rew": 909.4, "rew_std": 323.0765234429763, "Agent": "dqn"}, {"env_step": 1300000, "rew": 1074.6, "rew_std": 300.64337677720425, "Agent": "dqn"}, {"env_step": 1400000, "rew": 1264.8, "rew_std": 315.2956707600027, "Agent": "dqn"}, {"env_step": 1500000, "rew": 1273.2, "rew_std": 365.40629441759756, "Agent": "dqn"}, {"env_step": 1600000, "rew": 1206.4, "rew_std": 444.22498804097006, "Agent": "dqn"}, {"env_step": 1700000, "rew": 1501.1, "rew_std": 372.9220964222957, "Agent": "dqn"}, {"env_step": 1800000, "rew": 1625.4, "rew_std": 438.0347474801514, "Agent": "dqn"}, {"env_step": 1900000, "rew": 1565.2, "rew_std": 472.6666478608365, "Agent": "dqn"}, {"env_step": 2000000, "rew": 1754.0, "rew_std": 312.49191989553907, "Agent": "dqn"}, {"env_step": 2100000, "rew": 1821.2, "rew_std": 352.37389233596747, "Agent": "dqn"}, {"env_step": 2200000, "rew": 1993.0, "rew_std": 548.2636227217706, "Agent": "dqn"}, {"env_step": 2300000, "rew": 1839.2, "rew_std": 397.0201002468263, "Agent": "dqn"}, {"env_step": 2400000, "rew": 2161.7, "rew_std": 328.52276937831874, "Agent": "dqn"}, {"env_step": 2500000, "rew": 2045.4, "rew_std": 817.1477467386177, "Agent": "dqn"}, {"env_step": 2600000, "rew": 1969.4, "rew_std": 666.9255130822332, "Agent": "dqn"}, {"env_step": 2700000, "rew": 2051.1, "rew_std": 532.0207608731073, "Agent": "dqn"}, {"env_step": 2800000, "rew": 2071.5, "rew_std": 529.4195406291686, "Agent": "dqn"}, {"env_step": 2900000, "rew": 1928.8, "rew_std": 357.8560604488905, "Agent": "dqn"}, {"env_step": 3000000, "rew": 2327.6, "rew_std": 610.7462975737143, "Agent": "dqn"}, {"env_step": 3100000, "rew": 2295.2, "rew_std": 519.696988638572, "Agent": "dqn"}, {"env_step": 3200000, "rew": 1959.3, "rew_std": 419.5507239893646, "Agent": "dqn"}, {"env_step": 3300000, "rew": 2432.6, "rew_std": 510.47276127135325, "Agent": "dqn"}, {"env_step": 3400000, "rew": 2435.4, "rew_std": 451.0752043728407, "Agent": "dqn"}, {"env_step": 3500000, "rew": 2519.0, "rew_std": 417.8040210433595, "Agent": "dqn"}, {"env_step": 3600000, "rew": 2485.6, "rew_std": 568.3300449562736, "Agent": "dqn"}, {"env_step": 3700000, "rew": 2359.6, "rew_std": 628.5970410366247, "Agent": "dqn"}, {"env_step": 3800000, "rew": 2478.4, "rew_std": 378.3150010242787, "Agent": "dqn"}, {"env_step": 3900000, "rew": 2657.6, "rew_std": 525.0781275200862, "Agent": "dqn"}, {"env_step": 4000000, "rew": 2616.8, "rew_std": 352.63715062369704, "Agent": "dqn"}, {"env_step": 4100000, "rew": 2332.2, "rew_std": 373.4396336759129, "Agent": "dqn"}, {"env_step": 4200000, "rew": 2553.5, "rew_std": 363.4631343066309, "Agent": "dqn"}, {"env_step": 4300000, "rew": 2390.0, "rew_std": 644.888207366207, "Agent": "dqn"}, {"env_step": 4400000, "rew": 2727.2, "rew_std": 635.8051273778783, "Agent": "dqn"}, {"env_step": 4500000, "rew": 2780.6, "rew_std": 470.3411953040048, "Agent": "dqn"}, {"env_step": 4600000, "rew": 2597.2, "rew_std": 523.4158576122813, "Agent": "dqn"}, {"env_step": 4700000, "rew": 2602.5, "rew_std": 744.5147748701835, "Agent": "dqn"}, {"env_step": 4800000, "rew": 2417.0, "rew_std": 749.8470510710835, "Agent": "dqn"}, {"env_step": 4900000, "rew": 2945.2, "rew_std": 587.9389083909995, "Agent": "dqn"}, {"env_step": 5000000, "rew": 2675.3, "rew_std": 784.2958689168265, "Agent": "dqn"}, {"env_step": 5100000, "rew": 2855.4, "rew_std": 1029.4697858606633, "Agent": "dqn"}, {"env_step": 5200000, "rew": 2557.8, "rew_std": 957.7696800379516, "Agent": "dqn"}, {"env_step": 5300000, "rew": 2583.4, "rew_std": 686.686566054703, "Agent": "dqn"}, {"env_step": 5400000, "rew": 2643.4, "rew_std": 625.6280364561678, "Agent": "dqn"}, {"env_step": 5500000, "rew": 2624.8, "rew_std": 485.9606568437408, "Agent": "dqn"}, {"env_step": 5600000, "rew": 2627.2, "rew_std": 482.2772646517769, "Agent": "dqn"}, {"env_step": 5700000, "rew": 2659.2, "rew_std": 828.4439389602655, "Agent": "dqn"}, {"env_step": 5800000, "rew": 2599.4, "rew_std": 550.9120074930297, "Agent": "dqn"}, {"env_step": 5900000, "rew": 2938.3, "rew_std": 744.541207724596, "Agent": "dqn"}, {"env_step": 6000000, "rew": 2851.0, "rew_std": 557.9026796852655, "Agent": "dqn"}, {"env_step": 6100000, "rew": 2454.4, "rew_std": 921.5052034579078, "Agent": "dqn"}, {"env_step": 6200000, "rew": 2610.6, "rew_std": 869.3878536073529, "Agent": "dqn"}, {"env_step": 6300000, "rew": 2773.0, "rew_std": 432.34268815373764, "Agent": "dqn"}, {"env_step": 6400000, "rew": 2506.0, "rew_std": 803.5655542642429, "Agent": "dqn"}, {"env_step": 6500000, "rew": 2808.7, "rew_std": 689.5932206743335, "Agent": "dqn"}, {"env_step": 6600000, "rew": 2985.2, "rew_std": 595.4958941923949, "Agent": "dqn"}, {"env_step": 6700000, "rew": 2698.0, "rew_std": 634.7957151714243, "Agent": "dqn"}, {"env_step": 6800000, "rew": 2821.2, "rew_std": 647.6642339978331, "Agent": "dqn"}, {"env_step": 6900000, "rew": 2988.2, "rew_std": 699.9722565930738, "Agent": "dqn"}, {"env_step": 7000000, "rew": 2854.4, "rew_std": 386.69864235603416, "Agent": "dqn"}, {"env_step": 7100000, "rew": 2749.0, "rew_std": 739.4631836677199, "Agent": "dqn"}, {"env_step": 7200000, "rew": 2854.4, "rew_std": 721.7993072870048, "Agent": "dqn"}, {"env_step": 7300000, "rew": 2570.2, "rew_std": 562.2785430727372, "Agent": "dqn"}, {"env_step": 7400000, "rew": 2909.4, "rew_std": 663.843385144418, "Agent": "dqn"}, {"env_step": 7500000, "rew": 2631.1, "rew_std": 731.3366461486802, "Agent": "dqn"}, {"env_step": 7600000, "rew": 2852.2, "rew_std": 665.8404914091662, "Agent": "dqn"}, {"env_step": 7700000, "rew": 2876.5, "rew_std": 423.60199480172423, "Agent": "dqn"}, {"env_step": 7800000, "rew": 2636.4, "rew_std": 778.3766697428694, "Agent": "dqn"}, {"env_step": 7900000, "rew": 2651.3, "rew_std": 599.0412423197588, "Agent": "dqn"}, {"env_step": 8000000, "rew": 2770.2, "rew_std": 600.3961692082987, "Agent": "dqn"}, {"env_step": 8100000, "rew": 2965.0, "rew_std": 660.43697655416, "Agent": "dqn"}, {"env_step": 8200000, "rew": 2998.4, "rew_std": 484.83795230984134, "Agent": "dqn"}, {"env_step": 8300000, "rew": 2604.2, "rew_std": 553.038479673883, "Agent": "dqn"}, {"env_step": 8400000, "rew": 2286.0, "rew_std": 568.7192629056976, "Agent": "dqn"}, {"env_step": 8500000, "rew": 2715.2, "rew_std": 530.8809282692307, "Agent": "dqn"}, {"env_step": 8600000, "rew": 2736.2, "rew_std": 531.8183524475251, "Agent": "dqn"}, {"env_step": 8700000, "rew": 2767.8, "rew_std": 546.1792379796215, "Agent": "dqn"}, {"env_step": 8800000, "rew": 2634.8, "rew_std": 725.9069912874514, "Agent": "dqn"}, {"env_step": 8900000, "rew": 2286.2, "rew_std": 622.9314247973047, "Agent": "dqn"}, {"env_step": 9000000, "rew": 2815.0, "rew_std": 796.1378021423176, "Agent": "dqn"}, {"env_step": 9100000, "rew": 2723.2, "rew_std": 613.141549725673, "Agent": "dqn"}, {"env_step": 9200000, "rew": 2820.4, "rew_std": 687.1970896329524, "Agent": "dqn"}, {"env_step": 9300000, "rew": 2704.2, "rew_std": 625.2215287400139, "Agent": "dqn"}, {"env_step": 9400000, "rew": 2331.2, "rew_std": 761.4608066079304, "Agent": "dqn"}, {"env_step": 9500000, "rew": 2712.7, "rew_std": 589.839308625663, "Agent": "dqn"}, {"env_step": 9600000, "rew": 2890.0, "rew_std": 690.3222435935264, "Agent": "dqn"}, {"env_step": 9700000, "rew": 2330.1, "rew_std": 573.4458038908298, "Agent": "dqn"}, {"env_step": 9800000, "rew": 2720.6, "rew_std": 1005.5040725924486, "Agent": "dqn"}, {"env_step": 9900000, "rew": 3213.9, "rew_std": 381.56741213054346, "Agent": "dqn"}, {"env_step": 10000000, "rew": 2365.6, "rew_std": 703.0867940731073, "Agent": "dqn"}, {"env_step": 0, "rew": 84.0, "rew_std": 39.97999499749844, "Agent": "fqf"}, {"env_step": 100000, "rew": 235.4, "rew_std": 48.70359329659363, "Agent": "fqf"}, {"env_step": 200000, "rew": 270.2, "rew_std": 64.16509954796298, "Agent": "fqf"}, {"env_step": 300000, "rew": 268.0, "rew_std": 43.174066289845804, "Agent": "fqf"}, {"env_step": 400000, "rew": 273.4, "rew_std": 98.09403651598807, "Agent": "fqf"}, {"env_step": 500000, "rew": 311.6, "rew_std": 46.21514903145937, "Agent": "fqf"}, {"env_step": 600000, "rew": 390.6, "rew_std": 107.00299061241232, "Agent": "fqf"}, {"env_step": 700000, "rew": 513.8, "rew_std": 207.3131930196436, "Agent": "fqf"}, {"env_step": 800000, "rew": 677.2, "rew_std": 171.06536762302298, "Agent": "fqf"}, {"env_step": 900000, "rew": 902.2, "rew_std": 367.83088505453156, "Agent": "fqf"}, {"env_step": 1000000, "rew": 1180.2, "rew_std": 368.2884195844338, "Agent": "fqf"}, {"env_step": 1100000, "rew": 1722.4, "rew_std": 516.4639774466366, "Agent": "fqf"}, {"env_step": 1200000, "rew": 2106.6, "rew_std": 570.7236108660653, "Agent": "fqf"}, {"env_step": 1300000, "rew": 2475.0, "rew_std": 793.9652385337787, "Agent": "fqf"}, {"env_step": 1400000, "rew": 2825.5, "rew_std": 731.4583036646724, "Agent": "fqf"}, {"env_step": 1500000, "rew": 3100.2, "rew_std": 422.5548011796813, "Agent": "fqf"}, {"env_step": 1600000, "rew": 3458.9, "rew_std": 911.015197458308, "Agent": "fqf"}, {"env_step": 1700000, "rew": 3497.4, "rew_std": 772.6115712309776, "Agent": "fqf"}, {"env_step": 1800000, "rew": 3650.5, "rew_std": 925.8434262876202, "Agent": "fqf"}, {"env_step": 1900000, "rew": 3701.9, "rew_std": 668.0494667313193, "Agent": "fqf"}, {"env_step": 2000000, "rew": 3597.7, "rew_std": 658.9843776600474, "Agent": "fqf"}, {"env_step": 2100000, "rew": 3653.4, "rew_std": 609.672239814148, "Agent": "fqf"}, {"env_step": 2200000, "rew": 4249.8, "rew_std": 837.1662678345324, "Agent": "fqf"}, {"env_step": 2300000, "rew": 4032.9, "rew_std": 788.8272878140056, "Agent": "fqf"}, {"env_step": 2400000, "rew": 4410.0, "rew_std": 802.1447500295691, "Agent": "fqf"}, {"env_step": 2500000, "rew": 4966.7, "rew_std": 1177.294359962707, "Agent": "fqf"}, {"env_step": 2600000, "rew": 4576.1, "rew_std": 841.7940900243955, "Agent": "fqf"}, {"env_step": 2700000, "rew": 5155.4, "rew_std": 1126.5631984047766, "Agent": "fqf"}, {"env_step": 2800000, "rew": 5071.3, "rew_std": 472.3333674429534, "Agent": "fqf"}, {"env_step": 2900000, "rew": 4688.0, "rew_std": 717.3926400514574, "Agent": "fqf"}, {"env_step": 3000000, "rew": 4985.2, "rew_std": 726.9461878296082, "Agent": "fqf"}, {"env_step": 3100000, "rew": 4975.1, "rew_std": 585.9778920744366, "Agent": "fqf"}, {"env_step": 3200000, "rew": 4920.8, "rew_std": 1034.2605861193783, "Agent": "fqf"}, {"env_step": 3300000, "rew": 5047.4, "rew_std": 724.611233697077, "Agent": "fqf"}, {"env_step": 3400000, "rew": 5616.9, "rew_std": 1700.5169478720288, "Agent": "fqf"}, {"env_step": 3500000, "rew": 5794.7, "rew_std": 1492.3058031114133, "Agent": "fqf"}, {"env_step": 3600000, "rew": 5340.5, "rew_std": 1678.8342532841054, "Agent": "fqf"}, {"env_step": 3700000, "rew": 5262.5, "rew_std": 1011.5026692994933, "Agent": "fqf"}, {"env_step": 3800000, "rew": 5265.4, "rew_std": 708.2388297742507, "Agent": "fqf"}, {"env_step": 3900000, "rew": 5469.6, "rew_std": 858.3154664807107, "Agent": "fqf"}, {"env_step": 4000000, "rew": 6005.2, "rew_std": 1882.1700667049192, "Agent": "fqf"}, {"env_step": 4100000, "rew": 5602.9, "rew_std": 1134.739304862575, "Agent": "fqf"}, {"env_step": 4200000, "rew": 5792.3, "rew_std": 707.0452672919888, "Agent": "fqf"}, {"env_step": 4300000, "rew": 5279.0, "rew_std": 1276.4659807452763, "Agent": "fqf"}, {"env_step": 4400000, "rew": 5126.0, "rew_std": 1668.219589862198, "Agent": "fqf"}, {"env_step": 4500000, "rew": 5870.5, "rew_std": 1084.202771625308, "Agent": "fqf"}, {"env_step": 4600000, "rew": 5440.8, "rew_std": 1613.5675876764506, "Agent": "fqf"}, {"env_step": 4700000, "rew": 5901.3, "rew_std": 586.3447876463131, "Agent": "fqf"}, {"env_step": 4800000, "rew": 5909.6, "rew_std": 1153.2979840440196, "Agent": "fqf"}, {"env_step": 4900000, "rew": 6558.0, "rew_std": 1928.9374277046936, "Agent": "fqf"}, {"env_step": 5000000, "rew": 6140.0, "rew_std": 1449.9375848635693, "Agent": "fqf"}, {"env_step": 5100000, "rew": 6061.0, "rew_std": 844.278626994667, "Agent": "fqf"}, {"env_step": 5200000, "rew": 5817.9, "rew_std": 983.7778661872811, "Agent": "fqf"}, {"env_step": 5300000, "rew": 6269.0, "rew_std": 660.6495288729116, "Agent": "fqf"}, {"env_step": 5400000, "rew": 5512.1, "rew_std": 1459.216464408211, "Agent": "fqf"}, {"env_step": 5500000, "rew": 5616.9, "rew_std": 1634.4490478445637, "Agent": "fqf"}, {"env_step": 5600000, "rew": 6840.6, "rew_std": 1181.8537303744486, "Agent": "fqf"}, {"env_step": 5700000, "rew": 6313.4, "rew_std": 1765.277666544275, "Agent": "fqf"}, {"env_step": 5800000, "rew": 6400.5, "rew_std": 2038.3985012749592, "Agent": "fqf"}, {"env_step": 5900000, "rew": 6898.0, "rew_std": 1592.9492145074807, "Agent": "fqf"}, {"env_step": 6000000, "rew": 6413.2, "rew_std": 2133.357813401212, "Agent": "fqf"}, {"env_step": 6100000, "rew": 6410.2, "rew_std": 1778.3248184738356, "Agent": "fqf"}, {"env_step": 6200000, "rew": 6357.5, "rew_std": 1512.9386140884897, "Agent": "fqf"}, {"env_step": 6300000, "rew": 6276.0, "rew_std": 815.767613968586, "Agent": "fqf"}, {"env_step": 6400000, "rew": 6026.5, "rew_std": 1442.6516038184686, "Agent": "fqf"}, {"env_step": 6500000, "rew": 6285.0, "rew_std": 1306.420376448561, "Agent": "fqf"}, {"env_step": 6600000, "rew": 6946.2, "rew_std": 1895.469588255111, "Agent": "fqf"}, {"env_step": 6700000, "rew": 6952.1, "rew_std": 1505.6863185936172, "Agent": "fqf"}, {"env_step": 6800000, "rew": 6325.1, "rew_std": 1797.747893893913, "Agent": "fqf"}, {"env_step": 6900000, "rew": 6713.2, "rew_std": 1581.9958154179803, "Agent": "fqf"}, {"env_step": 7000000, "rew": 6725.5, "rew_std": 1307.073238192872, "Agent": "fqf"}, {"env_step": 7100000, "rew": 6847.9, "rew_std": 1273.460596170922, "Agent": "fqf"}, {"env_step": 7200000, "rew": 7050.2, "rew_std": 1556.5933187573432, "Agent": "fqf"}, {"env_step": 7300000, "rew": 6831.8, "rew_std": 1364.3794047111676, "Agent": "fqf"}, {"env_step": 7400000, "rew": 6303.4, "rew_std": 1708.135252256097, "Agent": "fqf"}, {"env_step": 7500000, "rew": 7570.5, "rew_std": 2275.7164695980914, "Agent": "fqf"}, {"env_step": 7600000, "rew": 7652.3, "rew_std": 2182.971646632177, "Agent": "fqf"}, {"env_step": 7700000, "rew": 7493.9, "rew_std": 2103.570604947692, "Agent": "fqf"}, {"env_step": 7800000, "rew": 7694.6, "rew_std": 2340.8724954597587, "Agent": "fqf"}, {"env_step": 7900000, "rew": 6932.5, "rew_std": 1200.7625285625797, "Agent": "fqf"}, {"env_step": 8000000, "rew": 7276.4, "rew_std": 1941.6771204296558, "Agent": "fqf"}, {"env_step": 8100000, "rew": 6880.9, "rew_std": 1708.650546483979, "Agent": "fqf"}, {"env_step": 8200000, "rew": 6877.8, "rew_std": 1889.6905460947833, "Agent": "fqf"}, {"env_step": 8300000, "rew": 6632.9, "rew_std": 1580.6722905143872, "Agent": "fqf"}, {"env_step": 8400000, "rew": 7083.5, "rew_std": 1896.2999894531456, "Agent": "fqf"}, {"env_step": 8500000, "rew": 6696.8, "rew_std": 2655.081648462058, "Agent": "fqf"}, {"env_step": 8600000, "rew": 7298.9, "rew_std": 2318.328382693013, "Agent": "fqf"}, {"env_step": 8700000, "rew": 6763.7, "rew_std": 1158.4843589794382, "Agent": "fqf"}, {"env_step": 8800000, "rew": 7196.0, "rew_std": 1865.8348265588784, "Agent": "fqf"}, {"env_step": 8900000, "rew": 6880.7, "rew_std": 1600.4205728495244, "Agent": "fqf"}, {"env_step": 9000000, "rew": 7794.2, "rew_std": 2350.0790965412207, "Agent": "fqf"}, {"env_step": 9100000, "rew": 7289.3, "rew_std": 1832.8727206219203, "Agent": "fqf"}, {"env_step": 9200000, "rew": 6713.8, "rew_std": 1709.8212070272143, "Agent": "fqf"}, {"env_step": 9300000, "rew": 7391.5, "rew_std": 2495.9832631650397, "Agent": "fqf"}, {"env_step": 9400000, "rew": 7061.4, "rew_std": 1013.7232561207226, "Agent": "fqf"}, {"env_step": 9500000, "rew": 7424.5, "rew_std": 2155.5881911905158, "Agent": "fqf"}, {"env_step": 9600000, "rew": 7426.3, "rew_std": 1927.6538615633253, "Agent": "fqf"}, {"env_step": 9700000, "rew": 7352.0, "rew_std": 1948.6867372669215, "Agent": "fqf"}, {"env_step": 9800000, "rew": 7327.9, "rew_std": 1429.7993880261663, "Agent": "fqf"}, {"env_step": 9900000, "rew": 8051.5, "rew_std": 3155.5843912023647, "Agent": "fqf"}, {"env_step": 10000000, "rew": 6903.5, "rew_std": 1400.5262046816547, "Agent": "fqf"}, {"env_step": 0, "rew": 45.4, "rew_std": 52.91540418441496, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 200.0, "rew_std": 31.41973901864877, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 289.4, "rew_std": 83.21562353308423, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 258.4, "rew_std": 86.97493891920823, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 267.0, "rew_std": 81.28591513909406, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 300.6, "rew_std": 89.50553055537965, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 325.2, "rew_std": 81.07379354637354, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 408.6, "rew_std": 74.08670595997638, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 465.0, "rew_std": 195.36273953853123, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 629.4, "rew_std": 227.03488718696954, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 899.2, "rew_std": 221.7118851121879, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 1039.5, "rew_std": 408.2810918962572, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 1266.2, "rew_std": 453.6681165786284, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 1240.1, "rew_std": 317.7037771258, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 1547.9, "rew_std": 501.95188016382605, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 1760.2, "rew_std": 333.3532060742779, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 1911.5, "rew_std": 621.3912213734596, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 1998.1, "rew_std": 404.5299618075279, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 2403.4, "rew_std": 561.4866338569423, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 2352.4, "rew_std": 371.63858787806197, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 2128.1, "rew_std": 730.9558741811984, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 2500.0, "rew_std": 809.2574374078993, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 2503.2, "rew_std": 550.9215552145332, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 2622.2, "rew_std": 507.82079516301815, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 2551.8, "rew_std": 607.7318158530126, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 2391.6, "rew_std": 668.416516851581, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 2284.1, "rew_std": 935.7713876797045, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 2470.0, "rew_std": 762.4539330346457, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 2389.0, "rew_std": 905.0358003968684, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 2890.4, "rew_std": 717.7201683107421, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 2774.2, "rew_std": 525.8086724275284, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 2885.2, "rew_std": 427.62993347051844, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 2853.4, "rew_std": 634.3021677402656, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 2818.2, "rew_std": 437.66238129407463, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 3153.4, "rew_std": 560.2157084552342, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 2667.6, "rew_std": 998.5805125276579, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 3060.6, "rew_std": 483.220901865803, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 2940.4, "rew_std": 498.1427907738905, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 3141.6, "rew_std": 600.0958590092087, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 3165.2, "rew_std": 600.9986356057724, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 2781.6, "rew_std": 783.5125014956686, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 3374.4, "rew_std": 895.0686230675277, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 2629.0, "rew_std": 847.0873626728237, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 3079.4, "rew_std": 804.6664153548352, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 3388.8, "rew_std": 672.935182614195, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 3347.8, "rew_std": 759.8049486545872, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 3110.0, "rew_std": 800.3929035167666, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 3388.4, "rew_std": 840.9579299822316, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 3641.4, "rew_std": 761.8887320337531, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 3562.0, "rew_std": 694.3111694334176, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 3529.8, "rew_std": 537.6299470825635, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 3322.8, "rew_std": 854.5160969812096, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 3274.0, "rew_std": 1038.5505283807813, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 3571.0, "rew_std": 705.0641105601675, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 3157.2, "rew_std": 1001.435449742019, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 3315.6, "rew_std": 1095.1945215348735, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 3545.9, "rew_std": 659.3630942053096, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 3607.2, "rew_std": 404.7084876797125, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 3753.6, "rew_std": 658.8455357669201, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 3261.0, "rew_std": 661.858746259351, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 3644.2, "rew_std": 767.9252307353887, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 3731.4, "rew_std": 678.6693156464347, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 4187.6, "rew_std": 725.6907330261287, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 3814.6, "rew_std": 838.6646767331983, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 3318.2, "rew_std": 769.7981293819828, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 3726.2, "rew_std": 650.0095076227732, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 3536.0, "rew_std": 672.9190144437888, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 3278.2, "rew_std": 785.3837024028446, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 3081.8, "rew_std": 919.7605992865751, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 3286.2, "rew_std": 544.497897149291, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 3537.8, "rew_std": 511.0807763944952, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 3516.8, "rew_std": 652.3656643325122, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 3074.8, "rew_std": 885.5579935837065, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 3015.6, "rew_std": 826.9422228910554, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 3113.0, "rew_std": 853.1176941079115, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 3382.6, "rew_std": 425.42407078114417, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 3832.2, "rew_std": 956.4151609003278, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 3565.6, "rew_std": 824.5613621799168, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 3260.4, "rew_std": 1026.301242326053, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 3165.4, "rew_std": 1141.938019333799, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 3833.2, "rew_std": 872.2041962751612, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 3275.8, "rew_std": 543.5265954854463, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 3510.4, "rew_std": 1006.9696321140971, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 3475.6, "rew_std": 1033.5646278777153, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 3522.6, "rew_std": 554.0274722430288, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 3770.6, "rew_std": 639.6787005989804, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 3319.4, "rew_std": 514.5678186595038, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 3270.6, "rew_std": 850.6858644646684, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 3856.0, "rew_std": 599.3169445293533, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 3440.7, "rew_std": 711.9547808674369, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 3568.7, "rew_std": 857.8783188774502, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 3740.8, "rew_std": 602.7020491088444, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 3701.8, "rew_std": 647.5816241988341, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 3148.5, "rew_std": 721.4049140392655, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 3532.6, "rew_std": 894.7174079003939, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 3562.2, "rew_std": 658.007568345532, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 3524.8, "rew_std": 867.9291215300937, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 3570.2, "rew_std": 838.2216651936408, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 3432.2, "rew_std": 583.9133154844133, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 3285.6, "rew_std": 924.0051082109882, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 3202.8, "rew_std": 982.7004426578835, "Agent": "qrdqn"}, {"env_step": 0, "rew": 106.6, "rew_std": 87.09557968117556, "Agent": "iqn"}, {"env_step": 100000, "rew": 228.6, "rew_std": 33.87093148999596, "Agent": "iqn"}, {"env_step": 200000, "rew": 229.6, "rew_std": 75.1308192421725, "Agent": "iqn"}, {"env_step": 300000, "rew": 251.2, "rew_std": 79.04530346579739, "Agent": "iqn"}, {"env_step": 400000, "rew": 247.6, "rew_std": 64.6083585923679, "Agent": "iqn"}, {"env_step": 500000, "rew": 382.2, "rew_std": 127.84506247798544, "Agent": "iqn"}, {"env_step": 600000, "rew": 441.6, "rew_std": 243.14736272474764, "Agent": "iqn"}, {"env_step": 700000, "rew": 692.8, "rew_std": 305.80542833638515, "Agent": "iqn"}, {"env_step": 800000, "rew": 990.8, "rew_std": 394.5460175949062, "Agent": "iqn"}, {"env_step": 900000, "rew": 901.2, "rew_std": 464.5894531734443, "Agent": "iqn"}, {"env_step": 1000000, "rew": 1541.4, "rew_std": 385.48883252307064, "Agent": "iqn"}, {"env_step": 1100000, "rew": 2180.2, "rew_std": 539.3918427266026, "Agent": "iqn"}, {"env_step": 1200000, "rew": 2100.2, "rew_std": 646.6129908995024, "Agent": "iqn"}, {"env_step": 1300000, "rew": 2565.6, "rew_std": 635.4090336153555, "Agent": "iqn"}, {"env_step": 1400000, "rew": 2368.0, "rew_std": 440.5024404018666, "Agent": "iqn"}, {"env_step": 1500000, "rew": 2376.0, "rew_std": 1055.6806335251206, "Agent": "iqn"}, {"env_step": 1600000, "rew": 3192.5, "rew_std": 493.9407353114339, "Agent": "iqn"}, {"env_step": 1700000, "rew": 2622.4, "rew_std": 1216.6698155210393, "Agent": "iqn"}, {"env_step": 1800000, "rew": 3191.4, "rew_std": 527.0340026981181, "Agent": "iqn"}, {"env_step": 1900000, "rew": 2762.6, "rew_std": 706.9370834805597, "Agent": "iqn"}, {"env_step": 2000000, "rew": 3111.6, "rew_std": 1020.695762703069, "Agent": "iqn"}, {"env_step": 2100000, "rew": 3645.5, "rew_std": 998.2598108708975, "Agent": "iqn"}, {"env_step": 2200000, "rew": 3387.8, "rew_std": 938.3493805614196, "Agent": "iqn"}, {"env_step": 2300000, "rew": 3795.2, "rew_std": 690.2713669275294, "Agent": "iqn"}, {"env_step": 2400000, "rew": 3738.6, "rew_std": 1253.164011612207, "Agent": "iqn"}, {"env_step": 2500000, "rew": 3917.4, "rew_std": 391.9112654670697, "Agent": "iqn"}, {"env_step": 2600000, "rew": 3715.0, "rew_std": 903.7580428411135, "Agent": "iqn"}, {"env_step": 2700000, "rew": 4198.8, "rew_std": 916.1332654150268, "Agent": "iqn"}, {"env_step": 2800000, "rew": 3842.8, "rew_std": 1014.2438365600256, "Agent": "iqn"}, {"env_step": 2900000, "rew": 3685.0, "rew_std": 1446.485741374591, "Agent": "iqn"}, {"env_step": 3000000, "rew": 3950.0, "rew_std": 1456.4194450775506, "Agent": "iqn"}, {"env_step": 3100000, "rew": 4272.0, "rew_std": 806.635977377652, "Agent": "iqn"}, {"env_step": 3200000, "rew": 4197.4, "rew_std": 668.5554875999449, "Agent": "iqn"}, {"env_step": 3300000, "rew": 4473.6, "rew_std": 668.1130443270808, "Agent": "iqn"}, {"env_step": 3400000, "rew": 4128.8, "rew_std": 1420.9650804998691, "Agent": "iqn"}, {"env_step": 3500000, "rew": 4091.2, "rew_std": 799.4804312802158, "Agent": "iqn"}, {"env_step": 3600000, "rew": 3836.0, "rew_std": 495.31727205903087, "Agent": "iqn"}, {"env_step": 3700000, "rew": 3937.6, "rew_std": 955.3729324195865, "Agent": "iqn"}, {"env_step": 3800000, "rew": 4366.0, "rew_std": 646.7463181186267, "Agent": "iqn"}, {"env_step": 3900000, "rew": 4184.6, "rew_std": 648.5627494699337, "Agent": "iqn"}, {"env_step": 4000000, "rew": 4264.2, "rew_std": 1133.6307864556254, "Agent": "iqn"}, {"env_step": 4100000, "rew": 3667.2, "rew_std": 1318.5249940748186, "Agent": "iqn"}, {"env_step": 4200000, "rew": 4149.6, "rew_std": 734.6094472575206, "Agent": "iqn"}, {"env_step": 4300000, "rew": 4311.5, "rew_std": 1162.0347025799185, "Agent": "iqn"}, {"env_step": 4400000, "rew": 4001.8, "rew_std": 1118.5291949698942, "Agent": "iqn"}, {"env_step": 4500000, "rew": 4658.6, "rew_std": 651.7754521305632, "Agent": "iqn"}, {"env_step": 4600000, "rew": 4676.1, "rew_std": 562.302134088072, "Agent": "iqn"}, {"env_step": 4700000, "rew": 4486.8, "rew_std": 643.8162470767571, "Agent": "iqn"}, {"env_step": 4800000, "rew": 4090.2, "rew_std": 1062.8171808923678, "Agent": "iqn"}, {"env_step": 4900000, "rew": 4424.2, "rew_std": 889.2979028424614, "Agent": "iqn"}, {"env_step": 5000000, "rew": 4119.8, "rew_std": 986.707433842474, "Agent": "iqn"}, {"env_step": 5100000, "rew": 4387.0, "rew_std": 1373.3178073556026, "Agent": "iqn"}, {"env_step": 5200000, "rew": 4230.2, "rew_std": 906.2165083466533, "Agent": "iqn"}, {"env_step": 5300000, "rew": 4634.0, "rew_std": 1000.1627867502369, "Agent": "iqn"}, {"env_step": 5400000, "rew": 4360.6, "rew_std": 547.0027787863604, "Agent": "iqn"}, {"env_step": 5500000, "rew": 4132.2, "rew_std": 1382.0892735275822, "Agent": "iqn"}, {"env_step": 5600000, "rew": 4627.2, "rew_std": 630.4678897453858, "Agent": "iqn"}, {"env_step": 5700000, "rew": 4543.6, "rew_std": 817.3174658601149, "Agent": "iqn"}, {"env_step": 5800000, "rew": 4541.4, "rew_std": 589.8366214469902, "Agent": "iqn"}, {"env_step": 5900000, "rew": 4541.8, "rew_std": 957.1254672194237, "Agent": "iqn"}, {"env_step": 6000000, "rew": 4616.6, "rew_std": 624.175648355493, "Agent": "iqn"}, {"env_step": 6100000, "rew": 4831.4, "rew_std": 685.3571623613486, "Agent": "iqn"}, {"env_step": 6200000, "rew": 4185.4, "rew_std": 1318.965063980089, "Agent": "iqn"}, {"env_step": 6300000, "rew": 4762.2, "rew_std": 578.2092700744256, "Agent": "iqn"}, {"env_step": 6400000, "rew": 4953.0, "rew_std": 491.9441025157228, "Agent": "iqn"}, {"env_step": 6500000, "rew": 4542.0, "rew_std": 540.8837213301949, "Agent": "iqn"}, {"env_step": 6600000, "rew": 4407.3, "rew_std": 992.3926692595023, "Agent": "iqn"}, {"env_step": 6700000, "rew": 4558.4, "rew_std": 883.3956305076453, "Agent": "iqn"}, {"env_step": 6800000, "rew": 4337.2, "rew_std": 886.7474048453709, "Agent": "iqn"}, {"env_step": 6900000, "rew": 4499.8, "rew_std": 1165.5764067619075, "Agent": "iqn"}, {"env_step": 7000000, "rew": 4851.0, "rew_std": 666.8494582737546, "Agent": "iqn"}, {"env_step": 7100000, "rew": 4711.8, "rew_std": 1179.0499395699912, "Agent": "iqn"}, {"env_step": 7200000, "rew": 5200.4, "rew_std": 528.0430285497575, "Agent": "iqn"}, {"env_step": 7300000, "rew": 4526.0, "rew_std": 615.5309902839987, "Agent": "iqn"}, {"env_step": 7400000, "rew": 4689.4, "rew_std": 1031.8333392559093, "Agent": "iqn"}, {"env_step": 7500000, "rew": 4679.8, "rew_std": 1083.7780030984204, "Agent": "iqn"}, {"env_step": 7600000, "rew": 4287.0, "rew_std": 1172.4614279369705, "Agent": "iqn"}, {"env_step": 7700000, "rew": 4314.4, "rew_std": 984.6696095645484, "Agent": "iqn"}, {"env_step": 7800000, "rew": 5033.0, "rew_std": 813.2641637254159, "Agent": "iqn"}, {"env_step": 7900000, "rew": 5103.8, "rew_std": 708.6434646562402, "Agent": "iqn"}, {"env_step": 8000000, "rew": 4809.2, "rew_std": 815.4278386221555, "Agent": "iqn"}, {"env_step": 8100000, "rew": 4326.3, "rew_std": 854.7598551640103, "Agent": "iqn"}, {"env_step": 8200000, "rew": 4424.6, "rew_std": 656.1347727410886, "Agent": "iqn"}, {"env_step": 8300000, "rew": 4463.8, "rew_std": 1188.5400960842676, "Agent": "iqn"}, {"env_step": 8400000, "rew": 4601.0, "rew_std": 1020.5477940792387, "Agent": "iqn"}, {"env_step": 8500000, "rew": 4801.4, "rew_std": 724.9215405821516, "Agent": "iqn"}, {"env_step": 8600000, "rew": 4811.2, "rew_std": 703.3446950109171, "Agent": "iqn"}, {"env_step": 8700000, "rew": 4873.2, "rew_std": 966.0274116193598, "Agent": "iqn"}, {"env_step": 8800000, "rew": 4744.0, "rew_std": 747.7903449497059, "Agent": "iqn"}, {"env_step": 8900000, "rew": 4795.2, "rew_std": 1258.5916573694583, "Agent": "iqn"}, {"env_step": 9000000, "rew": 4230.6, "rew_std": 1360.8685608830854, "Agent": "iqn"}, {"env_step": 9100000, "rew": 4927.6, "rew_std": 1000.1939012011621, "Agent": "iqn"}, {"env_step": 9200000, "rew": 4662.6, "rew_std": 837.6820637927017, "Agent": "iqn"}, {"env_step": 9300000, "rew": 4471.6, "rew_std": 785.4536523563946, "Agent": "iqn"}, {"env_step": 9400000, "rew": 5254.6, "rew_std": 424.59020243053186, "Agent": "iqn"}, {"env_step": 9500000, "rew": 5147.4, "rew_std": 802.4213606329283, "Agent": "iqn"}, {"env_step": 9600000, "rew": 4296.0, "rew_std": 1377.9889694768967, "Agent": "iqn"}, {"env_step": 9700000, "rew": 4708.8, "rew_std": 957.8067445993477, "Agent": "iqn"}, {"env_step": 9800000, "rew": 5341.2, "rew_std": 670.1965084958291, "Agent": "iqn"}, {"env_step": 9900000, "rew": 4807.4, "rew_std": 688.9702751207776, "Agent": "iqn"}, {"env_step": 10000000, "rew": 5173.0, "rew_std": 639.4342812205176, "Agent": "iqn"}, {"env_step": 0, "rew": 55.2, "rew_std": 71.61675781547221, "Agent": "rainbow"}, {"env_step": 100000, "rew": 197.4, "rew_std": 98.0124481889928, "Agent": "rainbow"}, {"env_step": 200000, "rew": 183.8, "rew_std": 83.80190928612545, "Agent": "rainbow"}, {"env_step": 300000, "rew": 341.6, "rew_std": 115.49129837351384, "Agent": "rainbow"}, {"env_step": 400000, "rew": 478.6, "rew_std": 112.00374993722309, "Agent": "rainbow"}, {"env_step": 500000, "rew": 327.8, "rew_std": 113.28000706214668, "Agent": "rainbow"}, {"env_step": 600000, "rew": 556.2, "rew_std": 241.52424308959132, "Agent": "rainbow"}, {"env_step": 700000, "rew": 778.0, "rew_std": 244.70390270692457, "Agent": "rainbow"}, {"env_step": 800000, "rew": 952.2, "rew_std": 287.64902224759953, "Agent": "rainbow"}, {"env_step": 900000, "rew": 1213.4, "rew_std": 264.05310072029073, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 1398.2, "rew_std": 236.1549491329792, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 1322.4, "rew_std": 223.74056404684424, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 1377.0, "rew_std": 333.29416436535456, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 1495.2, "rew_std": 277.13996463880846, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 1431.2, "rew_std": 408.9402890398548, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 1460.6, "rew_std": 341.7953188678862, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 1478.6, "rew_std": 316.41750899721086, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 1522.4, "rew_std": 258.7659946747254, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 1574.8, "rew_std": 316.74620755424996, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 1628.8, "rew_std": 394.08445795286065, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 1717.2, "rew_std": 368.0708627424887, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 1660.2, "rew_std": 333.7057985711366, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 1685.8, "rew_std": 311.28051657628686, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 1637.6, "rew_std": 437.96237281300773, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 1646.0, "rew_std": 412.8253868162664, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 1597.1, "rew_std": 315.6765591550947, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 1661.2, "rew_std": 427.9338266601508, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 1649.2, "rew_std": 378.05629210476053, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 1687.8, "rew_std": 342.1618915075143, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 1625.6, "rew_std": 356.8526866929826, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 1646.2, "rew_std": 357.99156414641953, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 1651.4, "rew_std": 435.95141931183116, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 1694.2, "rew_std": 385.55253857289017, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 1634.8, "rew_std": 408.7338498338497, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 1658.6, "rew_std": 404.9168309665578, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 1594.8, "rew_std": 372.0668757091929, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 1646.4, "rew_std": 462.23093795201555, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 1722.8, "rew_std": 375.3560443099325, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 1726.6, "rew_std": 325.04775033831567, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 1754.4, "rew_std": 369.6255402430952, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 1707.2, "rew_std": 340.19782480198194, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 1701.8, "rew_std": 354.3878666094538, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 1657.6, "rew_std": 428.869024295297, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 1686.4, "rew_std": 453.4417713444583, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 1743.8, "rew_std": 245.49940936792498, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 1714.6, "rew_std": 414.4838235685441, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 1804.6, "rew_std": 416.3316466472372, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 1770.2, "rew_std": 335.57884319485936, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 1752.0, "rew_std": 379.45750750248703, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 1681.8, "rew_std": 369.5407420028271, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 1798.8, "rew_std": 338.7603282558334, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 1814.6, "rew_std": 419.58651074599624, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 1811.0, "rew_std": 331.25005660376877, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 1854.4, "rew_std": 320.87106444801157, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 1821.8, "rew_std": 351.93914246642134, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 1869.2, "rew_std": 345.7851355972376, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 1842.0, "rew_std": 353.2319351361086, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 1894.3, "rew_std": 423.4864932911084, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 1768.2, "rew_std": 373.75334112218985, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 1788.2, "rew_std": 346.13690932924214, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 1827.0, "rew_std": 370.17320270381543, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 1777.0, "rew_std": 365.00767115226495, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 1762.0, "rew_std": 395.1910930170365, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 1882.0, "rew_std": 356.34477686644993, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 1807.8, "rew_std": 391.83103501381817, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 1864.4, "rew_std": 366.81635732338873, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 1839.8, "rew_std": 329.80776218882414, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 1803.2, "rew_std": 371.11852554136937, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 1861.4, "rew_std": 354.3445216170274, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 1861.8, "rew_std": 366.5399841763515, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 1877.6, "rew_std": 345.57175810531743, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 1860.6, "rew_std": 372.0484377067051, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 1861.4, "rew_std": 343.88259624470675, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 1931.6, "rew_std": 363.43890820879375, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 1901.2, "rew_std": 362.95145680930943, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 1897.0, "rew_std": 373.6364543242536, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 1901.0, "rew_std": 359.4754511785193, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 1892.6, "rew_std": 381.24957704894575, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 1892.4, "rew_std": 351.7485465499467, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 1915.4, "rew_std": 373.93480715226286, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 1863.4, "rew_std": 332.4106496488944, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 1909.0, "rew_std": 413.3543274238217, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 1866.6, "rew_std": 333.5890285965652, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 1887.8, "rew_std": 355.3504748836, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 1912.4, "rew_std": 447.0863898621831, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 1909.8, "rew_std": 365.22152181929255, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 1915.4, "rew_std": 369.93734604659744, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 1866.4, "rew_std": 375.5697538407479, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 1877.2, "rew_std": 429.923900242822, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 1829.0, "rew_std": 345.25845391532414, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 1908.6, "rew_std": 339.2050117554279, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 1874.0, "rew_std": 355.7178657306939, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 1831.8, "rew_std": 345.1578769201132, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 1870.8, "rew_std": 397.23262705875504, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 1910.0, "rew_std": 358.90277234928124, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 1902.4, "rew_std": 376.3017937772819, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 1889.8, "rew_std": 407.2625197584477, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 1912.6, "rew_std": 381.65329816470864, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 1894.6, "rew_std": 346.8568004234601, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 1934.6, "rew_std": 376.412592775534, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 1896.0, "rew_std": 353.1526582088828, "Agent": "rainbow"}, {"env_step": 0, "rew": 149.2, "rew_std": 108.08959246847033, "Agent": "ppo"}, {"env_step": 100000, "rew": 451.8, "rew_std": 93.66087763842489, "Agent": "ppo"}, {"env_step": 200000, "rew": 548.8, "rew_std": 87.63195764103413, "Agent": "ppo"}, {"env_step": 300000, "rew": 628.6, "rew_std": 55.785661240143064, "Agent": "ppo"}, {"env_step": 400000, "rew": 712.4, "rew_std": 68.37426416423068, "Agent": "ppo"}, {"env_step": 500000, "rew": 747.4, "rew_std": 46.5536249931195, "Agent": "ppo"}, {"env_step": 600000, "rew": 758.2, "rew_std": 58.05824661492974, "Agent": "ppo"}, {"env_step": 700000, "rew": 748.8, "rew_std": 55.246357345982545, "Agent": "ppo"}, {"env_step": 800000, "rew": 781.4, "rew_std": 39.2127530275547, "Agent": "ppo"}, {"env_step": 900000, "rew": 792.4, "rew_std": 79.78370761001271, "Agent": "ppo"}, {"env_step": 1000000, "rew": 785.8, "rew_std": 37.83596172955037, "Agent": "ppo"}, {"env_step": 1100000, "rew": 824.4, "rew_std": 24.83223711227001, "Agent": "ppo"}, {"env_step": 1200000, "rew": 814.2, "rew_std": 35.104985400937004, "Agent": "ppo"}, {"env_step": 1300000, "rew": 823.0, "rew_std": 42.22084793085046, "Agent": "ppo"}, {"env_step": 1400000, "rew": 822.6, "rew_std": 22.628300864183327, "Agent": "ppo"}, {"env_step": 1500000, "rew": 824.2, "rew_std": 23.142169301947472, "Agent": "ppo"}, {"env_step": 1600000, "rew": 841.0, "rew_std": 110.87740978215535, "Agent": "ppo"}, {"env_step": 1700000, "rew": 851.8, "rew_std": 50.91522365658429, "Agent": "ppo"}, {"env_step": 1800000, "rew": 865.0, "rew_std": 90.81960140850653, "Agent": "ppo"}, {"env_step": 1900000, "rew": 872.2, "rew_std": 84.7417252597562, "Agent": "ppo"}, {"env_step": 2000000, "rew": 843.8, "rew_std": 130.17357642778353, "Agent": "ppo"}, {"env_step": 2100000, "rew": 868.0, "rew_std": 104.34557968596465, "Agent": "ppo"}, {"env_step": 2200000, "rew": 860.4, "rew_std": 135.80809990571254, "Agent": "ppo"}, {"env_step": 2300000, "rew": 884.0, "rew_std": 147.23043163694115, "Agent": "ppo"}, {"env_step": 2400000, "rew": 922.0, "rew_std": 163.5506037897751, "Agent": "ppo"}, {"env_step": 2500000, "rew": 906.8, "rew_std": 148.42425677765746, "Agent": "ppo"}, {"env_step": 2600000, "rew": 895.0, "rew_std": 125.72111994410486, "Agent": "ppo"}, {"env_step": 2700000, "rew": 920.4, "rew_std": 155.8660963776279, "Agent": "ppo"}, {"env_step": 2800000, "rew": 934.2, "rew_std": 182.06251673532364, "Agent": "ppo"}, {"env_step": 2900000, "rew": 894.0, "rew_std": 235.24625395529682, "Agent": "ppo"}, {"env_step": 3000000, "rew": 922.6, "rew_std": 170.39964788696014, "Agent": "ppo"}, {"env_step": 3100000, "rew": 933.2, "rew_std": 172.90968740935253, "Agent": "ppo"}, {"env_step": 3200000, "rew": 931.8, "rew_std": 181.70404508430735, "Agent": "ppo"}, {"env_step": 3300000, "rew": 928.4, "rew_std": 214.5931965370757, "Agent": "ppo"}, {"env_step": 3400000, "rew": 933.0, "rew_std": 203.49201458533943, "Agent": "ppo"}, {"env_step": 3500000, "rew": 958.2, "rew_std": 223.07209596899386, "Agent": "ppo"}, {"env_step": 3600000, "rew": 951.8, "rew_std": 234.61704967883298, "Agent": "ppo"}, {"env_step": 3700000, "rew": 944.0, "rew_std": 233.30666514268296, "Agent": "ppo"}, {"env_step": 3800000, "rew": 934.8, "rew_std": 249.3434579049549, "Agent": "ppo"}, {"env_step": 3900000, "rew": 925.6, "rew_std": 264.6655247666382, "Agent": "ppo"}, {"env_step": 4000000, "rew": 910.4, "rew_std": 329.20364518030476, "Agent": "ppo"}, {"env_step": 4100000, "rew": 939.6, "rew_std": 328.4677153085216, "Agent": "ppo"}, {"env_step": 4200000, "rew": 925.8, "rew_std": 297.59227140502156, "Agent": "ppo"}, {"env_step": 4300000, "rew": 947.8, "rew_std": 306.41599174977796, "Agent": "ppo"}, {"env_step": 4400000, "rew": 938.0, "rew_std": 307.99350642505436, "Agent": "ppo"}, {"env_step": 4500000, "rew": 885.0, "rew_std": 320.93145685644464, "Agent": "ppo"}, {"env_step": 4600000, "rew": 937.4, "rew_std": 259.07226790994054, "Agent": "ppo"}, {"env_step": 4700000, "rew": 932.6, "rew_std": 310.10198322487395, "Agent": "ppo"}, {"env_step": 4800000, "rew": 906.4, "rew_std": 359.8041689586156, "Agent": "ppo"}, {"env_step": 4900000, "rew": 887.0, "rew_std": 377.4125064170503, "Agent": "ppo"}, {"env_step": 5000000, "rew": 901.6, "rew_std": 373.16462854884844, "Agent": "ppo"}, {"env_step": 5100000, "rew": 899.6, "rew_std": 394.11145631661105, "Agent": "ppo"}, {"env_step": 5200000, "rew": 871.2, "rew_std": 410.2703498913856, "Agent": "ppo"}, {"env_step": 5300000, "rew": 859.8, "rew_std": 379.5180628112449, "Agent": "ppo"}, {"env_step": 5400000, "rew": 908.4, "rew_std": 370.1597492975161, "Agent": "ppo"}, {"env_step": 5500000, "rew": 858.8, "rew_std": 425.68175906420987, "Agent": "ppo"}, {"env_step": 5600000, "rew": 917.0, "rew_std": 371.99059127886557, "Agent": "ppo"}, {"env_step": 5700000, "rew": 926.0, "rew_std": 387.98144285519635, "Agent": "ppo"}, {"env_step": 5800000, "rew": 924.4, "rew_std": 380.3491027989944, "Agent": "ppo"}, {"env_step": 5900000, "rew": 942.8, "rew_std": 393.7331075741536, "Agent": "ppo"}, {"env_step": 6000000, "rew": 953.0, "rew_std": 385.58864091152896, "Agent": "ppo"}, {"env_step": 6100000, "rew": 931.0, "rew_std": 386.86871158055675, "Agent": "ppo"}, {"env_step": 6200000, "rew": 947.2, "rew_std": 389.32474876380513, "Agent": "ppo"}, {"env_step": 6300000, "rew": 954.4, "rew_std": 382.7979101301365, "Agent": "ppo"}, {"env_step": 6400000, "rew": 966.4, "rew_std": 395.44081731657394, "Agent": "ppo"}, {"env_step": 6500000, "rew": 952.8, "rew_std": 410.60073063744056, "Agent": "ppo"}, {"env_step": 6600000, "rew": 952.2, "rew_std": 401.42491203212586, "Agent": "ppo"}, {"env_step": 6700000, "rew": 974.0, "rew_std": 328.4058464765815, "Agent": "ppo"}, {"env_step": 6800000, "rew": 992.8, "rew_std": 326.9534523445195, "Agent": "ppo"}, {"env_step": 6900000, "rew": 986.8, "rew_std": 301.4514222888988, "Agent": "ppo"}, {"env_step": 7000000, "rew": 1018.6, "rew_std": 286.2880367741551, "Agent": "ppo"}, {"env_step": 7100000, "rew": 995.0, "rew_std": 302.6037012331475, "Agent": "ppo"}, {"env_step": 7200000, "rew": 986.4, "rew_std": 286.39804468606275, "Agent": "ppo"}, {"env_step": 7300000, "rew": 997.6, "rew_std": 314.9346598899524, "Agent": "ppo"}, {"env_step": 7400000, "rew": 1001.6, "rew_std": 297.1273127802289, "Agent": "ppo"}, {"env_step": 7500000, "rew": 986.2, "rew_std": 317.547413782572, "Agent": "ppo"}, {"env_step": 7600000, "rew": 1022.6, "rew_std": 319.39574198789813, "Agent": "ppo"}, {"env_step": 7700000, "rew": 1019.6, "rew_std": 320.0022499920899, "Agent": "ppo"}, {"env_step": 7800000, "rew": 1003.2, "rew_std": 321.1394712582058, "Agent": "ppo"}, {"env_step": 7900000, "rew": 1024.8, "rew_std": 323.7668296783968, "Agent": "ppo"}, {"env_step": 8000000, "rew": 1018.2, "rew_std": 316.27260393527604, "Agent": "ppo"}, {"env_step": 8100000, "rew": 1014.0, "rew_std": 307.1468704056742, "Agent": "ppo"}, {"env_step": 8200000, "rew": 1004.0, "rew_std": 307.0244289954791, "Agent": "ppo"}, {"env_step": 8300000, "rew": 1017.0, "rew_std": 338.5513255032389, "Agent": "ppo"}, {"env_step": 8400000, "rew": 1018.2, "rew_std": 328.83363574914296, "Agent": "ppo"}, {"env_step": 8500000, "rew": 1000.2, "rew_std": 347.273321751038, "Agent": "ppo"}, {"env_step": 8600000, "rew": 1010.0, "rew_std": 339.7281265953704, "Agent": "ppo"}, {"env_step": 8700000, "rew": 1023.2, "rew_std": 338.9633608518773, "Agent": "ppo"}, {"env_step": 8800000, "rew": 1024.2, "rew_std": 358.4092074710135, "Agent": "ppo"}, {"env_step": 8900000, "rew": 953.8, "rew_std": 392.8872102779626, "Agent": "ppo"}, {"env_step": 9000000, "rew": 951.4, "rew_std": 427.01105372109515, "Agent": "ppo"}, {"env_step": 9100000, "rew": 979.0, "rew_std": 400.3560914985558, "Agent": "ppo"}, {"env_step": 9200000, "rew": 991.6, "rew_std": 416.51199262446204, "Agent": "ppo"}, {"env_step": 9300000, "rew": 989.2, "rew_std": 423.34780027773854, "Agent": "ppo"}, {"env_step": 9400000, "rew": 993.2, "rew_std": 427.4821165850099, "Agent": "ppo"}, {"env_step": 9500000, "rew": 978.2, "rew_std": 419.3723405280801, "Agent": "ppo"}, {"env_step": 9600000, "rew": 992.2, "rew_std": 368.224333796668, "Agent": "ppo"}, {"env_step": 9700000, "rew": 1026.4, "rew_std": 379.41723735223206, "Agent": "ppo"}, {"env_step": 9800000, "rew": 1025.2, "rew_std": 368.4651408206752, "Agent": "ppo"}, {"env_step": 9900000, "rew": 1035.2, "rew_std": 353.61696791867894, "Agent": "ppo"}, {"env_step": 10000000, "rew": 1025.8, "rew_std": 358.64461518333155, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/atari/benchmark/SpaceInvadersNoFrameskip-v4/result.json b/examples/atari/benchmark/SpaceInvadersNoFrameskip-v4/result.json new file mode 100644 index 000000000..c5fde60c4 --- /dev/null +++ b/examples/atari/benchmark/SpaceInvadersNoFrameskip-v4/result.json @@ -0,0 +1 @@ +[{"env_step": 0, "rew": 131.5, "rew_std": 72.94964016360875, "Agent": "c51"}, {"env_step": 100000, "rew": 175.3, "rew_std": 78.69695038564073, "Agent": "c51"}, {"env_step": 200000, "rew": 162.45, "rew_std": 70.4969680199085, "Agent": "c51"}, {"env_step": 300000, "rew": 216.1, "rew_std": 43.270544253568154, "Agent": "c51"}, {"env_step": 400000, "rew": 310.5, "rew_std": 67.2647753285477, "Agent": "c51"}, {"env_step": 500000, "rew": 371.6, "rew_std": 66.80149698921424, "Agent": "c51"}, {"env_step": 600000, "rew": 429.15, "rew_std": 59.84816204362503, "Agent": "c51"}, {"env_step": 700000, "rew": 411.25, "rew_std": 67.41819116529307, "Agent": "c51"}, {"env_step": 800000, "rew": 433.9, "rew_std": 56.295115241022465, "Agent": "c51"}, {"env_step": 900000, "rew": 468.25, "rew_std": 55.36661900459518, "Agent": "c51"}, {"env_step": 1000000, "rew": 479.2, "rew_std": 77.91508198032008, "Agent": "c51"}, {"env_step": 1100000, "rew": 517.25, "rew_std": 102.26613564616588, "Agent": "c51"}, {"env_step": 1200000, "rew": 511.4, "rew_std": 65.065659145205, "Agent": "c51"}, {"env_step": 1300000, "rew": 573.65, "rew_std": 58.454277003483675, "Agent": "c51"}, {"env_step": 1400000, "rew": 556.35, "rew_std": 71.15758919468814, "Agent": "c51"}, {"env_step": 1500000, "rew": 553.5, "rew_std": 38.90629769073382, "Agent": "c51"}, {"env_step": 1600000, "rew": 608.25, "rew_std": 35.925791570959156, "Agent": "c51"}, {"env_step": 1700000, "rew": 571.35, "rew_std": 70.93273221863092, "Agent": "c51"}, {"env_step": 1800000, "rew": 624.95, "rew_std": 94.19406828457936, "Agent": "c51"}, {"env_step": 1900000, "rew": 640.2, "rew_std": 96.80113635696638, "Agent": "c51"}, {"env_step": 2000000, "rew": 617.15, "rew_std": 67.16139143883188, "Agent": "c51"}, {"env_step": 2100000, "rew": 617.65, "rew_std": 94.80454894149331, "Agent": "c51"}, {"env_step": 2200000, "rew": 613.0, "rew_std": 115.9631406956538, "Agent": "c51"}, {"env_step": 2300000, "rew": 659.9, "rew_std": 81.69969400187493, "Agent": "c51"}, {"env_step": 2400000, "rew": 698.0, "rew_std": 80.07558928912107, "Agent": "c51"}, {"env_step": 2500000, "rew": 651.8, "rew_std": 74.98106427625578, "Agent": "c51"}, {"env_step": 2600000, "rew": 619.8, "rew_std": 103.08035700365032, "Agent": "c51"}, {"env_step": 2700000, "rew": 629.75, "rew_std": 97.50211536166792, "Agent": "c51"}, {"env_step": 2800000, "rew": 655.95, "rew_std": 62.26975590123989, "Agent": "c51"}, {"env_step": 2900000, "rew": 722.85, "rew_std": 111.88946554524246, "Agent": "c51"}, {"env_step": 3000000, "rew": 689.7, "rew_std": 116.6568043450531, "Agent": "c51"}, {"env_step": 3100000, "rew": 738.45, "rew_std": 90.73572890543173, "Agent": "c51"}, {"env_step": 3200000, "rew": 742.85, "rew_std": 114.76150269145138, "Agent": "c51"}, {"env_step": 3300000, "rew": 722.95, "rew_std": 115.68069199308933, "Agent": "c51"}, {"env_step": 3400000, "rew": 775.55, "rew_std": 107.4728919309423, "Agent": "c51"}, {"env_step": 3500000, "rew": 796.25, "rew_std": 82.22902468106989, "Agent": "c51"}, {"env_step": 3600000, "rew": 742.3, "rew_std": 119.33360800713268, "Agent": "c51"}, {"env_step": 3700000, "rew": 758.55, "rew_std": 96.7464340428111, "Agent": "c51"}, {"env_step": 3800000, "rew": 664.4, "rew_std": 103.92925478420403, "Agent": "c51"}, {"env_step": 3900000, "rew": 738.85, "rew_std": 97.65578579889673, "Agent": "c51"}, {"env_step": 4000000, "rew": 689.45, "rew_std": 113.2767518072442, "Agent": "c51"}, {"env_step": 4100000, "rew": 832.35, "rew_std": 157.338973239309, "Agent": "c51"}, {"env_step": 4200000, "rew": 672.15, "rew_std": 78.5875467233836, "Agent": "c51"}, {"env_step": 4300000, "rew": 722.05, "rew_std": 77.35387837723458, "Agent": "c51"}, {"env_step": 4400000, "rew": 897.7, "rew_std": 116.28654264359226, "Agent": "c51"}, {"env_step": 4500000, "rew": 823.1, "rew_std": 92.00076086641893, "Agent": "c51"}, {"env_step": 4600000, "rew": 690.8, "rew_std": 81.19273366502695, "Agent": "c51"}, {"env_step": 4700000, "rew": 811.15, "rew_std": 99.55050225890375, "Agent": "c51"}, {"env_step": 4800000, "rew": 755.0, "rew_std": 107.04998832321282, "Agent": "c51"}, {"env_step": 4900000, "rew": 805.75, "rew_std": 115.61017472523774, "Agent": "c51"}, {"env_step": 5000000, "rew": 760.75, "rew_std": 112.35040053333142, "Agent": "c51"}, {"env_step": 5100000, "rew": 820.95, "rew_std": 141.30984572916356, "Agent": "c51"}, {"env_step": 5200000, "rew": 797.1, "rew_std": 154.61869227231227, "Agent": "c51"}, {"env_step": 5300000, "rew": 825.8, "rew_std": 151.04969380968635, "Agent": "c51"}, {"env_step": 5400000, "rew": 787.95, "rew_std": 107.38399554868501, "Agent": "c51"}, {"env_step": 5500000, "rew": 825.0, "rew_std": 65.9052349969257, "Agent": "c51"}, {"env_step": 5600000, "rew": 822.5, "rew_std": 149.53043168532616, "Agent": "c51"}, {"env_step": 5700000, "rew": 865.65, "rew_std": 141.1168044564502, "Agent": "c51"}, {"env_step": 5800000, "rew": 756.65, "rew_std": 111.32251569201982, "Agent": "c51"}, {"env_step": 5900000, "rew": 833.3, "rew_std": 179.73886613640354, "Agent": "c51"}, {"env_step": 6000000, "rew": 838.7, "rew_std": 96.8695514596821, "Agent": "c51"}, {"env_step": 6100000, "rew": 797.05, "rew_std": 143.24549731143384, "Agent": "c51"}, {"env_step": 6200000, "rew": 787.65, "rew_std": 143.62260441866385, "Agent": "c51"}, {"env_step": 6300000, "rew": 836.35, "rew_std": 147.87225060842215, "Agent": "c51"}, {"env_step": 6400000, "rew": 936.1, "rew_std": 174.2318570181699, "Agent": "c51"}, {"env_step": 6500000, "rew": 878.6, "rew_std": 130.01822949109868, "Agent": "c51"}, {"env_step": 6600000, "rew": 869.35, "rew_std": 131.44923925226803, "Agent": "c51"}, {"env_step": 6700000, "rew": 831.1, "rew_std": 128.2900619689616, "Agent": "c51"}, {"env_step": 6800000, "rew": 848.35, "rew_std": 173.9251347563083, "Agent": "c51"}, {"env_step": 6900000, "rew": 833.4, "rew_std": 157.15466903658958, "Agent": "c51"}, {"env_step": 7000000, "rew": 832.3, "rew_std": 154.00165583525393, "Agent": "c51"}, {"env_step": 7100000, "rew": 832.85, "rew_std": 96.22423031648525, "Agent": "c51"}, {"env_step": 7200000, "rew": 867.75, "rew_std": 155.06728378352412, "Agent": "c51"}, {"env_step": 7300000, "rew": 881.55, "rew_std": 176.80051611915616, "Agent": "c51"}, {"env_step": 7400000, "rew": 848.7, "rew_std": 122.09365257866602, "Agent": "c51"}, {"env_step": 7500000, "rew": 891.75, "rew_std": 136.24688069823839, "Agent": "c51"}, {"env_step": 7600000, "rew": 947.85, "rew_std": 155.2700953178042, "Agent": "c51"}, {"env_step": 7700000, "rew": 810.6, "rew_std": 61.26001958863546, "Agent": "c51"}, {"env_step": 7800000, "rew": 809.45, "rew_std": 132.21695239264895, "Agent": "c51"}, {"env_step": 7900000, "rew": 933.9, "rew_std": 128.37421859547965, "Agent": "c51"}, {"env_step": 8000000, "rew": 859.35, "rew_std": 175.26181129955265, "Agent": "c51"}, {"env_step": 8100000, "rew": 922.05, "rew_std": 125.99334307811664, "Agent": "c51"}, {"env_step": 8200000, "rew": 878.3, "rew_std": 114.7343017584541, "Agent": "c51"}, {"env_step": 8300000, "rew": 895.25, "rew_std": 212.38682280216915, "Agent": "c51"}, {"env_step": 8400000, "rew": 877.2, "rew_std": 165.07804214976625, "Agent": "c51"}, {"env_step": 8500000, "rew": 872.55, "rew_std": 171.04918152391141, "Agent": "c51"}, {"env_step": 8600000, "rew": 921.95, "rew_std": 176.95118677194566, "Agent": "c51"}, {"env_step": 8700000, "rew": 881.1, "rew_std": 133.7792584820233, "Agent": "c51"}, {"env_step": 8800000, "rew": 875.65, "rew_std": 134.4557641010604, "Agent": "c51"}, {"env_step": 8900000, "rew": 865.25, "rew_std": 158.70353650753975, "Agent": "c51"}, {"env_step": 9000000, "rew": 873.9, "rew_std": 141.55260506257028, "Agent": "c51"}, {"env_step": 9100000, "rew": 923.35, "rew_std": 146.47082473994607, "Agent": "c51"}, {"env_step": 9200000, "rew": 894.5, "rew_std": 181.60740623664003, "Agent": "c51"}, {"env_step": 9300000, "rew": 873.55, "rew_std": 141.41206631684582, "Agent": "c51"}, {"env_step": 9400000, "rew": 919.55, "rew_std": 149.74168591277447, "Agent": "c51"}, {"env_step": 9500000, "rew": 886.55, "rew_std": 105.35142381572258, "Agent": "c51"}, {"env_step": 9600000, "rew": 860.15, "rew_std": 190.00829587152242, "Agent": "c51"}, {"env_step": 9700000, "rew": 919.65, "rew_std": 205.74645197426855, "Agent": "c51"}, {"env_step": 9800000, "rew": 877.75, "rew_std": 124.24014045388068, "Agent": "c51"}, {"env_step": 9900000, "rew": 880.1, "rew_std": 104.3469692899607, "Agent": "c51"}, {"env_step": 10000000, "rew": 880.55, "rew_std": 143.47516335589236, "Agent": "c51"}, {"env_step": 0, "rew": 189.2, "rew_std": 81.34807926435633, "Agent": "dqn"}, {"env_step": 100000, "rew": 245.5, "rew_std": 101.77032966439678, "Agent": "dqn"}, {"env_step": 200000, "rew": 230.55, "rew_std": 65.04092942140356, "Agent": "dqn"}, {"env_step": 300000, "rew": 289.9, "rew_std": 61.85903329344874, "Agent": "dqn"}, {"env_step": 400000, "rew": 272.75, "rew_std": 70.29838191594456, "Agent": "dqn"}, {"env_step": 500000, "rew": 295.65, "rew_std": 66.4168841485356, "Agent": "dqn"}, {"env_step": 600000, "rew": 313.0, "rew_std": 92.10130292237999, "Agent": "dqn"}, {"env_step": 700000, "rew": 321.55, "rew_std": 54.48323136525586, "Agent": "dqn"}, {"env_step": 800000, "rew": 398.9, "rew_std": 85.19647880047626, "Agent": "dqn"}, {"env_step": 900000, "rew": 368.95, "rew_std": 76.96442359947874, "Agent": "dqn"}, {"env_step": 1000000, "rew": 365.3, "rew_std": 76.99974025930217, "Agent": "dqn"}, {"env_step": 1100000, "rew": 436.35, "rew_std": 96.35638276730815, "Agent": "dqn"}, {"env_step": 1200000, "rew": 403.95, "rew_std": 62.60089855585142, "Agent": "dqn"}, {"env_step": 1300000, "rew": 449.65, "rew_std": 59.11558593129226, "Agent": "dqn"}, {"env_step": 1400000, "rew": 420.15, "rew_std": 76.2200924953519, "Agent": "dqn"}, {"env_step": 1500000, "rew": 467.6, "rew_std": 49.78092003970999, "Agent": "dqn"}, {"env_step": 1600000, "rew": 407.05, "rew_std": 62.21030863128715, "Agent": "dqn"}, {"env_step": 1700000, "rew": 471.3, "rew_std": 63.85264285838136, "Agent": "dqn"}, {"env_step": 1800000, "rew": 440.8, "rew_std": 76.10525606027484, "Agent": "dqn"}, {"env_step": 1900000, "rew": 511.2, "rew_std": 51.454931736423475, "Agent": "dqn"}, {"env_step": 2000000, "rew": 446.15, "rew_std": 89.50224857510564, "Agent": "dqn"}, {"env_step": 2100000, "rew": 512.9, "rew_std": 72.38224920517462, "Agent": "dqn"}, {"env_step": 2200000, "rew": 458.2, "rew_std": 57.65682960413277, "Agent": "dqn"}, {"env_step": 2300000, "rew": 443.95, "rew_std": 83.05884961880943, "Agent": "dqn"}, {"env_step": 2400000, "rew": 429.95, "rew_std": 97.29631287977978, "Agent": "dqn"}, {"env_step": 2500000, "rew": 518.2, "rew_std": 83.67950764673512, "Agent": "dqn"}, {"env_step": 2600000, "rew": 500.35, "rew_std": 86.74043174898313, "Agent": "dqn"}, {"env_step": 2700000, "rew": 472.85, "rew_std": 108.66325275823469, "Agent": "dqn"}, {"env_step": 2800000, "rew": 483.6, "rew_std": 62.72750592842027, "Agent": "dqn"}, {"env_step": 2900000, "rew": 442.75, "rew_std": 133.11221769619797, "Agent": "dqn"}, {"env_step": 3000000, "rew": 496.85, "rew_std": 91.74694817812743, "Agent": "dqn"}, {"env_step": 3100000, "rew": 488.3, "rew_std": 120.88097451625711, "Agent": "dqn"}, {"env_step": 3200000, "rew": 496.5, "rew_std": 77.99935897172489, "Agent": "dqn"}, {"env_step": 3300000, "rew": 489.05, "rew_std": 103.76065005578945, "Agent": "dqn"}, {"env_step": 3400000, "rew": 499.35, "rew_std": 79.70321511708295, "Agent": "dqn"}, {"env_step": 3500000, "rew": 518.35, "rew_std": 78.03109956933838, "Agent": "dqn"}, {"env_step": 3600000, "rew": 521.85, "rew_std": 87.429986274733, "Agent": "dqn"}, {"env_step": 3700000, "rew": 560.4, "rew_std": 98.244796299855, "Agent": "dqn"}, {"env_step": 3800000, "rew": 551.25, "rew_std": 61.10615762752556, "Agent": "dqn"}, {"env_step": 3900000, "rew": 520.0, "rew_std": 123.95079668965424, "Agent": "dqn"}, {"env_step": 4000000, "rew": 568.7, "rew_std": 94.99899999473679, "Agent": "dqn"}, {"env_step": 4100000, "rew": 540.9, "rew_std": 120.96668962983156, "Agent": "dqn"}, {"env_step": 4200000, "rew": 542.15, "rew_std": 113.86111056897346, "Agent": "dqn"}, {"env_step": 4300000, "rew": 564.95, "rew_std": 118.0547436573389, "Agent": "dqn"}, {"env_step": 4400000, "rew": 560.8, "rew_std": 101.43401796241733, "Agent": "dqn"}, {"env_step": 4500000, "rew": 572.3, "rew_std": 100.23228022947497, "Agent": "dqn"}, {"env_step": 4600000, "rew": 577.25, "rew_std": 122.57757747646998, "Agent": "dqn"}, {"env_step": 4700000, "rew": 597.7, "rew_std": 134.22410364759378, "Agent": "dqn"}, {"env_step": 4800000, "rew": 561.1, "rew_std": 95.81330805269172, "Agent": "dqn"}, {"env_step": 4900000, "rew": 556.8, "rew_std": 126.28364898117255, "Agent": "dqn"}, {"env_step": 5000000, "rew": 604.65, "rew_std": 157.45920900347494, "Agent": "dqn"}, {"env_step": 5100000, "rew": 551.65, "rew_std": 108.79270425906326, "Agent": "dqn"}, {"env_step": 5200000, "rew": 511.25, "rew_std": 115.59849696254706, "Agent": "dqn"}, {"env_step": 5300000, "rew": 551.55, "rew_std": 108.7601604448982, "Agent": "dqn"}, {"env_step": 5400000, "rew": 569.1, "rew_std": 100.45765276971187, "Agent": "dqn"}, {"env_step": 5500000, "rew": 502.8, "rew_std": 87.80495430213492, "Agent": "dqn"}, {"env_step": 5600000, "rew": 569.9, "rew_std": 101.9560689709053, "Agent": "dqn"}, {"env_step": 5700000, "rew": 518.95, "rew_std": 81.64326365353115, "Agent": "dqn"}, {"env_step": 5800000, "rew": 488.6, "rew_std": 77.79293027004447, "Agent": "dqn"}, {"env_step": 5900000, "rew": 546.3, "rew_std": 118.97693053697428, "Agent": "dqn"}, {"env_step": 6000000, "rew": 554.15, "rew_std": 153.27508766919692, "Agent": "dqn"}, {"env_step": 6100000, "rew": 515.95, "rew_std": 145.70954841739095, "Agent": "dqn"}, {"env_step": 6200000, "rew": 475.1, "rew_std": 145.77187657432418, "Agent": "dqn"}, {"env_step": 6300000, "rew": 559.6, "rew_std": 122.7236326059492, "Agent": "dqn"}, {"env_step": 6400000, "rew": 511.9, "rew_std": 133.77664220632838, "Agent": "dqn"}, {"env_step": 6500000, "rew": 543.75, "rew_std": 91.17270699063398, "Agent": "dqn"}, {"env_step": 6600000, "rew": 521.35, "rew_std": 109.17922192432037, "Agent": "dqn"}, {"env_step": 6700000, "rew": 516.6, "rew_std": 75.09121120344244, "Agent": "dqn"}, {"env_step": 6800000, "rew": 583.9, "rew_std": 113.4287882329702, "Agent": "dqn"}, {"env_step": 6900000, "rew": 526.35, "rew_std": 107.32288898459639, "Agent": "dqn"}, {"env_step": 7000000, "rew": 540.0, "rew_std": 147.050841548085, "Agent": "dqn"}, {"env_step": 7100000, "rew": 521.75, "rew_std": 136.49674904553586, "Agent": "dqn"}, {"env_step": 7200000, "rew": 561.3, "rew_std": 84.21229126439917, "Agent": "dqn"}, {"env_step": 7300000, "rew": 491.65, "rew_std": 89.11146110349667, "Agent": "dqn"}, {"env_step": 7400000, "rew": 521.25, "rew_std": 41.02392594572099, "Agent": "dqn"}, {"env_step": 7500000, "rew": 501.35, "rew_std": 102.60459297711775, "Agent": "dqn"}, {"env_step": 7600000, "rew": 491.5, "rew_std": 119.28767748598344, "Agent": "dqn"}, {"env_step": 7700000, "rew": 503.5, "rew_std": 155.50707379408823, "Agent": "dqn"}, {"env_step": 7800000, "rew": 504.8, "rew_std": 110.91780740710664, "Agent": "dqn"}, {"env_step": 7900000, "rew": 551.55, "rew_std": 103.75245780221306, "Agent": "dqn"}, {"env_step": 8000000, "rew": 528.65, "rew_std": 35.64621298258764, "Agent": "dqn"}, {"env_step": 8100000, "rew": 521.05, "rew_std": 94.89137210516033, "Agent": "dqn"}, {"env_step": 8200000, "rew": 519.65, "rew_std": 79.50504700960813, "Agent": "dqn"}, {"env_step": 8300000, "rew": 544.2, "rew_std": 153.77226668030877, "Agent": "dqn"}, {"env_step": 8400000, "rew": 540.2, "rew_std": 130.77427116982912, "Agent": "dqn"}, {"env_step": 8500000, "rew": 524.4, "rew_std": 132.1672803684785, "Agent": "dqn"}, {"env_step": 8600000, "rew": 572.25, "rew_std": 186.15480788848834, "Agent": "dqn"}, {"env_step": 8700000, "rew": 564.35, "rew_std": 140.56280624688736, "Agent": "dqn"}, {"env_step": 8800000, "rew": 486.55, "rew_std": 130.3735881994509, "Agent": "dqn"}, {"env_step": 8900000, "rew": 576.0, "rew_std": 83.01776918226604, "Agent": "dqn"}, {"env_step": 9000000, "rew": 553.25, "rew_std": 74.99208291546515, "Agent": "dqn"}, {"env_step": 9100000, "rew": 488.35, "rew_std": 62.5244152311719, "Agent": "dqn"}, {"env_step": 9200000, "rew": 557.05, "rew_std": 100.2916870931983, "Agent": "dqn"}, {"env_step": 9300000, "rew": 541.2, "rew_std": 124.49461835758201, "Agent": "dqn"}, {"env_step": 9400000, "rew": 445.8, "rew_std": 82.59031420209031, "Agent": "dqn"}, {"env_step": 9500000, "rew": 530.65, "rew_std": 123.81034892124325, "Agent": "dqn"}, {"env_step": 9600000, "rew": 553.6, "rew_std": 85.22347094550891, "Agent": "dqn"}, {"env_step": 9700000, "rew": 590.65, "rew_std": 110.74724601542019, "Agent": "dqn"}, {"env_step": 9800000, "rew": 561.0, "rew_std": 100.72661018817222, "Agent": "dqn"}, {"env_step": 9900000, "rew": 525.75, "rew_std": 88.93038007340348, "Agent": "dqn"}, {"env_step": 10000000, "rew": 522.1, "rew_std": 134.1502515838118, "Agent": "dqn"}, {"env_step": 0, "rew": 230.2, "rew_std": 115.47709729639034, "Agent": "fqf"}, {"env_step": 100000, "rew": 197.8, "rew_std": 50.49366296873302, "Agent": "fqf"}, {"env_step": 200000, "rew": 274.45, "rew_std": 80.67882311982494, "Agent": "fqf"}, {"env_step": 300000, "rew": 331.75, "rew_std": 106.72845215780092, "Agent": "fqf"}, {"env_step": 400000, "rew": 342.3, "rew_std": 107.6478518132155, "Agent": "fqf"}, {"env_step": 500000, "rew": 344.15, "rew_std": 89.13586539659555, "Agent": "fqf"}, {"env_step": 600000, "rew": 418.7, "rew_std": 101.0124249783164, "Agent": "fqf"}, {"env_step": 700000, "rew": 455.75, "rew_std": 68.63499471843791, "Agent": "fqf"}, {"env_step": 800000, "rew": 513.6, "rew_std": 56.154608003261856, "Agent": "fqf"}, {"env_step": 900000, "rew": 530.0, "rew_std": 71.92808908903392, "Agent": "fqf"}, {"env_step": 1000000, "rew": 524.25, "rew_std": 79.38332633494265, "Agent": "fqf"}, {"env_step": 1100000, "rew": 552.4, "rew_std": 55.314916613875496, "Agent": "fqf"}, {"env_step": 1200000, "rew": 592.0, "rew_std": 123.01138158723363, "Agent": "fqf"}, {"env_step": 1300000, "rew": 626.2, "rew_std": 132.57247074713513, "Agent": "fqf"}, {"env_step": 1400000, "rew": 666.45, "rew_std": 91.45120283517325, "Agent": "fqf"}, {"env_step": 1500000, "rew": 633.95, "rew_std": 123.25632843793458, "Agent": "fqf"}, {"env_step": 1600000, "rew": 672.8, "rew_std": 103.08981520984506, "Agent": "fqf"}, {"env_step": 1700000, "rew": 617.5, "rew_std": 140.43023178788818, "Agent": "fqf"}, {"env_step": 1800000, "rew": 673.4, "rew_std": 67.20520813151315, "Agent": "fqf"}, {"env_step": 1900000, "rew": 668.5, "rew_std": 96.4898958440727, "Agent": "fqf"}, {"env_step": 2000000, "rew": 667.75, "rew_std": 174.6682927723289, "Agent": "fqf"}, {"env_step": 2100000, "rew": 699.8, "rew_std": 121.638028593035, "Agent": "fqf"}, {"env_step": 2200000, "rew": 714.25, "rew_std": 161.04211405716208, "Agent": "fqf"}, {"env_step": 2300000, "rew": 747.05, "rew_std": 150.87817105201134, "Agent": "fqf"}, {"env_step": 2400000, "rew": 735.6, "rew_std": 94.85483646077304, "Agent": "fqf"}, {"env_step": 2500000, "rew": 686.05, "rew_std": 107.51405722043978, "Agent": "fqf"}, {"env_step": 2600000, "rew": 727.95, "rew_std": 72.91243035312978, "Agent": "fqf"}, {"env_step": 2700000, "rew": 804.25, "rew_std": 120.79305650574456, "Agent": "fqf"}, {"env_step": 2800000, "rew": 799.6, "rew_std": 149.8772497746072, "Agent": "fqf"}, {"env_step": 2900000, "rew": 837.3, "rew_std": 153.77031573096286, "Agent": "fqf"}, {"env_step": 3000000, "rew": 825.05, "rew_std": 126.28864754996785, "Agent": "fqf"}, {"env_step": 3100000, "rew": 897.25, "rew_std": 165.72601636435965, "Agent": "fqf"}, {"env_step": 3200000, "rew": 835.4, "rew_std": 150.30997970860085, "Agent": "fqf"}, {"env_step": 3300000, "rew": 886.3, "rew_std": 185.1247147195641, "Agent": "fqf"}, {"env_step": 3400000, "rew": 787.0, "rew_std": 143.65931922433714, "Agent": "fqf"}, {"env_step": 3500000, "rew": 887.85, "rew_std": 202.29138019203884, "Agent": "fqf"}, {"env_step": 3600000, "rew": 860.05, "rew_std": 139.24967683984045, "Agent": "fqf"}, {"env_step": 3700000, "rew": 864.55, "rew_std": 175.68529392069217, "Agent": "fqf"}, {"env_step": 3800000, "rew": 982.3, "rew_std": 242.51723650083102, "Agent": "fqf"}, {"env_step": 3900000, "rew": 976.7, "rew_std": 136.36333818149217, "Agent": "fqf"}, {"env_step": 4000000, "rew": 940.7, "rew_std": 151.9544668642551, "Agent": "fqf"}, {"env_step": 4100000, "rew": 923.85, "rew_std": 171.70586041250894, "Agent": "fqf"}, {"env_step": 4200000, "rew": 1001.85, "rew_std": 166.15249772422925, "Agent": "fqf"}, {"env_step": 4300000, "rew": 1156.5, "rew_std": 218.98983994697107, "Agent": "fqf"}, {"env_step": 4400000, "rew": 1059.3, "rew_std": 177.61998761400702, "Agent": "fqf"}, {"env_step": 4500000, "rew": 1082.8, "rew_std": 197.79777551833087, "Agent": "fqf"}, {"env_step": 4600000, "rew": 1097.7, "rew_std": 135.50944616520283, "Agent": "fqf"}, {"env_step": 4700000, "rew": 1051.95, "rew_std": 234.61686320467248, "Agent": "fqf"}, {"env_step": 4800000, "rew": 967.5, "rew_std": 162.95152653473363, "Agent": "fqf"}, {"env_step": 4900000, "rew": 987.2, "rew_std": 236.65536123232027, "Agent": "fqf"}, {"env_step": 5000000, "rew": 1005.5, "rew_std": 246.8736518950534, "Agent": "fqf"}, {"env_step": 5100000, "rew": 1098.95, "rew_std": 251.61572387273415, "Agent": "fqf"}, {"env_step": 5200000, "rew": 1028.55, "rew_std": 254.31441661848427, "Agent": "fqf"}, {"env_step": 5300000, "rew": 1025.2, "rew_std": 199.16051315459094, "Agent": "fqf"}, {"env_step": 5400000, "rew": 1034.65, "rew_std": 224.61445300781517, "Agent": "fqf"}, {"env_step": 5500000, "rew": 1263.2, "rew_std": 179.57897983895555, "Agent": "fqf"}, {"env_step": 5600000, "rew": 1016.95, "rew_std": 171.7589080659283, "Agent": "fqf"}, {"env_step": 5700000, "rew": 1224.7, "rew_std": 191.47979005628764, "Agent": "fqf"}, {"env_step": 5800000, "rew": 1192.7, "rew_std": 211.82247283987599, "Agent": "fqf"}, {"env_step": 5900000, "rew": 1256.45, "rew_std": 423.3461024977081, "Agent": "fqf"}, {"env_step": 6000000, "rew": 1206.3, "rew_std": 349.3533454827648, "Agent": "fqf"}, {"env_step": 6100000, "rew": 1323.8, "rew_std": 327.38587324440255, "Agent": "fqf"}, {"env_step": 6200000, "rew": 1459.2, "rew_std": 292.0249304425908, "Agent": "fqf"}, {"env_step": 6300000, "rew": 1187.2, "rew_std": 343.017506841852, "Agent": "fqf"}, {"env_step": 6400000, "rew": 1257.5, "rew_std": 311.28724676735476, "Agent": "fqf"}, {"env_step": 6500000, "rew": 1111.55, "rew_std": 231.75153181802273, "Agent": "fqf"}, {"env_step": 6600000, "rew": 1306.1, "rew_std": 182.76703750950279, "Agent": "fqf"}, {"env_step": 6700000, "rew": 1163.85, "rew_std": 369.6850044294467, "Agent": "fqf"}, {"env_step": 6800000, "rew": 1146.1, "rew_std": 217.4428430645626, "Agent": "fqf"}, {"env_step": 6900000, "rew": 1197.9, "rew_std": 226.09840777856002, "Agent": "fqf"}, {"env_step": 7000000, "rew": 1633.55, "rew_std": 109.7614344840664, "Agent": "fqf"}, {"env_step": 7100000, "rew": 1409.85, "rew_std": 353.492153378261, "Agent": "fqf"}, {"env_step": 7200000, "rew": 1372.45, "rew_std": 253.83640893299764, "Agent": "fqf"}, {"env_step": 7300000, "rew": 1275.55, "rew_std": 352.75008504605637, "Agent": "fqf"}, {"env_step": 7400000, "rew": 1356.95, "rew_std": 431.4569184750663, "Agent": "fqf"}, {"env_step": 7500000, "rew": 1394.0, "rew_std": 367.9727571437864, "Agent": "fqf"}, {"env_step": 7600000, "rew": 1537.6, "rew_std": 332.01941208308887, "Agent": "fqf"}, {"env_step": 7700000, "rew": 1574.95, "rew_std": 366.9757110491102, "Agent": "fqf"}, {"env_step": 7800000, "rew": 1337.1, "rew_std": 339.9577767900008, "Agent": "fqf"}, {"env_step": 7900000, "rew": 1460.65, "rew_std": 323.72148909208977, "Agent": "fqf"}, {"env_step": 8000000, "rew": 1490.3, "rew_std": 428.0282817758658, "Agent": "fqf"}, {"env_step": 8100000, "rew": 1340.1, "rew_std": 215.97648020097003, "Agent": "fqf"}, {"env_step": 8200000, "rew": 1639.3, "rew_std": 353.53735304773664, "Agent": "fqf"}, {"env_step": 8300000, "rew": 1621.2, "rew_std": 447.873486600848, "Agent": "fqf"}, {"env_step": 8400000, "rew": 1636.0, "rew_std": 445.03949262958673, "Agent": "fqf"}, {"env_step": 8500000, "rew": 1507.95, "rew_std": 247.5409511575812, "Agent": "fqf"}, {"env_step": 8600000, "rew": 1481.65, "rew_std": 305.7656005831918, "Agent": "fqf"}, {"env_step": 8700000, "rew": 1612.35, "rew_std": 260.7944640900186, "Agent": "fqf"}, {"env_step": 8800000, "rew": 1461.6, "rew_std": 150.4408189289064, "Agent": "fqf"}, {"env_step": 8900000, "rew": 1593.3, "rew_std": 260.38521463401105, "Agent": "fqf"}, {"env_step": 9000000, "rew": 1542.55, "rew_std": 377.05214825007954, "Agent": "fqf"}, {"env_step": 9100000, "rew": 1562.2, "rew_std": 291.7097187273678, "Agent": "fqf"}, {"env_step": 9200000, "rew": 1645.4, "rew_std": 301.2403359445743, "Agent": "fqf"}, {"env_step": 9300000, "rew": 1787.55, "rew_std": 340.77921371468653, "Agent": "fqf"}, {"env_step": 9400000, "rew": 1669.3, "rew_std": 312.634627000913, "Agent": "fqf"}, {"env_step": 9500000, "rew": 1691.45, "rew_std": 373.35073657353354, "Agent": "fqf"}, {"env_step": 9600000, "rew": 1444.45, "rew_std": 174.3102765186264, "Agent": "fqf"}, {"env_step": 9700000, "rew": 1547.25, "rew_std": 277.2487375985687, "Agent": "fqf"}, {"env_step": 9800000, "rew": 1697.55, "rew_std": 281.5422215228117, "Agent": "fqf"}, {"env_step": 9900000, "rew": 1566.15, "rew_std": 436.8016168697181, "Agent": "fqf"}, {"env_step": 10000000, "rew": 1580.2, "rew_std": 413.62206179071256, "Agent": "fqf"}, {"env_step": 0, "rew": 104.2, "rew_std": 85.97418217116113, "Agent": "qrdqn"}, {"env_step": 100000, "rew": 222.7, "rew_std": 70.10249638921569, "Agent": "qrdqn"}, {"env_step": 200000, "rew": 284.55, "rew_std": 65.67931561762806, "Agent": "qrdqn"}, {"env_step": 300000, "rew": 298.65, "rew_std": 112.2911505863218, "Agent": "qrdqn"}, {"env_step": 400000, "rew": 401.8, "rew_std": 97.01886414507233, "Agent": "qrdqn"}, {"env_step": 500000, "rew": 307.5, "rew_std": 84.26268450506429, "Agent": "qrdqn"}, {"env_step": 600000, "rew": 300.85, "rew_std": 93.35230313173854, "Agent": "qrdqn"}, {"env_step": 700000, "rew": 326.1, "rew_std": 88.10839914559793, "Agent": "qrdqn"}, {"env_step": 800000, "rew": 373.1, "rew_std": 67.90500717914696, "Agent": "qrdqn"}, {"env_step": 900000, "rew": 435.5, "rew_std": 72.41926539257355, "Agent": "qrdqn"}, {"env_step": 1000000, "rew": 410.55, "rew_std": 76.28939965683306, "Agent": "qrdqn"}, {"env_step": 1100000, "rew": 413.0, "rew_std": 106.63043655542258, "Agent": "qrdqn"}, {"env_step": 1200000, "rew": 435.95, "rew_std": 79.69894917751425, "Agent": "qrdqn"}, {"env_step": 1300000, "rew": 429.0, "rew_std": 77.78110310351737, "Agent": "qrdqn"}, {"env_step": 1400000, "rew": 486.8, "rew_std": 72.63580384355913, "Agent": "qrdqn"}, {"env_step": 1500000, "rew": 430.25, "rew_std": 113.51965688813546, "Agent": "qrdqn"}, {"env_step": 1600000, "rew": 468.6, "rew_std": 107.82086996495623, "Agent": "qrdqn"}, {"env_step": 1700000, "rew": 475.6, "rew_std": 44.46223116308942, "Agent": "qrdqn"}, {"env_step": 1800000, "rew": 501.05, "rew_std": 96.80765723846436, "Agent": "qrdqn"}, {"env_step": 1900000, "rew": 462.0, "rew_std": 61.099099829702894, "Agent": "qrdqn"}, {"env_step": 2000000, "rew": 496.1, "rew_std": 102.8520296348108, "Agent": "qrdqn"}, {"env_step": 2100000, "rew": 519.55, "rew_std": 87.50984230359464, "Agent": "qrdqn"}, {"env_step": 2200000, "rew": 485.35, "rew_std": 75.20473721781096, "Agent": "qrdqn"}, {"env_step": 2300000, "rew": 512.45, "rew_std": 120.2733241413074, "Agent": "qrdqn"}, {"env_step": 2400000, "rew": 489.4, "rew_std": 75.57109235680004, "Agent": "qrdqn"}, {"env_step": 2500000, "rew": 511.45, "rew_std": 56.399224285445634, "Agent": "qrdqn"}, {"env_step": 2600000, "rew": 513.45, "rew_std": 94.62939553859572, "Agent": "qrdqn"}, {"env_step": 2700000, "rew": 497.9, "rew_std": 62.18231259771544, "Agent": "qrdqn"}, {"env_step": 2800000, "rew": 509.8, "rew_std": 98.18966340710207, "Agent": "qrdqn"}, {"env_step": 2900000, "rew": 481.3, "rew_std": 49.9585828461937, "Agent": "qrdqn"}, {"env_step": 3000000, "rew": 519.35, "rew_std": 65.75106463016398, "Agent": "qrdqn"}, {"env_step": 3100000, "rew": 485.7, "rew_std": 51.05692901066417, "Agent": "qrdqn"}, {"env_step": 3200000, "rew": 518.6, "rew_std": 81.14117327226664, "Agent": "qrdqn"}, {"env_step": 3300000, "rew": 559.25, "rew_std": 62.88889011582252, "Agent": "qrdqn"}, {"env_step": 3400000, "rew": 512.15, "rew_std": 106.45211364740486, "Agent": "qrdqn"}, {"env_step": 3500000, "rew": 522.7, "rew_std": 51.48456079253275, "Agent": "qrdqn"}, {"env_step": 3600000, "rew": 565.4, "rew_std": 101.5477227711188, "Agent": "qrdqn"}, {"env_step": 3700000, "rew": 577.85, "rew_std": 100.99580436830037, "Agent": "qrdqn"}, {"env_step": 3800000, "rew": 509.1, "rew_std": 87.09069984791716, "Agent": "qrdqn"}, {"env_step": 3900000, "rew": 546.35, "rew_std": 75.80997625642684, "Agent": "qrdqn"}, {"env_step": 4000000, "rew": 516.45, "rew_std": 87.6491443198392, "Agent": "qrdqn"}, {"env_step": 4100000, "rew": 520.0, "rew_std": 117.6093108559012, "Agent": "qrdqn"}, {"env_step": 4200000, "rew": 546.85, "rew_std": 85.65396955191278, "Agent": "qrdqn"}, {"env_step": 4300000, "rew": 545.15, "rew_std": 87.88431316224755, "Agent": "qrdqn"}, {"env_step": 4400000, "rew": 489.25, "rew_std": 74.9827480157936, "Agent": "qrdqn"}, {"env_step": 4500000, "rew": 593.25, "rew_std": 62.53169196495486, "Agent": "qrdqn"}, {"env_step": 4600000, "rew": 527.6, "rew_std": 122.62091991173449, "Agent": "qrdqn"}, {"env_step": 4700000, "rew": 520.9, "rew_std": 74.23099083267041, "Agent": "qrdqn"}, {"env_step": 4800000, "rew": 598.05, "rew_std": 122.61779030793205, "Agent": "qrdqn"}, {"env_step": 4900000, "rew": 545.5, "rew_std": 72.01284607623838, "Agent": "qrdqn"}, {"env_step": 5000000, "rew": 603.55, "rew_std": 73.38203117930165, "Agent": "qrdqn"}, {"env_step": 5100000, "rew": 559.75, "rew_std": 47.47433517175359, "Agent": "qrdqn"}, {"env_step": 5200000, "rew": 558.3, "rew_std": 102.89951409020357, "Agent": "qrdqn"}, {"env_step": 5300000, "rew": 614.8, "rew_std": 85.48280528854912, "Agent": "qrdqn"}, {"env_step": 5400000, "rew": 604.75, "rew_std": 84.51220326083092, "Agent": "qrdqn"}, {"env_step": 5500000, "rew": 611.15, "rew_std": 93.74754663456532, "Agent": "qrdqn"}, {"env_step": 5600000, "rew": 520.85, "rew_std": 106.81691111429876, "Agent": "qrdqn"}, {"env_step": 5700000, "rew": 660.4, "rew_std": 123.0060567614457, "Agent": "qrdqn"}, {"env_step": 5800000, "rew": 585.9, "rew_std": 127.98120955827851, "Agent": "qrdqn"}, {"env_step": 5900000, "rew": 570.45, "rew_std": 98.77789479433139, "Agent": "qrdqn"}, {"env_step": 6000000, "rew": 641.5, "rew_std": 90.51408730136983, "Agent": "qrdqn"}, {"env_step": 6100000, "rew": 592.95, "rew_std": 103.75438544948354, "Agent": "qrdqn"}, {"env_step": 6200000, "rew": 612.3, "rew_std": 82.66323245554823, "Agent": "qrdqn"}, {"env_step": 6300000, "rew": 642.25, "rew_std": 79.97319863554289, "Agent": "qrdqn"}, {"env_step": 6400000, "rew": 652.8, "rew_std": 100.57017450516828, "Agent": "qrdqn"}, {"env_step": 6500000, "rew": 617.95, "rew_std": 120.11233283888878, "Agent": "qrdqn"}, {"env_step": 6600000, "rew": 579.0, "rew_std": 103.84363244802255, "Agent": "qrdqn"}, {"env_step": 6700000, "rew": 566.85, "rew_std": 83.09273433941141, "Agent": "qrdqn"}, {"env_step": 6800000, "rew": 572.8, "rew_std": 120.3420541622919, "Agent": "qrdqn"}, {"env_step": 6900000, "rew": 600.65, "rew_std": 63.689893232757115, "Agent": "qrdqn"}, {"env_step": 7000000, "rew": 576.3, "rew_std": 126.27830375800905, "Agent": "qrdqn"}, {"env_step": 7100000, "rew": 573.25, "rew_std": 80.12154828758615, "Agent": "qrdqn"}, {"env_step": 7200000, "rew": 580.7, "rew_std": 85.19865022404991, "Agent": "qrdqn"}, {"env_step": 7300000, "rew": 549.95, "rew_std": 106.52029149415617, "Agent": "qrdqn"}, {"env_step": 7400000, "rew": 559.15, "rew_std": 76.05657433779146, "Agent": "qrdqn"}, {"env_step": 7500000, "rew": 558.75, "rew_std": 96.65175890794745, "Agent": "qrdqn"}, {"env_step": 7600000, "rew": 628.15, "rew_std": 106.18169569186584, "Agent": "qrdqn"}, {"env_step": 7700000, "rew": 630.65, "rew_std": 103.51402078945634, "Agent": "qrdqn"}, {"env_step": 7800000, "rew": 617.2, "rew_std": 153.99938311564756, "Agent": "qrdqn"}, {"env_step": 7900000, "rew": 596.9, "rew_std": 75.67886098508619, "Agent": "qrdqn"}, {"env_step": 8000000, "rew": 528.0, "rew_std": 121.1131702169504, "Agent": "qrdqn"}, {"env_step": 8100000, "rew": 606.8, "rew_std": 102.84313297444804, "Agent": "qrdqn"}, {"env_step": 8200000, "rew": 591.8, "rew_std": 142.44142655842785, "Agent": "qrdqn"}, {"env_step": 8300000, "rew": 550.85, "rew_std": 137.40925187191726, "Agent": "qrdqn"}, {"env_step": 8400000, "rew": 569.7, "rew_std": 142.38858802586674, "Agent": "qrdqn"}, {"env_step": 8500000, "rew": 603.85, "rew_std": 53.07732566736949, "Agent": "qrdqn"}, {"env_step": 8600000, "rew": 570.5, "rew_std": 92.73537620563148, "Agent": "qrdqn"}, {"env_step": 8700000, "rew": 667.8, "rew_std": 81.47244933104687, "Agent": "qrdqn"}, {"env_step": 8800000, "rew": 550.0, "rew_std": 169.62207993065053, "Agent": "qrdqn"}, {"env_step": 8900000, "rew": 636.75, "rew_std": 63.59490938746591, "Agent": "qrdqn"}, {"env_step": 9000000, "rew": 586.6, "rew_std": 137.99434771033194, "Agent": "qrdqn"}, {"env_step": 9100000, "rew": 609.55, "rew_std": 123.41463649016674, "Agent": "qrdqn"}, {"env_step": 9200000, "rew": 626.9, "rew_std": 111.03260782310753, "Agent": "qrdqn"}, {"env_step": 9300000, "rew": 624.4, "rew_std": 161.2231062844281, "Agent": "qrdqn"}, {"env_step": 9400000, "rew": 633.05, "rew_std": 107.944997568206, "Agent": "qrdqn"}, {"env_step": 9500000, "rew": 552.85, "rew_std": 160.7512130591866, "Agent": "qrdqn"}, {"env_step": 9600000, "rew": 555.75, "rew_std": 80.15804700714708, "Agent": "qrdqn"}, {"env_step": 9700000, "rew": 582.25, "rew_std": 108.67411145254421, "Agent": "qrdqn"}, {"env_step": 9800000, "rew": 635.15, "rew_std": 106.95303876000905, "Agent": "qrdqn"}, {"env_step": 9900000, "rew": 597.35, "rew_std": 98.45660211484042, "Agent": "qrdqn"}, {"env_step": 10000000, "rew": 550.15, "rew_std": 221.34204864869213, "Agent": "qrdqn"}, {"env_step": 0, "rew": 193.85, "rew_std": 59.73192195133185, "Agent": "iqn"}, {"env_step": 100000, "rew": 178.3, "rew_std": 102.48638934024362, "Agent": "iqn"}, {"env_step": 200000, "rew": 275.5, "rew_std": 63.457466069801434, "Agent": "iqn"}, {"env_step": 300000, "rew": 309.5, "rew_std": 43.517812445020716, "Agent": "iqn"}, {"env_step": 400000, "rew": 321.25, "rew_std": 78.36525058978629, "Agent": "iqn"}, {"env_step": 500000, "rew": 374.9, "rew_std": 70.88398972969847, "Agent": "iqn"}, {"env_step": 600000, "rew": 344.3, "rew_std": 138.2237678548809, "Agent": "iqn"}, {"env_step": 700000, "rew": 402.65, "rew_std": 115.49524882002723, "Agent": "iqn"}, {"env_step": 800000, "rew": 502.4, "rew_std": 117.13129385437523, "Agent": "iqn"}, {"env_step": 900000, "rew": 550.95, "rew_std": 73.10145347392212, "Agent": "iqn"}, {"env_step": 1000000, "rew": 542.7, "rew_std": 35.80237422294784, "Agent": "iqn"}, {"env_step": 1100000, "rew": 579.8, "rew_std": 73.14273716508016, "Agent": "iqn"}, {"env_step": 1200000, "rew": 617.6, "rew_std": 98.75621499429795, "Agent": "iqn"}, {"env_step": 1300000, "rew": 650.15, "rew_std": 124.93219160808795, "Agent": "iqn"}, {"env_step": 1400000, "rew": 666.45, "rew_std": 72.53014890374898, "Agent": "iqn"}, {"env_step": 1500000, "rew": 619.95, "rew_std": 84.52113640977622, "Agent": "iqn"}, {"env_step": 1600000, "rew": 633.65, "rew_std": 143.48554805275688, "Agent": "iqn"}, {"env_step": 1700000, "rew": 659.7, "rew_std": 71.16923492633597, "Agent": "iqn"}, {"env_step": 1800000, "rew": 746.45, "rew_std": 159.69368334408222, "Agent": "iqn"}, {"env_step": 1900000, "rew": 713.35, "rew_std": 60.149418118548745, "Agent": "iqn"}, {"env_step": 2000000, "rew": 708.95, "rew_std": 140.94013800191908, "Agent": "iqn"}, {"env_step": 2100000, "rew": 723.65, "rew_std": 82.80701962998064, "Agent": "iqn"}, {"env_step": 2200000, "rew": 680.25, "rew_std": 95.15467671113176, "Agent": "iqn"}, {"env_step": 2300000, "rew": 799.4, "rew_std": 105.6581279410155, "Agent": "iqn"}, {"env_step": 2400000, "rew": 761.5, "rew_std": 83.66719787347967, "Agent": "iqn"}, {"env_step": 2500000, "rew": 796.4, "rew_std": 124.04732967702287, "Agent": "iqn"}, {"env_step": 2600000, "rew": 689.55, "rew_std": 71.40919058496603, "Agent": "iqn"}, {"env_step": 2700000, "rew": 688.0, "rew_std": 80.3962063781619, "Agent": "iqn"}, {"env_step": 2800000, "rew": 757.45, "rew_std": 125.27738223637978, "Agent": "iqn"}, {"env_step": 2900000, "rew": 756.0, "rew_std": 107.79216112500946, "Agent": "iqn"}, {"env_step": 3000000, "rew": 744.8, "rew_std": 124.25441642050394, "Agent": "iqn"}, {"env_step": 3100000, "rew": 812.6, "rew_std": 155.1967783170772, "Agent": "iqn"}, {"env_step": 3200000, "rew": 757.55, "rew_std": 168.36262203945387, "Agent": "iqn"}, {"env_step": 3300000, "rew": 770.5, "rew_std": 111.00945905642456, "Agent": "iqn"}, {"env_step": 3400000, "rew": 759.45, "rew_std": 102.85267376203694, "Agent": "iqn"}, {"env_step": 3500000, "rew": 850.85, "rew_std": 200.12159428707338, "Agent": "iqn"}, {"env_step": 3600000, "rew": 785.85, "rew_std": 128.4011390136396, "Agent": "iqn"}, {"env_step": 3700000, "rew": 787.85, "rew_std": 137.1677895863311, "Agent": "iqn"}, {"env_step": 3800000, "rew": 791.75, "rew_std": 188.92634146672083, "Agent": "iqn"}, {"env_step": 3900000, "rew": 774.5, "rew_std": 60.62507731953833, "Agent": "iqn"}, {"env_step": 4000000, "rew": 872.55, "rew_std": 194.64755970728223, "Agent": "iqn"}, {"env_step": 4100000, "rew": 782.7, "rew_std": 128.8107526567561, "Agent": "iqn"}, {"env_step": 4200000, "rew": 826.2, "rew_std": 168.36124851045741, "Agent": "iqn"}, {"env_step": 4300000, "rew": 795.05, "rew_std": 154.91133754506157, "Agent": "iqn"}, {"env_step": 4400000, "rew": 824.45, "rew_std": 175.53866383221674, "Agent": "iqn"}, {"env_step": 4500000, "rew": 912.3, "rew_std": 182.14118150489747, "Agent": "iqn"}, {"env_step": 4600000, "rew": 857.55, "rew_std": 158.4999132491876, "Agent": "iqn"}, {"env_step": 4700000, "rew": 815.05, "rew_std": 86.60411364363705, "Agent": "iqn"}, {"env_step": 4800000, "rew": 806.95, "rew_std": 147.00245746245196, "Agent": "iqn"}, {"env_step": 4900000, "rew": 912.15, "rew_std": 95.28878475455545, "Agent": "iqn"}, {"env_step": 5000000, "rew": 883.0, "rew_std": 149.37553347185073, "Agent": "iqn"}, {"env_step": 5100000, "rew": 886.6, "rew_std": 178.2464305392958, "Agent": "iqn"}, {"env_step": 5200000, "rew": 933.15, "rew_std": 92.64341584807849, "Agent": "iqn"}, {"env_step": 5300000, "rew": 874.25, "rew_std": 130.7188299366239, "Agent": "iqn"}, {"env_step": 5400000, "rew": 882.05, "rew_std": 148.7500336134416, "Agent": "iqn"}, {"env_step": 5500000, "rew": 801.65, "rew_std": 157.15773127657448, "Agent": "iqn"}, {"env_step": 5600000, "rew": 927.7, "rew_std": 267.2525210358174, "Agent": "iqn"}, {"env_step": 5700000, "rew": 952.6, "rew_std": 184.16715233721783, "Agent": "iqn"}, {"env_step": 5800000, "rew": 857.65, "rew_std": 235.34772677890902, "Agent": "iqn"}, {"env_step": 5900000, "rew": 836.4, "rew_std": 238.53121389034183, "Agent": "iqn"}, {"env_step": 6000000, "rew": 890.35, "rew_std": 114.51791344588845, "Agent": "iqn"}, {"env_step": 6100000, "rew": 935.55, "rew_std": 166.9722207434518, "Agent": "iqn"}, {"env_step": 6200000, "rew": 941.05, "rew_std": 148.40981268096797, "Agent": "iqn"}, {"env_step": 6300000, "rew": 965.9, "rew_std": 189.78208556130897, "Agent": "iqn"}, {"env_step": 6400000, "rew": 875.15, "rew_std": 215.37328641221964, "Agent": "iqn"}, {"env_step": 6500000, "rew": 939.0, "rew_std": 153.9548635152524, "Agent": "iqn"}, {"env_step": 6600000, "rew": 928.2, "rew_std": 232.79499565067974, "Agent": "iqn"}, {"env_step": 6700000, "rew": 847.65, "rew_std": 67.1215501906802, "Agent": "iqn"}, {"env_step": 6800000, "rew": 961.7, "rew_std": 153.62831770217363, "Agent": "iqn"}, {"env_step": 6900000, "rew": 917.75, "rew_std": 210.0694230486674, "Agent": "iqn"}, {"env_step": 7000000, "rew": 887.35, "rew_std": 105.70029564764708, "Agent": "iqn"}, {"env_step": 7100000, "rew": 958.85, "rew_std": 133.01297869005117, "Agent": "iqn"}, {"env_step": 7200000, "rew": 886.9, "rew_std": 131.38260919923914, "Agent": "iqn"}, {"env_step": 7300000, "rew": 919.7, "rew_std": 193.17805258362037, "Agent": "iqn"}, {"env_step": 7400000, "rew": 843.9, "rew_std": 261.7283706440706, "Agent": "iqn"}, {"env_step": 7500000, "rew": 865.8, "rew_std": 213.59625464881168, "Agent": "iqn"}, {"env_step": 7600000, "rew": 951.8, "rew_std": 178.61973575168003, "Agent": "iqn"}, {"env_step": 7700000, "rew": 889.7, "rew_std": 187.84557487468265, "Agent": "iqn"}, {"env_step": 7800000, "rew": 977.9, "rew_std": 223.82055312236184, "Agent": "iqn"}, {"env_step": 7900000, "rew": 909.35, "rew_std": 181.14414840121114, "Agent": "iqn"}, {"env_step": 8000000, "rew": 985.15, "rew_std": 156.5410569147915, "Agent": "iqn"}, {"env_step": 8100000, "rew": 1051.1, "rew_std": 157.7045972697055, "Agent": "iqn"}, {"env_step": 8200000, "rew": 953.55, "rew_std": 201.69462684960152, "Agent": "iqn"}, {"env_step": 8300000, "rew": 951.6, "rew_std": 148.2414921673416, "Agent": "iqn"}, {"env_step": 8400000, "rew": 930.85, "rew_std": 137.40233804415413, "Agent": "iqn"}, {"env_step": 8500000, "rew": 1027.05, "rew_std": 82.30353880605621, "Agent": "iqn"}, {"env_step": 8600000, "rew": 999.15, "rew_std": 210.70109752917756, "Agent": "iqn"}, {"env_step": 8700000, "rew": 1005.65, "rew_std": 197.8955595762573, "Agent": "iqn"}, {"env_step": 8800000, "rew": 1114.7, "rew_std": 116.91389994350544, "Agent": "iqn"}, {"env_step": 8900000, "rew": 955.6, "rew_std": 172.78857022384324, "Agent": "iqn"}, {"env_step": 9000000, "rew": 858.45, "rew_std": 104.03327592650344, "Agent": "iqn"}, {"env_step": 9100000, "rew": 887.4, "rew_std": 217.57881330681073, "Agent": "iqn"}, {"env_step": 9200000, "rew": 965.85, "rew_std": 178.4683515360637, "Agent": "iqn"}, {"env_step": 9300000, "rew": 970.6, "rew_std": 139.28151348976647, "Agent": "iqn"}, {"env_step": 9400000, "rew": 964.0, "rew_std": 120.89272103811709, "Agent": "iqn"}, {"env_step": 9500000, "rew": 993.35, "rew_std": 285.66554307441424, "Agent": "iqn"}, {"env_step": 9600000, "rew": 965.5, "rew_std": 75.48609143411785, "Agent": "iqn"}, {"env_step": 9700000, "rew": 984.5, "rew_std": 142.40224717328024, "Agent": "iqn"}, {"env_step": 9800000, "rew": 959.0, "rew_std": 233.88319734431545, "Agent": "iqn"}, {"env_step": 9900000, "rew": 1060.1, "rew_std": 261.16113799721427, "Agent": "iqn"}, {"env_step": 10000000, "rew": 966.65, "rew_std": 156.9350263644162, "Agent": "iqn"}, {"env_step": 0, "rew": 129.2, "rew_std": 69.53567429744247, "Agent": "rainbow"}, {"env_step": 100000, "rew": 177.85, "rew_std": 75.14188246244566, "Agent": "rainbow"}, {"env_step": 200000, "rew": 198.55, "rew_std": 53.13823952672877, "Agent": "rainbow"}, {"env_step": 300000, "rew": 274.85, "rew_std": 47.645592660811765, "Agent": "rainbow"}, {"env_step": 400000, "rew": 297.05, "rew_std": 50.52496907470602, "Agent": "rainbow"}, {"env_step": 500000, "rew": 363.35, "rew_std": 90.23110605550616, "Agent": "rainbow"}, {"env_step": 600000, "rew": 377.1, "rew_std": 62.0112086642407, "Agent": "rainbow"}, {"env_step": 700000, "rew": 449.6, "rew_std": 20.95924616965028, "Agent": "rainbow"}, {"env_step": 800000, "rew": 478.55, "rew_std": 50.6070400240915, "Agent": "rainbow"}, {"env_step": 900000, "rew": 467.45, "rew_std": 44.51092562506424, "Agent": "rainbow"}, {"env_step": 1000000, "rew": 518.3, "rew_std": 61.56102663211522, "Agent": "rainbow"}, {"env_step": 1100000, "rew": 546.95, "rew_std": 26.70809802288437, "Agent": "rainbow"}, {"env_step": 1200000, "rew": 539.1, "rew_std": 56.16929766340327, "Agent": "rainbow"}, {"env_step": 1300000, "rew": 585.25, "rew_std": 74.84425495654293, "Agent": "rainbow"}, {"env_step": 1400000, "rew": 547.5, "rew_std": 76.41760268419836, "Agent": "rainbow"}, {"env_step": 1500000, "rew": 622.95, "rew_std": 78.23376828454577, "Agent": "rainbow"}, {"env_step": 1600000, "rew": 608.95, "rew_std": 82.29776728441665, "Agent": "rainbow"}, {"env_step": 1700000, "rew": 593.7, "rew_std": 66.87682707784514, "Agent": "rainbow"}, {"env_step": 1800000, "rew": 589.45, "rew_std": 61.96388060798, "Agent": "rainbow"}, {"env_step": 1900000, "rew": 616.65, "rew_std": 62.149839098745865, "Agent": "rainbow"}, {"env_step": 2000000, "rew": 625.85, "rew_std": 97.02269064502386, "Agent": "rainbow"}, {"env_step": 2100000, "rew": 625.05, "rew_std": 74.01602866947131, "Agent": "rainbow"}, {"env_step": 2200000, "rew": 604.05, "rew_std": 120.92465629473585, "Agent": "rainbow"}, {"env_step": 2300000, "rew": 645.65, "rew_std": 99.99626243015285, "Agent": "rainbow"}, {"env_step": 2400000, "rew": 700.1, "rew_std": 88.73691452828412, "Agent": "rainbow"}, {"env_step": 2500000, "rew": 651.45, "rew_std": 63.471430581010225, "Agent": "rainbow"}, {"env_step": 2600000, "rew": 664.25, "rew_std": 97.90409848417991, "Agent": "rainbow"}, {"env_step": 2700000, "rew": 724.25, "rew_std": 75.68726775356606, "Agent": "rainbow"}, {"env_step": 2800000, "rew": 670.4, "rew_std": 85.67461701110778, "Agent": "rainbow"}, {"env_step": 2900000, "rew": 741.0, "rew_std": 110.0034090380839, "Agent": "rainbow"}, {"env_step": 3000000, "rew": 760.65, "rew_std": 146.2280838279706, "Agent": "rainbow"}, {"env_step": 3100000, "rew": 758.85, "rew_std": 83.78127774150977, "Agent": "rainbow"}, {"env_step": 3200000, "rew": 781.65, "rew_std": 80.49038762485866, "Agent": "rainbow"}, {"env_step": 3300000, "rew": 759.45, "rew_std": 155.77362581643916, "Agent": "rainbow"}, {"env_step": 3400000, "rew": 764.45, "rew_std": 146.94462392343587, "Agent": "rainbow"}, {"env_step": 3500000, "rew": 801.25, "rew_std": 66.33259002933626, "Agent": "rainbow"}, {"env_step": 3600000, "rew": 816.85, "rew_std": 83.54371610121254, "Agent": "rainbow"}, {"env_step": 3700000, "rew": 808.7, "rew_std": 91.75380101118428, "Agent": "rainbow"}, {"env_step": 3800000, "rew": 858.65, "rew_std": 116.32176279613373, "Agent": "rainbow"}, {"env_step": 3900000, "rew": 785.0, "rew_std": 113.13421233207929, "Agent": "rainbow"}, {"env_step": 4000000, "rew": 784.1, "rew_std": 148.00249997888548, "Agent": "rainbow"}, {"env_step": 4100000, "rew": 847.8, "rew_std": 141.88837161656343, "Agent": "rainbow"}, {"env_step": 4200000, "rew": 864.45, "rew_std": 98.91623981935423, "Agent": "rainbow"}, {"env_step": 4300000, "rew": 874.8, "rew_std": 130.1499519784775, "Agent": "rainbow"}, {"env_step": 4400000, "rew": 896.05, "rew_std": 163.69735031453627, "Agent": "rainbow"}, {"env_step": 4500000, "rew": 803.35, "rew_std": 121.67580901724055, "Agent": "rainbow"}, {"env_step": 4600000, "rew": 883.9, "rew_std": 127.14004089978893, "Agent": "rainbow"}, {"env_step": 4700000, "rew": 884.0, "rew_std": 62.155450283945335, "Agent": "rainbow"}, {"env_step": 4800000, "rew": 880.95, "rew_std": 157.68995687741182, "Agent": "rainbow"}, {"env_step": 4900000, "rew": 889.8, "rew_std": 118.07925304641795, "Agent": "rainbow"}, {"env_step": 5000000, "rew": 926.05, "rew_std": 152.34573344862665, "Agent": "rainbow"}, {"env_step": 5100000, "rew": 909.15, "rew_std": 130.32882451706527, "Agent": "rainbow"}, {"env_step": 5200000, "rew": 860.3, "rew_std": 148.12835650205534, "Agent": "rainbow"}, {"env_step": 5300000, "rew": 921.85, "rew_std": 225.55631780112037, "Agent": "rainbow"}, {"env_step": 5400000, "rew": 906.55, "rew_std": 165.13622406970558, "Agent": "rainbow"}, {"env_step": 5500000, "rew": 830.05, "rew_std": 163.59407843806574, "Agent": "rainbow"}, {"env_step": 5600000, "rew": 936.0, "rew_std": 105.19054139988063, "Agent": "rainbow"}, {"env_step": 5700000, "rew": 953.05, "rew_std": 209.43226231887004, "Agent": "rainbow"}, {"env_step": 5800000, "rew": 1002.05, "rew_std": 93.83001918362801, "Agent": "rainbow"}, {"env_step": 5900000, "rew": 925.0, "rew_std": 173.92857729539446, "Agent": "rainbow"}, {"env_step": 6000000, "rew": 959.65, "rew_std": 155.2884493450817, "Agent": "rainbow"}, {"env_step": 6100000, "rew": 968.05, "rew_std": 146.51168042173293, "Agent": "rainbow"}, {"env_step": 6200000, "rew": 1050.5, "rew_std": 181.52906103431485, "Agent": "rainbow"}, {"env_step": 6300000, "rew": 949.45, "rew_std": 170.18320275514853, "Agent": "rainbow"}, {"env_step": 6400000, "rew": 989.1, "rew_std": 128.6547317435313, "Agent": "rainbow"}, {"env_step": 6500000, "rew": 1003.1, "rew_std": 173.66603006921073, "Agent": "rainbow"}, {"env_step": 6600000, "rew": 1086.4, "rew_std": 179.66382496206631, "Agent": "rainbow"}, {"env_step": 6700000, "rew": 878.0, "rew_std": 83.01204731844649, "Agent": "rainbow"}, {"env_step": 6800000, "rew": 1107.55, "rew_std": 113.496354567008, "Agent": "rainbow"}, {"env_step": 6900000, "rew": 1062.7, "rew_std": 188.38619906988941, "Agent": "rainbow"}, {"env_step": 7000000, "rew": 1025.8, "rew_std": 146.94577231074055, "Agent": "rainbow"}, {"env_step": 7100000, "rew": 969.65, "rew_std": 143.79204602480627, "Agent": "rainbow"}, {"env_step": 7200000, "rew": 1074.2, "rew_std": 236.38752082121428, "Agent": "rainbow"}, {"env_step": 7300000, "rew": 1129.1, "rew_std": 145.2378738483871, "Agent": "rainbow"}, {"env_step": 7400000, "rew": 1020.55, "rew_std": 165.74822020160576, "Agent": "rainbow"}, {"env_step": 7500000, "rew": 1026.55, "rew_std": 126.17734543094492, "Agent": "rainbow"}, {"env_step": 7600000, "rew": 1062.0, "rew_std": 134.57005610461786, "Agent": "rainbow"}, {"env_step": 7700000, "rew": 1086.0, "rew_std": 98.97221832413376, "Agent": "rainbow"}, {"env_step": 7800000, "rew": 1066.7, "rew_std": 159.72964659073153, "Agent": "rainbow"}, {"env_step": 7900000, "rew": 1040.4, "rew_std": 127.58032763714004, "Agent": "rainbow"}, {"env_step": 8000000, "rew": 1074.7, "rew_std": 214.01894775930472, "Agent": "rainbow"}, {"env_step": 8100000, "rew": 1095.35, "rew_std": 139.572033373452, "Agent": "rainbow"}, {"env_step": 8200000, "rew": 1175.95, "rew_std": 163.02261346205933, "Agent": "rainbow"}, {"env_step": 8300000, "rew": 1147.0, "rew_std": 173.63841740813004, "Agent": "rainbow"}, {"env_step": 8400000, "rew": 1167.4, "rew_std": 160.64289589023224, "Agent": "rainbow"}, {"env_step": 8500000, "rew": 1162.35, "rew_std": 261.15216349860094, "Agent": "rainbow"}, {"env_step": 8600000, "rew": 1090.85, "rew_std": 134.61947295989538, "Agent": "rainbow"}, {"env_step": 8700000, "rew": 1165.2, "rew_std": 295.2810694914254, "Agent": "rainbow"}, {"env_step": 8800000, "rew": 1233.65, "rew_std": 176.00952389004408, "Agent": "rainbow"}, {"env_step": 8900000, "rew": 1189.25, "rew_std": 256.7154309736756, "Agent": "rainbow"}, {"env_step": 9000000, "rew": 1097.2, "rew_std": 220.08159850382765, "Agent": "rainbow"}, {"env_step": 9100000, "rew": 1151.05, "rew_std": 172.71746437462542, "Agent": "rainbow"}, {"env_step": 9200000, "rew": 1204.9, "rew_std": 126.59498410284667, "Agent": "rainbow"}, {"env_step": 9300000, "rew": 1064.65, "rew_std": 216.47644791062143, "Agent": "rainbow"}, {"env_step": 9400000, "rew": 1358.15, "rew_std": 267.57840439766437, "Agent": "rainbow"}, {"env_step": 9500000, "rew": 1092.1, "rew_std": 237.28230022485874, "Agent": "rainbow"}, {"env_step": 9600000, "rew": 1312.5, "rew_std": 333.92401830356556, "Agent": "rainbow"}, {"env_step": 9700000, "rew": 1284.1, "rew_std": 214.49811187980188, "Agent": "rainbow"}, {"env_step": 9800000, "rew": 1226.6, "rew_std": 304.27987117126236, "Agent": "rainbow"}, {"env_step": 9900000, "rew": 1122.35, "rew_std": 192.80275542636832, "Agent": "rainbow"}, {"env_step": 10000000, "rew": 1184.0, "rew_std": 231.1005192551501, "Agent": "rainbow"}, {"env_step": 0, "rew": 171.85, "rew_std": 31.587220517164848, "Agent": "ppo"}, {"env_step": 100000, "rew": 226.2, "rew_std": 53.99453676067608, "Agent": "ppo"}, {"env_step": 200000, "rew": 240.45, "rew_std": 20.0517455599257, "Agent": "ppo"}, {"env_step": 300000, "rew": 282.7, "rew_std": 25.0421644431946, "Agent": "ppo"}, {"env_step": 400000, "rew": 291.8, "rew_std": 47.00276587606308, "Agent": "ppo"}, {"env_step": 500000, "rew": 320.5, "rew_std": 31.345653606201928, "Agent": "ppo"}, {"env_step": 600000, "rew": 314.0, "rew_std": 56.18807702707043, "Agent": "ppo"}, {"env_step": 700000, "rew": 320.9, "rew_std": 56.30133213344068, "Agent": "ppo"}, {"env_step": 800000, "rew": 331.25, "rew_std": 52.53439349607074, "Agent": "ppo"}, {"env_step": 900000, "rew": 385.95, "rew_std": 86.00071220635328, "Agent": "ppo"}, {"env_step": 1000000, "rew": 396.05, "rew_std": 54.37713214210547, "Agent": "ppo"}, {"env_step": 1100000, "rew": 366.65, "rew_std": 46.54301773628349, "Agent": "ppo"}, {"env_step": 1200000, "rew": 377.25, "rew_std": 51.198266572219026, "Agent": "ppo"}, {"env_step": 1300000, "rew": 386.5, "rew_std": 81.74686538332831, "Agent": "ppo"}, {"env_step": 1400000, "rew": 400.45, "rew_std": 102.20431742348265, "Agent": "ppo"}, {"env_step": 1500000, "rew": 417.4, "rew_std": 66.27586287631418, "Agent": "ppo"}, {"env_step": 1600000, "rew": 428.3, "rew_std": 44.33801980242239, "Agent": "ppo"}, {"env_step": 1700000, "rew": 392.8, "rew_std": 61.047604375601836, "Agent": "ppo"}, {"env_step": 1800000, "rew": 443.6, "rew_std": 57.05953031702943, "Agent": "ppo"}, {"env_step": 1900000, "rew": 424.75, "rew_std": 63.06078416892704, "Agent": "ppo"}, {"env_step": 2000000, "rew": 438.4, "rew_std": 42.03617489734288, "Agent": "ppo"}, {"env_step": 2100000, "rew": 468.85, "rew_std": 68.96160163453283, "Agent": "ppo"}, {"env_step": 2200000, "rew": 474.1, "rew_std": 64.23659393211942, "Agent": "ppo"}, {"env_step": 2300000, "rew": 467.0, "rew_std": 42.47646407129482, "Agent": "ppo"}, {"env_step": 2400000, "rew": 488.1, "rew_std": 49.019791921222996, "Agent": "ppo"}, {"env_step": 2500000, "rew": 528.75, "rew_std": 90.16602741609503, "Agent": "ppo"}, {"env_step": 2600000, "rew": 522.45, "rew_std": 87.87617709026718, "Agent": "ppo"}, {"env_step": 2700000, "rew": 504.35, "rew_std": 51.12047045949401, "Agent": "ppo"}, {"env_step": 2800000, "rew": 528.55, "rew_std": 70.213050781176, "Agent": "ppo"}, {"env_step": 2900000, "rew": 521.1, "rew_std": 44.84852282963175, "Agent": "ppo"}, {"env_step": 3000000, "rew": 565.5, "rew_std": 67.83251432757008, "Agent": "ppo"}, {"env_step": 3100000, "rew": 526.7, "rew_std": 55.79569875895453, "Agent": "ppo"}, {"env_step": 3200000, "rew": 610.9, "rew_std": 55.02990096302191, "Agent": "ppo"}, {"env_step": 3300000, "rew": 552.1, "rew_std": 85.30791288034189, "Agent": "ppo"}, {"env_step": 3400000, "rew": 594.4, "rew_std": 72.59814047205342, "Agent": "ppo"}, {"env_step": 3500000, "rew": 560.7, "rew_std": 89.29171294134747, "Agent": "ppo"}, {"env_step": 3600000, "rew": 580.25, "rew_std": 79.42205298278306, "Agent": "ppo"}, {"env_step": 3700000, "rew": 629.95, "rew_std": 90.99023299233825, "Agent": "ppo"}, {"env_step": 3800000, "rew": 593.6, "rew_std": 96.24598692932604, "Agent": "ppo"}, {"env_step": 3900000, "rew": 633.6, "rew_std": 63.77060451336494, "Agent": "ppo"}, {"env_step": 4000000, "rew": 623.85, "rew_std": 79.62538853908345, "Agent": "ppo"}, {"env_step": 4100000, "rew": 625.55, "rew_std": 71.11520582828963, "Agent": "ppo"}, {"env_step": 4200000, "rew": 631.1, "rew_std": 60.92405108001273, "Agent": "ppo"}, {"env_step": 4300000, "rew": 652.7, "rew_std": 78.92122654900898, "Agent": "ppo"}, {"env_step": 4400000, "rew": 645.25, "rew_std": 61.85194014741979, "Agent": "ppo"}, {"env_step": 4500000, "rew": 684.05, "rew_std": 84.49658277113933, "Agent": "ppo"}, {"env_step": 4600000, "rew": 696.05, "rew_std": 90.35857734603837, "Agent": "ppo"}, {"env_step": 4700000, "rew": 651.7, "rew_std": 98.24744271481065, "Agent": "ppo"}, {"env_step": 4800000, "rew": 710.2, "rew_std": 113.41190413708783, "Agent": "ppo"}, {"env_step": 4900000, "rew": 719.95, "rew_std": 103.00544888499832, "Agent": "ppo"}, {"env_step": 5000000, "rew": 702.85, "rew_std": 71.93714270111094, "Agent": "ppo"}, {"env_step": 5100000, "rew": 657.1, "rew_std": 91.01615241263497, "Agent": "ppo"}, {"env_step": 5200000, "rew": 669.75, "rew_std": 95.95891047734962, "Agent": "ppo"}, {"env_step": 5300000, "rew": 730.45, "rew_std": 102.41861403084891, "Agent": "ppo"}, {"env_step": 5400000, "rew": 707.9, "rew_std": 79.9180204960058, "Agent": "ppo"}, {"env_step": 5500000, "rew": 711.65, "rew_std": 116.25189245771442, "Agent": "ppo"}, {"env_step": 5600000, "rew": 742.6, "rew_std": 103.81541311385318, "Agent": "ppo"}, {"env_step": 5700000, "rew": 752.15, "rew_std": 98.74513912087015, "Agent": "ppo"}, {"env_step": 5800000, "rew": 791.7, "rew_std": 111.0621897857232, "Agent": "ppo"}, {"env_step": 5900000, "rew": 806.95, "rew_std": 144.94213500566354, "Agent": "ppo"}, {"env_step": 6000000, "rew": 827.45, "rew_std": 113.05871262313224, "Agent": "ppo"}, {"env_step": 6100000, "rew": 779.5, "rew_std": 100.94874937313487, "Agent": "ppo"}, {"env_step": 6200000, "rew": 812.75, "rew_std": 158.00810896912856, "Agent": "ppo"}, {"env_step": 6300000, "rew": 839.65, "rew_std": 123.6092735194249, "Agent": "ppo"}, {"env_step": 6400000, "rew": 852.95, "rew_std": 132.6488691998541, "Agent": "ppo"}, {"env_step": 6500000, "rew": 833.05, "rew_std": 148.62073374869334, "Agent": "ppo"}, {"env_step": 6600000, "rew": 887.55, "rew_std": 111.08947969992478, "Agent": "ppo"}, {"env_step": 6700000, "rew": 793.6, "rew_std": 104.03119724390372, "Agent": "ppo"}, {"env_step": 6800000, "rew": 832.25, "rew_std": 154.1725088983117, "Agent": "ppo"}, {"env_step": 6900000, "rew": 871.05, "rew_std": 154.96926308142525, "Agent": "ppo"}, {"env_step": 7000000, "rew": 833.1, "rew_std": 101.21086898154763, "Agent": "ppo"}, {"env_step": 7100000, "rew": 885.15, "rew_std": 144.50104670901175, "Agent": "ppo"}, {"env_step": 7200000, "rew": 850.1, "rew_std": 142.2687246024227, "Agent": "ppo"}, {"env_step": 7300000, "rew": 861.5, "rew_std": 87.94373201087159, "Agent": "ppo"}, {"env_step": 7400000, "rew": 834.6, "rew_std": 195.45917732355264, "Agent": "ppo"}, {"env_step": 7500000, "rew": 880.95, "rew_std": 143.8566039499056, "Agent": "ppo"}, {"env_step": 7600000, "rew": 921.95, "rew_std": 171.26462711254766, "Agent": "ppo"}, {"env_step": 7700000, "rew": 906.05, "rew_std": 214.73034834415, "Agent": "ppo"}, {"env_step": 7800000, "rew": 934.75, "rew_std": 217.31075099957664, "Agent": "ppo"}, {"env_step": 7900000, "rew": 927.8, "rew_std": 146.93998775010158, "Agent": "ppo"}, {"env_step": 8000000, "rew": 904.5, "rew_std": 154.3149377085705, "Agent": "ppo"}, {"env_step": 8100000, "rew": 902.9, "rew_std": 179.20083705161647, "Agent": "ppo"}, {"env_step": 8200000, "rew": 941.1, "rew_std": 163.1423917931817, "Agent": "ppo"}, {"env_step": 8300000, "rew": 956.8, "rew_std": 210.935440360315, "Agent": "ppo"}, {"env_step": 8400000, "rew": 913.4, "rew_std": 155.79261856711955, "Agent": "ppo"}, {"env_step": 8500000, "rew": 907.55, "rew_std": 156.9779363477556, "Agent": "ppo"}, {"env_step": 8600000, "rew": 883.95, "rew_std": 164.77324570451358, "Agent": "ppo"}, {"env_step": 8700000, "rew": 963.85, "rew_std": 182.24695470706774, "Agent": "ppo"}, {"env_step": 8800000, "rew": 993.0, "rew_std": 205.16420253055844, "Agent": "ppo"}, {"env_step": 8900000, "rew": 961.75, "rew_std": 131.86114856165935, "Agent": "ppo"}, {"env_step": 9000000, "rew": 969.8, "rew_std": 228.0311601514144, "Agent": "ppo"}, {"env_step": 9100000, "rew": 1003.2, "rew_std": 189.2723170461016, "Agent": "ppo"}, {"env_step": 9200000, "rew": 953.9, "rew_std": 193.50074935255418, "Agent": "ppo"}, {"env_step": 9300000, "rew": 955.5, "rew_std": 164.37198666439485, "Agent": "ppo"}, {"env_step": 9400000, "rew": 989.6, "rew_std": 161.20899478627115, "Agent": "ppo"}, {"env_step": 9500000, "rew": 1055.5, "rew_std": 215.21524109597814, "Agent": "ppo"}, {"env_step": 9600000, "rew": 1071.5, "rew_std": 225.1992451141877, "Agent": "ppo"}, {"env_step": 9700000, "rew": 954.35, "rew_std": 160.38080464943425, "Agent": "ppo"}, {"env_step": 9800000, "rew": 965.05, "rew_std": 193.5224082632293, "Agent": "ppo"}, {"env_step": 9900000, "rew": 1018.95, "rew_std": 173.74959712183508, "Agent": "ppo"}, {"env_step": 10000000, "rew": 1129.5, "rew_std": 145.34132241038677, "Agent": "ppo"}] \ No newline at end of file diff --git a/examples/box2d/acrobot_dualdqn.py b/examples/box2d/acrobot_dualdqn.py index 76246fd3e..8d3bd46b0 100644 --- a/examples/box2d/acrobot_dualdqn.py +++ b/examples/box2d/acrobot_dualdqn.py @@ -99,7 +99,7 @@ def test_dqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -132,7 +132,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/examples/box2d/bipedal_hardcore_sac.py b/examples/box2d/bipedal_hardcore_sac.py index 1d2d7f1c1..f440c8000 100644 --- a/examples/box2d/bipedal_hardcore_sac.py +++ b/examples/box2d/bipedal_hardcore_sac.py @@ -161,7 +161,7 @@ def test_sac_bipedal(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -180,7 +180,7 @@ def stop_fn(mean_rewards): update_per_step=args.update_per_step, test_in_train=False, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/examples/box2d/lunarlander_dqn.py b/examples/box2d/lunarlander_dqn.py index 88f4c397b..cd1b2c2c5 100644 --- a/examples/box2d/lunarlander_dqn.py +++ b/examples/box2d/lunarlander_dqn.py @@ -100,7 +100,7 @@ def test_dqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -127,7 +127,7 @@ def test_fn(epoch, env_step): stop_fn=stop_fn, train_fn=train_fn, test_fn=test_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/examples/box2d/mcc_sac.py b/examples/box2d/mcc_sac.py index 0638e8f61..48436bf67 100644 --- a/examples/box2d/mcc_sac.py +++ b/examples/box2d/mcc_sac.py @@ -128,7 +128,7 @@ def test_sac(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -146,7 +146,7 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/examples/inverse/README.md b/examples/inverse/README.md new file mode 100644 index 000000000..8e5276bbd --- /dev/null +++ b/examples/inverse/README.md @@ -0,0 +1,27 @@ +# Inverse Reinforcement Learning + +In inverse reinforcement learning setting, the agent learns a policy from interaction with an environment without reward and a fixed dataset which is collected with an expert policy. + +## Continuous control + +Once the dataset is collected, it will not be changed during training. We use [d4rl](https://github.com/rail-berkeley/d4rl) datasets to train agent for continuous control. You can refer to [d4rl](https://github.com/rail-berkeley/d4rl) to see how to use d4rl datasets. + +We provide implementation of GAIL algorithm for continuous control. + +### Train + +You can parse d4rl datasets into a `ReplayBuffer` , and set it as the parameter `expert_buffer` of `GAILPolicy`. `irl_gail.py` is an example of inverse RL using the d4rl dataset. + +To train an agent with BCQ algorithm: + +```bash +python irl_gail.py --task HalfCheetah-v2 --expert-data-task halfcheetah-expert-v2 +``` + +## GAIL (single run) + +| task | best reward | reward curve | parameters | +| --------------------------- | ----------- | ------------------------------------- | ------------------------------------------------------------ | +| HalfCheetah-v2 | 5177.07 | ![](results/gail/HalfCheetah-v2_rew.png) | `python3 irl_gail.py --task "HalfCheetah-v2" --expert-data-task "halfcheetah-expert-v2"` | +| Hopper-v2 | 1761.44 | ![](results/gail/Hopper-v2_rew.png) | `python3 irl_gail.py --task "Hopper-v2" --expert-data-task "hopper-expert-v2"` | +| Walker2d-v2 | 2020.77 | ![](results/gail/Walker2d-v2_rew.png) | `python3 irl_gail.py --task "Walker2d-v2" --expert-data-task "walker2d-expert-v2"` | diff --git a/examples/inverse/irl_gail.py b/examples/inverse/irl_gail.py new file mode 100644 index 000000000..1b9d2da73 --- /dev/null +++ b/examples/inverse/irl_gail.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python3 + +import argparse +import datetime +import os +import pprint + +import d4rl +import gym +import numpy as np +import torch +from torch import nn +from torch.distributions import Independent, Normal +from torch.optim.lr_scheduler import LambdaLR +from torch.utils.tensorboard import SummaryWriter + +from tianshou.data import Batch, Collector, ReplayBuffer, VectorReplayBuffer +from tianshou.env import SubprocVectorEnv +from tianshou.policy import GAILPolicy +from tianshou.trainer import onpolicy_trainer +from tianshou.utils import TensorboardLogger +from tianshou.utils.net.common import ActorCritic, Net +from tianshou.utils.net.continuous import ActorProb, Critic + + +class NoRewardEnv(gym.RewardWrapper): + """sets the reward to 0. + + :param gym.Env env: the environment to wrap. + """ + + def __init__(self, env): + super().__init__(env) + + def reward(self, reward): + """Set reward to 0.""" + return np.zeros_like(reward) + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--task', type=str, default='HalfCheetah-v2') + parser.add_argument('--seed', type=int, default=0) + parser.add_argument( + '--expert-data-task', type=str, default='halfcheetah-expert-v2' + ) + parser.add_argument('--buffer-size', type=int, default=4096) + parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64, 64]) + parser.add_argument('--lr', type=float, default=3e-4) + parser.add_argument('--disc-lr', type=float, default=2.5e-5) + parser.add_argument('--gamma', type=float, default=0.99) + parser.add_argument('--epoch', type=int, default=100) + parser.add_argument('--step-per-epoch', type=int, default=30000) + parser.add_argument('--step-per-collect', type=int, default=2048) + parser.add_argument('--repeat-per-collect', type=int, default=10) + parser.add_argument('--disc-update-num', type=int, default=2) + parser.add_argument('--batch-size', type=int, default=64) + parser.add_argument('--training-num', type=int, default=64) + parser.add_argument('--test-num', type=int, default=10) + # ppo special + parser.add_argument('--rew-norm', type=int, default=True) + # In theory, `vf-coef` will not make any difference if using Adam optimizer. + parser.add_argument('--vf-coef', type=float, default=0.25) + parser.add_argument('--ent-coef', type=float, default=0.001) + parser.add_argument('--gae-lambda', type=float, default=0.95) + parser.add_argument('--bound-action-method', type=str, default="clip") + parser.add_argument('--lr-decay', type=int, default=True) + parser.add_argument('--max-grad-norm', type=float, default=0.5) + parser.add_argument('--eps-clip', type=float, default=0.2) + parser.add_argument('--dual-clip', type=float, default=None) + parser.add_argument('--value-clip', type=int, default=0) + parser.add_argument('--norm-adv', type=int, default=0) + parser.add_argument('--recompute-adv', type=int, default=1) + parser.add_argument('--logdir', type=str, default='log') + parser.add_argument('--render', type=float, default=0.) + parser.add_argument( + '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + ) + parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument( + '--watch', + default=False, + action='store_true', + help='watch the play of pre-trained policy only' + ) + return parser.parse_args() + + +def test_gail(args=get_args()): + env = gym.make(args.task) + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + args.max_action = env.action_space.high[0] + print("Observations shape:", args.state_shape) + print("Actions shape:", args.action_shape) + print("Action range:", np.min(env.action_space.low), np.max(env.action_space.high)) + # train_envs = gym.make(args.task) + train_envs = SubprocVectorEnv( + [lambda: NoRewardEnv(gym.make(args.task)) for _ in range(args.training_num)], + norm_obs=True + ) + # test_envs = gym.make(args.task) + test_envs = SubprocVectorEnv( + [lambda: gym.make(args.task) for _ in range(args.test_num)], + norm_obs=True, + obs_rms=train_envs.obs_rms, + update_obs_rms=False + ) + + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + train_envs.seed(args.seed) + test_envs.seed(args.seed) + # model + net_a = Net( + args.state_shape, + hidden_sizes=args.hidden_sizes, + activation=nn.Tanh, + device=args.device + ) + actor = ActorProb( + net_a, + args.action_shape, + max_action=args.max_action, + unbounded=True, + device=args.device + ).to(args.device) + net_c = Net( + args.state_shape, + hidden_sizes=args.hidden_sizes, + activation=nn.Tanh, + device=args.device + ) + critic = Critic(net_c, device=args.device).to(args.device) + torch.nn.init.constant_(actor.sigma_param, -0.5) + for m in list(actor.modules()) + list(critic.modules()): + if isinstance(m, torch.nn.Linear): + # orthogonal initialization + torch.nn.init.orthogonal_(m.weight, gain=np.sqrt(2)) + torch.nn.init.zeros_(m.bias) + # do last policy layer scaling, this will make initial actions have (close to) + # 0 mean and std, and will help boost performances, + # see https://arxiv.org/abs/2006.05990, Fig.24 for details + for m in actor.mu.modules(): + if isinstance(m, torch.nn.Linear): + torch.nn.init.zeros_(m.bias) + m.weight.data.copy_(0.01 * m.weight.data) + + optim = torch.optim.Adam(ActorCritic(actor, critic).parameters(), lr=args.lr) + # discriminator + net_d = Net( + args.state_shape, + action_shape=args.action_shape, + hidden_sizes=args.hidden_sizes, + activation=nn.Tanh, + device=args.device, + concat=True + ) + disc_net = Critic(net_d, device=args.device).to(args.device) + for m in disc_net.modules(): + if isinstance(m, torch.nn.Linear): + # orthogonal initialization + torch.nn.init.orthogonal_(m.weight, gain=np.sqrt(2)) + torch.nn.init.zeros_(m.bias) + disc_optim = torch.optim.Adam(disc_net.parameters(), lr=args.disc_lr) + + lr_scheduler = None + if args.lr_decay: + # decay learning rate to 0 linearly + max_update_num = np.ceil( + args.step_per_epoch / args.step_per_collect + ) * args.epoch + + lr_scheduler = LambdaLR( + optim, lr_lambda=lambda epoch: 1 - epoch / max_update_num + ) + + def dist(*logits): + return Independent(Normal(*logits), 1) + + # expert replay buffer + dataset = d4rl.qlearning_dataset(gym.make(args.expert_data_task)) + dataset_size = dataset['rewards'].size + + print("dataset_size", dataset_size) + expert_buffer = ReplayBuffer(dataset_size) + + for i in range(dataset_size): + expert_buffer.add( + Batch( + obs=dataset['observations'][i], + act=dataset['actions'][i], + rew=dataset['rewards'][i], + done=dataset['terminals'][i], + obs_next=dataset['next_observations'][i], + ) + ) + print("dataset loaded") + + policy = GAILPolicy( + actor, + critic, + optim, + dist, + expert_buffer, + disc_net, + disc_optim, + disc_update_num=args.disc_update_num, + discount_factor=args.gamma, + gae_lambda=args.gae_lambda, + max_grad_norm=args.max_grad_norm, + vf_coef=args.vf_coef, + ent_coef=args.ent_coef, + reward_normalization=args.rew_norm, + action_scaling=True, + action_bound_method=args.bound_action_method, + lr_scheduler=lr_scheduler, + action_space=env.action_space, + eps_clip=args.eps_clip, + value_clip=args.value_clip, + dual_clip=args.dual_clip, + advantage_normalization=args.norm_adv, + recompute_advantage=args.recompute_adv + ) + + # load a previous policy + if args.resume_path: + policy.load_state_dict(torch.load(args.resume_path, map_location=args.device)) + print("Loaded agent from: ", args.resume_path) + + # collector + if args.training_num > 1: + buffer = VectorReplayBuffer(args.buffer_size, len(train_envs)) + else: + buffer = ReplayBuffer(args.buffer_size) + train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) + test_collector = Collector(policy, test_envs) + # log + t0 = datetime.datetime.now().strftime("%m%d_%H%M%S") + log_file = f'seed_{args.seed}_{t0}-{args.task.replace("-", "_")}_gail' + log_path = os.path.join(args.logdir, args.task, 'gail', log_file) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + logger = TensorboardLogger(writer, update_interval=100, train_interval=100) + + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + + if not args.watch: + # trainer + result = onpolicy_trainer( + policy, + train_collector, + test_collector, + args.epoch, + args.step_per_epoch, + args.repeat_per_collect, + args.test_num, + args.batch_size, + step_per_collect=args.step_per_collect, + save_best_fn=save_best_fn, + logger=logger, + test_in_train=False + ) + pprint.pprint(result) + + # Let's watch its performance! + policy.eval() + test_envs.seed(args.seed) + test_collector.reset() + result = test_collector.collect(n_episode=args.test_num, render=args.render) + print(f'Final reward: {result["rews"].mean()}, length: {result["lens"].mean()}') + + +if __name__ == '__main__': + test_gail() diff --git a/examples/inverse/results/gail/HalfCheetah-v2_rew.png b/examples/inverse/results/gail/HalfCheetah-v2_rew.png new file mode 100644 index 0000000000000000000000000000000000000000..f900a8c1adfc9b7e7e869b76e6e1d876b077c957 GIT binary patch literal 203438 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

sK?l*Qc<)llrUj${WNU1mT2w|^M zr8S>Cj;t-UXwSew-hQt*tL-NNSVLxTYCXxKA@T-_wJXwy1^3{XOT&1pnM)!d3wY=8 z;CEdRSfm4&0!A1sa%clmRHCP+jsW0IhmptcS3TL3mQ%trX638?$=65q6-zRxS$`1l zYl#is)@eZy{`EQv`UKL~NfLP7AuQ$KZEnCDhXA{!4b{0D87aqGT_8zn-?zAKaS^b& zLZb#e&%Li5XDg=$f;*T?1Zk29h`g9E@7A)zir~!YuIn8I*Mr&~D1r@OEfWNmVlu}? z$w3fD5H-+CzC?`yUDNw#mFn{5KddbdL6EV7rv1hWu5P_6)aK^JkXO_k zv;HqfYLIN64x@l2OX)`tZ)lH89Ws?+l83kve)NM6tDXYTA~^!jM(vR-B>7c2l(ivH zHllhun%0tSHj!J4R36JwfT8Q)@DKZrPd4y}VO-3WWFGFg9bTtHm@Odu;Z3~J>V0)V z>`4)QoMk2m!$4eP)JLuz5FI*LEEq3wt~rl}#CPq#{|RN1@#uUFoY33A$ZC#9$!^<< zReNVc4;Ks%PfQ=F4p_=z!8~I66smm(q;jYR;~z^V>Z+!W3RM$7-#;o9!&q^ z@*;eXSrDVA>}G?sT%&hI`57W1qJKnKL4Uv$B+qi{>3`FIz2?C6Z?9OE;pp&e^MvB3 zpa>AU0iM6c(FlIy&`Hnlz?NYMV8#-*3Q%!phnW7gW%1T8D;)r;zW2s!@?LE zF-49w@jtYHuNyZIFL<=z=)R%{MYfWsSCey!Y4Qb3Tp*8qR8U)(xO`~vlf7f#XK=Z;X$|xrY)dQA`z4l`n!4czsivyA2_>Fo+uLf zEVSVf4NMuqG1o(bjuOzAc5g-Fu-uRSEGzVbb==+S}! zHqrfvd8beHQ>?wQ>!sT%fxbbkno)PPk!|?d8)0^bbg~rCvqsAOf_@NV4%_ zvZfz)nx)S0A*e*MsHQ@<7*J*?25STc4lJIf&oYtUMtJmgKfLv-_<_w^JF?|fNqeKud(e_j-4PucF^xrR>GGG-dmONX5ZeQAD~Q;PfS zO}C!;IA%$M*J0hei-){v=mDX|qjFQXus%1(rkd<2E_hJu0$S=q0yPw=p{mHd)SeR_ zF{hwQ4LgD)eG8UpN!&n!2Js+6DLdTk=o+kGqOwOD@AmW6kpRj>B~>Faie73H&$Qo% zJOJnEfB6*UP(DG%-%gS`3d(G-iU$}wovK0%q8IGl5|ipKfgbGK&uLepa^MP14nn+9 zm926^B*wB3*&nFx)zGN@2M5ZJynaN2E0R?gSv7LS>s+_@SX*~%o>lz z;Enbg;@-iIP;UtE_Qfs=2EuWnccrLQ*e?0;8ehmtF404XR~AZ`ZA5c1LXg{K zxJwJZNy4~&xpN(Sr@Q4CzEDU`hu~K3e_A@aGP=1xdY-Xm!}ETyqPC%O3n^cUI?n+` zdA);mA0-0~1y2o}4ma6tM~Aeq#|bm=aeA-$?tW2m@%#6#Z-#S<5}BT8{d%ukX3`xo z8cD~{DzyA$g~sh5lyVQ%znTH5U1sV?VV8Q53;7GjQ5tcJ?6@OSz2S7`UUA`>%w#As z3iYC*WIt`J*>G>t&D4z7yRbd#0?{P->KqBR;>&yW@6#}nS=@inp1qVM_P-ueDB2|o zaVUAkI#Ial^LdKPhVE`sYT)VHSZYGUQ;*T}oV_1dW6LzAV#g%8W9J$2Rll~Y_bc+j z+Xco6T{2^lVWCZKU-`YY6j*Ca?X|UMt%KuFN3;emUD$prc@>a!&rJn*lTt5o`0ora zFboc1du0|6*%WT`X52`UHK4UJ9$Q|uGE`0cWb~%;u%J7s1N zziq1M);wD$GM&1?TgY83@e9CYeI=vjxWp^(za>RYkItNq8EV@5!yFa{LxG6~T}ZxY z@k$3mfBCAaDt=@spxe>7%s@f=R0M%lp>j?XuBPMcbm;~x#$X70Dkw8a-l!k8a}|00RZQU`(}MU&?g zUqZbr8gAFllWYkoqA1Y7(}M?*q-xLZerK-wBKEW1i&6oGge-#05Gm>&dZx90_2`n( zMr-uK5;Xl>^v>6pG|L-|n6u>Tw!qdBST*WeW$r-ivLPHxuQn$V@!B67a`wKql`|2f43oUD}Hw#i=HZ!drI0sGHs;PEkM*NM$}3B2asMk-eUhetnKTjcgY z%(q!c{&6%Q>GWX{kzt^`MQ1iz#lwWJV@EPK?5pD2uHF}3^JAO(B!M&s?}jBi?m4%#Z3#`7 zZvN&&jYZR^mJ6rP2&|#78n`%TQGQ4jwyeT_FCY~EaM9!ee&5}d{=ifI5JQ;ZC!Ea} zm3Lx2B!px`1qG|OjsdJe`jhOfpINdouZ-|8kdR?e48+&S(}|LnLV}=3gU{h-%>Gqc z)+uQGlcDxP%ie-smV~ePC&Rj!mfJtue*D#HnfyBMfWH0`p2r6ua@n z*ESX4{P)@``kSW3bI;dp=04sf7U+1riq(prtVZjeyQ!BMdqj*|bp1%-GV3|MV2@r| zHzFeiOWwXfV_Erb?`5R}r!9&~E_kmPuYNE22*;aFj;H#rIDGii#dV5&z+yfh^E;du zP(t{1Xq4mC;U|+w$<7}|JDygB(ViiS8K3)E%$jP%qEEbWP79ql$+vD~ucWBqf76oH z!Uz`(iiSu_2h0&1bim?74ZOgV4?JwY?)DEPvsv^+J#gCiK{KOABKIgb&(cpP1v>kCj*vP94H#h1z5&WtSdVSy>sdFrvHU4_yHd6xf{FOji1n@jh=K|@-^oMMeJ}JLi&x^Zd`aIUT-bT7z={BJn@-;LuJTz{P11}9Y(ihgxP!@FY zpM@I8&Fokky1dN;g?DZ2@VquZXkBhTEVVps{fue5`%xCtWl=DpDia+aQXseH#Yh3#rAw@ zftXSi>n}7A5}r}20e@APC?tV#0L6b4(G_hT$=guF%u$p{+*K=DRL4K}Hh5Hhl5^PK zBuq~F_S=i6%OvZmB-@_@wx#?t!aKhcVmy4PpPvGXGO@et3E@i39$c?RJQ#~^;k86s zh}pS9LY@VxKHkEKlCt?ov^Qxyu=?6YWmOazrVzmL3@p$tH*V#_USXRnqwb_M>N7IL z;Jj1mnQCq@80lZ@<6c%fyLp@hUb*oUFWwp6SunJ1QE8Cyky<~kaM1pOO_f(zdvB5? z#NOixE4R_IW35dQ*4h;4-dgZsxnhS8lCcE+NjtUt(hV4`u0Q(AM`dLV2Bl*Bu31TF;hL(h zJ##^2TcWqG#+-ZMp?2AQhV$Ic7Vd$q1!$;z8@eHiw3GhHzL@Jw@5Sil4#$4n8rxS5 z7XCKFAva6Vs^&nKJPh#rKs}aqx-Ya@BxDGNK~w$1kxS3@=tXsV2D2p1et3OUMu;W& z1%xmV^?DkF)qY6OBxFRvMDnP7zccljDI8f%Mdh>2tC1oV5-<=DT6}pH$~yDKN+Fu; zaRKll5z0!Xpm735$RrfPPGR^21QxUP_D+Y(a+lS+%(eNjiLHr>eY+NiwE;el6Z25V z4m?9k@cc|blsw(q`ugZ@-GX`~F-HMgIaIw=6G{mWL1L1mHib$az<6bXLjwE^5!vR* z=PHGFA$#x4$Da3W`k~T-cay1k#P^lGfaA_ga~V`#tQYH?Y(xG?P(m5WP1+}alFD_` z%$BvZdYWEEmUb`&n3{UmCpomt3=}cdZmHS3^1Y#wU&ZT#^Q0feT=!8-I8(@EY}=Z( z)B$2yrUkaYgpSK{Sx z8(A8^@SM>AV>Hh1fKBjYRU4USUZAW$c4R(J6@#m4eN9#JJQf4@W&m1;kIs<<56`o(HuG~=vV>fRbDtE=m2ZvP+zGsY80(1F(VoJKiZNLfwIIdkq{Mjz0_ zf@iFb`gfEk#)6A?%_dfO_y-k}#nXSs?T=D?>hs$5^}Qzq_q&Het-+3r7tbLglF6$3 zUKSl4y?gz`$)EDwe4Bo-;o?$p_psuHid-*tq0kudtMRWel_`ijl=ZA zJAw@C&q*pV;W|ig^7~{|mp8=UjPl|?xltx+G3fnerdy^$vj4W%M{^}Y%!+yG8q=|kdfBhmgkV)KqunN=qJmL?fhN) z6&Do5t*y(hr09^Jvec&~p9&?cNmvW#MzeU!TL-rp^=2EBYBqmgv^e6P7tH=VxM*Ta z$8_v{2`*}BjNd3gOUPpGgTSAJhBZ`9W>crJD0}o7k$%I_a5;p8;80l37`3x|cCKDA6N$nb92vUrt_1X*Z(BG`8{Xf)%86p78YLJd+~yrQr__;x1=O3jKk)Ip4pgF0qtP)8>&qi_mB@>%XGKc zcy}p;YN@u~QM?sjKW&ud&43a16KhgueQzSwG9t+*70ZNa7S zyCUnsOA#4PNx6`OhRTSH$YSuh1o1$Qb!o)r1U-~8NN{-x{!qO~vd~yiz{UU^U_C+# z27A*Pb(6J$X5SrK2g_P}+cRV%RH1=RRnHgVTr@4YK5q3FaEF^wY!jjU;g zK-NnP=6FDl3V4)zD6a|m3lg? zbfqvM8-#Wr-(UXhjcuY??2VL}bYwZ4%~O2ltV=GkpwcG`uEgOsf=P^H9jSdDdyqFzCdN+w$%SH4Fz*StJLIEeIR01n3Icqt{pf8K~dw2kqWwjL2T)8bLgT zEdGora0~x_mOGP4m~}$$1~YsUMJ|*8kh0&^yK*DTnUAgH!7EL;(G()J8y2lL;L#8H zFcitWZ{WLYyx!2{fkJ}(dgUlL)tYMTM@?!T=WaiW^2h{0fR1sK;scc;0k6VWBZRIK z?~*Pqj^&;RO%7cN_Ue3;@4xq3WYr%e#Jngl%jSI39b?{iy?VISs7|NoC_`tKd=by~ z>QG}q!ZAq&JdnsDR;WwK5n~&K#}8o_8P__Cc|1#X*rp8t#o?;}Ykh&0RWtrGAj3sv- zBFz}VLg)z zLd)Esp^F|yr@Or^VaZS5Ucl7bY%fvrKzhcv>7h#f-C2M{4D}%>k2HuBxQs1vSe%=c zFpWcR(|KhkV6KpOvLAZkDy!bl)vU~;uNQAbP8a95wjIlIHCET~+dnF$Etr*?HwCNY zT3bP|hvczr5W(%fcvs-Hcq3$YE>_&pchJcl79?GKqC{Xh1EHqw~@p~K9sz= znk&kFGbhwRqjEhLt1Ye4>p;N^8S!7F3A59zS%7@J%b_1b@my{GhmBVZe4lF#{PuA7 z+}ySyG$F@*>I3i3tf?{h)9*G4GXU%j16_VQ1~`Fi2(_EW?|SC9zX0f_=I-uZ<8$K? z5gqN^un#Qt3tsqK27~TGo`;90c3T?j2YBwz5E23sWBn}M(H)q#PF542G=lD)8Bg?E z`lC?9&>pM@?SM{xRnnR(W|pA}X~U9z$2U`l#eyz|Fdht*B- zA%{&Jjhs<}_EsTon91Yn?ZdQYcLoC&-@Z$H%1!CR^P1Yr28n&f<7ZdI#M6J&m^Tfs zh)KK%0BV#d8FF%Na=R(fkR+>A3S&YiCM-f>OJ8r@pe~3UFVQ$!WFRbx*4L5Edn9!L zGcRD~ii32`vU@wc;pAoIjMwUE?QOxQ^W0{w-kI(*AfU8XIK&kn^eKIqv)++EFHu7U z>Bt6Mhh06;_)1difO`RZPj}wxk_(0`kCP3l{{H@2MGS!juSZ}|5cavQw|N*DD{-4P zUT&mJnJ|4}9c!0|{S8aRrf`jXj8PrS2{79HT*LIQsT#FSt%0*Y#*cDFR~@DNtZ5luhaolyYmw=Z%I z%t`Y%dVX9Y!YLs{q(fn zj>cxbX^I$M(K`QS@-24@c&Nt)kCD=2gT^*eCy6QmO)f1C9ipQIc2v4Jm}ICZ5$JBu zR(UGYWg1#{mX2oSY~r|{4PT$;ZqRTkh%<;`Midmf1S&RhSU$VJHyF-dw9067jVnJ^ zJVP|gZco5q7z>t{ES`hP<~E(J<|P*Lr&7au>|tiYGJ65l-{WCH3<%6a|@Xu}L@MLQL^N zb3&JEWg&e*6+jt_I-1}^#bv+zoaTC~UJ!%SWhO=8>><-8_?d*L@WrAbmQ0F_av)tjcMcTUPr^5?oS~(7?iM9g4Gu&U@1Umd)w7FgdM&}B?hQ}%;z_d8NmqXBtE`GRN>e4M_7#f$7fS967>AE<;l zwwio+{^Za6*c2DGOwdn~{L?kU|Bw&5uWw_EVtrqEOLjDvJZue}GO`QEeeEP3bxAE}Fj`UuA`o)HO%YD3YY?;*!Rl;NxKv>HXx_E?wMyq2hPn^+7fRx^zz-KMlG z5I1|JnMEIE4-aGeRC~(*bq};!kztdxOuK5X+FDmM)en zhZa>gSMO!>mS#Cg_7WB~pty1aw>vh~JC|v;cq1=l2}$W;(EDI1UBr>%qWtpoE>+a~ z?#O3OA$|XQ+~=7X^zXvTGrUAouX~m(H-*62QCj_6eTaNGhqpi@#PEfR^~Qx|=6*5t zqwJ`$oe`gcWqcO1YflHwm-g)ToaDq}vH82dUlxq4;H@~HsaO9InT(aN{&*JpRrIE~U zi%da(2%(KfEPYaKAeJimZC|Gr&T#IFq}GiN8p(yws03;f4Peor(DF6ghj@#Go6EQZ zDCzlovA)aoJLc`X`Bh;#!h$ZQT|B}IX*{~^6#?cq3$Mi!56oR7Kt{f5Ap=LpIr6}A zR`yTMnT=G^Pa|`F%|AL<{QPothkbwS(8HOz9h9wqg)Z+wztyHYqzeZ4skRxk(G8WT zK9$j&78Jsy!Yr~GRRyz*lss8(WSK^K0vd-&D?2v8;1a~Q^rYJ^>(~wta|m7aRT%2D zZo?&*SDdfT0;_b(>AV*VBKEM8RT;hq%M{_7GeKp6oYQeh@pVv3pkD^!u+~SUX1oyb zHoRd+2Tc+}AbVcWA4sr+NJ*tg(V+s=s^s9wQE3Z@c`kU%6ZY!xZhm@z*4+KwS}sM& zJ$)sV+{2GzB0^rp5d-G3a`pau>;0TDc*=R)Op&8ZF01pY-4EYQ8P3xT>SxwtE6)?x z?My398SWNH(73<~(0miYyOHzz3;##jTZTm$w(X)aj535Ubi>dCC?FyoLx)HUN+}3p z(J0;BDJ2~ODk&0DQc5UFNlJHj$G#u*{noelI`*;FUfVy;4~4n!=gRXs&+E~gd#6{$ z^&{LdrYPIp09ilLs6^X8%%r$feopmo0<`@Jir=pG+8|(KGH|IZ#MLi<4K@5w)U46d zXYal&?z)XvwsID@ z92Pz8XNbyBfLaS%onP#LCy|jO&oD1hH@)^kI#_*2%eX4;rp5WIj^V1oNd~qNQ{mA| z0Q<_g2bBpQ=GCL0*1OXtB{EO0gkB&0iO*vV-pzgci1O{>eJ(2^99XM_6K`RCwfKa! zSXBAdb>32!1RSZJ<{{Qarosm0;0dPvZ@lfbXAP?ya_)d5qoFl|WvplUx5hk>Yz~?w zOEpYOsa*c`lKM`vXr-+r6*R>GMQI)=O6^Kz9k+~4m zsLSF#dMegd+s#1S`erxsreEOjM@B*gWiTLLU_816n^c2(tWl8+ zPZaVUa6m+Vv~107R!~$0JJ}G!bpRs==PnTu4GxR}Hx8r&7nKD5 z8R+}$4^kh_TbnqN9(WH&c^)7m?MtuV@-R!p>2^3hBAaDAPkrCJpNJ_P`18G9>>u@J z{0jSC@^H?&_Q~%%YaKR@YGC$dj!($Q!j?pFl^uZSRn+aLk2O_im(h=gs5(H;D#@EA z5}dE5ghF0}b&Zq{GS`LOS0*DpZs5XiFLy!*uky~2k*Bj-hL-!ayt?*G8JL1O>#v9@ z#0>qJH@}|RWarq)^*M1$RhJ|A9>J=}PCT6KoN6249U}Kj|KAb-C~2-cMT357hX2I* z5_6XPy*)R%0FzEMSN#sdGuvt43yIKVNINn1x+TjmZ%(wDyO4te2{Q;9&IaspJd%l)b7Im1*Pv@(XXA&qizmvZn zai`Gz$Wm~GyQdiwD=AQQNs+YqMZ%7%=dUd zUo75d*yOwU-cxapQ}9Pv02g6HFwHGUo7g(7NGg(|viIfhH&6`$3C=$b9DQ zyw_Pvf2cfVn_rjdXt_m}8_ZpObRw=oyB{W-hH(o7S5qcb%-Xp|RK4a$@dsVM7z-ec zvYe7R5iKWsklijyiE>;KzYJNmfW~4?Kw2`VRD?(l+ednwz@MvDsuX^3Znlr4j%W|;vl>*B~SzQq6yug3N^RvgPNQGSOS-Z)fglLp-p6!ZI2{8 zlU27@k9`#{(295b&pEiRU?FYPzr2x8+fh!XV?YJ3mmgT+a90ORdd873dP?5w&m2WE zM{N%Cbx56ZRNfnRz0#^%_ygjh@ZECP7bdn9+0c%U=dS zH*{5kbqXTm*3(n&?!6Mn+m296k`Vjr154}p`0qVFRdKS|*ugb+{o%bUxNsk3XpV@s z@8>r3AAHAb{$0%M?4jiBS$XJBZ3h81qC~|TdUrpiYX@I$^i{b6`+@exFy)4Ogyfe* zZRe;N^I9^JHrI<~|9X+NQ(&~3V0tS~bP>CTkzLo;ev)sI;WHM@1e~woUHHCB7O;=4YzOyPeSy%>jBHOXI;5D%U?Y;Ruoc6zrfmCdxs~z~#uq5j{8MWC` z_MI>Pe2X2_s}+d3?PSea<`=}5$(m&Bp7g;Y(q7kneKAI3+U4)PwfyEY4W$xc`^#i& zE1G&_%bc^b`BTfpm@pxh|I9rkr<8Lde|*G*t6W??pyCV?QD#?x27ZU=6pB>9n1n~~Lt#Dy z3iGX+vTr0nsoKcGYzCYSe3Jeo>l@(h#SCk`z9qa)$>3;#ui}=Kki{R33sT+=!s#Pu z2G9~8Bpg#{6T~%K9#xpW+{3o4s=ae&!x7S;?$U|moWe~UPhgl}ER*^&@RCX)*~RfS zUP7%@ecpG+x3)&f`d5_(-06FIA&35O|NX(0VrU7qI+Q@x586)U8efgmDepYO!_SQseT4f4nh2Mm+ z*923Qo2JV{L?Q(d({fTn6(6XZ$P8vh_x?~<apK0`MXyZIH}A$2C^h>^1-?l$lNB$fLLBCb-?Q>2Wp5mPi$UjbIc_R#p8YxeBm zGPcsQ-t_WHi8c?u@D%qqoS@#U3K1?ClPmCG<6O?pjoV(;?MnWy;*$y#pP*^dJ}Y1` ztSyda+d4mc%^x2=X=nO=9P^ncn-g$MB`I^m^Wt#dLqv&2)`=61{%RhhZ<9IIn`-mD z?>3p7G=6AgFtH)q3`P962+zNWIHW4Zyj`OQT|!x9F*}o2g7%5KrLx>Z+)ABMU@1qz zXI_{pl8whabVUTe0C&h7YH+p|GFMxn2IrnY)g{#hU`pd`CM^ckcE4&+XT6ty*B%y&{pe18*fANlvluJTr&A`3Kv9V9rS0hvUSvQV9^xvdhy z_ZnFNRY!g?Hn%VW56|%3Ci_uH=Z{H; z1Dsb4J5HU29^ef$OoqJq&uA{$OUT~jt|L4g+ZzE{jUS;~l_RZBpbewR4sQw+g}Sms z>*ZnIQxwiA%?5d4&VgAZyU|{7cQ_zOP5fYv1WdEI<6fS%2R(m5`XQon6A#a~<(7@c zJc7u{^J+dSraNB_e`qoZBb$7Cl;&Q>Am_b|f@1#yS*n`-UDny11~TZ+)rqRWQod44 z6nt?CzReeQPmQ^+p|X9?#yRWs>Yw~7xt{%0<+sjz2+AAeT-sY1@?#X?C#Z>=-rp

DMBAp5*?VGz}5du@Np7#PPxT6pk34j_@-7M$<7?8qdonJ{U2@=oatpsPOf9 zGx~fd-A#G?IZdl>ai>QWRqGG`=3LJO9E6`3mh~K%SHqxrHB?KYBWQ+KqCvi5AZEfw zM-zwF=rePWHx1zE=G9Y8vJRgRtlf} zCqzgZ?c1`B4a&o?I@co6pjWs;?5WPJ;*`S;G~E1Sbn1tmr%iVkJ}akp4tGc<9DXCz z`nqN7X8q!mXpZM3`QI1}I+~28lovdb=1nvqJzq=L!=okZ>B;A2x2{hy#SgA2sF^-+ zENu`YLBvsD&09W}tHb>vrhQUpsq!9Iasd0H(R##5(spRY4Pd&s=V3L|CQ$ze3?-;m zD>1b_p~X<+J8tv!>Nog-28`W|NQ4D!46uxnu#c|5GF1Q@NP}LayhaYVRa_7br8K4= zL?4aajSO4VM6_28fURZ6HRizbZF*B~{LadT-89wFPZn}P)Le?dU4nc*s zu{&?1f{U9kc|RmYw<)nqb4ygw7{o;MZHRoL0cq)_*{`B3I7HRv*Bfee27OC( zQRhO|eYzJ+4kebiSklA$H2~ag#`_^+ZLZ0rU)tdcyeS2E(IlUu_nJ3G34|9W*1)Ub zdvYN3s{7f{!~1T7PrDIU^{>EG5LE^aPsl{5!BY@Iy-6e-$Emk|6NXn#0J#wFT!;9L&j7Ve(Q50PNzdSlVs; z!1K^tb_2;5heij%TYi(7hT@5|>J%x1zNNFMQxl92*K<<9j5Ke?d)rLt|NN3}6sO4p zhU(>i)pCWXEOz6^SkDta(gs}1T(Bb_3M8(E zg9L#|;?Co{bZ0dn2k`0udfGLGwRy#PDQ?&J?mWqyLC6M*S>hmB9G5{(;0p0;X|--n zy(p7G+Op-{8{2;tFUOI<(i|i-uS&izD9hFluci3 zgeVDptupaZ$Q$t5B+%EBL4AD?2q{bg_ny47gZg?4{}fb)Ak^1e%Kc(MZbSfwV(2~b zHk0rS!S9ih@;5E6iw5G0ORyy-CcF`e#d60ra&)N@t3EmM0g_d&7Li*vEJ5|-J|Axa_28ao{GPW042y{hNhCC@qd!@;9YL4z zoji8t8E3^~_Z}&sXm>V+IWcX{^~lqdyBu}9@1n;%c5gX@R|GMh8<7MKHsqD|Tcg~I z3+ipf*D0Cf}5-+{)6cJqANckRh-FLr^cMzx&{x z($nmb!OWpC_R%N%Ch`JUrTxK!TXJe=R=uc%>BYqDQ^Ag5v&e-EOB+TYEy>Cop)0a* zN6RZ6bTKe7WtuyNG#ujwijN6{$1h{ZBu8P_b1{gGh&C#Y1kXP6L!>e9UOhl!v`?^q zlDX1Tg7~!pqJPOpuUsn_^XKRwJJ!4zEPKwmrRU}YlZmBf!n5h3P4hed%BsNFNpVWT zy!uRD6cYEs2Vg`y#BiB#-~*Y0rca8QAs=Y+Q$=N{Kt5o1?-v@Wq58!+n&SdUkO*Cm zEVLzEbR8ZKn8oJ$3wuxC9TMutWl!9x7TlWIE7urepa7{o-{e0kK>Jdc(2}2acE?0o^JC_T85uu z%|{^pQr$5Fen&g@e!Bk7MKx!bkNwts_oZ9HYkJ2 z;5z@;>^b8uDkIKon>o@xf4NG`Kx2xuE{-D54Lt2!Rp`K_il1%Yo*vU#=3@dTJAHbl zVAJyaT~2A85o$c@0mPjk7*4`F&@iRnU*+RIdg3%wHds$NcD;!^o~ASdwfuNiUBL|i zd3V%T25>aWcGdrg+ufu!eDRl{EFpU3fyNUsUst8Rtw{Dptn}rBkea&tr31ED0JDH3 zSz`G2me?N}H$>Tap2W~5^}UsPYV8{3K7{_>o&^RE<_Su}A>S+5l1^3c-S4uWELoxx z#fA}Mpf(pifuWQ}%>Xn2X(tRBSIF z2blkfSD=A(Mi_JjU$MQGq`#=c2t&p7jFq20$_YgG$ZCoNOZ2ynE&U60 ztAIJ%La37%`y*AE`kX<&m92~s&2nDs+hedXT~!6fd`jc?{1C_SA1Me$;7g(H;IFcR z(~LCvEMH|Mk{hNkttsle!X-*EH>+`UV6p0)orQk6bfrDAEPcCa3%sc8XyGLgJK`rS zbPCeBZJ!g&d*Xx`59}wafP{c{!4m{e?*{N#^c4cN_Ys)2M(eiPVIJ}RQ74W?Q9{S3 zc>uGHt6O!KWE?LiXDeUm@Tj6Dw4Z!mgjcziDTPAr!E3<`NdoDB{9mK`3(V@5JD7TX zC=chJ7~xSX)cpX;n@d=`#2c@ozX{iIkSFrkDuOr@?IbJli}OD?)rYrTt3Zz#0t$tP z`T~g`&gmW@+qK|PRGcJAB{88IOril=c^_imZ5!uDNmkz^e{5l=eU&9%+riFxukHq@ zjlMsh*IfJgz&2X>XRX|@!5YL1zW+k2JnUa^4^8vA3Mj7x;0cCc`S!kJ0fmMmC^XI- z@2%YWq&#jBa9ixhGKJQfH}9dF>H9G$C53BafbsverdQ1ph69SSD7P zBX296Q&L6^ri=XIykLnvl%#xLSIx=xiM9pYR@*(v_^n8KQ{>S+yXK1@Zw5h|T8FZf zzfs(#OIDy4ZL*-1{_e(gx8M)+Y8!P^nbA&8Gq)i#_y;)1<4;B*k%zG@vb>ucoksiw z_hq_gxjxtU*@JMb2EL{Z45s%9j>nVEGQA=>S`X++Z9uNPXU;Oc8x45%L_=(+_N2Mv zb4M$IZ!{fv2pVOp!g-EJK>`FYGK>^TfWc4#6wrV2-V{oJ3jSfJ3{fZnS}FZPAvZ!W z-STNOz7L{iLx~Q~s%jW=TfU`RT!cf=Sk<(}mO8*^)5X8jcQ?h z@?{)m?2ZJ?fdmO65Q-Y5P}+m`2?B5>aPqFR7McE35GuruY0hg>f9bo#cCmX z6((t$;>7T<;WCL{m7(HE-0aFk&xmXyUmAUjnmaNWB8oE^I%P7qHg0ci6>|0=VOZ?~ zMu8;8$gv^;l6fJp<*31ungj4w(m+GU?6YN|%p41xkD#&Moh0cvT(hrdD>WwysX4a& z>l~{158|_w>E@YZalXe^q~v$i^D6x2=tNtrTUc4&NvaCS60o%@o@52tiUpj8&iRYB zkT=MR1z;XYoAj?)%lix7|A~x3*mG{@vACj=u||Na}IAO!ZJ<*xa!sTV!* zh-%O(J1iAIX0L*%VlRX@8$%d9-z}L$3?M>kfD&L7n^;pxjsj1&%&j^CaEX4leiO2k z$G!f!Y(1PQiz)bLRm#*GNzT{(cV5+rx{!!dS?p!`?BE-|9SmU6AC72FH#@YeYnhT5 z0B?^40aamOTNt8LK$r=jXy>Tl23e-I?5WwQyc+)f9nd8Bub1ItJu1qVY3CjB_t|ov zbhvhL1t|&??!jcx6|nf@AK}6>A?>9GHD`G*H}DB3fBYnA%w5PP`fW09K+U1?O!X31 zPyKKLfZRK6oR+UfJAy70mUATkn zQH~mzk=RFjA6Rw)#Le8&CA>2(JpVvWg?e5A!DR6T8t_2#AwuDa{1gm8a)6o`RjD=p z2-a%sc=Px|DZezd@_cDj4Pc>zM2f!iP2}7paH2`!rUmUP(v4SuqahA)G$6^e-*8Z7 zT?i-|G7zNv-d}Sb3#7?j&-~ZJ&n}VA-U-%if`5Ru(R-sSd1A@)*7!~LhK-VE0L~Kb+m7_#(mQyRW zrw#flqmUrMIF9CxS)O@Y7`O>Yg5{Uva8pwUlRTxc!()N11lW*><(j4uxlB zIsN_4jj;&TG<-e332!M%J`5@jN)m**^_hiG!+>%M^3#m?A}O3?z? zaF?LfYb_NNb|KGq5Nwi%J}XyFp1ACqm!(N`%`P2(&lr6E41@zF8K2N!6L!!Z3WDYp z_voM8BJtq8xZgi%9Qo}Ts>TVXX|WGh_DtX#(_B=6PWhci(a8GI++JZUm7o!d8d-PftMHy|pqBE2r?h*2el4D&Yh)X06AVGux zJ7T(J_~e5Ylpxsr-B1~lP=c^l{l$#j2=J`2Z=bWoiKm1))qpvkJEdc@Qs0=mO z7|+%W5W1I1mWIA*k*T=%i_n3@Ix@7fZ8m3FJVxNj2YIaE3@iPe zomJiYH_!)(p{bTmh4K8uDFx@0%u?Ugn05CV{}?#Y<+r!ZQmoFegYH8yfY^F?dAFO3 zPi3~NB!Qcf)F78)@wh7v{E|y>ap)GXQHHwYSbq_(*74ISvc}B76|Jwd*_`JG)+@`O zBRTFA8US~YO~VIxQ$%*CBtT59=bNIxK-jYeB+f;LQw+aL1a}gm$;1L=Cg9UMS`q;S zyp|cVgu_Xe5J?xWb@>Bl1uSg91^6-|&oB`9eP4wr=>eV-I4KRCV%NE(122(No(n9|fumVB@ zD5cC3!isk?e8L3wuFA%1IaI&@|8ro&?L(~)6|ryoORjga2bW&{w?`lMTlVq4T_3W& z`>FDPmGcM~{0yU*5_RXd8$pB5tyxdEwFilEGy&8~J-;){oPBk+oo|$3(T~^3B$1+4 z>9?o)7Cke+Pf*l^C71F>l;;+o`8E1R`H<_vExL5xN{g{#+9t2w%4#Ol(nJ@<)=372 z+JM&F5X7npA2^4OYDUZWpTFs@ZnwKTPE=lw2XCGAr$3VuV%=6@y(z(~(tdJ-%{$E- z^8|uG1ioD@+yna$aEQEYsNp)Q;1f9!Ve%Ci9wJCS>GDcHlz-13x*%7Ck5FZ;d#? zh`+@kD^v^yeMV*RwsGDgO1fiz91HrJY8n-f#k(QZWq6=3z#vTh_!QLsvHr_we?2-I zZ_xT$cEj*7$`2b951M1du4b%8fhIWxj+6tLeQ4zkR0rj5o3bATCDT{zXt@~#v2@lG zh*1%f=25!9IS9%gHelA7aN(*PQP^*Mi#CB`sY>q8C;iYeksp<55^8VtR!3A?b@Jta zy3~Hm<`$UN4MfW~F#AIXSDN(k@WJGRAHk%ffVa8>xw`SB%wwbmIj|j_TXatd5Keb6 z*R~8rPi`93nd6Sr7OFFWdC=ddYz#U0y>k(TxAJ=%tvB@a006VM@zr~&!1l;q=i%q? zt-+Oxtp>YFC={tp@Mn!8X6k@J&(Ik+Z{ayG!~V|reLkx^hL1^^1bq?6wqR>YZvFu)=%6vuk435TURoeEmD}S0FXPx- z;98BK*52>ChB-)fgtw0rBxR1PJ8i&`&q_IXTZqn-*DDUa2J8S%E_075@2?pD)NG(Q zd+?jl%Dk~a>-b0jNwOo)-`4OyY`}sT%;GF^BI#^E6vuEG|m)C5tjCUZA}V^BatbF;8x!wM8KE zeP*9BaJ;je3(A%)F=b}qxL-`#Cq?y1e1K58q$7t3GWI{Xt7du|zx0#; z?Y^vUu3Do;*JodtxB?;ci$DtcP~=5r2*>}73u6L+NgzMXyYg}YNCvg~rzWB7dK$RDj#gt%4(`&jlZ0|BKF_s;Q#L~Y6J3}Hv#SdvIG^Q5E zs}oyv-O+0if&cMEW8N*L?L@G3V}(9O4k38M=QM0w*Tgtt2X%bkRYck?%CZ=)izX>? zr^x-8lj6e`*6!vgI(xcTXc&Iy?`_sfd1igD?-G(x5eQ8w-UEc!DW@T(;9xoBX+`MFdR5DG)f>A7&PhW4;xU_Ji|S%RsYwpb^Pst zr;L|AhqHm%$V%XQu<@!Y;@S~8C%iTdUlEULhZHUY5p&G>G-OsFQ45JCCA(@O2JD&n z^l9o>rmTR~sIaK}k$~l&&#$?3@-y;Zy6&xH0^Q565OVGp=AUZ{fF#pl_O;&U8nSYG zUCx}LwrG~8K*=s>+l);lj@jJYbXe?R)311uwAzq+J3;H?;~%iGD*!H!AiL~?DIf+h zv`-_O8R8_Bwvq1srs^>>oY~r~d#m|k_xx;ZGWG)SRsNCy#$^h~EVxMfWSIH*_@k#* zcPFe3Y(0m--h|O4ypK1li7(7YK12KKRA!v#9Ga3gXk29Zu-7bE%BwT%qJA5D_@F>D zW`b!sc2>(QM7=s6gGcfoMP3D8OxlwAumPikFb>3;bOMzY+0QF_eac_{2@!6_BdXxoGOE#)E;1~y@=Kl@a$q#vcQl^Zo^q1@2P?j8S z?ZJM-Y(048Xfkgk#Fhk(L80Jo_h)X@_oU+S_f&g;VHKxn^?@_YLgxvYp`_y1A$MU% zho!q_RG;HON`=-UxOn6BbanDj2VBctu+uALL^sdgl-hY2qPDw!89PCVz551~&mV1A zEyn|wpWDTUxMb9_fDxJlW@X1`R9(bea`!(I$|`FYmrAux86$(x;5y~{Yy#yijQkv~ zyJ{F_E21q8qZg#RyL%|Kd)AX22=?K?IwSdxDA(X_Kua!0xA#i4Z(TJNiv+8cdb(1@3ZC`9+gkLZ0~HBEfeZ#Shgwel#t0Q@)I)gJ z`4RThu{TY#^2^%oV2=byB0$>w#)}sqwAH8WE}I07*A8>_IOjUJR*s+F`+0Wftsai; zjT_|ewZS3_h)a^>^>h*_UmXo!aXNo745>cS-@`T~yT@s{()-FJeekP!nNt+$wBsgN z!J=iNMv=hcA=SE`FI2z^wq5AbeU4~Wwx3QNBYW_|czI~LXMe{$aQXAvw37CF?`9EU zP=B<7F|i=2Pgpj1!UXL7ic3yb0oxbs48H&O z1v@Lu2!I4cPXnC(H;Kdu)?Um%T-$UtKOEpc-4zc5r}I_ai!bZl)x)e6qky(kZFK!dZ@ z?EXx~4@9f(o&>!<-e#x!WR#ifVxgw*4S|FVs%t<`-jlY3Q%wZ`I%q1mcX}hGGL6_g zc)j4Do*9ri&@5mk!LQbq%K&4378S(6$^oua+4T_%2~11`ck&JLi@c1_1QUq@wL5_Y ztR7-X;6N-10NUV?N8GD4L^5Da#QQQyqZv1A8aMe$n-eV=S5W!_9MvwuCWGzs~Q(4>QJ> zy2Q3v%!?Ag&nosbi8#^(FvGyKTw`pKQMkCM^GQ!%b@(ZU>X73s10)bT%^RxTvh;@BlP-D?3CUF1OXc^gKFrN*xmF;h8}he_sO(}#H25eub7f)4KL)aMDyk> z0~N3~*bu`b@_+07cS&rUHkuP*TTFhJgyj+wG9Jd?Vj|P;MQ0~#HbJ@+e z9)TSIhu=Nxa!ZwjkOda0-_XnxqK0@0Z+4cFi5lnQjm`;u+1HzxOtM((XBM5B3l1*CwIb|w0ltsvjv;m_su>?EMu^)M{Y4oZ<4>?HW z$0WHtb(5Fl$JKD9fv0{zSNVN-hX&fa)~V!H%hCF$KL*UFmBBkJ|B_%RS!BXOHKx5) zrozXXR#bV^HuhiLCakBvf{;T&EvC&c+1gIfsfoULz$9nIT&51xP1P1MCp>Z+(NPz` zi2`GDk{2(SHP3n1dt>rJx|KF(5ww}W01>3H<#2g$oPtEv{+R1xUx9W-Aq%LUOi9H~ zAU!KcT-pi>0e8f^f#!d$V32?M<4?(Ku=q^N(2y=YA-wd_x1O;&*QelKw>T5BD}4gN z(#7b(u4zznW%}X}4R=tOhJpQn2~^5Wxu*Ucpw>g+4Ph|;P}Mh?k)e#5xa{3|(^XsN zsKE`V={{7_BT1l4)jnL6Xty^qPv}h{I=eP5Jr^FDm|ii79oP5j64cGHNBx6nhjLpu zT%r9+D>zLhKoC?W_0igdxJ^j!I;1HlJl1`^dB;E#>;f>pRRbLVsIN%piJ+~sDK}v$ z8xF)!5(UpYBf=KL9Y>1(-jT7xX><^fFDKDzXq38jUS^%1vn(1QFfiWX+%yF0_Y_4+ z_fRIY<688C3i|!k5sMn# zhWcrb^w->aZ@aS<#b(I6V%Tm!X$>Ja6QF^rT&srDS8tHhA>2ha?X*FpfI{KJ+;Pdf z3|jCvWTOaxGc*jU>d9X7uStZ2oUdCW1M#8$T<4;aBCZ%LJCc@NZ z@Go3+zsvFKEh|pT*S)b9A+~Ld*`1<+YwLbo3rt1;*~Z#JD6@mg^P5ZM1QXM;<$)Xf zILf0RGlQz;=UmYRe>#m{-v*bhLuW(drSdy3AX+6DZGsWvDOJYhF;bhf^WZkg z%hXQ|qfCC8h7?UuxhL`lB!SX2@hbW=sV$WJ73o+VsQ!WguL&Z8@_&7Lu9qy~Dky?a zdGa(XXa`mC6`AD^a(Hb2Gd3ozCqrdy{RP_JEW0Ur3^N8Ec>baIf7u|z<-o1`L8%$& z>e~$ZIImq}-TXEV)+0Rqk$g+QY2)FukqXQ1YYdi5k2PZUR)%Ev|2U?{d;oK5R0cCl z=7qW78_Vk?Q^hkgX5^m;?_hz01$zme(%l8yP(I!x-Eo);ZiG@lQbX$RUYL=J>&7xN zK3P|2J^siC$Ud+$o(|uS0Xs@S%|PXG972H8Fk!0t@{N|uDGt<4@MF#Y%vua^MW4RK znd!t5(LH!f&z5%dy7O~i{;j0<1A?_ zyOmyaU#iuEhbu%)^5)oDGYou3d)U;z-U(so_=EY?r=7L7PoRZF8Cx9NX!g!~-|rr+ zS1KI+2=1eGwOE}TY_=*SZ$KMe zcK`P_y0At$Y@uF{*Lb^H72J#M8Xrme3;1wMbTUVtwMnW-l=zD!Xx0$t-g?ql-=NUJ zJHmOm54IE?-64uuymB1x?uMn%LTYn(?RSi1=vD0f`($3l!)NTRMxw1BevXg7zNTl~ zSuYjv)xo=HtTr*UOqe%km+OXWZg{@ zbL@I6Ol+X~Jyk3r%O}GLw5~$;uThM|lO*sMm05C>+Rdsw8}8eeZvsmR@$m3obh97r zEXsmStlS~3*0cut2jR%eUYI1}FYy%S0Sx56UgPk8@^5<)Py)m@bxA>MW5KAH6iF&a ztYuJ3&%^wgQ<=x)fObq>*%F7V`mSc$hsf~^z~dIN26!>&T2cH(v5F~?3e94e4x2Cd z@??CgoA2)?fKhlugulprpefI;3tOO4Ni9>`dfh;6Fd9z*7N^D7sy*N_D8FA$4>ns_MF?Qm;nZ^SxQA$#-lt*OR(CtCd%ftrRux=nw#Q2#Y3s?0l?E1Va8 z7rt3-m|EL(7>k{devx{^ZbpgZrI@v=X88*EH{BBZqtF82>n_9AfR)xjoOKC_{_pIv zw!hu?^@M+%QRxuDH?u!Msv~LC?3aCE35BvtQHa-8C+WJssA${z;4CL) zo9VxZTtNQS5NDU)n*m~e^kv9SU}ieRHn97Q*K@%v_w#k3B29Z0x3bES=aWt(U~u|B zUmxh*1!N8n4+R?=XFC%XeTgJBPWIyL?H$)fm48a?)2)s-jIWM8lyO33DI&aO&(BUR zD~YK2{aP+oj%wvhEGGOTcx|$Kjcj}d zw{oCqlNFk-y<5;`CEhUSp;LDIrH9lI1NBqK6F-oM<;FdZuS4rVxpY4)*mHyOF(33k zU|mFWU`>5>8GwomcKj?yDl{Q|`Yz%ICQmK(1u@lUhs7zaecpx>8PD@mA&JA8Se}6y zQov}ppZlH(uCqHY-9rT=@ObOlX=p!LlOJxmc_+m?<2uoFB0rGrQ0OcIB$^g_>Q^26 z@Bra3t6ArOarb0N4!xC7lpB?o!i!b7Q zUMsKnM|HHk@D``*4K4&8Ug0emzS|Qye=>o5RIi-!hd{i!+eEE8BrMEKZB(5&jR=a& zC|;5s=3QjpHImGpTq{wbk^7_B)kc+n-dkFY8?WuB+SjkAZHr}$Eql(>(l-D4g}g^V zs^0hecSu+G55+>=>{`PUgEz*-l)JmTlQFa_aX7l4W%7DW+}!BY@<>xtQy(@Fz3=C8 zVJx6$b&67nmKCZgsPkWya&DYU78B%-oZxqY6ZV1 z55F0crPOc=tx9cv>>~UgUgczPhRbcYuV*h6&&2MO=($gGGvXCP+Q&S+rC7ac^((|E zSUU&CCvavR>j%mfc1FaKxK=8EwNGF$bJURL6E8h2nCC>)s66jrg=wYv-wY-ye2vHv z#Uc@BH3__zgtMo9elI;F1aD_|*FR8%j_%_T!GsOahawF=uMm63v4SrhH%gIAMjWL4@az=z*d?KUmPTOB z?@Y_!yD$v~9)x*D9JLi=Ve5hyYdL=?L-y=yh?V$cy4GmORo+hq7=t!vf8FrG~S+>oiK4CB6JJ8?xMknxD zl;aBB{v&ErpTMAM#(agdO*Y-qEiEZD(|6_lc>l=~Z1kXeoCIXVB$wZ}O0GFso8KOjuvq&(Dl$%5c=OO)VcN#n z4M-}6T2BvD`;6d)4Y$Lrx*-*794^@h z5APQZZmrgw_3wr5)@(Cfpnz?@U)CGW)h=JY+?OGZ%}+%jO(g1SXpyDWTOS6xF_LoW zO5S4Au0D?$^!I75#YcKkU!%T)vJ8C(<@zG8hsRuXL^Y?|>9zlI;_shq%S7q6+i_j8 z=*^>wl~9vGLQnO}-0b#xxVuF;eOSGN#ccGL;HK)BgJbR!dWy3%JkLN|Z!d9#FxoZ6eoSwv0o&h}qpu-Ai*f%%B3AKQbhy^N zP6*G37Dzq=t8wmIJb^fUi-3}juXlvmlmS=L0QajdSr;F)ZbjhT0;ny9=uR^HGG}U2oc;3__DO<{b zv->%gPS=l3srGJqYK@)bRllzaTZ$93<2)v(_J$MrzoFFb780v=w##db>no%GcNHKp z4bER;K}2HKcFuIPqNe+W7X$Xpi+2#Mb>++_z7c{U&C8(OD zFad0YiPbQl02Tud>zmW#-ROm}fv>d2Ni@3Zu`N#=>P*LcZv3Qp9b8d6SaKTuO>ZYo z(CtR+U2>BI_W9z=Mm366xFVhf>qo8iBj4!ZZit!s1L4;*sq;PM-Nl-Q`giwOZrE8| z&56N3Uz20sdF1vOt5vU#8S`V|+JA)H!2OYuJ#8yqZZVsJnX>rHzz zsY5ZvWKkz}HbXm+<4GDqd#qX2#pWOW50>y72ESc~c_U_i(5vj(du~3O?%n3B4-kgc zu520wsjQ4Ty2RV>2eI0|ikwhORZ!CFJeE%jEAjcW%OrV?@KfHpY#|z$Nrx@J`MPXW5?L1&EiGR3x>R=K1TwI zQ81v19YT+f<9t_@>+JLrPV&)$oJv(KH8>qx^|{7c7)O?=K0MGw$qy zgBBAWHTnZ)w!S)_Q=6-kZ4{FW6#Kc|?3zb8FRk?YT*pS4)VjYauk{}EsfHBOr+A@3 z9Mm^-ih^8}8C0mUEr@REFa(*E@r=0O;-lh9+Q1*#2gwO8uQ~sCPe?CPE4Zm}AlD4< zEgB*j5pDj^6KW^>N=*X6=1u+`C=@5C6_vQ?sR$5o`7gDPt^!@%)aOIJQB~!x>#EQD z@*B;e-!&tR8kJA;`E;{wuUC?=XJZ51W9)tt9B%I;2ikg!&x+wep&)g-5k!;SVAI(6 zDpy8-=pB0XG*ygRAk2*e`*>WD)4Ch6CR9Jn*7b8rX0KJCqvhAJ^L(+HHNg@&@I7-m zGELzKmV7Lrhw{Q;z}JGy`QngpJUn}H{l4U%gi&4iTkhsXP z_lzt!7ent?f3wpyQbK{;ZKO(V{dI7zR?ky~L*B@#Ioz%X)p??xs}cBc7%^YnA<2EB zwb^f+5{g<=w<=2*i%i6JZjpaT?)vemi(ZwWD^)eiHc9Y0^Kxa{gAVrbb2!_dlk^N@ za*()>ryl9VIC>u=U#SqkQf&l6B@{h$`5cr~%1_`SdzRTvg~fK+!jH)3BMgf_7E@pY z@u?Y&E!S&ImAy&s7RC^T5(59B?fN4sYYk{bheyig?ZpcCd#LvEhZ-mi9<1>P;b~Sv zUhfQ@>ET4PTFtV^D0XifNCLsj(Rp5Br*U+?!|}(G2z+r(x1CF~yqz<1xL1?4mLA1I z!;*S9US+MS`~%OH*7npZ+FG5jRsx@sxqpns6XKnl3m*8R%xM%*#{1UfaL1D0bBEor zpr-ET;`&;%hqD3-s6TQ7+cnMR-Zt6NHI>p;0lUe8gb0f>Fc#c!%w}nN{>G_Lo5_vn z<`-E9`nz`z$H7aX{PwD)Es;?)-Zt}1TA|p}SXiF`bw|1|NzZ8%Fx12w5$fF#yzAgX zoI-*-7|JR3kv6)yvHNuQ*S&Wh%0>u=L<9jciU>O9HO69&?QhG%8h=v%D0%9s?={~7 z4_*H9`v((q!|d1Fe_34n>wVOlcLEia29~79pD`WJrCLYNlFsjqo_j8?Eyx_bsv9lJ zcYME1=McLs?y&#b$@00%;@*dm>-%eZ8xtqAsS-sW^HLRLse1)o-R^-96N3WA$J*m1 z?S&bHo(nBKjgJ=?PKi;*w@lnXfY|OcfyD@uht3uKR9=G%GFBCma6WR`FCI%o9R>@B zBwwTT{nbt^s6Y}W^}%U1qxQ}Z##Duh%byzdOi8cldIQaID-nFT(Rfn-UlP?Iop&95u4@gQ@hE(Q= z;_XYYRAWn~3y8nutScsN5;9HZ4gfzT3(CR~^ zI3FIB3Y4m2%7X9pLBqFC=5(7Ksb0?C^r1D8CWFP#6**|f@EWm6y|G|h%*Zw7$khpB zE~jlaLS5JXJ7x>Fl0hi%oL`S}9#OF>dfp$sLw{6CgbjDYC38O|Cbx1<3XLtYzTKW0 z2%L}!TpW|nF+XAI?M=!7`{`x?36R%+1JBA)=WsxWZWPg$# zVaHIV9QGr ztX_azDS>X-+Y2oA1FrOS;RYUXB?Q9;wFWEri!4bOo=XDmAfL4xp?w1ms-UbG{5%l` zgZ=qMvPG2BLuN48F@`r8&2XMABW4>`4z)z;Ut#l0&K~xN7~;+CC&bQr8dO)GNu4S? zj$lKO34 zvdwy8f46&99nj!+u9AP)LeTkT3;VH%*Z@F7DHM25PX~?yHY^h&BkGvu6Ty0b#Teex z*L*1O@4XK~`yml@U;$(vWg}+__z!sMd`;RESgtqB)fbk?V_$B#iMmSy$dQ-J27{5j zILzU^bw}zp84itOcWazrll_NFQiyJ31UoVUZS$a=9!In1>gpe!HIzmGpvuU`H8>C? zaP&QuEAV|>!Wh9sXU;_Tbh5tX$gKv9_x~@}-a4+zwOIp({K^a7+o zKvWD;VFMN^-61I)j8<3*jv>duEG58IxTbZ{+g7~`;@sRhI^)*&4e}nKt@Uqp| zDd~wY0iY%gvTaFa!l?Np(aAcTIUTN~&mdt6;eX@i6l!)>^;)l-@VgeGnWyr=OaI5x z=V$fz!0YsTkXjcSu47YZS+UY2Dk( z8-jsbCOen3HCB+RmSR-PO7a?R*ks4v?kM@@3XRC;n9famm6fHbkMjU1ML9`;cE2W$UT^4kPG7bjJzhbX5Al^v-Gc4tPC+?nD zsTWzGi_92~Q7w5o|Mb!klX61j7%YSZjS_*g6^hCx(}M;iO$wMM#nX$BI7E$`$AFQBvWZvotr!-@AB?--kgJM~I*6Phnm8PVu0zgHGWvl6 zouPo7;RIU^4<7#w-ny>y4$U!HID__als>YHU9(9SOqVgzHhFzL_9s{h z6GTahU!DrOHu~N*bZU3&z4pC&Iz5liUy*;`8*R_E!V&bjF0$*@ zcMk3Q$=kYz6kKo^Y`=j8j>Lkoh#wMH8Jm)C2oU&LIQV~pbxZpQfdkF1}jbcTqBemx>b_6K5cf2R^ie1?f4HYwP@XEQHpB_D3%+jp4HcP?vHr0V=XShvqnrn2U z%8owhT^3-;wrL2GsivP#6f$kx?PJ)u$30DRe2@Qw`ww1=1H9I0h%-KA5G0?>Z1Ib` z!5w;h8J&efVhXMWqsM^On2ME6<&UnPw~=W#N&HL8^>KURCgctl=Ja|wv3L&PZ?=g( zUHd`E6~EELp<(qQcH1^QQJpd-z4@K?$5&sZyq~7LLvkWjoJ~7+q8-P*9zCBBc*JCz zdPV7Ep;$Q;O<&2S3~3cxRT}y%2@|$owUvha>%N4sj{3wa+YInU*7G7VhvmJ7em*^r zrKecQ|3CVy|HYxG&>DpuXJ_7VOVSR}b=L{y6*SkYLD&}{IbGPSpFgf#xV^>MbPI6I zYlCkvVL)Z2=Zx`t(JY(!g&`jwc@$(t8N<~PbLpQH#CTHAu&*eIXxO*w&1fDd3Hjr_ zwd)tw%gw*P@iU434W0!ycM$(uLDUhoy=3?DHluj_@Qp8se!vH!J0vjoWK56Xu!4j@ zeBump!of$2eixWYMW{lE`iXR6$`p*j zs??~fbnDnC*#VXna$sS{sr3k|&})^qDQV#YR^w*p1F(RgqF^wK!M~2)qR!O0jI=d@ z^s>7w04ckw*G(5kHftf9w_ZGVr;E4G<$F*|sONMCoF&$>lz*hMA4#j(UTSD-xX;l1 z{y2W7O4!>ad9R~2c?HwU`Wl&_XUPVJ9i_%548J^v0Oq^+DT!gDFurQzb<`w;V4CL< z^Y}bzaC;8Y8;Rmzt#!l`ctub_&U*1TvS-wSJ@pz#}q3?n2;%SAlH|;_<>MJzbQ_}i- z{Y&rkE7R$J4UYePqTtd#wV^KtPpt;Tz2d5rN9zliri|K9BygJFLaw}^;emM;@_ z4gBg&^<_a@_w34PxQ40NPOpUtv5$O^glF)@qXU>20+JZ|<2P+$`zXhZ$6dln(Zs1s zOjg{AfaRIl=JFN3i;{7Vt&bV0-c{ww zhdc}gn>gMCzGHbg+*C((q)zV$t4X7HYr6nvY;ah5c#91fMBJS?^OVf~1f7LnC%&GZ zpg8mk#jFme$xo40a9zA>x4CvbK5D)<@b?v?KmvUXSvVS92YJ2HsZSpcLfr!i^p0sY zYIuAlat@mr8YW2y^k;3>0680D|?yA5rb$h$v?TWI_|zQbDs?) zBK93Z9YygH?Dgq~>kpdA&dF!{T%|46sTjYY0o7XoD>$rgnozO+P`T!s9l(Cx(h=N> z|H&zC@9c`kCpL;=DBP1 zO?mH@ZBA!KHFb&p_g>cZ29SYG9btRH!+H98Pa^rYn5G15*2Uqdkd%dkiXL_dsuRF~ zt=d!uj9LI5;$%pG4{R=bh6MkgOZ*ZpP{x0J<#d(@`~Z)9Q?Tw1dMbP8Nkw3XJucIG zK2(|cEz}Fm_dd;LZ*}683CgjOkz6V7L-I0PCiQfl^UO3=t5U1+j%}W?9s}2YoBqw9 zs#L%8AJ+!s(M9HoY6gwf|GEyw7EH!W(h3_F%i8(Wbn30PgRWcjqi069h;?1Q@ zM$O4ro&S84k$f6GXbD7=FWE`JPyn+XTN;w;o6aU1?i=@C-r+6|lZIxK?qA$#zuhz8 zFJiZ-V%t-_I!q%?PY+n?Dt=R$GI%hQe<^AA=ABhHqm6*i8J))}TG35#zt*>mL~X9r zE<3)EzQ2>~^?{B&Mp2ob}yEmOQ^?WSXPVPt7zy=GqiVio$B9x;QYN;^1P<23|4AgcN?Q((i*VR%p$* z3f58V3Z|!3&N>v0ZZfB5T$%X|DIF0=nPdpz5lewU%GA5!NU=S-Juvey2}IK06M`0B zuH^uv^a!PT;)fh=aFp#tBevN@>TYNx%dpE?mJ~&j6l&6NWVoxQD1N$eZ*J?@`i@rv@ zS**)9rvLGxbwQM2tA!|&gqX*Fn-bHbO2wG7@Aoe<>U?$3Of<3jV*9U0x^gOUDm%h% zYConz{0NQQJ`GLNiJyuriY6s^+(nc{MEb+m$tS)xm_F9;q?^?na?f+v&iFN(HrlRJ zVA8A768N$Gn$*Gh8z(^wnOyY1vl!wf&&5TyUay_5?T6%*sxd3AkAEj*f4Uwdm;fd4 z$+kJEhcIeEc(`ekr~RUVL5+Nj_6mNv>u}RjuA+00!Yt3JQjGTB3E5)ztCyNF$=8I0lh|NKL4hPSaBRBVNT82(4q6NgGV$Jy z6QCvgoNEx-_0iwt-BWUMpnRpt?{3BX{PIHcbq@v zukL+V&X32DrEUwAk!QPJtRgO#j}13<7dI6;2+4SbmK~kZloNl&MD@%O(ybXPQu>Vu z&RZi7Xx@bV73lZ5-Mh+berqwV-&&Zn=;p+-2E2mrX;kLBn>^hjawo%vZ|w2Je0=^_ zhK5>5hOI`3fU?qk^?vV7r=7trg$ucHx67x+TU%Sx4j#H%{!qkw$K!Ifmu!-(`-A&2 zG3pO%fP5W<=mtTrVQ@|qkkz^TH2r@ran*4RmcREW-u6-((w4g>)3Xl`!QnIND7_ef1nZlFe3qZV^C)aEA9$AZP`V_4{3nvruz_ZS z0RAh1uRYveT|wqa`6CS!a9*xTV;xxDp24O4sN|sM+@M11yLTDYI~!qdYzEE%z3s)4 z>6DZ7JqEG6a=Tj&@g+m;(z6^%XH+LTQnI^^-QO=)b80@&EqD4}twwe2305Xpfy&bd zk1Y7Y9-DE21z(!@H8%Y<#gCrQ%O}fRVw`j$`RCiQ?=w%WjBc`IXFQ&@kmsrA9c*u( zQZW}A{|QApwRBBnAR4U6nwsaU4f~7n0@;|>)TFDjA)|$sSD&kgeqy%3!3*=9{;}0J zQPqQ&IU1QYX8&lp+nm;C!;NnZ{(Gia14E_vGsQ{B6!nly5m|NIEVGL2l!nD~ zoy062_>hng<4(*~j2UsD`%Gz2miFWEWr4G*Ym}#6T+jqj6G_i!kmXqY_>hWF9m^J4 z`P)7nlXW{W{k^iUNG!0Y=?c8>gA$~8yf^|Ww4Vv<#zFt+>yNEFlb0imfzUE3y>#tg zET*oSCBR#!LUy9vl z-3WvEZ|~K9!1{dS?W}1hul+&F`B~543XndqQS{&i zIUZoiiP4H20Fi=gbeYf`DmaK-4Ry89)VPCuHoI0L5e3-$Zm6ns;%3hW8xEn$rTdyw zxT%amcamMIH#d7lVaqs6f)>~H{t^*j5c|$l?|Kb9v)D34Q?huiv09j$f4C>{{bE+7 z?%c1u>ay>}AacF_y`pqLYKRu*ya-CZKH%GfSnrBt4F>;221Uf56*WEQY^c13Qd?td z_B4xb(ndjb5|T*>A_}p%aC;N=<9&L-1-dPfQ|`KXy>QBDhje>a$mp?PhRr}5Qo#pi zfrm3MjpsURx3-rl0q3_*zS|4rd)4|7Rr)74zJ)BUE*;NP&y-!frwJYDu5XhvsPWyr zE?73@$Jm2dZasD&ozPd81Y!!G$R}c`z#=i_g_ZD8tS-x5 z^0){hD1HBfhpd3hZycR0=lMwL&d<~FhV~@ioCiE#rt_}M4(Q|>)%bbeX6dUR^Z|wwP8b3)8>N?IwyPC}^Nm%Tm%yQ4tL4p0D;~^#Z#wUoyO^Ukjs1eWce45=b>?4{ zgb8N7rV{#{DqKb`$OSn#JthuPg;Z)KPiPVNs!h~&g&s_YQ~@ba*GkHR`2L&6;``TD zoov?!s$^9!!!lNldNZJ>p@vM*{RBM zr&8&ZlhPEKA8|oQnmjf~23*xS<{K3xkk&`Vd`=1wYxricv35Q~{mh;6fPW4)X2kSn z-1MuNxAqdxZ?|<<`{|f7?{D3Fd4sVkcsTdVUq~HAsiyD-dxG=xv1es{(lI+Ta#Qh^ zqsLtyOl9v5@;!yglqB)uf5|^kX<65gmF|0WBb19bq3e~5-2+;g9v$Y?ibi(V5|SdJ z>`&Q$74BtF|I63HB7Tz|QH&$rldsa>&-Ps-;&zc;p&1z&qG%+05ugjqU!*K!h>r6E-cHIABipL#>Q zq`r&^tu@I1!YIy>6B0@_-`-h_5`w$NLKCuM(WcX3SiMixbjJ*ATjC3U6G zR947@0!H<&+IpU)U1h+*Ze5_U{4S3lhmWVm&q99)6QBVQQ#T}44*IbO#I#oS??h&r z0mS@}n0M*bT?jZT$Qo$4Auh_ij1G1q_awStKVxO}|S10vjn zva3fRAvvhLM2IRtYD70nMnFzSPPqA0p2ueBmEp;%%eO@3%7Z;?YuF;`DE5eU(Si#- z9b4+Iiz(w!XXs`f5hDZMCXd|0fw5|l=v+?2uBfxb)d=AV^T21elQQIepRR^MhozXV zJZG;Zuk(1!*2S2cuvCM;H{MS#-=446Yx_aa{Voe0PGjfnHlgD#`P;7}Nx!rYx_!;P z%?2|GoiC2kAzj4az3~r2O4qQ#l7MlpC8NlJZN`R$ElFwd=_0_+Y5GDw(5_;uQe`ZOtsKZQ=-p7PdgcbI7J?8?+MD#v5)WSvRU04?3zPfM8P zU@lCbqZ~$SJOUN6{I9NrH<5)xMC{WO9X!)D+%mC#2fL+rB}+TT$jFN7J_Em3LvlsdXz6pgpvjv2 zM~m*R^N?pZ+;OuKoTwJ{;+v*Fpc>2yL4YsJL)k zD>NX9NwDk(+vO?`N$aAoKG7siGBOLz>@RnTo}a7r4@FbfbuwIg8=i`Yt|eE}9J{B# z7NsLw+yh7sYtX6QgjgV==tzJPVF$PN?!!nU4l0o!%X-ZLA#@*ZSEOq{Edhq~0OR{SF<`wyzt(t#8essNUiEVVI7m<5W-d?b0z? zm<$p-AQ;HR9FTtUZ6wRy`q%#+c|yg0EAv{;+8V1@;>Ow$jU4Zjn|{8^%=`DK;o@k^ zetE3tql#cA@YAP=MWH^U2ej<1Q-bLSGw&JJAznWaukIy2RyD^X5h9kM50rTL{{qAn zuRvh~A&|cqbK-Om@|d9E+qg~~sX9~UD!dl7$Q=?LU7@m7<1zN(XIot~m zpe13EyjF?x?gkEb9Ca0%uryS_VET!W;!q2+9&5H63vEKyAG5U2!Pp&AcIpNK$a0;g zYd#d)42Uj!Z_TSpIZe^au9*&+c%j){9)iO9g>mJh@7}wf&j5`jtUkX|9Km%aQ4K-u zP!Gv_x2Q&n%oSk%>W9CH zJOAj)@4D504=Q}<5l|5TprQ<^Ixc#2KrnnDXr$p+@&s-UVS4AUW#cqIfLC2l6#NbA zh|Qb>Hd zLz+)q@_t?%ov$M#Mw_eR!CddtRyddt^*{-?5LDs^*0|6@kl!xEY)`HxPx9oVe; zQ{Qd;$|Vs6#krNtzecrwDo3O#GGBn!_GFETrI8mH5zlU1=Q)pIVR;><6aLgcPh9=q zzofE-X^G1UKDe#6ire4HGCodjeW6O%eOR)+K9Pb<)X~t^rb%z}@q`P4J;dzeGYa;F zTR&pv!^f%XF~!~LeM?4F$is}y!*19e^51xj2R4e1P=wYMD7;b2K^>BFz|hhiE-HS- z(mc0q|8<~1()Vi`BYKPKPYqwynmzukp~{^V&qIrKlMXi(jNq|!K?2!h%LSm`M+0cwES zvA(HN7`1T3z(N88fPC@{LG8~RbGa|V*y5NQr=KA?8jnzRuo?r}!+ZIW%lj9xU5lln zwGeQ~sgL;hJjVnVH0!U;Q1flrOE)F`;R5c2->+DV-AtRvk-jG$(#8E^(SXJRhdtq2 zv91%d{Vv6D;M7gQ#_s1$Re5G^4qTTgy=ohIlY(@Imv8mPKQdc4Kak*D)mTrxBe^-< zb1O;F%{voIgB z6%0-hZTVT51XhThjqssCw*3%s9!}*6^|9zy0b*a9$mHca9G*d5Q{{&Q7E06yDNqX> zxVLPPd$ow~?+BKr-D6(9R|3Ztz%Cq+F5GWWm#NLO+%mb>A_~Lrbcvkv*uoZT@4=3f zW&_>LSLVojbyy~bKXIEp3D7+DO6X+0(Yq+bNEUKnU zfGT7|&IDY>Z2a{@O)vH(1y%C(#rNhk@0eL)3}I$3;Q%|!KKGlj{2i1p&)poEn7m|j zpG&=?>Jz!D9_yIa&oPDvDoWhUM^z)%(AU4b=Cz3YHMJ~o?U8Ems4D>(bRGGSQi2AT zFa;J9iF6(9l=!hxq=X{lb!S6}MhFN`B3;LOmkbo%?Nh)C;0N|dNAEzm_i$K-drLZ^ z?t>+{_2d4Usy@ip9;0V)I2{Do9GUJ@foiJ-fx5(Z?G{Q3^MRBe3_9Z=gUGlrYqL#6Puh82Mdx)U&+&) zFOPjBejUlN71{57$4?%<;2^t)^#FMJFWLK1!PXbFFdao8?N2|SB}}jg-2>xu^i-G} zgg^4LrRW)3;Gn|!NtJw3J)vS`y088bF_q>J0a6Ow20|yTQ;Uy~UwdkgO z{%^_Q$3c*Qs?El++pYmCGit(StEaWJu$ zypU8t%{D;)guH*tgd@c@ATss-^G*n4$wtlu@Tf5m)@|JJF!0XwdX~%Dzr!YAF$A2 zPAk^z>mH4MNH4J)WN5q%egGX6}zKb-E_ye1)>C ztSowg)-6B<==#9$DV@2FFj~~2;K``9NbjOitjJN&7jsBa)L^QH7yZo4)NoIZB1hr+ z{F4-pa%b#VCm+HMZ*ApH(>q8QR9fSH<>oCmV5H4ToDx`AYxGmZMjb-DaOmz@!h#7? zlZe5R<~oq>ba&d=OT9ckUp8l)Sx3dQ)DZY$NiND6>x@Ts+wuPqy=Wf$!(58qNv_I( z8l>mbKSC{LWA(G5+n?=@7+GjN+3J>2Oozaq_K7>o{{MQL6c8!PMBeF?v5UjGMv8AO z=?YE0*0AYV!-O%s7aED9i?iX6;_ur%oCqc};j4>2P}g~2h9BS+PiD3%!H^)x8x=WC z*9R_$R#zuJ=KN;Q!a1-?znOV&%i?g(+7AUmAb==AEX^0PV7ELgWPgNa0lQl@%W(Z1 zXK(4pR!6~);z>y>Ato(Mss`F<5B`BSvj4L zPDyb5%jIfi^iS8!T6$MR$be}w!8Dnc05#n%|#aMZ?R1nQN%a8-VEw>^$6N*wQ)TB*{c83rp>B06Ay4$XZZfl zwy~daQ>YBgm`&v6mH*3?I(=!>4n)a@mU)9>S?)Vb!^<_3qvp%FpclbmA62SV?5xl4 zIb7=e?G;%Xfs}Xe_o-C9&c_i&%m+QJ3_q&mFJASsR$;8T$ zxBVOL%bWw;Bog0YdGE|E&JG8uk zRfR*sTaeOkhvWQaEAhKAf|PV7$I$F3UtOfxPI~+k5gZD8Lr|cyS(xpg;grPi#pi!! z0sK3(x{IG7pP-8`&8#Y6EDabIy}ovjGEBy+;0YFOu7rQC%siy|*HGJE08HKF8oP6T zIj!H`hkI3jq-cBR!K58i@EEBINI#37zc*{~H%g>Dl-fWGDAC{S>+9g>173`_IlQte zx>rB;q2!tlKzsNfEhro{d2UaQfb#dKD|Z zsLt%3SU{R7yDPO>1=r_KxV{mcy`LZWQ!ZKDn0fAd&VGozTZ|$>d%ox=(g9*)8$9w0 zfpVXf5%EdYpt+?JJKq~S*WcY33loaFKq_y&GN)COnnm&O49W5%v_}N-KWo2z@Eib+ zBKB$wQzXGB=^{Kipf8yd0}uK0UHNeO-9d$UUKJlwglp~>6ZXMe{mH&QjoE#lVeoHH z-Sqml_$BZD`r2$qmNOueDiETlxI#5%zC0I8BHgU@9e*Tckk_9GMFojrPYiU`S7D^} zUaOeQ@0fziNEK=tHRL7OTdv<9Emjb;n8Kesz_DGQ`lTonZenGpC{u<)vpWkDOQVLVUzf;o8wV&1*}j6<|lw zqwP&R!Zj8IZ4Io`@#-*t!ptM_$?aC080oB#n_4gy|(ww3a+!OfwuR*BjlhY*%;uK8pxiSyjj zXD4Rwg>4<(uJ^l;cR{8gM74&f-QewGOv*@2s>=TEBbUv9+Gu!dwT(h>kvnuS2#~cF zqO(XFuJ#)F@`sqnKk4wJ{0b5A9>^Yh zBerUc7&a^=CUmzNjxpO;K@;0 zFw|h?H#me|U zz%vM{TsQ=tAqwI+PQ&9v5L6#%v7bSJfkMb7Wi5Ly=qZ0&56p;DQu|Xc`WL6zw9;m9 zE`NiF!nm)56RMIH)uSoZyw2_VQ#TxWW0Ono0?5SC67G*Km=XLvy5L2d^BzRwmQOD^ z)%tKtoW!}**t=3H`s~i!loe|Ol}S1ULy9r3J4*OARu@@&b1vpO`k5|x7yc6k7|oN2 zbICnOk0K%rLE`^al3Lpa=vexnV(cWtH2A@#FL)B+?C0bChv!Xs^6P1hl-J3g-thQa zdI}7f<{+PoVKPvsKMNW`MwdDZ1HGSz^?Qq9=7^TfdvgF*i@(n>?&+73hXST_a-jIfGDrZ(roNTfm z^~Jj!y405=$-vyQ#ODvAKXLydJ-LXaCwCz|`8`HfCRb1czEQkA`Z*4)fQKgmqr8Ho zCt1KMmy9s260ZHH$JS{H6pNLqmPjJnOwQiYw#TW24Lfi5E$AkKIR)SFD@udOdq(ebjoYkj zE#|u~z-3hYqgB{ufReN-kp&LNf_TPLTCTBT?-v^jRBWCsk>oO*hQTR09IGr~jN^J9 z?=^oPfM?^nG)>h=?>z3Qg|x=ZiJs4u*3;yLJFg>6;<{WhoW=tWJSC6TvFR-97(~rX zvB+$h?sz#^Amx&O^r>*9(C1LD4L*a%{j~?b1PCf%JS?)5G|rnK_NW{@^m~Efvj>ne zU6e%w4;^ZJI=7|JU5wITph{x$t4u?cJRtd(XW#rKfmHj(UdlU!HZ{Go^vbs2LF#4eQfTpN9@+=Y5s(|DkfYi)iMt@!W0) zd|Q#-q843m%kfVt>*$n$K>q7vY){3#zGe3&wn!5J9yDPu7V8kr&7CVPdGkVq zEGR*{IJoroxqk6YCLRoM`w@CzuzJnPui|q+BXE9t%aMtJd3|*;UiLfhFhB2*B`CJ< zb2T{Qd~_#*WTftTt{w#)HcSL5Wv?3B<4IL36`Y0a8eCTi4uVmDTUXJ z6m=rhMTV3F16>VQfXuswIE`7MfUJ9}i4$X>-he zN(;Cc9+Tk-Iph`O&9?%57B>0C`Md{UjxpjB%a}^Dz zh(k8hva)4)^g7hUyWg4hE2llG>U#lX`Z)CSbviVP7N6Kgug?+ceX zj({PLz?TOcB&&vL=W!$$tu{72<(QQz);hMARpifhK*X2l<2e9xfsi*0>d(Smhx`5# za<8I>b4?Vp?vb@@eB(BJSzRnYdE3(maVT7W_#pijaMfE*-DF;$*~0DV^;uV;W?pKE z9Wf9?u4AHS!%H;cvsuG}72cy863KEC*sl`%UPK=0!sz_>9EdZl&s;hsF{k6;f%O{0 z+7)mvC{Cx=* zgPfmkod!Ky6u86Wg(fb2MgJQ}E9@%u?|LP%ef-{xjZeAey|3clu?S2oK=Q*omdZNS z2Fqy_UMAF+C=f`?42lt;?71Oz?iUN5&rL$^ZPBaKTR1EkT#yDosqYMT;18#nM2rbg zdQhHJ`t%{~8Wt0R@SZ2=PV3k|J~g6@sDW1wfV=n`#=@eW3X$lWs$PRNhqlGk-Pent zk$kV&_}$n)XsvK>^&aX->TlY|AFcH5;(nf0cU(xnvzx`P^iOT9^eAvrPdd;`Ktaf- z13JS=5KZhmaBuURP*>XnKetoQ`{M=RFR^4lT`WIANgI2o!G#cW8u4p-N?{QSI1W@} zlULeS_gja@0c8fdKWpfEDa}ozxv>nf{xCTWZtJ!E4AD1x$)nvhLz$`d@$QLupdbz( z1hjV!)t(fJ&_`cWI|)2`)4MEjX6?$v-y<0e-Z%pfyN~SSTw)+a4>nR0-hPUnc+0B1g1W>mOknue_xC_YJj!+A z3S-Gk`)zZ1yN5Tcrzb?sCg{zG8K8fmjVgUbtPkA2tx!l$?ptpgu8ib<;ToA!o@#?R z@Cxm{^*x`@5U5_x**@&EHg*P_{GPc>6N*gKUAGKbQ^3)JZx1HAQz7;f`GeHe3W9%{ z`+}wZBlf&~c&c|CBrE2CZXY0Tjdx>Mmd|7M&Uh3^)66&RBD;mAZ`EV- zzy_1RE4u2(By>+4c~{!>+y3|^#8hP8{9phMXq1Evut<{!5z+ph=!0{4 zs3129Oz`?H8s}9CP~_qaL&MtVy@&gHiOmZeOoTj~f^3a685tR`q@-lc$C^fpApeEM z#RCSma?qF0_cZ6IZ?l| zEMKxhi2nCW0J3X6sJAedaPjv38sOin*Wo%GUSbZQPjl%4oG;v7pjmy^$#uW}FAMoU z2s;%a$=Y-ZL4%Mp5`tv?>8ro)MNDbU21--`%*Ig?$ccBeJadMk5;%6q z9-r$Uo)7~4F89;N!FMop_})y_=8QeR&Z83{Kn>Qvon$4ODDN%z!lXL6Jz4e_wIk+m z2~dSU0Db4j%kr7f)*GxY!K4=)Nl|ggrW%df@OU45DH`-ztqH^Hvj>O5QkT?!wcQ%= z3jRk+9PShd=AjGDj|S z>hi<4`1HuN;RRBCG5*yQf|W~WVf1lXwW=Qf;bBIYEbR&WOhLQ)Ba=Pog~F3A#7SD`%tP{^_In1`nt*&{o^cSA z3QVhI0N0Im)`D(dj!=Zob&sVr98Ktd<~PNgb+++%~cvqm7cd40Vx% z9)j7#5KMTl(DP$l;9J%{CYHfQ9YfsB1Cek#bOrJ;S7sQPfkSBl4kuNVXS3oOe7>bR zGNBSD3m4cH_GA39O%~9tVsIK5%b+0GH1=_Aeq?eY#e2n7f5~u2elUPt^x3(m)N`ED zPE$`nN6`h8q#v#Pc>?-2OFueayRY8-1xYTu^>$>5| z)ui}eMoRrh+?4$>TPLQ|%8_Yy(95&?rBOYt45pj|qpIQo+gE00(!6H-OT|9tnN%D4 z-nBJvoF8ejhMB2eP3#yZ81_H*bvg~$4PL(ju3+{Dsa!>dMI$pg2?&P_^6T=(HCWqkH<(<8Y{LP?IV({b6NH1t+O=~E(EBnRG<(!J9cT!GLB;5r6!1B>Mj%-`d?|r;^c1mgy}juLrKG zVyMbmWWGh)gU%|?&1Q2^y^*)~o`S%|ad&&wphrj8FNjipD+;#n{djxKW~px=uX^XF z+W;_+b6gk4|HHZVTOS8gZ3e<%NIOVSs7K zfF+>$0+Kb-b&b`Op0wkcGAA+|qo3ab;E*IoZajwMzU#yULv6``ZVGi+QLr6RZ=#OR zGGy-W&>}w@etK^1lfF)AMEpYuo8*+_Z90;2EytgqLIg`ksmo@oHVswvrv|E1F60?& zGf6vT0C_3a{oQF{KjK}Rl~~f*%lW3hnzmFdEVHgSKcZTH47QU9(}3`aMNpC5et2F~ z)}2=^8zanu>XR$voW}0bn_~d!cq1v2eSMZlf-9S2WM7I!*XwcFPRB{yPhDNKXw@S? zb>d97z339YC(jn&*#73J=3Kt$@GJ_xSRe8g?At6>(9 zK+vi$9YDn)*Rs_zLc-5S$QL>``tvE(_I7^~7$L|BbX*)((o*pR@nLO+l^w6|PQvr_*eGB%ZO7g+K zL)su>OD-aqU`6~?X+Dp?A~$5X3W&zV>Rjgw`jEjP*nE%;>a&uFh?40yeTG+&eL9^$ z-{h5-PXWczX&}K46BxTqa&8RzQ(D2=o!HoOEARSA4s(6@4tsbe+LQXhxNdv|AShGS^+yD7|J@Z$`0`$ttHdgJdowKacOjPa1aWy93KgQzZU z+zK>}rfSdG@0?4hIrLi`+8Ubq!uEZW!IQ)W+UwIQ{%h3Sq0tY{P8yhnp zq8Ijo^>;e)H8@Gh-sK8lkO|r~ATEr7!6BT(`{2R;#JV4OrYj0QB(Xib?urH-v`a@1S-|ul9>J24?EL0>4#-Uf_O5&Jnq*xl=t zhH*##+;@4`fCbt}fxaS#;`;EGx`9(2FM}-jTXNBU#I9px=|sL=V9`9<2gEVW2$N-@ zjX{MRh93vZ(g}W(xCtrizJS!4+yYjbBH2(_3B>xR)DuV}sT<+*yg%Dn|X{^?VR6RV`V z^Tl4B5Bf ze{~nQxK+vxvl+(o&cUOp@g>sj1+@Oz7F#7fS#N;p~?SsjJQ_E}{oAOF+ zv2CUJi#aqef!W&+Yk21Y29__}Bk ze)e*{kYMoehLOU=L1^a3bMxu(Eh)pE&f{HeukBbbRc|)r zKHl#sRJ0EI;7^d8x~Uu+^Ev$;zvBz3`&CNSqGR@gHPN(tqs%;7u=gtm^BnN-(=o%mMnoDH$L3l_Q=+0aF}x{OAv8t#$_Cz6IC z)NNHu(8b*iaNcBg*DG5Dbg1|1%L{ARsF4}Q{surXJ*yOf??a@Z^4E{~t1Ku^$q638 z%11g+7mW628XfptG;q+Q)jdwP@HXZsTt<;AMEJ+`JKo!d(%ysN#xvrnu!&-9)x zY)ZB3{(+0S?Mnjz?$znWf(i9`3Cf=iz_~mkQ<5lqwc`#UDYN~y4nfCk8G*Z5x0u>i zsUUXQ_*A#7s~1}IIKEaXt8w#^(9PO<*bX+j^id~XV!%Ue$i1+#&L5WGh+XKn{q8!^ zc%gc#u&u$ps4+%Ij@Q-Ib^G**xiNDh%I{ND>?+OQ-Di&*7}_b9H)F5OO6zuO z=lj2&w>07oyu#si?^-`TNa~2psaOF;Wz*wu@Gq#;FrRCvsX!)8`XRRb2l!9!Lq)fB z=m^nW0&wz2zT4mBZq_R4>&HyN0=5F1v-A?T4O7OLJ(oIrin%M+hQkWi#~(Mzt%eew zksOQdkq}OFyFRdcb@4^<_xs*Eiz)U?ovN#)CbLBHM3iEd?Xjf}6Roh~jvsc{%_Lp- z>Ub=nlcklw26~%{n+1)u<8DU|kus<0jxu9o&)7)2bl>3Y zcW3+q<4bo2PFQ>IMvhPN=`aZ?D>+MSn;)WZy-zYPi7F#XlN+^m9pkk&wl(Qj>efo) zc2(xwzXov<$(-MdC0?xSiw$|TUI0|V&wK9jaZ`RO7HkdnqxK< z1s?N_bOnn3$8MJ>oROY>EjLh@Z`GOB!8u*0kA z#jC%X!m`uS6z@_nm5q;;I5{}HGISXVEHJq3GO#dMS(f(Z&4mX-CW1OL^8x*?6G`?h zobk;JmWfmnLZK8ylzKe&l;|mp?wn~;()kf0sd#UJpQWkps=*=3~cy?q}~ zPS?BZ{r-M`zuWEm{k;FVx~|uCIuU*?ui8wF$Nw;$ z`u6Ud>t8zOOsK`FSL;_FiAsxgO4+|tjZ&XF;S%R|MEqx3 z0)O{&%^_+FF6q51Y2>zSs^0PmoP^u=JZwClP&plw)jxQ{N-*+8q|(UvQu;;j#+1>% zuy8)S;Sn;?E=jp#GRqlGd2br?!=AAinl687P3mLQKU`-!kPNRajJ}m15r^#{H$8pC zDbj#8z**?wT|X%i%#rOpj@eIHtjFf(?RgI#WU!9RmpET!_w;&p<&K>3qF8C&7Y2V-f~37 zIU{dvNq1;!TJ61y;f-Ahsm*E75XhreXC*VlK+L5xmo_1i|c4wGsxk3FVwi=?3M z>~%e@BW?ZMDLi>&$?uGtd-BMNxpnP#1NaX)A;3T282 zDfoIAfo_7E_`nN)K2)QxWXE%ZNoOQwBFAWIHAc4g@{c+Udd=-vC>eT`&YGOQ$kyo= zo9IqB?>3j>l$j&171?^JCax@Thrg6t_+D=hLlR1-*&)AL{3HilpXER`Ytm^rN4yi; zLF_7Af1dB%QLG*OOM47`^6`o+xU5_1-r;cg^F-?1i_`%$pc(hQ?{D{9)}vP&HdSw| ze^*Qy_F7g@*fr}^QPTr$`?uydKj%DZJ8G4dS3391DLjxyDD>NfdGY^o8pQ7+x641G z-u>~^&5U*pw{x)x1@d2e+yus*KgG1ATGvwE{A@5G+EAu_EV9g$nWI6(ruNFB8Ean( z$mxl+pd{);;4Ai$ferypy={3pE@Hodme<^DmaC8e<@k_#&*S%nPrL@Z93l`iAYpUL z!^_{Gp(w%B(tSZwZ?57MSCUtdpUT`)zKVlI*vDR*1Us?JLy3dBpVa0Q^VJRYQVWNi zuMFN3Ny%7OpV{mEqCj`rqW!-@4pG?+kG$2Ns=3$d43$-u9+<>a?X93e z<2^!^w61DR%|z_GgC~kK0v*2A%*N4o2?=DazL_mmdN(z!K4nQ-eZlr++pBM~In!w@ zvCT82&-uKo8--oVk;ZHVNT4wdEB9=-mKc$ ztE|OGsSZyEH>Q?+(|%gEs2nP5CT-jJPHA*MznfHxk72>m$*0Txb7>R#m2AOAywz-= zH1fSF4U7M*>(n%tnl~GVJ`}ula z+5A0G>6tJwA=NKzk5gtnXuiED{AjM%Ik~3GJK}wzP8l$B%~RsCx2`M<=dgp2`d>@pd?> z+t#HjwFzBS|7ArV8}dH*n7Ufo9Q-bNXJ1H77VUR@GxC!kO7MFyZs4^i5z%IMo}5e~ z%FO&5xxBr1J!C-biGl@oE`aVzJc<}&&QSAUT!B_Ul-MbSzAm zgybyJF*VXkRy3Hw%e|{Kk>np)#Hyv^IF>WQ*SNhv@3?is?3qt*tYRO{|{)w|Jqe=77ttsA=je z-(M6qPX&q}+sJM3IqzEeTsym;?!O_G8FHBHy7yk{bjjx$!>=*a) zb}#U>u{>$%Za)ZtHO~bj*QAJEWfZgW%&M-L!%kZHN#UcKWeysob?tx zIreASM{)t_S3PM9EB*}V*Gb`OjwE%^uNSwW*eM4hhC5j8$c^-iT@!nU za2y!8JI7kM5yO`yt69XL6MgpCheAjWzf?m2e{5sz(Z^n=7!`;7eLr2Rycaa71Xu0c zmQOYDNedo%M0Y*==@}!(;t^5^ZD_X49fUSSV?!&2ZMn>kDS~%3M^Gipu|9#|CF$}# zWkM9>!WWiU8L(au{o&8tn>qnjr%xdkx7*VPPS0uFf0kfR;W*fI?pB2m949Sk92+@( z8&C6m&4Jd%8NI8%Z=TzSK5I*laSKtZx)7yaQ!Wz_r!BHBQ!7KhJ{PpTb#}It zi$6=Himx3vQ^lsWS8RwiNg1rObRp|*>>Ic+UMWZd_X7{sS(!Ni38t-`)^^sy5c<*}KK5bNNEil2J^v(!A1UDZm6f z*H;F}NOzAtzj_|B5Y?#@E74`uN;7W?Tc@XKxbkxPAE(-FT=}n1=cN0urPigT@&>ZA z=~@wQo|joJ%k8(IrwSjvx?0kXtWOqMT&YQ-a)L?I06uCkoScD!F%iCw##2oJhIDO0B{J)H+Tln5LRk>=g0w zf{626_sn#P{m;i>?lQ8rUw>7;;G%bH!%igQ;$t>#*L8uktd}i^R@6q$Ehp@J{xj1e z)%xz(e}gof&Fi0gYoC#tMick^ThyLY9bM!9AG1?7sx#?p6j3uH-|j2jX|<207nr(}N}A6dQrG{#Wk zY7Xs<+`A(g*X(Z92WDvDN5x zi@=%(+TLuZp+N8jZQo-KLnp@}SHZ{LzY_~m-29N~viwC9qV1UPZ!_D@FwV@)^u9-2 z{JE6LL)se~0&P^CX3jsE&DR=dt~!5_<4B!Nnuu{b#sD7WTv3@p&y42oRQ7i!p}GbP zD>`>dl0!EP`KFhpHyl5^tUu`KWxCNi+n}YP(jzYE*gJ`z_m@w|wrP+j_=7b#Hcg<# z`RoC;{Fj>(MFO9bNknOPb9v|bY>udmeO!!D!Qct)Th*d%!9^|IC2Buk z>|?6CK`!2V;+dP{g&!_AYiWQMxF>j^p&|ng+l#M78)A$tb+UUdLWPC0 zO)ItK>_TB?$rQgW`Gh{*wX_c+Yftvyuqr(mG;>wSrt@3;LKtYGe;K{M)T5E;01q-q z!_K65vf^>5HfeT@i~ZsSc+oFj)@@jAaQ_c?vxHG+3sx9*IFsSFd4>bGRqh1Woktvv z-S_P{Yays(UC>_YAi{g~VAYvq<%UMJGN+Jm7MFyP^snb6zT1sF+o^292TX8(e#h2$TOF}h?;M# zuryK}ykAZTbdao=J$=Kmx1i5;=JG#U__Dt;O z)7h|7cd*E{%YQYy3N@NiMb7!+xs9y+K*z+n)zc98Y3Eht>u6DQd<)@b-CIR{k_#fb ztppy(g2Po?V`))D$FtAJi-3bevo%M1d9cI31cu7-;C#RXuwfZa&jKHlWR(>H2<~v# zS?;PimF-2vChrCwurrMfz4jI?RiFOcT??ls2E8=4ao?C0LIY3fM!TJ%$ZD?Sb37#L ztEerRIvmG0P2P~I0a18e$`K1Td?`qMOPq}|_AoC{i0hRexu+SNEucNDm@UK{P7*_B zDveEsG@tP~w}U)u8=S!S{KL7!C_hk&*28+{p)`|D$FeArFwDIXvMebiqB~Q6Fm>o> zVH%6#9#An=m!W9?-S3f9k+B{Iwoao84YiGItriWt%%aksx@$#r^Z_<7=7ABedoleN995dukGe-W4;MEuRtv zy%*?i%xHN2tf^FwY=@P}a*U;QZJ7DZc6rwGpl-=?1C}`B^Kg5OySdDm7Id=s0}jV4 z{J?JR|CxD*Uh(bWdd|2Rv zGfn~3aqJ?yc9QIe*WP%N%LPZuroaCoRFdtYJlFy_QVhz6T2C}!a4DMTBrP`IH|T#X zPoLJ4unkJ~M)BIRnN|>CRuRJ_-8!_L*0Ma>WZEO!0c=eZn&&4hL&* zN5G#?G|1)H`cTARq_Im)E@^DxZtB$3Cq+_4{R#evbWPR%`+sSSnMLghQx3Fqh?5he zVF@XjJ_siAT(4Vwt$D@3x<){rk z_Bznz^?{}$oB||_M;VmIy*yCc<9c1LB{GOAd_v;Ntk2OIBckFKaH7&T{qxESJI;kO z-3|?Bc1#{o?tW4}b9iKRfMw`)#N({c~9E)4d3?f`Z-#=7y9ebS|P7_bkuFNV13jK6Rct1%e{J)M5 z+kT}hA}(dyoW>Fr+SZwR;uc+xg@CjBvk%c+zWU=IJA+mo+C*$q=3bdLx~ebiXEX74 z?VYVUaxAh`h{7Su%~jFOBxo1IMs9Zg-RsO?pSLV8@XI$|@el3YM-LMDeSklJkOK0< zF*tA)XKVnRtFF_-d#WI#6Mnj>F*Y_frKH3_iy-{~fs%5dqy6Q2ZliG(h4`q`S?Ada zwF%dYWX#S77K1!o;1&f@B2nz)mWBszeZFVNWaH-f@r08?O19bDs{s8QR^?ofP8pA% zFZi;d@~LAV#4;^8#$}@AlOZvNCGXdvN1>Qzl>sajaB5d%Wk4*wIUtDZ*bV9wDfNpz zqzG90biWNL_BvD;Uq5a7ic0|>cl4J0xQB-(V(Cxi68j4m;-zL9M5Y1F@?J;(#sTQm z*}moTDelhH%N>A~mJu7P!?G{gcUk?FKav(#|4G+K09HR*7sPSJC|1hvW|dJQyoC1z zhJ|f^^s0QODARdSX@=7`&XVt}Y46455i>h+F_rGw)4ILKlG*S2C2EA;cQ3gyu77iN zNxP)e^Z)q<+4iQU>HK;*oH_&9j#HQQtV-unQd1S7VZsH?vwIhPC-WyS7yo>gF#xcO zJA1?#9s4}B&!0bNzH7e@(Sr)!xd=9zZS7aO|Dem0C~A2lXzqw4wrTG)1iZe*!@<$LLe zH!jb8$DrwW-PB`_S_K?_!pGIpxLw9xMcreR&^`iqqC7XqTxI(L0|SlYZ?%tz zFVh=3%6*XCxa~Au$8EAQmOmk4*;R0J8a8dchh?_ROTPr5q*B$m9s6*r$|AAPtSTPT zJZ_fg4nAe01B#tvm*8%q>$fBG)^6S@bp7%uU1cQuyN0aU{X77`f$0iUD-02r(ji1GzNdcb%5Kc zwBMm^;J!3HsD0rAlgn9!iRUMd_WR_~OEJ2PzRVen)TcamroS}j8?2^^BxQC?63;8> zHGEW6$DPQy;uqL>q?3O<_l)G0mBfyMYq{7Y^GkQWY|o`>l?UUNGf$u{6H$_*)~2QV zcrKqjb%Z{*aqRB;@P6&3wL57nc`d7NyjybyZi+lN4(`{MxtuxDc^y>#bmA*&l?#Yf z6or2g+f7JmQ2cextwE{cHJIqmeHUHff)F&uvgA@{LqO?0wkze5YdQ3-H*j$xruR#x zs`s~cbnpOnFJj{Mu%r!O2DpOiwJNJ%RhQ7KSFdu06I{4TdZDjJuRj4>RiiFAbc^*z zXVddK;`nN$z+b?PWJ$j;$kmX#NBSk65DwPOUgy$woeI{FjSu?J6sfkBN#3{{aw~0- zrAuv8U(E_!9@_D{^lD@r9kJoM-!315+9ae-5%)96(wtg2TBlpD48^F~ z%PQ0dOVrG^b)!Btq>PP+Khb{(^`h`{uR7(RpYc&sx~^XQY;+%~nRTtmHcA$@J`cDB zCFdPH^XiKeK0fM z0T)Vf*YcqG@--cu#?qc$LLFuSXA<4-j&wqxbVc&7%wX_x5Fu=NIbhA^BS$b0Z#so( zNGQP1h#7nC#p8s4H6=_U)Xl6QYkvF+jPf~N{?If(mEbZip;uu22mm&-dTT#3vLZhl zxnBTC-pAqG9&$NyW|`GV`6V#ygS{K;`6X-foiAMyZ9hmHzS%? z%=zklh}tvv85T{P(uRs(TYfi4o&An;ES?{sB(3^~zQdzQ;Fr&qed{2%sKp4g;thdu zL?h@$N}(5U)DPevfQbqRl*nm-i-!8}x%g6=#@~u8nfV~8ZD=SM#-$l5RJO=&ISLe@ zUK#ymwBg(}SLsdq9?87Wb zKM!poDaIb;GW&bNScd)TuZdRc&wGZ1XELstG@q3fThkCl9ct08;^m3j)z~?c<~<8L z42#^_0SoZuut?VQ3Qg({_p(dNulF-fqez4!Bo-;zpTP+S+|A2>(!N1~;0;1ap~t!d z`vzheN~;BT?o; z8GuU*UJ8}3=A6;dsTVJ!-Vi!>q{~{q@LS-gjpMwQ+FI$w#rh>1Qwu*H2iKQ4%?z}v z3q^qKbQ`<$*L>;a9kQ}nWy{ZY?LX4cbh4V&1Cq3?j%P1l3e&aNci!Os^yyPzG6${h z_GdjV7p`sOHT(4DeYrpV&aiTQT{uks$aGP$aaf`j{e;6r6Swk(gYhP3OS@Cb$A}~p=R5ns_T#X$lVuN{7Z&Or>2bWm z%g0B4G_D`VdQrbZ^2war>#x`NIv)`~w!S{M&OE>Q&ms6V(Jn~NM|H{q=saJ6bIcMr z&O(xpEh)`ju=lcCADCNJA0M|9tSJ4yeaAt^ML?epG|N*(FgbJy&r?uLiF|hnZ!ydHMVB8z`_^fIQU3o_XdRGG`Re zZIW1Garykq&i>ZyM&`7{r`0>|y0ITHda-W5BkRW-zOu=c(=TUl=q=3EG)}h99SLiq zJk~fX2KDQfknNWVtR)~0{bSL0Ja&LOi*9N$ND1eX}8fhWcELq_OtdxZ{j z9{KywJGk$ApY-*=7b?G3dg9yq%0!fv`%32{-Js;YM;RG>^EYTr6J1|Fgx@!KbVXJ4 zf$n)u?S2M~C2mrUTzq=qd^p6Ak>f*Wxki7^SVedRy*{+2Ar_lhZUnt)@?3*DLw|MX zP{z9DD7DczsQrq&+mPM*msWU=x7J}-3W~Do)ADoyB%q@`J6cxMZcLO@E|j$dv0(9l zl+Zn25FwPTcu|wY(EMfEjvLr6aDStQ9|HDziXpZ$$i zz@3BGp_0M1U9f9uiCf$Km($SFCWxk0p54i5=zJQ(nET4}%vhIFy%)a=o{5<+r>k>Q zGRAF1GJnTopPQioMZ6N@G|}v!unMu~Aq1@bUD3WCbdXb=KP<RjyiIP@y3OrkDu^<)Sn+@7vWaQ{p*ZZyxy=Qzo13R|UfV07mF9$kY6lOrWoj+2JZ zg>QaS*e7=F%p2iLLfVsfo%>EuaD%J3QRWDEwfC0tXlnJCFlU%`cBf2}w$OcziQ_i^ z9U2G!Typ6Ep$a?{x@PA(7n51yH2U)rDtZi3LuK;QXWBey@P%NH6Ii!Hn6F)NSl;Sel^#Ix{UBJ5adH0t4dBc+3#JR|!g)^*z&6Mzf!7_$O~X$Ozzgn?9%8?U zTExZcUkaSRuXd)6QEgZ-KOb!lOSS8mN=qE^Tev~flYe4%{mlIsekhl;c8)DLB)$ns zkmxbEA!RU3B|;orn3)XhB5vAm)K^I;p{4A=C9 zcasEx4>4;{3lu&8jIb<+E&UQJqq$dnp*_iW9lUuC{Kf+)xGoA!LT-Mqu7jWs%Sn zAWBr++2wQbO>QnqEBuk|e zGUP{t110Orzgk;cce|AO>Q*2;WgWo07*s|71LXB%bTphz-tTSMrEg#&?;FRzvN~Q_ z^_6{=+8Tjk9Bc-Ur$8wuWjt1lY|+_p-Li~Ym?4x`7K*@nwf{6)amI|$37;o-%CiYSa&0$`ix~h@Cio5 z@=`6#t|VUBVOjvCBEL#KO3wgPD%u;~$rf@6EcM}CA8c?6sN>=j-9<)14pJwOl*@^s zhWzAmi4rfEjaBuj4@ZjS$1xT z0E7p;``>yI4#8`@oP-%jZopAqnfN&3aVSuS(l2#0WF_9O@8Pxnt%f|Gc_DB8zIrOu zE@Ou?q;7f9QmmzobY2scvGdMb8>Gm+{e}8Uie2Jk4fnC?XQVG8<{f%PquvKgomQJa z)-@{z@WvLR`1wm!Hb#4Ta3LRN;(ZR@4U{<~q{NY=2|f(oO@*lhA4WQJSrqdX`LIap zZ+8@c9x8hacS6Av0<1R)5qIqoYA7#Ev8cFl<`V#iz?^IJ>O3C&l%Bd&m>4s7*P%=O zpwfj)%TxcV5e@#l>&Cg=sPpZAy{?eNZt84B4O6yYQMIj#blic$3RHor|3Wp1p zm+P`JAIN>zr6)vFIWs`_Cd#i^x4ewK{F%;<3$K>v=q&DkY99K3aV`NI+CWnF%_0(N zyxg-fox9xF)GH)VzU=E%9V!j3y5)*yul-}oX_XO6E0IgPibgH#j7;U*CT`@dPTV$k zn|jpqf_5UO{LDkg2O}01&@LC?c%fFF6=6V zq4QSnRIs8@giI3VdmEkurk9t-<}Yj}%B6#3e$l-sU%NbFu>Qd5MSWO}Y71rWVb{(e zKM7s+8vlvtLkI868bPn2dDdk=g)P_IJ(uEqzCAVZ-0ymi*3P~{5(JVU#~KY$P-V&9 zAde$(-8>|{lL)Zw&ZoqlbP6P>IulQWS%(N>CI2!fh5;;KbM&6eYI;DD@STMun06#V zN{MI59mLz!yI=Jht!XT6*A^LJtK$>Yb8WQASbFE5I_U0hnauNL4bLk(#Ml-rcI>Ok zySy-$9*Y*s7cN<4lZKv;=KSTEH=9bUfGhakbmtV#4BBLJ7FPqvJqN%@af)BYVq)PO z79S{IvW1|!o(+c*YZ4rUwDAku>wjxud1c~~#;Al;zpt{ynDTbrmIScUt+cF1E$izn zCZAl}GrN3Kson2ZFKT+JGH-Av^KEmXU$p;Yk<*rv0Tdv)r!tC{(` z25Vu4uzK+eV-(%pTn}UKP^lO?MU04-PbTH@J9W*f&+io+o?$w>;Q91W-hMu!=;GA@>vajuSHA)#pXz4R}FdLN>c+2jQ=sUFX*;DNYZ$ zm}i$S8aw>-*f1Awm$60L=hi1gdD@w7GkaD$ubVlo7gDa)sjTuiw|}+t|A!Bgd9LKj zmz7rQg`+e4PN{peMa(U=WSb1yTFso74b5Gzc$HDJj|tacQtyt*pmv@zh!>dNcH>U{MZmO@fDV*43Zq} zRvVpGCZD=~HJWbUe}nDQa2B(L%*l3$XZ4QbNIgBEXn@6DIf|(V{+x`&zmWs{>~<=W z?7e{=$KenNKa0Zx9G`L9-A6bcz-ZNm?1$M2pw?i`BsoXH+iCKaciLcQb-hJdLB zRl`BnS52>Msz+MSZbaP4B8FP2#0=cF^zRJ(JW?i53bsBiP^N!~CXN%;>ZrWD{kgf$lHJ?;Pz>CPHUtmMTOSF{V5n*~4OZ`X6o- z3PgYh*HDhU)`M?W%$$5#`rkVloy(RUU2T}4>1rDQL^=xXC}S?+Huf82R48N{G-oD-3)Dj zb1r@XRM7hCAg3CwO2?T2vE<;95W*fm>WKD%ra2k&nUu;etUq6@mD!26$1P@@NIdAP z@7g^pcI24sn#xaiyO%o!vQiMzl)KFOdj(A@p!^&5HX_9VCgW8EE7-LDw4_I{JK!*v zF0#ld5{iKmWBb@;;L$}Pscfo5_9WDkheu^6fjNLr{2O+`?fql5>G0F?F$|51;i)?x zHR4T|WB1=Wt*iemITLS#4NG|{+&Z}}6OaT=Qk3}{ba`-b2e z^KbrIndHTMMIHzqkskmHyV+SqaH&1!)`tTkbrV8|wlBnVll7-MYN8Paf9OkR|hqOKYcOZ0c4@RT{(==0X}5c zPmF#8AgY{Bw?oh!S@-6m!)9HKZMwaaWJkDyX-CG#X|8>e5LfNz(qAZiF^7T7YU^9U zjcqwl(C79BJUylkzD;FI(}3eh2msFE(oa-JKvd+)Uw;Ij!D-egU^7waU3&Y89nFBV zL0vC8ohlc zS2irtNS2BI*}|@#+=AIEwqW%y>^j(GfE~1b_Tj@7KxE*(`RE(mCtxAT-@^h}eBu3G zSW$th$UWZ7m>0-(ov#k~90e>Xi{9(wp@tMaP4U*r3w-6_5#kSD9;*hNZ_I4Sz@Dhg zvLQmoTKs2|PgUa8is#)1VzhHU_ai(h1bIa5p>zVU6H+KJWYY3){RtazjajQIZd?H? zKx%yXsW~ufaOv@0KP|j9%An|T6z(C=0ZyYDi~Wd-pFf9f9c(e%@nQkQQ{gUCjJThsa5yIU85M7Sk^RC zGTM9$3I^||jj4fU)jh2E5XVUeY<@|uOKlAeXwuC`vk*@{%G#-mw}yG2Y$8|S#ujh( zU=2_|HuXAnh858H_Gw`}ApU{P>UYLHoCE**nHJC9eM5lj!%thQP_Ih;IGLaZ;Afbg zm5w~?HPq9k8+5}N>wt4;aL#4GoI=>rRIY{NtTVt`5vvb@I0ar{t(xYzFJTC1T3aH) zcNO(WcCqGSG3F=;(ahF!?z|toevo3}#38LH-Scc>VMFt?GYw)4F)*~lo!gV?NB9U~ zg@Qo+8oo9Y1S4kdsu(sIVMK{v4C7cm5BE?9XhU!u9@|Ck*#PVgakABEK*7g8!quJF zRuq`VUd)|+4UGa$0rjD{biN)Z*{6G*UXHZYqLOHgxTzw1E4=a_$7RQ(frnG7HY_lY z2c7EgAD-b95N!RR>bSQD6Oe7RAop40AS7LI4H^{ z5~TUk(F~2~HyexJ6RNpC<_%wZ>(0W=L(#@d?IXACtfG1&p=0wB+mwS--~_j=5Yn}S zL>(w`&dXE}%Z@x3M#0k41C6oKP3bXs;(&n49<>7aY^axbE8dPgfo%Lp?%)Spiaxy0 zj@-0q?H4h0Aboc1N-V8qVc1ApHU~tEOb$AVtOt>FhYra6J+{h@_eFBBIhTn*D5g#I zI0ZJ412V;NPY-D%2VZh+P@bs5A(*eky2YrY>XyAr6I7{C^k{4Ylcfd#cSQh-i80ut z8xe(xP3uf(7b%G(+-QrG=tjivoqsbws<+RR2i@pVtu#Ix4Jb*w=$v>A$1#69*p5p< zIjQJhrgdZbn|-iZ+M}x*S}o01YJ*Q{oQqdq^T4Hm21=|LxD-2KfDU&Kl&6wiMx7%B z4K?y&4l|Lw2gV3+dkj*mK=x}L=%JxZ^s^PyBjBCcq+fLH@zel@hU_$1_-wW~r7*HM zY}DWlIO8qN6O5Zv9aPtg_Q%LjxFDI!H8sH| z1Co>bPX-)@uZ1H%W1XSShESpdz81aPrT@(Km|%|!h)c`*`lW!u`1B4W=Hcxytl=IRR%^uQnaL8|n6;p>LEgXiG z@KdiZ^YZiGyRD3IqcLm%_lWt&%_l3~HHHEIX()%QJ2@3XbNO8$bBT-7cAAmJM}2He z&$?(l8xRlonMUcFJ70U92NSeTKB3Z7VbhP@&6Y(+!7N=NLcin_{vaA+82XEW%(m3o z;I2E|CmINkM81F?HhD(i=6l^Y&XK&K za{n<=9^eYAjs~-R`tQpnyy7Br;+JAOdzUo@JuIa&m4zZ0f}0gPzvL_}FO&U4FkYyR0^1r8Bpo80Eing6yZPu6 z3I`GR#SS8X_6MZN1lCNjDMWNT45LqnwD7F2FO=Watw1=heTR($vR*lSF`);PfcgOJ zo6mXpmon@yp*08nn~UECT#8q9SmEGaoOld|7abhKe46?s z!eVSbVnYYtStE)KhlA^c;@%KgQ{dp6)VKrGP}}{W?of%Y#yw`~^KSFGiFHW-VDVm9 zWF*}e=)Yg_#dANjK5lTdv9U3yic<0|89k-sXm&x9v!te`X3qEflJ&6ufSp6>UciNU zHy7XCr_(e>nA(T)7u14!K3mK#9rA^>94Q_(XR!Pbl3kP_35=Rp>}zVBY~$s6vsy2A z*lg7`O-ufd5dqLtG$KH}HGVth5>%3KkEEHA_BgOKq&qywufgNRZYiBO|*k?25KISlw8h z3U+5);Xjqs^NaU2*!PZKyk!fe6Yu;OZED$GTDe9ax^z65_a&?)ID~)!g|J;}nTclT zFF?RN5hjI+AtbKe)jTlPu{p%*qw^c~_&;zRnf1jh$XX6WU%CH)LcHsc<%O)iegIxX zz>g}{M+;xMoH$1(1$$qVDWxVW3Z_cqU%U`Rt1A#7FSs=MP4W01DMsrGlEZGRi#?ZI z-CVMAC&`#COXu2U5>sseW^!gW`YzEQS{RnPwfh2kM4KjAceHPh^yFi8s8s&-;?uTRA`uY~Ktn7qso&?MW=-fM()Og)+105YYGeK`^LPeQ}!^vN3 z*I#|onfGSHVDUK4zO}VqYto~e|7@Vb;0hpo?|6QjS^#4K_R~<`M+RfL)6u2>O0e{i z=W@fh7FJVkZMS58T0t&U!V3GuB6?Sc#B-pdSwku1&~b@0M$96T(P`kp&d=AbT?++7 z$Eop>nG;JN9Li|+i(Gyi(D7=dEuH(}_X|=#pFB1OLlgnnu6fC;V^lnj=g`}}9Dw-7 zeo*9D`qR~67L)j1857ITI>it8WoP|C8-l@vI@`!`;(Vw<8#ZkK8Wv74!0-HfobVrG zS%1&?ZKo=le#9PI4&KS;EwwT-iOhUTlU~c!fXs3E^v*mzKJrjCG-!F|i|#JX48ON5 z9;4e2sHk6Y^LkuNt}rro)cRmI20SJmYu0eG5I@ORI>H8sa- z)AmKs{hve5ti0@p+xEY20(AxV>poR>P^P5`!T>?;#M?QmKXuDPHIIDZJo0wssz1VE z!SAd_n+48(Kz(&%SaSDL7{-qf$Z@(sq>1xkTThQ*r&W1rL$t8`eaZ2H|J={><8G4v z&$OV(@yLy`pKtGG5es#$k9I$>uB~FhV7nlrt{GdUmIk?>G~Gtx05;WH+(F^K2X}>G zv@9vEKmf#v_<@1GM9(YtC6w&J_Qyy$*}O?Fhn<202qs&;K9{9^@+5x0$c?X}2pQ+N zonmQe$#qCGR+LwVbqa7%F-k?#p-nKbFTEj;McH&R0E6tax*d8iw3kGQ*R0t4!>^#L-nj7` zt!3*;RdGka^sqR#kW+A;!}VitFALmdi5Pk}qmc<{U%`mSHE}W&7a)fFJz6WDKpbU7 zVlF2N6aU~MVKAGz88~t7-{d4;{ z4_fk3py*pSK>_NMz2ElqQHN5a3DvEn$yf_Q(cXWjYfH;p;$pQs+PyR8-tk*mO0ukO+GDnZ3mz0z^oa?g6 zTCCs;M9{Ri`c-lH0AhUKDBjB-XI19Z)$s)ON+}$ubHzh(1WGRApGz(~sE2*jl#~#B zD;L!ix%zc6xuk%^E)!)85sB}pRrH{?vDq5kDv>sQ!=?P)4MeNB{(YhiByEnigQCJ^ z>@Dc_Za(L|Xx&d7^Qyuu%3oYvOJSW71^|LVK|$Y28LHw=YioZqRr?|Q&zZfmBzdK4 zv7$0IVRv}lyMs`g2q~f~k{hCP`g0C7i@X0EXvG4FkwX%0Uy>wl++F+`xv3 zR0Oox%z{ydOgFVhup7pZTVWiTD<`z{e#kUO(;-)eWk}*%h`jlGrk0F(bEb9@Mv1+N z3nEIhiR%WSog8tQ5pxXmw;8sosG;HqElJFMC|!^-^MA|GFDf3sMVB71aQ<#jV!d!! zidozR6y%{4{!I#gH!P?Db>3P~1L}N;*T=_03;ycus!3ezeZLdJ-&F_=<`=5_1-YQFS@Zw(}8L!S6jW=xBCt;{Ew3@LZEx~n|$kZ z`HbcnP--?9xjF30a13lx3vsCoETc)?>+f*_E@3z1`{a*hG`di&?CHYq!?;19v2yD2 zE{roGTikwjb*R(&(@sXi&&VROaT8jm(TpneeQFiX{9X;AC7%xJb!-N;7eKv;n;(E4 zTdY9+X&p$f^fqnT@pf3Wlc{H5{SdbG;<>Orm((toiQ+MyN3Y4U9jjA5LUvS_G{Tpk^;EXs! zq{iQCfA#HKZ&UPZ2-@JQ3d*`VBXf? zcwj0xQ%cUqpMcJnsm4w6-Q&`)uWfupCU&s5ib{ab9); zk^Xbbl05T27>wgYUqU2PY4-Rko(WS2!p2SW%@%8iS_YD`3iR3_Y=7jB7bSes(kCL? z#p$AX0B1sg+13i+4@3#dKmbZlW8e?xpI_i#K>*tCN~to%{Xq9Y1E=t4)R(liUj+Mm z26ZpA^ZfB<8ghiK#O#vry$F#HAupDNG_etn1*4Lg7LK?w6e0e^vm_&)`%4jd4i@VJ zRSVmp5D5U|^G9oVzLU43U_XxCvAZwCl$A+Fo=^_tTDDd2!ObH0 zv-@EKpn8UTmd5_f&3wnnp} z;?oM@I8M}Ac|i6V48uw4)}RmK}on{PveL+xD?L^ySo9aZMH zM|EJeP*y`AOxNnxm%9{=w859kGjD$BEYx?k{y`J=5VRFa;h=$h1rtzid>~MTT7?rV z5AoFqzp0o)f+88@vcjRem&DJuk31bB?s)dCS;!M{?7sRFU7dsZ9H2NyLwVjPB(Z=f zY)-n}2N~*9NygE5V&ROOg#O(aO1OtTkDgB;0Rykxd9uLALmvJgT7fzDH-HOfh)8ej ztJ9ETVkzgNSTHc5d(U_9L2Mn>-GSjai~j=c{N9+m^~;&-O&91rcl5VXeOLEgBhe4_ zMhe3C*cDkHfDYX`Q{d-;YW$mzE~06>cDhHw9{Qj|-SzY>?Ab8F)&ENI2S*=TEN3}* z*US~XbstUOrQb-I!+7nrF?w~_Pt~BdrzQa~ZBn(f<^`y0L1Z$NfK+@fa0Mt~+U9Yt-sA( zdRwrAP*3ag?ztyp6Jl@Z9Aqqcbtc{gnlJ$BmuJqOR?Nd?3RJK)ZDN79HX@=&FipR; zBoS?}a*^P;jBN)%dC3;?A0)f{A7iz#X zmQagf5`grp5`>By$n*>c|A0MD4T&&Z0&J^P3v2Vl+SvPvzu`{tur z5Z30cF9iv>+7rOwX$UVQz8S1&!~Rp;C}rD;XW>YKU00;<>Qv>;K+4!I%o)W>>Ly5? z2(({}1PS<`e$AbudBnj)-Ci+SqibBU{IEhcBdf*c1YBrXTd4x~7NmiuMvnCN#!DKluvtRM4 z(|Np564wNChAz(m=oU7uENnToHJT;gln6&)@8s|{l6-L4#qqMqV6P9k@4#E5uq}T^ zd3FsfU^CUOC~9la9a7Rz+EW1(3-_a-VSaU7$L+1Tc23iS|LIrA1#}B&YCAOYvUhh6 zS%SL}0Jn1yTn;qHYc_=z#Z? zu@fjYV88C3$hU?}L^on*a}L>aw=^AxY&$R0^YMc9NuLTTN~Kh)$Zh?8Vju7Etmf3q9~RtY$;j7$hy{!CL_G3wW? zL2gnAm8zp#PvA4?e!EeMv&~l>cNB$#9Cy^%8issrQwImR8<+wey7U41ZV8P4y95R| z`Gcwdmp9QPZapfLC$4=27(qV7fj2=;Q0;SdA2NqvFg~!f48I1sDU5ed=y3%t93Kwh zu0@uT_yj)F^hiW&awI*mKF8#}F|5{w!M?9~)v(X_yi=hB#vD?8w&x}7Ry}7oQZpak ztp0fvwp?Cabq&=$Rl3X|kd9t^%oQ8FEi13DX&dG~1pR%En4PleAh)$6von)=024Y& z9$L#WkOwD`h<9U_AqU~A_2Rtd?xT2@t`0^!2cTUUH9c)(e(hS|9%H6itL4D+PtleKs;e4TKm8 z+q4qs=^b_$H~4bv^97FJL|FHtTF8dkhti%aA9d)?!)`8f_lbq8V=!um(m+vHhH+R3 z^4$%f`iSe?|Bx1VyO)1gqqJ56T9}s05iF%R4(aoU?yi}EFW?O2?FUW`p0=~ItA*ca z;;UhDcxd3ZGVzto@9pT->WU9Ln|E=?$7;fP&?pd0Q*>yZU{mD!OY?L+!A`kr#G3nlFpy zKw6M6TFasJ02v^nkix4ar)y6Sq#>P+aY#7k0<#oYU~rT(p68v@W%X zd!O)SAL!T#9yX~Dce^6F{Nu4n@!0Dy_`#i7Nv;M`s8*c1LWwyBy4L)_|H|il*)Z1 zt}Sn8I`kkwhLz{qz22zbx7nD5hF^JQyyLe!IZ)qzeT_7=@jr*{;d=M{QXk`a_R%iW@PLC@I7dmEHTO3K|!%l%6?|G6XwZVh-`yg7o4470`EX5|V25-TB8T2B}IQ8J#8 znD?Th@hn+NMqef0)ybLf4i6JuVEZ)|53{Zn%K}DqG8;>!w6|`(?e6=c>8E=7k{>J-8N|iSLw0KTa&ElrLwH2N+-{BZ%BGf z*uCC~%Ht8RE|pK5)|c9cX!>vd`4?;=6>gNsN02c48uz`prj~%5aC6%L@mUX$KudU;m`VRQ1^VW$|5zh%F z?3G0fT8ZuDTfb|&h*Gfe5;5=EYX5k0A;e*MlaK_aX8hd#xO?F#%bP{aytB{g`<+G( zJO6xUP9dS<>iYIh)z-40$%jM2ze`6bLWx{kd7M_~>d3}?DOCtvNq#bWdY<%3PjI>H zLUy}qqi?nmns(jcqKG-n)A9$zM=fy@rSDU7=(9z{c8#CmHx2V#@u)%p9*9PVulSp* z>N-czQ2<2EHgmu6FNDnlq9lwP730QqGtZ4n?g%e4fu^%_6eCylk|HH?^4M|lAamXQ zcM;_19=cZX7|8}z_rUMz`g0HNH@widal_DZs53F}Q;OS=AFb)k_rjuo1;jQaR({yo z)*PVyq$E(m24}raV)L~!*vGqBCV8NA9Jj9NRp`b2DR#_jzI%B^QnT?<*l)Xdl5XU^ zSRRYwXyikRf@eVN?lRhbZo*@Mwn!=cXb@73i${v$Oum@LZ%8)y8n3^Y+Ku4b9Di!m zUvq#{Oqzh64Pr-ce>jbV+&}F+@cY#5Z=9LAxzP~PI{*7MCkmSEX6d2(H~mVK)~~6k z4<`ZOz+yRtN7nUqb~Nltr+Yc{m^;=j{YCtt@u(xqad?X zu8a}$3~3{~PW9Yxef{hqWQGF2Ja(>a@{tgy+J4(9dB9=w;L6I#$ExNCH)cX_7U|o8 z@!u+`>d8vpcaoRj2Cm9l@ksx&O8b<5Rqn2OafwF9)f5Zr{Hzpd->iV#5_7i*G3TF> z1M_dY41V@M6CIam7Cy81tSe}||C!ybug)Hc&o^G!Rjqu^Y_p1Q9ouk@vBYC{7Nj>6 ziQNwaTXNI#rclaz%yeXfr ze|Nyn?03kx;<#vjY=5o@(t2Zwu4R*T|WMm>KUoro=+;q)46Dw;G`JRvL7o>g!<# zGNNN6SzB^}40}fF@!m70twE}vhCL)s8rVt3##HW4?TS00u%UZGDgViHh3TtJ=j`Y6 znk6HIyLPn8CETlW44XV_1SdY(ZTdbQGTU&DAOm(S95Hu!W&net6M8N&WWcW78D$t0 z9n*4&W(2;i1qz9Oc?EpC^C8-BOdhD;d@rIUesYLeYv|SMW0Xuo$z^!I)+fYuR>LIM z0!ck$@>I94t&HAn%H{pVdOpI?9V5FDu#}djH5)e;`*1bybHz6AWZa^q&a=)m|HhXgO>`K4-ooIT&(@?Z%vbZS$zb!w|}sIQ8QFUU3M(K6ytaBsm6 zXzMka_{H(~%G{Ds`e@4}RV!1(1X{9@Wk-`bZlYzalcz!D zYPzPyt2e zGpuO6zyYt@oneK6<4r}?1uhVo#QW)8-A8WlzKGXui+o5NJ{R6xYF^m|%#wI-f2t11 zeNUE$b$Y_PtLM4WY{;9){%LpRn1>5q_LcJ~yzV0>CpTBl&eQM* zID|G{tmqoJeDL9PRAZl5bLPHCG2z2veP4rN@QmmreM2Vv*xeal7(63njsH{#!a+xn zm}h!urZZ;fS~BN2ZcI(D zE0XpGv9lNBP8`)_``#sNw@yn$zT?trbaJ>OZtOA{uKVVL$(=8=F~5iJe?9PYv|&wP zU!Q6P5R*y9O#i725wmk3X(N*c_D;vp%XvaV6JvKGas@09W&bg(6IiytYX37T_&Cxy z?V9irkXQF4QS&e1&Q)bs(ayM6^M+b0vj4<7kML@?a4~<0eqWI>L4_Pi+Txek%?`%R zQU5NZsFRG9*EDhlz79lG8c7!1mK0s!gXO6lQJrlUfWf+n0@(r|{OsKsG$ zJi8AwNdv3&d$rXCU%_ec0aGLrXu%wNZVniHBeXBbs=M1ZKUyI~98kC8J?@{h5RnO6F~@t;*9XF4k|ZMO;(o7(qfRR&6h^hz4lYN6@R$ zOgkEgytC&g0BN=RqZL61k_yB(c_E$=+A_RVsFh)Osgn4b1*mmkThgRl{QZKeJWEDt z0I$u}=k8_)-J9s;p=k}RTVxnF`<1dkZ`i7JgctmTIxvtN|2LbgO>oqa`zqc zN$kfbZEfjB9j6_cZYX&wGUzSn(|Y|RJk`)nC;t^8HBtalqn!c%=K~5(r_PTaBK%Hu zgZIw0L@U-C{MFjue}tbwD2u*;vZ(*I7x+DKPFE#Z3JU@_ci?`72EA^quFAn+VU?b) z9|gT5H3!Hou7ircRL_Z==vNj>smXMGq+SB|&T?OJhCm0?P))pc3k3jfouW}mxkL|B zH+W}McrAz^#Hiq;08`^Yij9QqS#qy9jI*lK9F4$&mP4r=jl`DJQWhy6Uz<5Dug!X; zE-mdrV%#G-sp?lCzUP+8&S8GSH$FXKdk_E&!x3~D{0Mf?V9yv!0C)|4jU#@k1m+g3 z;Frw|gslg^UEXv0K@hO7ueMR~$ixvZF%B{OY>~~M#FOi|Dvi!unV1zVhYN;1^1)dm zA4s7%=SIZGG>aA*{NuDYBGT`lxy>{f0e{Xf=ktcC5*DQp;iVBg@)>lT!lc_21mT$T%8pBk3wwy6azOdTcpXqQ5T$wN=URO}P@ zu1gQELxH(e0tExj=Fq`Or>T|Xem88d{Q563&D095iTjQ$gITand6ynJGLx%t&|FqJ1XDu`gwM$pc`U)7_ON!q*37R5Lcw^5#AK7`9h0 z5jOM!a6xGN+Ow5xfUfw}mG!RoQQmO=l#O?B?z>w^+QSb5@7l;u_5?`Xh0*O^8+@;` zz`O8AoUNDeYeB{c9~cW@ERn{KQD{|xsiP$RZwqJv>c4nR^~ttY<|E~UCU5`r z>xEcSecgi$?lHx=XH%w*ijpfl2R>Q`9sMPjqz`nlqdDCZR2>UEdT3e0 zir>ZwUlpSM@(bZZINny3NEn!*KnWf@D%3;A1qz1k$N_R2O{O3svi{lwg0ss_X7j=0 z**|*y^Evi^OyK6*e^86wgaBhnbt8h~U+-aSj-?U12o+TzRi|$kAM+9b9u1zy^Rg#_ z{rq6lLLB6Mjb4hW4?Q93UR?PIghS}Y_Yf&!{Gyn-g3+qkPd}augy*U5T+171V{yYW zvTivZ;~AE`CBwvn^zO+B9BV!dMuiq|qCD`L-I*{LjGmst2`j-DyrxoKkB|phcMcYD z`-=9T&SQ2rE|5pH)ImrWr~Guawl0M>F>39B5nunXoY{Sg$zG#_bPpqN$IBGKpkxX^ z05VZTF1H?T4ub_cxAlYrz?whv{aA$kkZ0I$aRyQ{H?8So&E^%=56rFl zm*OSN6@mEO8D$u}lY6m!OBuecljX9<0+LGWBk5H-NEWS*q)DPfZIgv5+z?OM$->zx z?#|i}Nn3vh*M72{LXTgfg@eX&qL}Qn~a)`f2 zHP)jz5PzxeuE)tC{-POL#9s=_^=BH0zahL^jX{XNvT^RWG!TC;og3d`8Dbu<+Gj7> zfoa~^#2k~Do~@SvqlVMxqY-ni5}($O@nN6P%&M3J*Jd+r>-M%pn^h;L2W^|mFp(kA zVQ$2oZbHH&T#n--L!yIbvXL+e72$XUK!z6o7Ybk{0`0%9E7r<<#i%?ub8>F}-Wb#`L>og%Zand`oxI}43 zJTyu|Z>Im9oh>{5RTi)*E@R}*9LZpY(czE^{W(|ae-0+u(r&cGZ&fUfDPBE zc;gz=vmD`k~_QQPP#j&xVQ;KoFjNT-25RRfvASU;`@)p_z zyqBUS#?U6%ok5!*M=ol66m5cj78Q@zXcHjWcSiJCA8A(fP;~mFm^68d{Qxl$Sx=eu zz2X>L*@LS(lD(S8nSH{ZYrhd_hz$Mc&Pu{iQIT`Iw_s>Hmos#3r6lTC*iveV23(QO zYpN47hnu0zKxeQXLx45|x!L+tGqf4di~|}l7_Y}Vpv@3=YOARn=>qwu+hzucLir2n zTdYIO>0ar*&&WBIoxVdtxY;Kj)c|&msC#agX1TXkgv;%>Ji#EbAZLpUkUH$u=<6T-=y0TPR|0eV86&>z(}Q{(O0!E?{$ASgh7{Tz z-bHsizkqS-AS|ijrGxZ#ndk~|pOFlFi_d_Nh94Pzo=DM`QV{icNeRN6Bg)iC@MwV| z8)o8SJb>5<_KWOQ2g?LmQRD}DJOK~{p6XR^H-`Vyk&-IQFkMXI9x_ggPPO`NE@<9H z=9B0*#aFTZX>eXkVY;Y}_$`YEf5P^Q&lO8IpXBA;?1l^dW;8v2WapSBHxf^%y$7)@ zqZc{?1?Gwjv?)?20Db}vMO)F^EPz7nOVE2{aGmfe2dMdU7DF-_Vi0BG<3KKc&BO?du7_mGU$7 zdhh0%Zr=SRI1%tV&Fy`Lz{)%!9)2*Gey7<-@d>r5!K~$$q?NDMhM#A0QN`0!2w0ud zYG;fe#{zP}75oAp&k7bM_se^A^Kr7IwrMq_SLoXL1vh4*@!SVIiaMAOKi7(i3 z|9Cm^iz9!pmQ&kOtE-^vLgui;XPy}fOUox-BkT(KCFeJ68NlDI$|&iXxxM4c`a zq0@!_QLk5^C|js5sd#%*BSH%7)bZnBgO*xGy&%NnL4^F70z%q3g`X%PLZ}Y+c!R;c zM9Huj<-cZUx*R={2J&H)P+AdtNa9|~1Rwup?5-0>a_5Qtm+e%0?4j>FPLmZ4T}{jL z_;~nnte`FJ=!8iyZ@`8tJlX7U#3B^5<(K=TywG+4tk6dyU9w5e@b%Bl8=jFDFvF!{ zZwhWW%@JpW(RPxlN#Y_r%Sj$Rmy|yJLfGJ^zGzLe``lx5YXe8^a9j)A#|oOCZmw;u5*W1) z>yyD8EXkiaG>YueC-M3T$Jo6}E_2x=4%i_pspq;bCau9*oEWv{*_J#{Pbx?RRWdD^tz>{<50pW@cP!5h>}iSrALR3UA0YJ zBU5y;*nM|8{xG|kh3n6LrvzU2Ek-ltY3v5pY`!=>&8{=JXv^(fuj2ab1O0A^1SU_Z zMG$JsJ(8Y|PAcBb^Mg51cYCjbJ1m!Fo{!WD7~sDdw7x!;QiWaqdv6YYn0VgT#HH^h zVbOqFUvNuQh*>)F;N|npMk3o;*?AFA_hNX~IOV}?KXQV1L$!`6G@34gpl&RUfP_2r zVuoIlU&F~HH`UfxW(5|;=aQbnlTIu0n?@MkJJ~DC4>k{il`)(D$MyElwuhDraJ^MZm}Y6ALlUqnofL3w-UO87*njiZQxAlNN5|@+Q@lrELLts zK)+NCC({V%$gv$|P|+^!M{1xtn>Lg{%BJo&RT<_C!=!o-)KUU?>%HYH-lp|I-f z>+frGU8Wij{ixzH(1St!l_{N_fE6Y=e@hZ1S_dSW-N#l0-$ffn3-A!)r%@Ea8kCQo@N^*qYu_X(|()pc2#EF-l!i4VQu*;K!J z;7zzsfrKf#5l%{d1+n_H>p?34Es;se7$Prqlw?uKQ>q+xLpof47+|m3u8S6Y6`988 z5t@NI&O&_lD^JOP3=a?aGm`S_)qpGsZ^4zm2Z=B2+Y}d|LbU;)_>D9W z;yV(d7go6?njQBe=|Ko4)M=q=UlI6SZ)Yu{O4Gb5UpNmQVw_x&%#QT#+2ZvZIVd(l z$}pHdE};Cul zQA3R0y<^#TAu^sl1A+nCqn29?g?|RU2pSW2HqCXQ;>(8xp$=bpeoh%WEaw$)7nwFt z=s@MmSV|B-v8ERxUz8085gE}?#v{-D7)45kccIRL8;z8yR?8pT%D>qPPCQjgbC?q( z#Raf4g$p2aiQ3xbxi~VQXs@|M2>?HLXOQEnh+5SpQW9uh3lbLp8Uyljr#`ZOR2772 zvtHj2T3@%~KY}{HM)3Qa5Zx(my<|Ha$kAx*Pfw$}4N?9WddKh55RM}~ChlUd_7gB| zV>&xEQH_`deP0>GYMM}N2?D_RI_wSbeGwVz1bFB1BS05Tiw-!;{Oq$eE+~?j7UU^y zW!CkQ`U;0egHHA2y`N~HuP~|h6_oHNH1i4#u3wnELJER0erm#A_!=A{XQ)*~B4v<> z9JQ~ge_wikWE27?Q4plNX6X7$XcF`%Bmo=@BqyM=k$TqXeSpLi%0)>iXrT@mTV&$L z0oo-ND!3X{J=U*v1LM8>)~`{XgmCDKi-lQsG<*~leDyM9;#5D%hvTgBp1gVUMr!uU%Y>8QE^IoVr-@#}?=-~#R%iHgG?F7xEFX&E}3eGyb7g)5V6 zhzMaR^NqN_sQ=0W7#?Zy`*r^**1+D<#uu#39Y&S)QC$IFTj=Hkbh2`%i zV^FXd#Tt5n<$|VyQz=xNjv@GXoweFXsO{CU`ywz#@(IO0R{LIGK_zTlHuOAZ~QvV`8nHo6? zT7p*jc*~a(U;m45Q`YBWt2R$+8?$85eS`vBJ}=AmR}BF5?tN*J&-x%4!;I#B%flGL zZ`7-}cGa;+Rf#8NF*=vfxr^l`fIkrT0=#NfT#RE})Q@~dY=Eu6#bQFQb&QC5cJFbk z9Q7(Dd3Z_~&uyn;#d!ChbC9qQ3tP~>KB$vL4LnYzSAE9;?pEq!E%X*K!k#OyU&P+4 zz;Fl9PYa;-D_z*S27F5kEpW^NY zP=t%qUlRWSP(aag$qZyONk4O2?&kRZ0HV*novrbxA{d=;F`!Sex1KfbXA`^rc#h5s z9hTv_PHoROk%zA8Y5T|>H25_>DJmbRV`DIlG}~Vlam0-g_@iCTOZ>CKlPKP6j&0-ZMk#_B6JR zfRt|H(o2wd!uK@rTwx|>fTtbiM_X-KcncH$aX9pUkkk4dfky0w1$NBI(u8N(s`>bi z4>w*KvdSyF^k%@_wKZ+H?oE24yDljpsPFcAiPq30dOXocYP8YQH3}krD4WGk#AACg z(F}6dNE_jkX0gTKA0E*5)B&MKLrPMfzHP%v)CZzPQ1L;;T=?}+7l11Vwc>ur0uRHE zBpRJb8%UzV@c5*vW#Jw{DL#cDzkLDnTb~~98c6gj?{BDal?gPi+MS_bxN_i{w#R_m zN_5D%9t8mGm}%)8uy0qk1w?=*p8R(#ckkYneg>w9Duer~ajWkm2qxbpy}Q-G!Ub5BY}Om-CYQ;y zbOd00Y5~S4FIegfEdF_!Cw5FXRDrL1Q(!?py4m>kwDW>#8K?p|N>WYz`}IYg4*=al zMf4X{&QBXqW7J_^;)Hlg&FWFPJrex;RT8M2bGPQ4Qssj5Wozfwjt=SEIe2b& z?lgKXIF5w5g%1vux4ZFm6nAjln}ZNHNp>$sN9v>fq!*Y<&(9u%{O*_XVKK|gj?X0A z$|o+9T34>U5(7GmYKeKG9AqPDPy*cG8yZOedJd2t+6f-p&d(qlYi<>QJo3w%XCcv$ z1!WV?RPAiV1MW@1PY!tY>e?jJ z?Y2}!+v!~FWqEmdo9V|090LG>M#0L+(p^h#InS5RBRi2r>S7gC>9)}bSR{1cCI_lK zlC`^4l_gqI1J3t5$>5IbT0^U?C}^Re59u-`MMYm+z}@tkO&9`n0&ufzer_j+ABU`` zGeW|&FbAW(Ir#L?91nWV#ZCx64kApYe{4yJmHc?!uYcI<7R1R~?zBe5t6GcBLuZkL ziez>EWMrBy0quV1hH$GnflpVS^62m#NKv4y5PH-JFa@eFxC5I&A3Y6y40xxo$6N?4 z_F*moua3^Eqb8WZG%~!yQq>BuwOA#%5n!w@0LJRm;h6x>KKQ=ahnEe@pSxgpAFlWi z*Mlqm|30J>@v-Am3qSraC`8KUz^jC%XfI?xNj4yqMIq)t!50Yp*xFm1z_h|UUxsjc zc{ZWTHXVIW3^)t?-`ihD5Trz8oibAU$xos9SU^}K5DtSq!r8=j3D1T<(;gciCOirU z^0_^?1Mi*a#30ri5c>2v&CFq=4!?x<<;CaZ0Vqf>#&MbX|JSGyL{1qn$2~otfUUC| zu_}kb9^t^~UBbbTsM&Lc6czwYQh=LmV!X#*3Wi`JVXq*>fTPqszEbE`J}j(GjHiX7 zXhMR;BwkLiKJWh;AEO1%v5Co^P{-iKg7xdxXQ&yM!aD*Kp?#^@P+5<6Z9;3Qg>>7o?Zc7DEefwAqc4Isqkn>kBd2y^!eB z(ZD}ZQegS+mP&!=1J0%3WB5VX9f5O)y)59JdxS&KGnDkM5(@a=6yZkQWqk>znUnAc zkHStgc`t7Ugu`Hua1c5~xCY|*pFMq)6x21^4{sdxCW<~LlljJr!aL^&n!NxyD6Z(g62=Bti*SiVdOVO@= z1T+t9;62Tw$grz<48UKvM>sHgmvCgu{@K&8(m)de$to<^V=oaIsHbWa3epcIzI%}= z0Ty#_eZeEVyS`$uK6_gVSiZZZEa3T+Kbj}l&j2_FJwxFpvPZZt0SXsWz)Jt4GXGJT z|ESD=R3D-X|FJT6ZxR1bSeZ23NezeY{5Pdq|53w* z8mIL=ZW&(F!y0-;j$eiwn7-fhuPpz4rPtn{3&H&+L$S`Qn3yVprFxDBFY;Y?GHRK7?A)EFImK<4nNNQA+Xt7U3D<&3+G+I9 zYi0ndE9(vFK=VseA~Z9DB5-C(IqP-a&TGq8qB;L(#jSTV27nG3HR z2>OP7s+jQ2Kb&+FMHcrG=M@vK_&!nj>&#v%JzPI8>?YHoyw7K9ZBJgn9qOy);H2X% z6r#DpIjMkh^mo770B-WByVP8UI|;X(Qz#G!p+Bv67JQg!po<4hxgeT3G>fUcP65rv z+%qyvC<(Hil1KNk6v_yODW!jB*cZafQFd3eFAVn5{r^2h@osk)Ik-eH940EaVjY9|T=l*mZc@BlmWmQ>!jMH(cMfkPjS(vaMBf zEVwYnKw91P@BaTmHU&fN_3yDR@Xo7@7e&HNU|>u4usneX27*T}i9Gqs3}n5dA_cS< zFAgT$Grt7H-nytLZ~I@Ig_|d$It|ztb$jlp*Ix;GI+{r}B#fCv>0t)*DJ6v0f&Y2C zQ)opJv|F#@*8)fVGYiQ6gKRc2-^>DmCA1_GzV=KXVK91O)n1$u2Bs{*_AGyyfyf%7 z8hM=eiY-irKKn+5j{X;C;ogg=z6_ofu8zUe|4C58HLhAa{5DiDQa&tabtD6F;`Mi@ z(29r`rlb-2Le2o`HDgB1!3Kkl^Mw`HQ_IgO!|!oTxw zrX;wi&$<51HzP-Z1M|z8zxC$b>W{zmWVi?z;a6z|j|cyU!ujuNNP%F{|2qjL*SoPi z)4kARmETZcTxSZwl|X|qZ%DfRP+DJ_rgaf(uyPox^%Hbk#|^%) z$|-yVEvNkwHXz%CT6_nb<`=_WQ{n-Jn^OV@Jw3gUQCEC?yr9SS!^yt4Slq8(Y;q9Q zw)nBL7U6&`dG>m2Eg=(Aja9zK&i3JJ6VonVUkE!)Pr8;>rcY~f=FisbKX@oZFMlCv zd!rCKpSC)_!D6)-egf3*H*%-hij`4_Rz1^Qtq#^I{U1TaP;CJ z04R`sNMA4CY}Bf}YWGl=?B!g)cJ`G&sXPTvrD~O}D_0{|W{2yYJ*7ww;H zH_4ivU+FUU;LcH>23O0rmDvKv0y2c211_pxt1Ti>&|6L9g*vK#2xAlg%<#)|AJg3j zQ2<03vI)!pV%0t+zF@1KZp3RzIQ=7b0E0cLJ?8qtFr+~Kb!)>L{7GC)Yp@X6@`h?;vge(RtoW5nK z+d|;UFNUah4L)o_1+zi40x=Lq*95GH4cKVAz1X`s*Nzjb5TioMh?r{nWCUgh&4w*=uO43$1*)@q{I>7 z&e}q};?ws+6FEk7T)N?Hz12246BnG{;1PG>f)k*51J=Ly>D#&QHw#`*eP4p$`XN!O znRe&gs-3Ob`jPeZosN9>lk)TqQ2@MgtbR+KjKO*I$XfqOB?lmehs!g%oz1%N@yMqN z&&ouAX_!R8oCAU7>j&tR=|mv7HWqbFC3F46(?Xly9%lQbm}203D}2i73wwN2Yp_Gh z=rFsv{lXHYhmZ)~lUy66T>EA1apKD6l;>RUz_z2i*Mu;pk12`qN?yfsPmPo+C1dRy zh&;2e?t5j!+hC=^;rKE580AA&90$}s-YKX#STj-uJqc<`AiipaGBbuKYE&s08ZS6` zOR?a^mu}TDZj(O@&x*_ePTiZ69)qyk@n>^MwBN{XK!|5VyQ{OyX2?gEg5l;9bQyg5b);+n6Ec^L^LtmSQ?I^^{|b+}8$w`1umJ zr6~FXW9)ORrm9%|Ou7E`uDF@GmyBBq2~cXzvt z6yy%WX9ja|{6TXJM*H?1r&g4ezAmag(tz?gn)tAXH02=+=^(}1Bb-N8m-0RM0EIhY zbC5uiu)hm(6eb6kUMdo5>ED+Nzi!i}$PxW5V@GY^go9t(#hb=vmIg;Man@58YwNBm z@turwI{H9E$SuEX>sVd7?kvZ!jvj`MDMmC~r3h?JC9(pc@o_2+od@0@<8sDZuS zgiVZ!%gIyfCZ0iqG>83izw0d1qymS$d??+qhrRZIMM5T?ud*=V8_q6c*`2tJOHUrV z{9wu-yIvElf|CH`_?$Vl$8{!9W&_yinq^RL?W1w*EVG(qhS)@sk8C6bai9!y$L-&3 z4LxU?#m*>LWa(s#N-+;fYuUDHBmgRXU{-X@<;S#)Q&oq{bw3wdwtIV=&>l)wsN0X9 zg^zQ{0nViSB8_LFzFdUbXT0(u}9%~2Sr@gb8w z-($h5=@ft&amqVjuaVm4*vq%-sy*Ptb6$C3qr2IiT~%VubPjuWY`$O|kgwh54lo$F zF@JqUM7Dl@9c|3PlI($VVLkTIa$76XlpOXBobWn|5vTqGkc1L8xTR&(9Ni1Ox2ZQp zlk(-C?I`;ky=%AzIOzIuAk()T4^9k8A6)VEV^HkvwvE0sJl?FMOEOPgfMGJD6$ zD&rNGZTy@S=obG`M7phO3IMn#wg569&-w69op!UT4X5aD4oxTMpkeVRo6-cc{XS#d zBPdO~!KmY;)0d5G4(b&RiPf!H55}l@Nim{+*DcfcjVv0?(5uC`+34{=`{Gm;7yKxX z?8buqAW&2-D+W87sz$%(7}pdP5_ayk6}jC{+=MRTE1Mn6!!#=rn{#!8B~u*7UENut z#s!|x>u61{DyqSg*rdFjU${>qR8maMnC(WcgerYUWsIacmlK~G*Be z*i1ETR=vq7syQ9#K~g@bi!wLI1;UK7k8VJk3N1p%7MGMxe&x55<~dlB=`rx3Z&TKI z7Gy6(@5f>!mAGVU>jnTzPpmcg6i%&SUlI5G;$U^%{&nwWM>09anYv{@BUC97@Fn8# z*N=pJwwAk0(CiXmfrC5FP~(hlLefL1-_&KmsV@L>8opS#1qxeNv=jkYwB`+ zswLyAR>3E?&>lp2E)$Or=T|K2b~JJub0{t7c36i_{Svf)c6aNb)Av`$R;t#%SbJNy zQiXQu4Gp2(F12mZfi)GI-xulKS&-T{s6F$Qm<%%0$bQ>pHCcPCyd8)JjPqB&1DC{g zt3q4==z~CM%~mO>T%S&s>AF;Gol1GF4}a4ZG;;X_==eumemBPZQ8T={@{9$JvWkhe zjq+mm3gv<9r3(G3`79n88>Ju@T{;;lQ%Jdtw04`;tM9G89yej7IB?#<*@b?b=G@jn ztow$3Y|nPRfIG9t*0hmTf7YexRmPwAD=b}lrmKtrk9XwoG@UqaEKqupCYb++K`~@z$WlIUX&)dF_RAm4<}dy8S$5l(*IOJV$M3(h9jz z8ofKrsO3dLxld@5&QS8zz;P&POUiyW#jRNWI4Ja5-8uS^DZXUfY;Ub*X<9u(qJaIu zjrIq(*YQB|nM=C}BGqq)9-R>L;Mypsh;x`82rIsKj1;(Of+@e<*j2e)@;y4@o#qzV z4e!q`l9?$#9X3t)uYJ1bJIO zjj24x(>x!9=x##I1>=#MRfD>=uA!l1>+0jZVsI7w|==WM= zO$|5Mc2SSe^mG;8w*Q5G$btL0#z=7>-%ishqoE!T|0dA{w%CEXxKUZlsT2~7D?pFD zZ?_KF2)q(4*O;(@&0p9gv-ft}_J0jJ@l_oq6s68Z279lRm1Z-2eR`UeGoL5BzR%vz zA5Nw7oZDZl-P;$fk7;1DJc8(&Rcq($<&JKxcu_M<+1@AjQoxh!?pmyRIjW$09WxI+Y&CEvdJ%?sw{zq>&7~5z(I@haaJD>vt}F`OYs9Md z^^abLig2$U?0w9WcXWnSZ%BG4q{TX6+5>V-^piy-k4Q1Sl49i%Ly4t0y+Na$^{#p& ze#ugEo9|{Q-Eputb30e^8g((W_POpCec=dX6sk%io- zI`Is($1zv1?}}HkZamo;JYuVX%jD&mw{ITOtpYrnIT}CI_ zSFsmk$2wC9l#^J7lIOpx?Z=DsCD<_>6}0Ni8C=R>biZBXQ*~2jPP*}hu$`>6d~(wQ z%^NUogu3)u2Ub6vhomBlV_Tx4ce;%{qJ>&z36$O27Vnl0J^Im>;@O~zPeC}*wz8g_ z)^C_6$PDSlxN|n^53ufoDS?MdV%~P?HT{6pS?OWpe8URws&RC1Lu~uKFE?R^Cp(XY zU_>Ry)P~86UvS%qfuu;CgQRqv+qabkZ@wqgDYj6zd3#LxC{D|S+^y=al@(8diqSx` zM-+<@W%zGM%6O5xhZWn@BDqg!NRrJ zHZ$<1{UlnA7He>lI8R(Y~~!ty@~=em-H*oh5_ly zC1D58LannZ@f5b0kZqL_6GHM75)XF@>f2Wu8vc{CP{mBzczQ>ZoGB4kL9vJvWYf*`lCLK%+9&a zs+UWh;c3r9v$uR75A#aW>^$ml=HKcSzQgm`=rj#!JM!01;it}dCjN12TqkB*BQIH?6O%_(FcV2FMn8Mn z-}}_YjF#vgJr(2La`l4Ika-12t)4)QCk{3XAJsSq6qHec*w+~SI$8R-f8hG;={!ZX z=;tcmrm9H%a_3wGzVXeVr({W<0!D@CTXvo`?Ay6}a0R(p2q|ZlZM6W#_w!fbM}~Sq zKZ0$nT9ZT+QMMjulPW%WhQJ)$@*jP6=0}>6x|BQ4|myaxP>G3Gza zzoU7*X1d#GDXmnMaiZ$jy2whEgW(S&9jucl0U;A;mV9duKLTs$)sj$kF?j{D{L^z( z#++gbZH|$tl1mNlfYWqP3lE`mCB5>jdSTuTXzGKo`L)k=AJ=>YH)tqQ+SyJs%m2cb z-yyj*srqDKb$M3$codgutChgn)>$NxoXeRQYAb(+Jvw0`V&GUFn@f=t-__OtJ)7LL7 zEO!aY8&1hCqk23uSA2L&w^qBE@(du+?G1bH0+mX zwthaC)YQS^j-pNYraH_W$7+q6XiZ>eIP2;P7FG6#I%7qW?Yl$o;KCnmunk8Qp{6aD z!5VYUJ)M)N^eELc)M`sl!TBSj$3va&f_Yw(Awd@Sz!Q=Q_g5X<6)>R#_uy)1?Q{5C zhO<7|3!7S^esErBVh=&uby68dq+kOY>gbADMs#I)Fn+t?Jq~9Ue?s~~4HPUe=*zzz zCwUGxk%dGTWo6&FS@GX%EBuEIe!f=o2l-VqVzLA?Z$6vRWy-3gU~T2-GF0y9IUV0T z^qh&Crtr~QxE8f?;0yZ&s&nz2x{$st6WbvW zH3TpJMyn7vmt@}2ps^KGdT)K!pFe*C%$ftuBs(O)F}jg|Kf@#V1JaTmRP#LK6T$aX zFIW;mgA>Y88lS%3hpTIceog7xs*K;V^fUwDXQ{C#3jm!SxL`u4x?`EgY z*E_VYi~>|(MV5?}0Peigrul5~xYGGWS) z&lrJ9As(7w*8Nje@?zZWigAZrRE4%~j6qT?Z{HUaeDYJ|EoKgN5(T{CW3BRxzvuyd zvED$@C|iU%JG=N>53cuKG?8-LoXteCe~bp#A&J?t@r0r+R3_+zVJ9N<>(Is3bu?PX z(c~FAg=ngfQ->~s6Z19+8&r<#$xoiYsANr|;X=K2Y4z3fdsADpJKNUxALOPU*gAjF znq%p8;udddRbj#k7o<)H3#?5!d9g9D=eXB2CGT=xA;& z1MU~ELB8+9Ey{Cza^R!LfQF0Ghs&`50!omb5%oJ?D8Y7!EQnI6q*BRdw3*m951G^4GsN!f&bd>< zorbP=XHf$m(O3y*Xffzb&Gbt7xu#>zsZ6~$?H-U*AL|5Ozfdim$|5=dcTCc)W*d@j zewCd!k;{8-;NfDHYvA;}E~TtXFj!VoyBsBxgXVW5gIlL(h#&m8FF$v<70&8xr&7Z< zZ~k8uV1qahK;N^h-zW1pGPJNxcnq-mOiB5Y$}?SQQzQ34ZW92Nkf}^ja^{Ck-C-HY z_n8{!f0uCiOBv$Z^JZeLvfmlVMr=cGw~m^Pg1q-v%O(f1|v+4szZ6IcOAV{1d(y4eLT=Kg{fEbpN!;b1%%xn>`yL(Gqn#H!EZd+DPj zz3I7jXE-mIbfq|qu|I5^2J5scutU%%Rjeruv`|Dems89Fim>vEJ7aFPqS11`69?sR=SkT}I!wKn^bv$Rv;%%}6y+a#t z*{Ow0{H*#s=tF`03CZ@}OSy#~j@P8-@juI*jV`~~1AZ>@E6d=ROEYtrI>|Rd%(ot* zRY4!!-5HgDN>&jwhqIv^mL{8vLcOJ5wPv3US%@&)ORyA5#m(F(A z8Ly``!r6=EDh4t>oRcnmCy^0bYy*-{kiQ5X)$AOVA;pSvKS6Zn31~XE;HNNxC$S$l z*)HyuJ2kxsTja3e^SD7h7f}+S?DHV)pRK8p0i=ubD%iauFsaE`CqAX#*?zSEwuADf z^$V+_7YMv>*c{sg?jr4Uc7IsB%xY+`Rc|CG_ev$6n~#rgShe)>&i2+AlseFO2oaz( z_Kr-rHf+_Tt*)>}Ljx?;P3c#wfmB7X;tj}Mk8XAyLZRZz+VhbDrj1ct8Xq^MGf|0T zQ6qQuC$wvz_(Q|&yVven)Ia6Xex3jAjNrVaelGvuY}wBChS}!o{IDv115^t&HBMBK zA?VdrqQ}DnohdULO+qH8l?T*J#poi7@dC5CZpr%N3(>j&f zk=8?E3)gN7SC+>+%*u0>8Tndni5)Ap;twX5K_50uw7#t0xs|=jm=VQ5%&>t?j_`n% zWDBb!VMOMvrj6aU))536HkgWe=r zQ|s75!Ve#|i7jiYXrm8Ib>t$UTi~7pSHG@`;y33K&+5J^Z zP8H=YFFi$AK!x*exQ|>_ zN^<7gXAxH^1P6yU?`%UBGgWeoqL1Y?A&TAKJBJrodQM zF!*F~>Ti(&1OwLHzrW^x7^SK(2@#P&q_D`MHD$1>K8Q9*!l=kJ(B8ozaNHU1p^{Qi z@tZf7_4J-Ye`+PT`ldqldX2|Al8#-U&j0*R5%ZvZtqk-UY!vho4@XxxXn{GgVlqQ21mUA9w}`n2d{u3 zCjy;gMOX7}f*${V^-b>v>N&g`_TK+@=g-Z*!>_Zd)d1QgZ1?jMToKvha5qfaP5mKo zqZW-8qw@CN_D~@XbE>Pf<=qHt*sM@Ba_NHHK>d literal 0 HcmV?d00001 diff --git a/examples/inverse/results/gail/Hopper-v2_rew.png b/examples/inverse/results/gail/Hopper-v2_rew.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf54253b12ee8b4bac6e9c649756c7cb216950c GIT binary patch literal 238281 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 literal 0 HcmV?d00001 diff --git a/examples/inverse/results/gail/Walker2d-v2_rew.png b/examples/inverse/results/gail/Walker2d-v2_rew.png new file mode 100644 index 0000000000000000000000000000000000000000..46e711ba7c07dba3c976a3ce59cbac2614f8acd7 GIT binary patch literal 210327 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

hxi!A$ZY=C(fJUVx076V}d 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 ak!=cJ8Ax&4yu$zL;s)b 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 b+Paez(~^OU7v8S}ufIFF94R~O^Xq>BAew^Z literal 0 HcmV?d00001 diff --git a/examples/mujoco/README.md b/examples/mujoco/README.md index ff37db4b2..8890466f8 100644 --- a/examples/mujoco/README.md +++ b/examples/mujoco/README.md @@ -247,7 +247,7 @@ For pretrained agents, detailed graphs (single agent, single game) and log detai ### TRPO -| Environment | Tianshou (1M) | [ACKTR paper](https://arxiv.org/pdf/1708.05144.pdf) | [PPO paper](https://arxiv.org/pdf/1707.06347.pdf) | [OpenAI Baselines](https://github.com/openai/baselines/blob/master/benchmarks_mujoco1M.htm) | [Spinning Up (PyTorch)](https://spinningup.openai.com/en/latest/spinningup/bench.html) | +| Environment | Tianshou (1M) | [ACKTR paper](https://arxiv.org/pdf/1708.05144.pdf) | [PPO paper](https://arxiv.org/pdf/1707.06347.pdf) | [OpenAI Baselines](https://github.com/openai/baselines/blob/master/benchmarks_mujoco1M.htm) | [Spinning Up (Tensorflow)](https://spinningup.openai.com/en/latest/spinningup/bench.html) | | :--------------------: | :---------------: | :-------------------------------------------------: | :-----------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | | Ant | **2866.7±707.9** | ~0 | N | N | ~150 | | HalfCheetah | **4471.2±804.9** | ~400 | ~0 | ~1350 | ~850 | diff --git a/examples/mujoco/mujoco_a2c.py b/examples/mujoco/mujoco_a2c.py index 02978697b..b8fc3370c 100755 --- a/examples/mujoco/mujoco_a2c.py +++ b/examples/mujoco/mujoco_a2c.py @@ -179,7 +179,7 @@ def dist(*logits): writer.add_text("args", str(args)) logger = TensorboardLogger(writer, update_interval=100, train_interval=100) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -194,7 +194,7 @@ def save_fn(policy): args.test_num, args.batch_size, step_per_collect=args.step_per_collect, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/examples/mujoco/mujoco_ddpg.py b/examples/mujoco/mujoco_ddpg.py index 8d436b573..51955fe71 100755 --- a/examples/mujoco/mujoco_ddpg.py +++ b/examples/mujoco/mujoco_ddpg.py @@ -128,7 +128,7 @@ def test_ddpg(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -142,7 +142,7 @@ def save_fn(policy): args.step_per_collect, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False diff --git a/examples/mujoco/mujoco_npg.py b/examples/mujoco/mujoco_npg.py index 23883a119..fd681bca3 100755 --- a/examples/mujoco/mujoco_npg.py +++ b/examples/mujoco/mujoco_npg.py @@ -175,7 +175,7 @@ def dist(*logits): writer.add_text("args", str(args)) logger = TensorboardLogger(writer, update_interval=100, train_interval=100) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -190,7 +190,7 @@ def save_fn(policy): args.test_num, args.batch_size, step_per_collect=args.step_per_collect, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/examples/mujoco/mujoco_ppo.py b/examples/mujoco/mujoco_ppo.py index 01dc5aa3f..392f1c22a 100755 --- a/examples/mujoco/mujoco_ppo.py +++ b/examples/mujoco/mujoco_ppo.py @@ -186,7 +186,7 @@ def dist(*logits): writer.add_text("args", str(args)) logger = TensorboardLogger(writer, update_interval=100, train_interval=100) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -201,7 +201,7 @@ def save_fn(policy): args.test_num, args.batch_size, step_per_collect=args.step_per_collect, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/examples/mujoco/mujoco_reinforce.py b/examples/mujoco/mujoco_reinforce.py index 914b46251..7d331af43 100755 --- a/examples/mujoco/mujoco_reinforce.py +++ b/examples/mujoco/mujoco_reinforce.py @@ -158,7 +158,7 @@ def dist(*logits): writer.add_text("args", str(args)) logger = TensorboardLogger(writer, update_interval=10, train_interval=100) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -173,7 +173,7 @@ def save_fn(policy): args.test_num, args.batch_size, step_per_collect=args.step_per_collect, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/examples/mujoco/mujoco_sac.py b/examples/mujoco/mujoco_sac.py index cb764f473..eb2afe70f 100755 --- a/examples/mujoco/mujoco_sac.py +++ b/examples/mujoco/mujoco_sac.py @@ -151,7 +151,7 @@ def test_sac(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -165,7 +165,7 @@ def save_fn(policy): args.step_per_collect, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False diff --git a/examples/mujoco/mujoco_td3.py b/examples/mujoco/mujoco_td3.py index 9e0ca0d82..d2a9bd7bc 100755 --- a/examples/mujoco/mujoco_td3.py +++ b/examples/mujoco/mujoco_td3.py @@ -148,7 +148,7 @@ def test_td3(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -162,7 +162,7 @@ def save_fn(policy): args.step_per_collect, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False diff --git a/examples/mujoco/mujoco_trpo.py b/examples/mujoco/mujoco_trpo.py index aef324fd5..dd2ce5334 100755 --- a/examples/mujoco/mujoco_trpo.py +++ b/examples/mujoco/mujoco_trpo.py @@ -180,7 +180,7 @@ def dist(*logits): writer.add_text("args", str(args)) logger = TensorboardLogger(writer, update_interval=100, train_interval=100) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) if not args.watch: @@ -195,7 +195,7 @@ def save_fn(policy): args.test_num, args.batch_size, step_per_collect=args.step_per_collect, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/examples/offline/README.md b/examples/offline/README.md index 1ac98ec91..04c42686e 100644 --- a/examples/offline/README.md +++ b/examples/offline/README.md @@ -10,25 +10,30 @@ We provide implementation of BCQ and CQL algorithm for continuous control. ### Train -Tianshou provides an `offline_trainer` for offline reinforcement learning. You can parse d4rl datasets into a `ReplayBuffer` , and set it as the parameter `buffer` of `offline_trainer`. `offline_bcq.py` is an example of offline RL using the d4rl dataset. +Tianshou provides an `offline_trainer` for offline reinforcement learning. You can parse d4rl datasets into a `ReplayBuffer` , and set it as the parameter `buffer` of `offline_trainer`. `d4rl_bcq.py` is an example of offline RL using the d4rl dataset. -To train an agent with BCQ algorithm: +## Results -```bash -python offline_bcq.py --task halfcheetah-expert-v1 -``` +### IL (Imitation Learning, aka, Behavior Cloning) -After 1M steps: +| Environment | Dataset | IL | Parameters | +| --------------------- | --------------------- | --------------- | -------------------------------------------------------- | +| HalfCheetah-v2 | halfcheetah-expert-v2 | 11355.31 | `python3 d4rl_il.py --task HalfCheetah-v2 --expert-data-task halfcheetah-expert-v2` | +| HalfCheetah-v2 | halfcheetah-medium-v2 | 5098.16 | `python3 d4rl_il.py --task HalfCheetah-v2 --expert-data-task halfcheetah-medium-v2` | -![halfcheetah-expert-v1_reward](results/bcq/halfcheetah-expert-v1_reward.png) +### BCQ -`halfcheetah-expert-v1` is a mujoco environment. The setting of hyperparameters are similar to the off-policy algorithms in mujoco environment. +| Environment | Dataset | BCQ | Parameters | +| --------------------- | --------------------- | --------------- | -------------------------------------------------------- | +| HalfCheetah-v2 | halfcheetah-expert-v2 | 11509.95 | `python3 d4rl_bcq.py --task HalfCheetah-v2 --expert-data-task halfcheetah-expert-v2` | +| HalfCheetah-v2 | halfcheetah-medium-v2 | 5147.43 | `python3 d4rl_bcq.py --task HalfCheetah-v2 --expert-data-task halfcheetah-medium-v2` | -## Results +### CQL -| Environment | BCQ | -| --------------------- | --------------- | -| halfcheetah-expert-v1 | 10624.0 ± 181.4 | +| Environment | Dataset | CQL | Parameters | +| --------------------- | --------------------- | --------------- | -------------------------------------------------------- | +| HalfCheetah-v2 | halfcheetah-expert-v2 | 2864.37 | `python3 d4rl_cql.py --task HalfCheetah-v2 --expert-data-task halfcheetah-expert-v2` | +| HalfCheetah-v2 | halfcheetah-medium-v2 | 6505.41 | `python3 d4rl_cql.py --task HalfCheetah-v2 --expert-data-task halfcheetah-medium-v2` | ## Discrete control @@ -42,14 +47,23 @@ To running CQL algorithm on Atari, you need to do the following things: - Generate buffer with noise: `python3 atari_qrdqn.py --task {your_task} --watch --resume-path log/{your_task}/qrdqn/policy.pth --eps-test 0.2 --buffer-size 1000000 --save-buffer-name expert.hdf5` (note that 1M Atari buffer cannot be saved as `.pkl` format because it is too large and will cause error); - Train offline model: `python3 atari_{bcq,cql,crr}.py --task {your_task} --load-buffer-name expert.hdf5`. +### IL + +We test our IL implementation on two example tasks (different from author's version, we use v4 instead of v0; one epoch means 10k gradient step): + +| Task | Online QRDQN | Behavioral | IL | parameters | +| ---------------------- | ---------- | ---------- | --------------------------------- | ------------------------------------------------------------ | +| PongNoFrameskip-v4 | 20.5 | 6.8 | 20.0 (epoch 5) | `python3 atari_il.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | +| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 121.9 (epoch 12, could be higher) | `python3 atari_il.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12` | + ### BCQ We test our BCQ implementation on two example tasks (different from author's version, we use v4 instead of v0; one epoch means 10k gradient step): | Task | Online QRDQN | Behavioral | BCQ | parameters | | ---------------------- | ---------- | ---------- | --------------------------------- | ------------------------------------------------------------ | -| PongNoFrameskip-v4 | 20.5 | 6.8 | 20.1 (epoch 5) | `python3 atari_bcq.py --task "PongNoFrameskip-v4" --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | -| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 64.6 (epoch 12, could be higher) | `python3 atari_bcq.py --task "BreakoutNoFrameskip-v4" --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12` | +| PongNoFrameskip-v4 | 20.5 | 6.8 | 20.1 (epoch 5) | `python3 atari_bcq.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | +| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 64.6 (epoch 12, could be higher) | `python3 atari_bcq.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12` | ### CQL @@ -57,8 +71,8 @@ We test our CQL implementation on two example tasks (different from author's ver | Task | Online QRDQN | Behavioral | CQL | parameters | | ---------------------- | ---------- | ---------- | --------------------------------- | ------------------------------------------------------------ | -| PongNoFrameskip-v4 | 20.5 | 6.8 | 20.4 (epoch 5) | `python3 atari_cql.py --task "PongNoFrameskip-v4" --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | -| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 129.4 (epoch 12) | `python3 atari_cql.py --task "BreakoutNoFrameskip-v4" --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12 --min-q-weight 50` | +| PongNoFrameskip-v4 | 20.5 | 6.8 | 20.4 (epoch 5) | `python3 atari_cql.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | +| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 129.4 (epoch 12) | `python3 atari_cql.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12 --min-q-weight 50` | We reduce the size of the offline data to 10% and 1% of the above and get: @@ -66,15 +80,15 @@ Buffer size 100000: | Task | Online QRDQN | Behavioral | CQL | parameters | | ---------------------- | ---------- | ---------- | --------------------------------- | ------------------------------------------------------------ | -| PongNoFrameskip-v4 | 20.5 | 5.8 | 21 (epoch 5) | `python3 atari_cql.py --task "PongNoFrameskip-v4" --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.size_1e5.hdf5 --epoch 5` | -| BreakoutNoFrameskip-v4 | 394.3 | 41.4 | 40.8 (epoch 12) | `python3 atari_cql.py --task "BreakoutNoFrameskip-v4" --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.size_1e5.hdf5 --epoch 12 --min-q-weight 20` | +| PongNoFrameskip-v4 | 20.5 | 5.8 | 21 (epoch 5) | `python3 atari_cql.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.size_1e5.hdf5 --epoch 5` | +| BreakoutNoFrameskip-v4 | 394.3 | 41.4 | 40.8 (epoch 12) | `python3 atari_cql.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.size_1e5.hdf5 --epoch 12 --min-q-weight 20` | Buffer size 10000: | Task | Online QRDQN | Behavioral | CQL | parameters | | ---------------------- | ---------- | ---------- | --------------------------------- | ------------------------------------------------------------ | -| PongNoFrameskip-v4 | 20.5 | nan | 1.8 (epoch 5) | `python3 atari_cql.py --task "PongNoFrameskip-v4" --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.size_1e4.hdf5 --epoch 5 --min-q-weight 1` | -| BreakoutNoFrameskip-v4 | 394.3 | 31.7 | 22.5 (epoch 12) | `python3 atari_cql.py --task "BreakoutNoFrameskip-v4" --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.size_1e4.hdf5 --epoch 12 --min-q-weight 10` | +| PongNoFrameskip-v4 | 20.5 | nan | 1.8 (epoch 5) | `python3 atari_cql.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.size_1e4.hdf5 --epoch 5 --min-q-weight 1` | +| BreakoutNoFrameskip-v4 | 394.3 | 31.7 | 22.5 (epoch 12) | `python3 atari_cql.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.size_1e4.hdf5 --epoch 12 --min-q-weight 10` | ### CRR @@ -82,7 +96,7 @@ We test our CRR implementation on two example tasks (different from author's ver | Task | Online QRDQN | Behavioral | CRR | CRR w/ CQL | parameters | | ---------------------- | ---------- | ---------- | ---------------- | ----------------- | ------------------------------------------------------------ | -| PongNoFrameskip-v4 | 20.5 | 6.8 | -21 (epoch 5) | 17.7 (epoch 5) | `python3 atari_crr.py --task "PongNoFrameskip-v4" --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | -| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 23.3 (epoch 12) | 76.9 (epoch 12) | `python3 atari_crr.py --task "BreakoutNoFrameskip-v4" --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12 --min-q-weight 50` | +| PongNoFrameskip-v4 | 20.5 | 6.8 | -21 (epoch 5) | 17.7 (epoch 5) | `python3 atari_crr.py --task PongNoFrameskip-v4 --load-buffer-name log/PongNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 5` | +| BreakoutNoFrameskip-v4 | 394.3 | 46.9 | 23.3 (epoch 12) | 76.9 (epoch 12) | `python3 atari_crr.py --task BreakoutNoFrameskip-v4 --load-buffer-name log/BreakoutNoFrameskip-v4/qrdqn/expert.hdf5 --epoch 12 --min-q-weight 50` | Note that CRR itself does not work well in Atari tasks but adding CQL loss/regularizer helps. diff --git a/examples/offline/atari_bcq.py b/examples/offline/atari_bcq.py index 83865d18d..f398f64e9 100644 --- a/examples/offline/atari_bcq.py +++ b/examples/offline/atari_bcq.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import argparse import datetime import os @@ -9,12 +11,11 @@ from torch.utils.tensorboard import SummaryWriter from examples.atari.atari_network import DQN -from examples.atari.atari_wrapper import wrap_deepmind +from examples.atari.atari_wrapper import make_atari_env from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import ShmemVectorEnv from tianshou.policy import DiscreteBCQPolicy from tianshou.trainer import offline_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.common import ActorCritic from tianshou.utils.net.discrete import Actor @@ -33,12 +34,21 @@ def get_args(): parser.add_argument("--epoch", type=int, default=100) parser.add_argument("--update-per-epoch", type=int, default=10000) parser.add_argument("--batch-size", type=int, default=32) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[512]) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[512]) parser.add_argument("--test-num", type=int, default=10) - parser.add_argument('--frames-stack', type=int, default=4) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--scale-obs", type=int, default=0) parser.add_argument("--logdir", type=str, default="log") parser.add_argument("--render", type=float, default=0.) parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="offline_atari.benchmark") parser.add_argument( "--watch", default=False, @@ -56,35 +66,24 @@ def get_args(): return args -def make_atari_env(args): - return wrap_deepmind(args.task, frame_stack=args.frames_stack) - - -def make_atari_env_watch(args): - return wrap_deepmind( +def test_discrete_bcq(args=get_args()): + # envs + env, _, test_envs = make_atari_env( args.task, + args.seed, + 1, + args.test_num, + scale=args.scale_obs, frame_stack=args.frames_stack, - episode_life=False, - clip_rewards=False ) - - -def test_discrete_bcq(args=get_args()): - # envs - env = make_atari_env(args) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n # should be N_FRAMES x H x W print("Observations shape:", args.state_shape) print("Actions shape:", args.action_shape) - # make environments - test_envs = ShmemVectorEnv( - [lambda: make_atari_env_watch(args) for _ in range(args.test_num)] - ) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) - test_envs.seed(args.seed) # model feature_net = DQN( *args.state_shape, args.action_shape, device=args.device, features_only=True @@ -118,9 +117,9 @@ def test_discrete_bcq(args=get_args()): # buffer assert os.path.exists(args.load_buffer_name), \ "Please run atari_dqn.py first to get expert's data buffer." - if args.load_buffer_name.endswith('.pkl'): + if args.load_buffer_name.endswith(".pkl"): buffer = pickle.load(open(args.load_buffer_name, "rb")) - elif args.load_buffer_name.endswith('.hdf5'): + elif args.load_buffer_name.endswith(".hdf5"): buffer = VectorReplayBuffer.load_hdf5(args.load_buffer_name) else: print(f"Unknown buffer format: {args.load_buffer_name}") @@ -130,16 +129,29 @@ def test_discrete_bcq(args=get_args()): test_collector = Collector(policy, test_envs, exploration_noise=True) # log - log_path = os.path.join( - args.logdir, args.task, 'bcq', - f'seed_{args.seed}_{datetime.datetime.now().strftime("%m%d-%H%M%S")}' - ) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "bcq" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer, update_interval=args.log_interval) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): return False @@ -170,7 +182,7 @@ def watch(): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) diff --git a/examples/offline/atari_cql.py b/examples/offline/atari_cql.py index 22ef7b253..c8300b3fe 100644 --- a/examples/offline/atari_cql.py +++ b/examples/offline/atari_cql.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import argparse import datetime import os @@ -9,12 +11,11 @@ from torch.utils.tensorboard import SummaryWriter from examples.atari.atari_network import QRDQN -from examples.atari.atari_wrapper import wrap_deepmind +from examples.atari.atari_wrapper import make_atari_env from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import ShmemVectorEnv from tianshou.policy import DiscreteCQLPolicy from tianshou.trainer import offline_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger def get_args(): @@ -24,19 +25,28 @@ def get_args(): parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=0.0001) parser.add_argument("--gamma", type=float, default=0.99) - parser.add_argument('--num-quantiles', type=int, default=200) + parser.add_argument("--num-quantiles", type=int, default=200) parser.add_argument("--n-step", type=int, default=1) parser.add_argument("--target-update-freq", type=int, default=500) parser.add_argument("--min-q-weight", type=float, default=10.) parser.add_argument("--epoch", type=int, default=100) parser.add_argument("--update-per-epoch", type=int, default=10000) parser.add_argument("--batch-size", type=int, default=32) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[512]) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[512]) parser.add_argument("--test-num", type=int, default=10) - parser.add_argument('--frames-stack', type=int, default=4) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--scale-obs", type=int, default=0) parser.add_argument("--logdir", type=str, default="log") parser.add_argument("--render", type=float, default=0.) parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="offline_atari.benchmark") parser.add_argument( "--watch", default=False, @@ -54,35 +64,24 @@ def get_args(): return args -def make_atari_env(args): - return wrap_deepmind(args.task, frame_stack=args.frames_stack) - - -def make_atari_env_watch(args): - return wrap_deepmind( +def test_discrete_cql(args=get_args()): + # envs + env, _, test_envs = make_atari_env( args.task, + args.seed, + 1, + args.test_num, + scale=args.scale_obs, frame_stack=args.frames_stack, - episode_life=False, - clip_rewards=False ) - - -def test_discrete_cql(args=get_args()): - # envs - env = make_atari_env(args) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n # should be N_FRAMES x H x W print("Observations shape:", args.state_shape) print("Actions shape:", args.action_shape) - # make environments - test_envs = ShmemVectorEnv( - [lambda: make_atari_env_watch(args) for _ in range(args.test_num)] - ) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) - test_envs.seed(args.seed) # model net = QRDQN(*args.state_shape, args.action_shape, args.num_quantiles, args.device) optim = torch.optim.Adam(net.parameters(), lr=args.lr) @@ -103,9 +102,9 @@ def test_discrete_cql(args=get_args()): # buffer assert os.path.exists(args.load_buffer_name), \ "Please run atari_qrdqn.py first to get expert's data buffer." - if args.load_buffer_name.endswith('.pkl'): + if args.load_buffer_name.endswith(".pkl"): buffer = pickle.load(open(args.load_buffer_name, "rb")) - elif args.load_buffer_name.endswith('.hdf5'): + elif args.load_buffer_name.endswith(".hdf5"): buffer = VectorReplayBuffer.load_hdf5(args.load_buffer_name) else: print(f"Unknown buffer format: {args.load_buffer_name}") @@ -115,16 +114,29 @@ def test_discrete_cql(args=get_args()): test_collector = Collector(policy, test_envs, exploration_noise=True) # log - log_path = os.path.join( - args.logdir, args.task, 'cql', - f'seed_{args.seed}_{datetime.datetime.now().strftime("%m%d-%H%M%S")}' - ) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "cql" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer, update_interval=args.log_interval) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): return False @@ -155,7 +167,7 @@ def watch(): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) diff --git a/examples/offline/atari_crr.py b/examples/offline/atari_crr.py index 0214bf2f5..49ef9c3a1 100644 --- a/examples/offline/atari_crr.py +++ b/examples/offline/atari_crr.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import argparse import datetime import os @@ -9,12 +11,11 @@ from torch.utils.tensorboard import SummaryWriter from examples.atari.atari_network import DQN -from examples.atari.atari_wrapper import wrap_deepmind +from examples.atari.atari_wrapper import make_atari_env from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import ShmemVectorEnv from tianshou.policy import DiscreteCRRPolicy from tianshou.trainer import offline_trainer -from tianshou.utils import TensorboardLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.common import ActorCritic from tianshou.utils.net.discrete import Actor, Critic @@ -33,12 +34,21 @@ def get_args(): parser.add_argument("--epoch", type=int, default=100) parser.add_argument("--update-per-epoch", type=int, default=10000) parser.add_argument("--batch-size", type=int, default=32) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[512]) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[512]) parser.add_argument("--test-num", type=int, default=10) - parser.add_argument('--frames-stack', type=int, default=4) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--scale-obs", type=int, default=0) parser.add_argument("--logdir", type=str, default="log") parser.add_argument("--render", type=float, default=0.) parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="offline_atari.benchmark") parser.add_argument( "--watch", default=False, @@ -56,35 +66,24 @@ def get_args(): return args -def make_atari_env(args): - return wrap_deepmind(args.task, frame_stack=args.frames_stack) - - -def make_atari_env_watch(args): - return wrap_deepmind( +def test_discrete_crr(args=get_args()): + # envs + env, _, test_envs = make_atari_env( args.task, + args.seed, + 1, + args.test_num, + scale=args.scale_obs, frame_stack=args.frames_stack, - episode_life=False, - clip_rewards=False ) - - -def test_discrete_crr(args=get_args()): - # envs - env = make_atari_env(args) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n # should be N_FRAMES x H x W print("Observations shape:", args.state_shape) print("Actions shape:", args.action_shape) - # make environments - test_envs = ShmemVectorEnv( - [lambda: make_atari_env_watch(args) for _ in range(args.test_num)] - ) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) - test_envs.seed(args.seed) # model feature_net = DQN( *args.state_shape, args.action_shape, device=args.device, features_only=True @@ -123,9 +122,9 @@ def test_discrete_crr(args=get_args()): # buffer assert os.path.exists(args.load_buffer_name), \ "Please run atari_qrdqn.py first to get expert's data buffer." - if args.load_buffer_name.endswith('.pkl'): + if args.load_buffer_name.endswith(".pkl"): buffer = pickle.load(open(args.load_buffer_name, "rb")) - elif args.load_buffer_name.endswith('.hdf5'): + elif args.load_buffer_name.endswith(".hdf5"): buffer = VectorReplayBuffer.load_hdf5(args.load_buffer_name) else: print(f"Unknown buffer format: {args.load_buffer_name}") @@ -135,16 +134,29 @@ def test_discrete_crr(args=get_args()): test_collector = Collector(policy, test_envs, exploration_noise=True) # log - log_path = os.path.join( - args.logdir, args.task, 'crr', - f'seed_{args.seed}_{datetime.datetime.now().strftime("%m%d-%H%M%S")}' - ) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "crr" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer, update_interval=args.log_interval) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): return False @@ -174,7 +186,7 @@ def watch(): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) diff --git a/examples/offline/atari_il.py b/examples/offline/atari_il.py new file mode 100644 index 000000000..348f9920d --- /dev/null +++ b/examples/offline/atari_il.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 + +import argparse +import datetime +import os +import pickle +import pprint + +import numpy as np +import torch +from torch.utils.tensorboard import SummaryWriter + +from examples.atari.atari_network import DQN +from examples.atari.atari_wrapper import make_atari_env +from tianshou.data import Collector, VectorReplayBuffer +from tianshou.policy import ImitationPolicy +from tianshou.trainer import offline_trainer +from tianshou.utils import TensorboardLogger, WandbLogger + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--task", type=str, default="PongNoFrameskip-v4") + parser.add_argument("--seed", type=int, default=1626) + parser.add_argument("--lr", type=float, default=0.0001) + parser.add_argument("--epoch", type=int, default=100) + parser.add_argument("--update-per-epoch", type=int, default=10000) + parser.add_argument("--batch-size", type=int, default=32) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--frames-stack", type=int, default=4) + parser.add_argument("--scale-obs", type=int, default=0) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="offline_atari.benchmark") + parser.add_argument( + "--watch", + default=False, + action="store_true", + help="watch the play of pre-trained policy only" + ) + parser.add_argument("--log-interval", type=int, default=100) + parser.add_argument( + "--load-buffer-name", type=str, default="./expert_DQN_PongNoFrameskip-v4.hdf5" + ) + parser.add_argument( + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" + ) + args = parser.parse_known_args()[0] + return args + + +def test_il(args=get_args()): + # envs + env, _, test_envs = make_atari_env( + args.task, + args.seed, + 1, + args.test_num, + scale=args.scale_obs, + frame_stack=args.frames_stack, + ) + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + # should be N_FRAMES x H x W + print("Observations shape:", args.state_shape) + print("Actions shape:", args.action_shape) + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + # model + net = DQN(*args.state_shape, args.action_shape, device=args.device).to(args.device) + optim = torch.optim.Adam(net.parameters(), lr=args.lr) + # define policy + policy = ImitationPolicy(net, optim, action_space=env.action_space) + # load a previous policy + if args.resume_path: + policy.load_state_dict(torch.load(args.resume_path, map_location=args.device)) + print("Loaded agent from: ", args.resume_path) + # buffer + assert os.path.exists(args.load_buffer_name), \ + "Please run atari_qrdqn.py first to get expert's data buffer." + if args.load_buffer_name.endswith('.pkl'): + buffer = pickle.load(open(args.load_buffer_name, "rb")) + elif args.load_buffer_name.endswith('.hdf5'): + buffer = VectorReplayBuffer.load_hdf5(args.load_buffer_name) + else: + print(f"Unknown buffer format: {args.load_buffer_name}") + exit(0) + + # collector + test_collector = Collector(policy, test_envs, exploration_noise=True) + + # log + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "il" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) + + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) + + def stop_fn(mean_rewards): + return False + + # watch agent's performance + def watch(): + print("Setup test envs ...") + policy.eval() + test_envs.seed(args.seed) + print("Testing agent ...") + test_collector.reset() + result = test_collector.collect(n_episode=args.test_num, render=args.render) + pprint.pprint(result) + rew = result["rews"].mean() + print(f'Mean reward (over {result["n/ep"]} episodes): {rew}') + + if args.watch: + watch() + exit(0) + + result = offline_trainer( + policy, + buffer, + test_collector, + args.epoch, + args.update_per_epoch, + args.test_num, + args.batch_size, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + logger=logger, + ) + + pprint.pprint(result) + watch() + + +if __name__ == "__main__": + test_il(get_args()) diff --git a/examples/offline/offline_bcq.py b/examples/offline/d4rl_bcq.py similarity index 63% rename from examples/offline/offline_bcq.py rename to examples/offline/d4rl_bcq.py index e488489e2..434763e6d 100644 --- a/examples/offline/offline_bcq.py +++ b/examples/offline/d4rl_bcq.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import argparse import datetime import os @@ -10,36 +11,38 @@ import torch from torch.utils.tensorboard import SummaryWriter -from tianshou.data import Batch, Collector, ReplayBuffer, VectorReplayBuffer +from tianshou.data import Batch, Collector, ReplayBuffer from tianshou.env import SubprocVectorEnv from tianshou.policy import BCQPolicy from tianshou.trainer import offline_trainer -from tianshou.utils import BasicLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.common import MLP, Net from tianshou.utils.net.continuous import VAE, Critic, Perturbation def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='halfcheetah-expert-v1') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--buffer-size', type=int, default=1000000) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[400, 300]) - parser.add_argument('--actor-lr', type=float, default=1e-3) - parser.add_argument('--critic-lr', type=float, default=1e-3) + parser.add_argument("--task", type=str, default="HalfCheetah-v2") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--expert-data-task", type=str, default="halfcheetah-expert-v2" + ) + parser.add_argument("--buffer-size", type=int, default=1000000) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[256, 256]) + parser.add_argument("--actor-lr", type=float, default=1e-3) + parser.add_argument("--critic-lr", type=float, default=1e-3) parser.add_argument("--start-timesteps", type=int, default=10000) - parser.add_argument('--epoch', type=int, default=200) - parser.add_argument('--step-per-epoch', type=int, default=5000) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--batch-size', type=int, default=256) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=1 / 35) - - parser.add_argument("--vae-hidden-sizes", type=int, nargs='*', default=[750, 750]) + parser.add_argument("--epoch", type=int, default=200) + parser.add_argument("--step-per-epoch", type=int, default=5000) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--batch-size", type=int, default=256) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=1 / 35) + + parser.add_argument("--vae-hidden-sizes", type=int, nargs="*", default=[512, 512]) # default to 2 * action_dim - parser.add_argument('--latent-dim', type=int) + parser.add_argument("--latent-dim", type=int) parser.add_argument("--gamma", default=0.99) parser.add_argument("--tau", default=0.005) # Weighting for Clipped Double Q-learning in BCQ @@ -47,14 +50,22 @@ def get_args(): # Max perturbation hyper-parameter for BCQ parser.add_argument("--phi", default=0.05) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" + ) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], ) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--wandb-project", type=str, default="offline_d4rl.benchmark") parser.add_argument( - '--watch', + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only', + action="store_true", + help="watch the play of pre-trained policy only", ) return parser.parse_args() @@ -74,10 +85,6 @@ def test_bcq(): args.action_dim = args.action_shape[0] print("Max_action", args.max_action) - # train_envs = gym.make(args.task) - train_envs = SubprocVectorEnv( - [lambda: gym.make(args.task) for _ in range(args.training_num)] - ) # test_envs = gym.make(args.task) test_envs = SubprocVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] @@ -85,7 +92,6 @@ def test_bcq(): # seed np.random.seed(args.seed) torch.manual_seed(args.seed) - train_envs.seed(args.seed) test_envs.seed(args.seed) # model @@ -166,38 +172,47 @@ def test_bcq(): print("Loaded agent from: ", args.resume_path) # collector - if args.training_num > 1: - buffer = VectorReplayBuffer(args.buffer_size, len(train_envs)) - else: - buffer = ReplayBuffer(args.buffer_size) - train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs) - train_collector.collect(n_step=args.start_timesteps, random=True) + # log - t0 = datetime.datetime.now().strftime("%m%d_%H%M%S") - log_file = f'seed_{args.seed}_{t0}-{args.task.replace("-", "_")}_bcq' - log_path = os.path.join(args.logdir, args.task, 'bcq', log_file) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "bcq" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = BasicLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def watch(): if args.resume_path is None: - args.resume_path = os.path.join(log_path, 'policy.pth') + args.resume_path = os.path.join(log_path, "policy.pth") policy.load_state_dict( - torch.load(args.resume_path, map_location=torch.device('cpu')) + torch.load(args.resume_path, map_location=torch.device("cpu")) ) policy.eval() collector = Collector(policy, env) collector.collect(n_episode=1, render=1 / 35) if not args.watch: - dataset = d4rl.qlearning_dataset(env) - dataset_size = dataset['rewards'].size + dataset = d4rl.qlearning_dataset(gym.make(args.expert_data_task)) + dataset_size = dataset["rewards"].size print("dataset_size", dataset_size) replay_buffer = ReplayBuffer(dataset_size) @@ -205,11 +220,11 @@ def watch(): for i in range(dataset_size): replay_buffer.add( Batch( - obs=dataset['observations'][i], - act=dataset['actions'][i], - rew=dataset['rewards'][i], - done=dataset['terminals'][i], - obs_next=dataset['next_observations'][i], + obs=dataset["observations"][i], + act=dataset["actions"][i], + rew=dataset["rewards"][i], + done=dataset["terminals"][i], + obs_next=dataset["next_observations"][i], ) ) print("dataset loaded") @@ -222,7 +237,7 @@ def watch(): args.step_per_epoch, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) pprint.pprint(result) @@ -234,8 +249,8 @@ def watch(): test_envs.seed(args.seed) test_collector.reset() result = test_collector.collect(n_episode=args.test_num, render=args.render) - print(f'Final reward: {result["rews"].mean()}, length: {result["lens"].mean()}') + print(f"Final reward: {result['rews'].mean()}, length: {result['lens'].mean()}") -if __name__ == '__main__': +if __name__ == "__main__": test_bcq() diff --git a/examples/offline/offline_cql.py b/examples/offline/d4rl_cql.py similarity index 63% rename from examples/offline/offline_cql.py rename to examples/offline/d4rl_cql.py index f494200f2..2b7f5ffde 100644 --- a/examples/offline/offline_cql.py +++ b/examples/offline/d4rl_cql.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 + import argparse import datetime import os @@ -10,32 +11,35 @@ import torch from torch.utils.tensorboard import SummaryWriter -from tianshou.data import Batch, Collector, ReplayBuffer, VectorReplayBuffer +from tianshou.data import Batch, Collector, ReplayBuffer from tianshou.env import SubprocVectorEnv from tianshou.policy import CQLPolicy from tianshou.trainer import offline_trainer -from tianshou.utils import BasicLogger +from tianshou.utils import TensorboardLogger, WandbLogger from tianshou.utils.net.common import Net from tianshou.utils.net.continuous import ActorProb, Critic def get_args(): parser = argparse.ArgumentParser() - parser.add_argument('--task', type=str, default='halfcheetah-medium-v1') - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--buffer-size', type=int, default=1000000) - parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[256, 256]) - parser.add_argument('--actor-lr', type=float, default=1e-4) - parser.add_argument('--critic-lr', type=float, default=3e-4) - parser.add_argument('--alpha', type=float, default=0.2) - parser.add_argument('--auto-alpha', default=True, action='store_true') - parser.add_argument('--alpha-lr', type=float, default=1e-4) - parser.add_argument('--cql-alpha-lr', type=float, default=3e-4) + parser.add_argument("--task", type=str, default="HalfCheetah-v2") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--expert-data-task", type=str, default="halfcheetah-expert-v2" + ) + parser.add_argument("--buffer-size", type=int, default=1000000) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[256, 256]) + parser.add_argument("--actor-lr", type=float, default=1e-4) + parser.add_argument("--critic-lr", type=float, default=3e-4) + parser.add_argument("--alpha", type=float, default=0.2) + parser.add_argument("--auto-alpha", default=True, action="store_true") + parser.add_argument("--alpha-lr", type=float, default=1e-4) + parser.add_argument("--cql-alpha-lr", type=float, default=3e-4) parser.add_argument("--start-timesteps", type=int, default=10000) - parser.add_argument('--epoch', type=int, default=200) - parser.add_argument('--step-per-epoch', type=int, default=5000) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--batch-size', type=int, default=256) + parser.add_argument("--epoch", type=int, default=200) + parser.add_argument("--step-per-epoch", type=int, default=5000) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--batch-size", type=int, default=256) parser.add_argument("--tau", type=float, default=0.005) parser.add_argument("--temperature", type=float, default=1.0) @@ -45,19 +49,26 @@ def get_args(): parser.add_argument("--gamma", type=float, default=0.99) parser.add_argument("--eval-freq", type=int, default=1) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=10) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=1 / 35) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=1 / 35) + parser.add_argument( + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" + ) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], ) - parser.add_argument('--resume-path', type=str, default=None) + parser.add_argument("--wandb-project", type=str, default="offline_d4rl.benchmark") parser.add_argument( - '--watch', + "--watch", default=False, - action='store_true', - help='watch the play of pre-trained policy only', + action="store_true", + help="watch the play of pre-trained policy only", ) return parser.parse_args() @@ -77,10 +88,6 @@ def test_cql(): args.action_dim = args.action_shape[0] print("Max_action", args.max_action) - # train_envs = gym.make(args.task) - train_envs = SubprocVectorEnv( - [lambda: gym.make(args.task) for _ in range(args.training_num)] - ) # test_envs = gym.make(args.task) test_envs = SubprocVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] @@ -88,7 +95,6 @@ def test_cql(): # seed np.random.seed(args.seed) torch.manual_seed(args.seed) - train_envs.seed(args.seed) test_envs.seed(args.seed) # model @@ -161,38 +167,47 @@ def test_cql(): print("Loaded agent from: ", args.resume_path) # collector - if args.training_num > 1: - buffer = VectorReplayBuffer(args.buffer_size, len(train_envs)) - else: - buffer = ReplayBuffer(args.buffer_size) - train_collector = Collector(policy, train_envs, buffer, exploration_noise=True) test_collector = Collector(policy, test_envs) - train_collector.collect(n_step=args.start_timesteps, random=True) + # log - t0 = datetime.datetime.now().strftime("%m%d_%H%M%S") - log_file = f'seed_{args.seed}_{t0}-{args.task.replace("-", "_")}_cql' - log_path = os.path.join(args.logdir, args.task, 'cql', log_file) + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "cql" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = BasicLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def watch(): if args.resume_path is None: - args.resume_path = os.path.join(log_path, 'policy.pth') + args.resume_path = os.path.join(log_path, "policy.pth") policy.load_state_dict( - torch.load(args.resume_path, map_location=torch.device('cpu')) + torch.load(args.resume_path, map_location=torch.device("cpu")) ) policy.eval() collector = Collector(policy, env) collector.collect(n_episode=1, render=1 / 35) if not args.watch: - dataset = d4rl.qlearning_dataset(env) - dataset_size = dataset['rewards'].size + dataset = d4rl.qlearning_dataset(gym.make(args.expert_data_task)) + dataset_size = dataset["rewards"].size print("dataset_size", dataset_size) replay_buffer = ReplayBuffer(dataset_size) @@ -200,11 +215,11 @@ def watch(): for i in range(dataset_size): replay_buffer.add( Batch( - obs=dataset['observations'][i], - act=dataset['actions'][i], - rew=dataset['rewards'][i], - done=dataset['terminals'][i], - obs_next=dataset['next_observations'][i], + obs=dataset["observations"][i], + act=dataset["actions"][i], + rew=dataset["rewards"][i], + done=dataset["terminals"][i], + obs_next=dataset["next_observations"][i], ) ) print("dataset loaded") @@ -217,7 +232,7 @@ def watch(): args.step_per_epoch, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) pprint.pprint(result) @@ -229,8 +244,8 @@ def watch(): test_envs.seed(args.seed) test_collector.reset() result = test_collector.collect(n_episode=args.test_num, render=args.render) - print(f'Final reward: {result["rews"].mean()}, length: {result["lens"].mean()}') + print(f"Final reward: {result['rews'].mean()}, length: {result['lens'].mean()}") -if __name__ == '__main__': +if __name__ == "__main__": test_cql() diff --git a/examples/offline/d4rl_il.py b/examples/offline/d4rl_il.py new file mode 100644 index 000000000..710441a48 --- /dev/null +++ b/examples/offline/d4rl_il.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 + +import argparse +import datetime +import os +import pprint + +import d4rl +import gym +import numpy as np +import torch +from torch.utils.tensorboard import SummaryWriter + +from tianshou.data import Batch, Collector, ReplayBuffer +from tianshou.env import SubprocVectorEnv +from tianshou.policy import ImitationPolicy +from tianshou.trainer import offline_trainer +from tianshou.utils import TensorboardLogger, WandbLogger +from tianshou.utils.net.common import Net +from tianshou.utils.net.continuous import Actor + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--task", type=str, default="HalfCheetah-v2") + parser.add_argument("--seed", type=int, default=0) + parser.add_argument( + "--expert-data-task", type=str, default="halfcheetah-expert-v2" + ) + parser.add_argument("--hidden-sizes", type=int, nargs="*", default=[256, 256]) + parser.add_argument("--lr", type=float, default=1e-4) + parser.add_argument("--epoch", type=int, default=200) + parser.add_argument("--step-per-epoch", type=int, default=5000) + parser.add_argument("--batch-size", type=int, default=256) + parser.add_argument("--test-num", type=int, default=10) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=1 / 35) + parser.add_argument("--gamma", default=0.99) + parser.add_argument( + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" + ) + parser.add_argument("--resume-path", type=str, default=None) + parser.add_argument("--resume-id", type=str, default=None) + parser.add_argument( + "--logger", + type=str, + default="tensorboard", + choices=["tensorboard", "wandb"], + ) + parser.add_argument("--wandb-project", type=str, default="offline_d4rl.benchmark") + parser.add_argument( + "--watch", + default=False, + action="store_true", + help="watch the play of pre-trained policy only", + ) + return parser.parse_args() + + +def test_il(): + args = get_args() + env = gym.make(args.task) + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + args.max_action = env.action_space.high[0] # float + print("device:", args.device) + print("Observations shape:", args.state_shape) + print("Actions shape:", args.action_shape) + print("Action range:", np.min(env.action_space.low), np.max(env.action_space.high)) + + args.state_dim = args.state_shape[0] + args.action_dim = args.action_shape[0] + print("Max_action", args.max_action) + + test_envs = SubprocVectorEnv( + [lambda: gym.make(args.task) for _ in range(args.test_num)] + ) + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + test_envs.seed(args.seed) + + # model + net = Net( + args.state_shape, + args.action_shape, + hidden_sizes=args.hidden_sizes, + device=args.device, + ) + actor = Actor( + net, + action_shape=args.action_shape, + max_action=args.max_action, + device=args.device + ).to(args.device) + optim = torch.optim.Adam(actor.parameters(), lr=args.lr) + + policy = ImitationPolicy( + actor, + optim, + action_space=env.action_space, + action_scaling=True, + action_bound_method="clip" + ) + + # load a previous policy + if args.resume_path: + policy.load_state_dict(torch.load(args.resume_path, map_location=args.device)) + print("Loaded agent from: ", args.resume_path) + + # collector + test_collector = Collector(policy, test_envs) + + # log + now = datetime.datetime.now().strftime("%y%m%d-%H%M%S") + args.algo_name = "cql" + log_name = os.path.join(args.task, args.algo_name, str(args.seed), now) + log_path = os.path.join(args.logdir, log_name) + + # logger + if args.logger == "wandb": + logger = WandbLogger( + save_interval=1, + name=log_name.replace(os.path.sep, "__"), + run_id=args.resume_id, + config=args, + project=args.wandb_project, + ) + writer = SummaryWriter(log_path) + writer.add_text("args", str(args)) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: # wandb + logger.load(writer) + + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) + + def watch(): + if args.resume_path is None: + args.resume_path = os.path.join(log_path, "policy.pth") + + policy.load_state_dict( + torch.load(args.resume_path, map_location=torch.device("cpu")) + ) + policy.eval() + collector = Collector(policy, env) + collector.collect(n_episode=1, render=1 / 35) + + if not args.watch: + dataset = d4rl.qlearning_dataset(gym.make(args.expert_data_task)) + dataset_size = dataset["rewards"].size + + print("dataset_size", dataset_size) + replay_buffer = ReplayBuffer(dataset_size) + + for i in range(dataset_size): + replay_buffer.add( + Batch( + obs=dataset["observations"][i], + act=dataset["actions"][i], + rew=dataset["rewards"][i], + done=dataset["terminals"][i], + obs_next=dataset["next_observations"][i], + ) + ) + print("dataset loaded") + # trainer + result = offline_trainer( + policy, + replay_buffer, + test_collector, + args.epoch, + args.step_per_epoch, + args.test_num, + args.batch_size, + save_best_fn=save_best_fn, + logger=logger, + ) + pprint.pprint(result) + else: + watch() + + # Let's watch its performance! + policy.eval() + test_envs.seed(args.seed) + test_collector.reset() + result = test_collector.collect(n_episode=args.test_num, render=args.render) + print(f"Final reward: {result['rews'].mean()}, length: {result['lens'].mean()}") + + +if __name__ == "__main__": + test_il() diff --git a/examples/offline/results/bcq/halfcheetah-expert-v1_reward.png b/examples/offline/results/bcq/halfcheetah-expert-v1_reward.png deleted file mode 100644 index 5afa6a3adc97e5b3db6c1b5253b7d4c0d25178e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56131 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 N-I2MSC9M7U{{!(S@jn0n diff --git a/examples/offline/results/bcq/halfcheetah-expert-v1_reward.svg b/examples/offline/results/bcq/halfcheetah-expert-v1_reward.svg deleted file mode 100644 index 87ede75ed..000000000 --- a/examples/offline/results/bcq/halfcheetah-expert-v1_reward.svg +++ /dev/null @@ -1 +0,0 @@ -1e+32e+33e+34e+35e+36e+37e+38e+39e+31e+40100k200k300k400k500k600k700k800k900k1M1.1M \ No newline at end of file diff --git a/examples/vizdoom/vizdoom_c51.py b/examples/vizdoom/vizdoom_c51.py index 53eafae20..9f5aab835 100644 --- a/examples/vizdoom/vizdoom_c51.py +++ b/examples/vizdoom/vizdoom_c51.py @@ -125,7 +125,7 @@ def test_c51(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -200,7 +200,7 @@ def watch(): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False diff --git a/examples/vizdoom/vizdoom_ppo.py b/examples/vizdoom/vizdoom_ppo.py index ec88cb914..9a219a3ee 100644 --- a/examples/vizdoom/vizdoom_ppo.py +++ b/examples/vizdoom/vizdoom_ppo.py @@ -202,7 +202,7 @@ def dist(p): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -261,7 +261,7 @@ def watch(): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, test_in_train=False ) diff --git a/setup.py b/setup.py index f462f5572..83ac36580 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ def get_extras_require() -> str: "dev": [ "sphinx<4", "sphinx_rtd_theme", + "jinja2<3.1", # temporary fix "sphinxcontrib-bibtex", "flake8", "flake8-bugbear", @@ -45,7 +46,7 @@ def get_extras_require() -> str: "doc8", "scipy", "pillow", - "pettingzoo>=1.12", + "pettingzoo>=1.17", "pygame>=2.1.0", # pettingzoo test cases pistonball "pymunk>=6.2.1", # pettingzoo test cases pistonball "nni>=2.3", diff --git a/test/base/test_env.py b/test/base/test_env.py index 348dd84c3..7e507c4ed 100644 --- a/test/base/test_env.py +++ b/test/base/test_env.py @@ -78,7 +78,8 @@ def test_async_env(size=10000, num=8, sleep=0.1): Batch.cat(o) v.close() # assure 1/7 improvement - if sys.platform == "linux": # macOS/Windows cannot pass this check + if sys.platform == "linux" and cls != RayVectorEnv: + # macOS/Windows cannot pass this check assert spent_time < 6.0 * sleep * num / (num + 1) diff --git a/test/base/test_utils.py b/test/base/test_utils.py index 38bf5d40e..b99b0742b 100644 --- a/test/base/test_utils.py +++ b/test/base/test_utils.py @@ -2,7 +2,7 @@ import torch from tianshou.exploration import GaussianNoise, OUNoise -from tianshou.utils import MovAvg, RunningMeanStd +from tianshou.utils import MovAvg, MultipleLRSchedulers, RunningMeanStd from tianshou.utils.net.common import MLP, Net from tianshou.utils.net.continuous import RecurrentActorProb, RecurrentCritic @@ -99,8 +99,48 @@ def test_net(): assert list(net(data, act).shape) == [bsz, 1] +def test_lr_schedulers(): + initial_lr_1 = 10.0 + step_size_1 = 1 + gamma_1 = 0.5 + net_1 = torch.nn.Linear(2, 3) + optim_1 = torch.optim.Adam(net_1.parameters(), lr=initial_lr_1) + sched_1 = torch.optim.lr_scheduler.StepLR( + optim_1, step_size=step_size_1, gamma=gamma_1 + ) + + initial_lr_2 = 5.0 + step_size_2 = 2 + gamma_2 = 0.3 + net_2 = torch.nn.Linear(3, 2) + optim_2 = torch.optim.Adam(net_2.parameters(), lr=initial_lr_2) + sched_2 = torch.optim.lr_scheduler.StepLR( + optim_2, step_size=step_size_2, gamma=gamma_2 + ) + schedulers = MultipleLRSchedulers(sched_1, sched_2) + for _ in range(10): + loss_1 = (torch.ones((1, 3)) - net_1(torch.ones((1, 2)))).sum() + optim_1.zero_grad() + loss_1.backward() + optim_1.step() + loss_2 = (torch.ones((1, 2)) - net_2(torch.ones((1, 3)))).sum() + optim_2.zero_grad() + loss_2.backward() + optim_2.step() + schedulers.step() + assert ( + optim_1.state_dict()["param_groups"][0]["lr"] == + (initial_lr_1 * gamma_1**(10 // step_size_1)) + ) + assert ( + optim_2.state_dict()["param_groups"][0]["lr"] == + (initial_lr_2 * gamma_2**(10 // step_size_2)) + ) + + if __name__ == '__main__': test_noise() test_moving_average() test_rms() test_net() + test_lr_schedulers() diff --git a/test/continuous/test_npg.py b/test/continuous/test_npg.py index b3f7add05..66be7cee7 100644 --- a/test/continuous/test_npg.py +++ b/test/continuous/test_npg.py @@ -136,7 +136,7 @@ def dist(*logits): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -154,7 +154,7 @@ def stop_fn(mean_rewards): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index e8885e9c6..310c16d62 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -23,8 +23,13 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v0') +<<<<<<< HEAD parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) +======= + parser.add_argument('--reward-threshold', type=float, default=None) + parser.add_argument('--seed', type=int, default=1) +>>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-3) parser.add_argument('--critic-lr', type=float, default=1e-3) @@ -67,12 +72,19 @@ def test_sac_with_il(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: +<<<<<<< HEAD default_reward_threshold = { "Pendulum-v1": -250, "CartPole-v0": 195, "NChain-v0": 3400 } args.reward_threshold = default_reward_threshold.get(args.task) +======= + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) +>>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d # you can also use tianshou.env.SubprocVectorEnv # seed np.random.seed(args.seed) @@ -140,7 +152,7 @@ def test_sac_with_il(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -158,14 +170,19 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) # here we define an imitation collector with a trivial policy policy.eval() +<<<<<<< HEAD args.reward_threshold = -300 # lower the goal +======= + if args.task.startswith("Pendulum"): + args.reward_threshold -= 50 # lower the goal +>>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d net = Actor( Net( args.state_shape, @@ -199,7 +216,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/continuous/test_td3.py b/test/continuous/test_td3.py index dc3e47e18..5f078e6a9 100644 --- a/test/continuous/test_td3.py +++ b/test/continuous/test_td3.py @@ -11,7 +11,7 @@ from tianshou.env import DummyVectorEnv from tianshou.exploration import GaussianNoise from tianshou.policy import TD3Policy -from tianshou.trainer import offpolicy_trainer +from tianshou.trainer import OffpolicyTrainer from tianshou.utils import TensorboardLogger from tianshou.utils.net.common import Net from tianshou.utils.net.continuous import Actor, Critic @@ -51,7 +51,6 @@ def get_args(): def test_td3(args=get_args()): - torch.set_num_threads(1) # we just need only one thread for NN env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n @@ -132,14 +131,14 @@ def test_td3(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): return mean_rewards >= args.reward_threshold - # trainer - result = offpolicy_trainer( + # Iterator trainer + trainer = OffpolicyTrainer( policy, train_collector, test_collector, @@ -150,13 +149,18 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_fn=save_fn, - logger=logger + save_best_fn=save_best_fn, + logger=logger, ) - assert stop_fn(result['best_reward']) + for epoch, epoch_stat, info in trainer: + print(f"Epoch: {epoch}") + print(epoch_stat) + print(info) - if __name__ == '__main__': - pprint.pprint(result) + assert stop_fn(info["best_reward"]) + + if __name__ == "__main__": + pprint.pprint(info) # Let's watch its performance! env = gym.make(args.task) policy.eval() diff --git a/test/continuous/test_trpo.py b/test/continuous/test_trpo.py index 89fc042c6..3511ca0a7 100644 --- a/test/continuous/test_trpo.py +++ b/test/continuous/test_trpo.py @@ -140,7 +140,7 @@ def dist(*logits): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -158,7 +158,7 @@ def stop_fn(mean_rewards): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_a2c_with_il.py b/test/discrete/test_a2c_with_il.py index ec7448413..b777e2e03 100644 --- a/test/discrete/test_a2c_with_il.py +++ b/test/discrete/test_a2c_with_il.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=1e-3) @@ -58,6 +59,11 @@ def test_a2c_with_il(args=get_args()): test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) @@ -90,11 +96,11 @@ def test_a2c_with_il(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( @@ -108,7 +114,7 @@ def stop_fn(mean_rewards): args.batch_size, episode_per_collect=args.episode_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) @@ -146,7 +152,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_c51.py b/test/discrete/test_c51.py index 3c74723eb..993c4a80e 100644 --- a/test/discrete/test_c51.py +++ b/test/discrete/test_c51.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -58,6 +59,11 @@ def test_c51(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -112,11 +118,11 @@ def test_c51(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer, save_interval=args.save_interval) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -177,7 +183,7 @@ def save_checkpoint_fn(epoch, env_step, gradient_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, resume_from_log=args.resume, save_checkpoint_fn=save_checkpoint_fn diff --git a/test/discrete/test_dqn.py b/test/discrete/test_dqn.py index c02866493..2644dc998 100644 --- a/test/discrete/test_dqn.py +++ b/test/discrete/test_dqn.py @@ -18,6 +18,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -52,6 +53,11 @@ def test_dqn(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -103,11 +109,11 @@ def test_dqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -137,7 +143,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_drqn.py b/test/discrete/test_drqn.py index 064dbba24..36ff5fa76 100644 --- a/test/discrete/test_drqn.py +++ b/test/discrete/test_drqn.py @@ -18,6 +18,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -48,6 +49,11 @@ def test_drqn(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -90,11 +96,11 @@ def test_drqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): policy.set_eps(args.eps_train) @@ -116,7 +122,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_fqf.py b/test/discrete/test_fqf.py index e952294f5..e25c42997 100644 --- a/test/discrete/test_fqf.py +++ b/test/discrete/test_fqf.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -55,6 +56,11 @@ def test_fqf(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -120,11 +126,11 @@ def test_fqf(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -153,7 +159,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step ) diff --git a/test/discrete/test_iqn.py b/test/discrete/test_iqn.py index c93ddfc0d..725c9a9d5 100644 --- a/test/discrete/test_iqn.py +++ b/test/discrete/test_iqn.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -55,6 +56,11 @@ def test_iqn(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -114,11 +120,11 @@ def test_iqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -147,7 +153,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step ) diff --git a/test/discrete/test_pg.py b/test/discrete/test_pg.py index fafd7cc49..1f5007f7a 100644 --- a/test/discrete/test_pg.py +++ b/test/discrete/test_pg.py @@ -18,6 +18,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=1e-3) @@ -44,6 +45,11 @@ def test_pg(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -91,11 +97,11 @@ def test_pg(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( @@ -109,7 +115,7 @@ def stop_fn(mean_rewards): args.batch_size, episode_per_collect=args.episode_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_ppo.py b/test/discrete/test_ppo.py index da74b7a86..b7dba97c9 100644 --- a/test/discrete/test_ppo.py +++ b/test/discrete/test_ppo.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=3e-4) @@ -55,6 +56,11 @@ def test_ppo(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -116,11 +122,11 @@ def test_ppo(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( @@ -134,7 +140,7 @@ def stop_fn(mean_rewards): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/discrete/test_qrdqn.py b/test/discrete/test_qrdqn.py index 956cb03fd..9c699b4e3 100644 --- a/test/discrete/test_qrdqn.py +++ b/test/discrete/test_qrdqn.py @@ -18,6 +18,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -55,6 +56,11 @@ def test_qrdqn(args=get_args()): env.spec.reward_threshold = 190 # lower the goal args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -107,11 +113,11 @@ def test_qrdqn(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -140,7 +146,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, ) diff --git a/test/discrete/test_rainbow.py b/test/discrete/test_rainbow.py index b226a025c..5e2345300 100644 --- a/test/discrete/test_rainbow.py +++ b/test/discrete/test_rainbow.py @@ -20,6 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -61,6 +62,11 @@ def test_rainbow(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -126,11 +132,11 @@ def noisy_linear(x, y): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer, save_interval=args.save_interval) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annealing, just a demo @@ -201,7 +207,7 @@ def save_checkpoint_fn(epoch, env_step, gradient_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, resume_from_log=args.resume, save_checkpoint_fn=save_checkpoint_fn diff --git a/test/discrete/test_sac.py b/test/discrete/test_sac.py index 118a2962a..6593c9864 100644 --- a/test/discrete/test_sac.py +++ b/test/discrete/test_sac.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -49,11 +50,13 @@ def get_args(): def test_discrete_sac(args=get_args()): env = gym.make(args.task) - if args.task == 'CartPole-v0': - env.spec.reward_threshold = 180 # lower the goal - args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 180} # lower the goal + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) train_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.training_num)] @@ -111,11 +114,11 @@ def test_discrete_sac(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = offpolicy_trainer( @@ -128,7 +131,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, test_in_train=False diff --git a/test/modelbased/test_dqn_icm.py b/test/modelbased/test_dqn_icm.py index 64bcda647..fba0b5523 100644 --- a/test/modelbased/test_dqn_icm.py +++ b/test/modelbased/test_dqn_icm.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -71,6 +72,11 @@ def test_dqn_icm(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -142,11 +148,11 @@ def test_dqn_icm(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def train_fn(epoch, env_step): # eps annnealing, just a demo @@ -176,7 +182,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, ) assert stop_fn(result['best_reward']) diff --git a/test/modelbased/test_ppo_icm.py b/test/modelbased/test_ppo_icm.py index f54819758..6efd96277 100644 --- a/test/modelbased/test_ppo_icm.py +++ b/test/modelbased/test_ppo_icm.py @@ -19,6 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1626) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=3e-4) @@ -73,6 +74,11 @@ def test_ppo(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 195} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( @@ -148,11 +154,11 @@ def test_ppo(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold # trainer result = onpolicy_trainer( @@ -166,7 +172,7 @@ def stop_fn(mean_rewards): args.batch_size, step_per_collect=args.step_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/modelbased/test_psrl.py b/test/modelbased/test_psrl.py index ca80ee780..7405ad5c3 100644 --- a/test/modelbased/test_psrl.py +++ b/test/modelbased/test_psrl.py @@ -81,19 +81,19 @@ def test_psrl(args=get_args()): logger = WandbLogger( save_interval=1, project='psrl', name='wandb_test', config=args ) - elif args.logger == "tensorboard": + if args.logger != "none": log_path = os.path.join(args.logdir, args.task, 'psrl') writer = SummaryWriter(log_path) writer.add_text("args", str(args)) - logger = TensorboardLogger(writer) + if args.logger == "tensorboard": + logger = TensorboardLogger(writer) + else: + logger.load(writer) else: logger = LazyLogger() def stop_fn(mean_rewards): - if reward_threshold: - return mean_rewards >= reward_threshold - else: - return False + return mean_rewards >= args.reward_threshold train_collector.collect(n_step=args.buffer_size, random=True) # trainer, test it without logger diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index e34fb31fd..e56795bd9 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -121,7 +121,7 @@ def gather_data(): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -154,7 +154,7 @@ def test_fn(epoch, env_step): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, update_per_step=args.update_per_step, ) diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index cd7b943ba..1f0a14518 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -149,7 +149,7 @@ def gather_data(): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -166,7 +166,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, update_per_step=args.update_per_step, - save_fn=save_fn, + save_best_fn=save_best_fn, stop_fn=stop_fn, logger=logger, ) diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 5bec8fc4d..4210726f5 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -182,11 +182,11 @@ def test_bcq(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): - return mean_rewards >= env.spec.reward_threshold + return mean_rewards >= args.reward_threshold def watch(): policy.load_state_dict( @@ -207,7 +207,7 @@ def watch(): args.step_per_epoch, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, stop_fn=stop_fn, logger=logger, ) diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index 0c9f63af1..59cfe1b1f 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -12,7 +12,7 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.env import DummyVectorEnv from tianshou.policy import CQLPolicy -from tianshou.trainer import offline_trainer +from tianshou.trainer import OfflineTrainer from tianshou.utils import TensorboardLogger from tianshou.utils.net.common import Net from tianshou.utils.net.continuous import ActorProb, Critic @@ -179,7 +179,7 @@ def test_cql(args=get_args()): writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -196,7 +196,7 @@ def watch(): collector.collect(n_episode=1, render=1 / 35) # trainer - result = offline_trainer( + trainer = OfflineTrainer( policy, buffer, test_collector, @@ -204,15 +204,21 @@ def watch(): args.step_per_epoch, args.test_num, args.batch_size, - save_fn=save_fn, + save_best_fn=save_best_fn, stop_fn=stop_fn, logger=logger, ) - assert stop_fn(result['best_reward']) + + for epoch, epoch_stat, info in trainer: + print(f"Epoch: {epoch}") + print(epoch_stat) + print(info) + + assert stop_fn(info["best_reward"]) # Let's watch its performance! - if __name__ == '__main__': - pprint.pprint(result) + if __name__ == "__main__": + pprint.pprint(info) env = gym.make(args.task) policy.eval() collector = Collector(policy, env) diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index 138d2d99c..a2e11f741 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -58,6 +58,11 @@ def test_discrete_bcq(args=get_args()): env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"CartPole-v0": 190} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) @@ -110,7 +115,7 @@ def test_discrete_bcq(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer, save_interval=args.save_interval) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -146,7 +151,7 @@ def save_checkpoint_fn(epoch, env_step, gradient_step): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, resume_from_log=args.resume, save_checkpoint_fn=save_checkpoint_fn diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index cbbc8225d..fae843375 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -107,7 +107,7 @@ def test_discrete_cql(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -122,7 +122,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index c62d5a8df..4f0aedead 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -108,7 +108,7 @@ def test_discrete_crr(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -123,7 +123,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) diff --git a/test/offline/test_gail.py b/test/offline/test_gail.py new file mode 100644 index 000000000..3ccaeaca7 --- /dev/null +++ b/test/offline/test_gail.py @@ -0,0 +1,228 @@ +import argparse +import os +import pickle +import pprint + +import gym +import numpy as np +import torch +from torch.distributions import Independent, Normal +from torch.utils.tensorboard import SummaryWriter + +from tianshou.data import Collector, VectorReplayBuffer +from tianshou.env import DummyVectorEnv +from tianshou.policy import GAILPolicy +from tianshou.trainer import onpolicy_trainer +from tianshou.utils import TensorboardLogger +from tianshou.utils.net.common import ActorCritic, Net +from tianshou.utils.net.continuous import ActorProb, Critic + +if __name__ == "__main__": + from gather_pendulum_data import expert_file_name, gather_data +else: # pytest + from test.offline.gather_pendulum_data import expert_file_name, gather_data + + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--task', type=str, default='Pendulum-v1') + parser.add_argument("--reward-threshold", type=float, default=None) + parser.add_argument('--seed', type=int, default=1) + parser.add_argument('--buffer-size', type=int, default=20000) + parser.add_argument('--lr', type=float, default=1e-3) + parser.add_argument('--disc-lr', type=float, default=5e-4) + parser.add_argument('--gamma', type=float, default=0.95) + parser.add_argument('--epoch', type=int, default=5) + parser.add_argument('--step-per-epoch', type=int, default=150000) + parser.add_argument('--episode-per-collect', type=int, default=16) + parser.add_argument('--repeat-per-collect', type=int, default=2) + parser.add_argument('--disc-update-num', type=int, default=2) + parser.add_argument('--batch-size', type=int, default=128) + parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64, 64]) + parser.add_argument('--training-num', type=int, default=16) + parser.add_argument('--test-num', type=int, default=100) + parser.add_argument('--logdir', type=str, default='log') + parser.add_argument('--render', type=float, default=0.) + parser.add_argument( + '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + ) + # ppo special + parser.add_argument('--vf-coef', type=float, default=0.25) + parser.add_argument('--ent-coef', type=float, default=0.0) + parser.add_argument('--eps-clip', type=float, default=0.2) + parser.add_argument('--max-grad-norm', type=float, default=0.5) + parser.add_argument('--gae-lambda', type=float, default=0.95) + parser.add_argument('--rew-norm', type=int, default=1) + parser.add_argument('--dual-clip', type=float, default=None) + parser.add_argument('--value-clip', type=int, default=1) + parser.add_argument('--norm-adv', type=int, default=1) + parser.add_argument('--recompute-adv', type=int, default=0) + parser.add_argument('--resume', action="store_true") + parser.add_argument("--save-interval", type=int, default=4) + parser.add_argument("--load-buffer-name", type=str, default=expert_file_name()) + args = parser.parse_known_args()[0] + return args + + +def test_gail(args=get_args()): + if os.path.exists(args.load_buffer_name) and os.path.isfile(args.load_buffer_name): + if args.load_buffer_name.endswith(".hdf5"): + buffer = VectorReplayBuffer.load_hdf5(args.load_buffer_name) + else: + buffer = pickle.load(open(args.load_buffer_name, "rb")) + else: + buffer = gather_data() + env = gym.make(args.task) + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v0": -1100, "Pendulum-v1": -1100} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) + args.state_shape = env.observation_space.shape or env.observation_space.n + args.action_shape = env.action_space.shape or env.action_space.n + args.max_action = env.action_space.high[0] + # you can also use tianshou.env.SubprocVectorEnv + # train_envs = gym.make(args.task) + train_envs = DummyVectorEnv( + [lambda: gym.make(args.task) for _ in range(args.training_num)] + ) + # test_envs = gym.make(args.task) + test_envs = DummyVectorEnv( + [lambda: gym.make(args.task) for _ in range(args.test_num)] + ) + # seed + np.random.seed(args.seed) + torch.manual_seed(args.seed) + train_envs.seed(args.seed) + test_envs.seed(args.seed) + # model + net = Net(args.state_shape, hidden_sizes=args.hidden_sizes, device=args.device) + actor = ActorProb( + net, args.action_shape, max_action=args.max_action, device=args.device + ).to(args.device) + critic = Critic( + Net(args.state_shape, hidden_sizes=args.hidden_sizes, device=args.device), + device=args.device + ).to(args.device) + actor_critic = ActorCritic(actor, critic) + # orthogonal initialization + for m in actor_critic.modules(): + if isinstance(m, torch.nn.Linear): + torch.nn.init.orthogonal_(m.weight) + torch.nn.init.zeros_(m.bias) + optim = torch.optim.Adam(actor_critic.parameters(), lr=args.lr) + # discriminator + disc_net = Critic( + Net( + args.state_shape, + action_shape=args.action_shape, + hidden_sizes=args.hidden_sizes, + activation=torch.nn.Tanh, + device=args.device, + concat=True, + ), + device=args.device + ).to(args.device) + for m in disc_net.modules(): + if isinstance(m, torch.nn.Linear): + # orthogonal initialization + torch.nn.init.orthogonal_(m.weight, gain=np.sqrt(2)) + torch.nn.init.zeros_(m.bias) + disc_optim = torch.optim.Adam(disc_net.parameters(), lr=args.disc_lr) + + # replace DiagGuassian with Independent(Normal) which is equivalent + # pass *logits to be consistent with policy.forward + def dist(*logits): + return Independent(Normal(*logits), 1) + + policy = GAILPolicy( + actor, + critic, + optim, + dist, + buffer, + disc_net, + disc_optim, + disc_update_num=args.disc_update_num, + discount_factor=args.gamma, + max_grad_norm=args.max_grad_norm, + eps_clip=args.eps_clip, + vf_coef=args.vf_coef, + ent_coef=args.ent_coef, + reward_normalization=args.rew_norm, + advantage_normalization=args.norm_adv, + recompute_advantage=args.recompute_adv, + dual_clip=args.dual_clip, + value_clip=args.value_clip, + gae_lambda=args.gae_lambda, + action_space=env.action_space, + ) + # collector + train_collector = Collector( + policy, train_envs, VectorReplayBuffer(args.buffer_size, len(train_envs)) + ) + test_collector = Collector(policy, test_envs) + # log + log_path = os.path.join(args.logdir, args.task, 'gail') + writer = SummaryWriter(log_path) + logger = TensorboardLogger(writer, save_interval=args.save_interval) + + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + + def stop_fn(mean_rewards): + return mean_rewards >= args.reward_threshold + + def save_checkpoint_fn(epoch, env_step, gradient_step): + # see also: https://pytorch.org/tutorials/beginner/saving_loading_models.html + torch.save( + { + 'model': policy.state_dict(), + 'optim': optim.state_dict(), + }, os.path.join(log_path, 'checkpoint.pth') + ) + + if args.resume: + # load from existing checkpoint + print(f"Loading agent under {log_path}") + ckpt_path = os.path.join(log_path, 'checkpoint.pth') + if os.path.exists(ckpt_path): + checkpoint = torch.load(ckpt_path, map_location=args.device) + policy.load_state_dict(checkpoint['model']) + optim.load_state_dict(checkpoint['optim']) + print("Successfully restore policy and optim.") + else: + print("Fail to restore policy and optim.") + + # trainer + result = onpolicy_trainer( + policy, + train_collector, + test_collector, + args.epoch, + args.step_per_epoch, + args.repeat_per_collect, + args.test_num, + args.batch_size, + episode_per_collect=args.episode_per_collect, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + logger=logger, + resume_from_log=args.resume, + save_checkpoint_fn=save_checkpoint_fn, + ) + assert stop_fn(result['best_reward']) + + if __name__ == '__main__': + pprint.pprint(result) + # Let's watch its performance! + env = gym.make(args.task) + policy.eval() + collector = Collector(policy, env) + result = collector.collect(n_episode=1, render=args.render) + rews, lens = result["rews"], result["lens"] + print(f"Final reward: {rews.mean()}, length: {lens.mean()}") + + +if __name__ == '__main__': + test_gail() diff --git a/test/pettingzoo/pistonball.py b/test/pettingzoo/pistonball.py index 8ce458788..4f739f047 100644 --- a/test/pettingzoo/pistonball.py +++ b/test/pettingzoo/pistonball.py @@ -135,7 +135,7 @@ def train_agent( writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): pass def stop_fn(mean_rewards): @@ -163,7 +163,7 @@ def reward_metric(rews): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, update_per_step=args.update_per_step, logger=logger, test_in_train=False, @@ -176,7 +176,7 @@ def reward_metric(rews): def watch( args: argparse.Namespace = get_args(), policy: Optional[BasePolicy] = None ) -> None: - env = get_env() + env = DummyVectorEnv([get_env]) policy.eval() [agent.set_eps(args.eps_test) for agent in policy.policies.values()] collector = Collector(policy, env, exploration_noise=True) diff --git a/test/pettingzoo/pistonball_continuous.py b/test/pettingzoo/pistonball_continuous.py index 7a7ffe341..da1285a40 100644 --- a/test/pettingzoo/pistonball_continuous.py +++ b/test/pettingzoo/pistonball_continuous.py @@ -230,7 +230,7 @@ def train_agent( writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): pass def stop_fn(mean_rewards): @@ -257,7 +257,7 @@ def reward_metric(rews): args.batch_size, episode_per_collect=args.episode_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, resume_from_log=args.resume ) @@ -268,7 +268,7 @@ def reward_metric(rews): def watch( args: argparse.Namespace = get_args(), policy: Optional[BasePolicy] = None ) -> None: - env = get_env() + env = DummyVectorEnv([get_env]) policy.eval() collector = Collector(policy, env) result = collector.collect(n_episode=1, render=args.render) diff --git a/test/pettingzoo/tic_tac_toe.py b/test/pettingzoo/tic_tac_toe.py index 2bc6a72f1..21d44ffa2 100644 --- a/test/pettingzoo/tic_tac_toe.py +++ b/test/pettingzoo/tic_tac_toe.py @@ -178,7 +178,7 @@ def train_agent( writer.add_text("args", str(args)) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): if hasattr(args, 'model_save_path'): model_save_path = args.model_save_path else: @@ -214,7 +214,7 @@ def reward_metric(rews): train_fn=train_fn, test_fn=test_fn, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, update_per_step=args.update_per_step, logger=logger, test_in_train=False, @@ -229,7 +229,7 @@ def watch( agent_learn: Optional[BasePolicy] = None, agent_opponent: Optional[BasePolicy] = None, ) -> None: - env = get_env() + env = DummyVectorEnv([get_env]) policy, optim, agents = get_agents( args, agent_learn=agent_learn, agent_opponent=agent_opponent ) diff --git a/tianshou/__init__.py b/tianshou/__init__.py index cd337d188..5a9abbf1b 100644 --- a/tianshou/__init__.py +++ b/tianshou/__init__.py @@ -1,6 +1,6 @@ from tianshou import data, env, exploration, policy, trainer, utils -__version__ = "0.4.6.post1" +__version__ = "0.4.7" __all__ = [ "env", diff --git a/tianshou/data/collector.py b/tianshou/data/collector.py index 00668251c..537986cf6 100644 --- a/tianshou/data/collector.py +++ b/tianshou/data/collector.py @@ -64,14 +64,15 @@ def __init__( super().__init__() if isinstance(env, gym.Env) and not hasattr(env, "__len__"): warnings.warn("Single environment detected, wrap to DummyVectorEnv.") - env = DummyVectorEnv([lambda: env]) - self.env = env - self.env_num = len(env) + self.env = DummyVectorEnv([lambda: env]) # type: ignore + else: + self.env = env # type: ignore + self.env_num = len(self.env) self.exploration_noise = exploration_noise self._assign_buffer(buffer) self.policy = policy self.preprocess_fn = preprocess_fn - self._action_space = env.action_space + self._action_space = self.env.action_space # avoid creating attribute outside __init__ self.reset(False) @@ -226,6 +227,7 @@ def collect( ] except TypeError: # envpool's action space is not for per-env act_sample = [self._action_space.sample() for _ in ready_env_ids] + act_sample = self.policy.map_action_inverse(act_sample) # type: ignore self.data.update(act=act_sample) else: if no_grad: @@ -364,6 +366,7 @@ def __init__( exploration_noise: bool = False, ) -> None: # assert env.is_async + warnings.warn("Using async setting may collect extra transitions into buffer.") super().__init__(policy, env, buffer, preprocess_fn, exploration_noise) def reset_env(self) -> None: @@ -424,7 +427,6 @@ def collect( "Please specify at least one (either n_step or n_episode) " "in AsyncCollector.collect()." ) - warnings.warn("Using async setting may collect extra transitions into buffer.") ready_env_ids = self._ready_env_ids @@ -451,6 +453,7 @@ def collect( ] except TypeError: # envpool's action space is not for per-env act_sample = [self._action_space.sample() for _ in ready_env_ids] + act_sample = self.policy.map_action_inverse(act_sample) # type: ignore self.data.update(act=act_sample) else: if no_grad: diff --git a/tianshou/env/pettingzoo_env.py b/tianshou/env/pettingzoo_env.py index de752516a..25c34f994 100644 --- a/tianshou/env/pettingzoo_env.py +++ b/tianshou/env/pettingzoo_env.py @@ -6,7 +6,7 @@ from pettingzoo.utils.wrappers import BaseWrapper -class PettingZooEnv(AECEnv, gym.Env, ABC): +class PettingZooEnv(AECEnv, ABC): """The interface for petting zoo environments. Multi-agent environments must be wrapped as @@ -32,17 +32,14 @@ def __init__(self, env: BaseWrapper): self.agent_idx = {} for i, agent_id in enumerate(self.agents): self.agent_idx[agent_id] = i - # Get dictionaries of obs_spaces and act_spaces - self.observation_spaces = self.env.observation_spaces - self.action_spaces = self.env.action_spaces self.rewards = [0] * len(self.agents) # Get first observation space, assuming all agents have equal space - self.observation_space: Any = self.observation_space(self.agents[0]) + self.observation_space: Any = self.env.observation_space(self.agents[0]) # Get first action space, assuming all agents have equal space - self.action_space: Any = self.action_space(self.agents[0]) + self.action_space: Any = self.env.action_space(self.agents[0]) assert all(self.env.observation_space(agent) == self.observation_space for agent in self.agents), \ diff --git a/tianshou/env/venvs.py b/tianshou/env/venvs.py index c668109b6..044ecaaa4 100644 --- a/tianshou/env/venvs.py +++ b/tianshou/env/venvs.py @@ -12,7 +12,7 @@ from tianshou.utils import RunningMeanStd -class BaseVectorEnv(gym.Env): +class BaseVectorEnv(object): """Base class for vectorized environments wrapper. Usage: @@ -196,6 +196,7 @@ def _assert_id(self, id: Union[List[int], np.ndarray]) -> None: assert i in self.ready_id, \ f"Can only interact with ready environments {self.ready_id}." + # TODO: compatible issue with reset -> (obs, info) def reset( self, id: Optional[Union[int, List[int], np.ndarray]] = None ) -> np.ndarray: diff --git a/tianshou/env/worker/base.py b/tianshou/env/worker/base.py index 3ae1b1618..b861a15d5 100644 --- a/tianshou/env/worker/base.py +++ b/tianshou/env/worker/base.py @@ -1,10 +1,11 @@ -import warnings from abc import ABC, abstractmethod from typing import Any, Callable, List, Optional, Tuple, Union import gym import numpy as np +from tianshou.utils import deprecation + class EnvWorker(ABC): """An abstract worker for an environment.""" @@ -33,7 +34,7 @@ def send(self, action: Optional[np.ndarray]) -> None: function is determined by such kind of different signal. """ if hasattr(self, "send_action"): - warnings.warn( + deprecation( "send_action will soon be deprecated. " "Please use send and recv for your own EnvWorker." ) @@ -54,7 +55,7 @@ def recv( info). """ if hasattr(self, "get_result"): - warnings.warn( + deprecation( "get_result will soon be deprecated. " "Please use send and recv for your own EnvWorker." ) diff --git a/tianshou/env/worker/dummy.py b/tianshou/env/worker/dummy.py index 958f6e907..be873861c 100644 --- a/tianshou/env/worker/dummy.py +++ b/tianshou/env/worker/dummy.py @@ -31,9 +31,9 @@ def wait( # type: ignore def send(self, action: Optional[np.ndarray]) -> None: if action is None: - self.result = self.env.reset() + self.result = self.env.reset() # type: ignore else: - self.result = self.env.step(action) + self.result = self.env.step(action) # type: ignore def seed(self, seed: Optional[int] = None) -> List[int]: super().seed(seed) diff --git a/tianshou/env/worker/ray.py b/tianshou/env/worker/ray.py index 1bc7991aa..e094692d6 100644 --- a/tianshou/env/worker/ray.py +++ b/tianshou/env/worker/ray.py @@ -24,7 +24,9 @@ class RayEnvWorker(EnvWorker): """Ray worker used in RayVectorEnv.""" def __init__(self, env_fn: Callable[[], gym.Env]) -> None: - self.env = ray.remote(_SetAttrWrapper).options(num_cpus=0).remote(env_fn()) + self.env = ray.remote(_SetAttrWrapper).options( # type: ignore + num_cpus=0 + ).remote(env_fn()) super().__init__(env_fn) def get_env_attr(self, key: str) -> Any: @@ -54,7 +56,7 @@ def send(self, action: Optional[np.ndarray]) -> None: def recv( self ) -> Union[Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray], np.ndarray]: - return ray.get(self.result) + return ray.get(self.result) # type: ignore def seed(self, seed: Optional[int] = None) -> List[int]: super().seed(seed) diff --git a/tianshou/env/worker/subproc.py b/tianshou/env/worker/subproc.py index 779b78e34..c2119ab50 100644 --- a/tianshou/env/worker/subproc.py +++ b/tianshou/env/worker/subproc.py @@ -53,7 +53,7 @@ def _setup_buf(space: gym.Space) -> Union[dict, tuple, ShArray]: assert isinstance(space.spaces, tuple) return tuple([_setup_buf(t) for t in space.spaces]) else: - return ShArray(space.dtype, space.shape) + return ShArray(space.dtype, space.shape) # type: ignore def _worker( diff --git a/tianshou/policy/__init__.py b/tianshou/policy/__init__.py index 7417f29b8..01d660c56 100644 --- a/tianshou/policy/__init__.py +++ b/tianshou/policy/__init__.py @@ -25,6 +25,7 @@ from tianshou.policy.imitation.discrete_bcq import DiscreteBCQPolicy from tianshou.policy.imitation.discrete_cql import DiscreteCQLPolicy from tianshou.policy.imitation.discrete_crr import DiscreteCRRPolicy +from tianshou.policy.imitation.gail import GAILPolicy from tianshou.policy.modelbased.psrl import PSRLPolicy from tianshou.policy.modelbased.icm import ICMPolicy from tianshou.policy.multiagent.mapolicy import MultiAgentPolicyManager @@ -54,6 +55,7 @@ "DiscreteBCQPolicy", "DiscreteCQLPolicy", "DiscreteCRRPolicy", + "GAILPolicy", "PSRLPolicy", "ICMPolicy", "MultiAgentPolicyManager", diff --git a/tianshou/policy/base.py b/tianshou/policy/base.py index 3572e83af..325a85b62 100644 --- a/tianshou/policy/base.py +++ b/tianshou/policy/base.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Any, Callable, Dict, Optional, Tuple, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, Union import gym import numpy as np @@ -9,6 +9,7 @@ from torch import nn from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch_as +from tianshou.utils import MultipleLRSchedulers class BasePolicy(ABC, nn.Module): @@ -64,6 +65,8 @@ def __init__( action_space: Optional[gym.Space] = None, action_scaling: bool = False, action_bound_method: str = "", + lr_scheduler: Optional[Union[torch.optim.lr_scheduler.LambdaLR, + MultipleLRSchedulers]] = None, ) -> None: super().__init__() self.observation_space = observation_space @@ -79,6 +82,7 @@ def __init__( # can be one of ("clip", "tanh", ""), empty string means no bounding assert action_bound_method in ("", "clip", "tanh") self.action_bound_method = action_bound_method + self.lr_scheduler = lr_scheduler self._compile() def set_agent_id(self, agent_id: int) -> None: @@ -178,6 +182,33 @@ def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: act = low + (high - low) * (act + 1.0) / 2.0 # type: ignore return act + def map_action_inverse( + self, act: Union[Batch, List, np.ndarray] + ) -> Union[Batch, List, np.ndarray]: + """Inverse operation to :meth:`~tianshou.policy.BasePolicy.map_action`. + + This function is called in :meth:`~tianshou.data.Collector.collect` for + random initial steps. It scales [action_space.low, action_space.high] to + the value ranges of policy.forward. + + :param act: a data batch, list or numpy.ndarray which is the action taken + by gym.spaces.Box.sample(). + + :return: action remapped. + """ + if isinstance(self.action_space, gym.spaces.Box): + act = to_numpy(act) + if isinstance(act, np.ndarray): + if self.action_scaling: + low, high = self.action_space.low, self.action_space.high + scale = high - low + eps = np.finfo(np.float32).eps.item() + scale[scale < eps] += eps + act = (act - low) * 2.0 / scale - 1.0 + if self.action_bound_method == "tanh": + act = (np.log(1.0 + act) - np.log(1.0 - act)) / 2.0 # type: ignore + return act + def process_fn( self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray ) -> Batch: @@ -245,6 +276,8 @@ def update(self, sample_size: int, buffer: Optional[ReplayBuffer], batch = self.process_fn(batch, buffer, indices) result = self.learn(batch, **kwargs) self.post_process_fn(batch, buffer, indices) + if self.lr_scheduler is not None: + self.lr_scheduler.step() self.updating = False return result diff --git a/tianshou/policy/imitation/base.py b/tianshou/policy/imitation/base.py index 405b8c762..20c6a6212 100644 --- a/tianshou/policy/imitation/base.py +++ b/tianshou/policy/imitation/base.py @@ -15,6 +15,8 @@ class ImitationPolicy(BasePolicy): :class:`~tianshou.policy.BasePolicy`. (s -> a) :param torch.optim.Optimizer optim: for optimizing the model. :param gym.Space action_space: env's action space. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/imitation/bcq.py b/tianshou/policy/imitation/bcq.py index afd9be90d..89facd7d5 100644 --- a/tianshou/policy/imitation/bcq.py +++ b/tianshou/policy/imitation/bcq.py @@ -36,6 +36,8 @@ class BCQPolicy(BasePolicy): :param int num_sampled_action: the number of sampled actions in calculating target Q. The algorithm samples several actions using VAE, and perturbs each action to get the target Q. Default to 10. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/imitation/cql.py b/tianshou/policy/imitation/cql.py index 50cd9d152..521e3f715 100644 --- a/tianshou/policy/imitation/cql.py +++ b/tianshou/policy/imitation/cql.py @@ -46,6 +46,8 @@ class CQLPolicy(SACPolicy): :param float clip_grad: clip_grad for updating critic network. Default to 1.0. :param Union[str, torch.device] device: which device to create this model on. Default to "cpu". + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/imitation/discrete_bcq.py b/tianshou/policy/imitation/discrete_bcq.py index bca9b09af..95b5dea5f 100644 --- a/tianshou/policy/imitation/discrete_bcq.py +++ b/tianshou/policy/imitation/discrete_bcq.py @@ -27,6 +27,8 @@ class DiscreteBCQPolicy(DQNPolicy): logits. Default to 1e-2. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/imitation/discrete_cql.py b/tianshou/policy/imitation/discrete_cql.py index 1adbb26f7..217e96001 100644 --- a/tianshou/policy/imitation/discrete_cql.py +++ b/tianshou/policy/imitation/discrete_cql.py @@ -23,6 +23,8 @@ class DiscreteCQLPolicy(QRDQNPolicy): :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. :param float min_q_weight: the weight for the cql loss. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: Please refer to :class:`~tianshou.policy.QRDQNPolicy` for more detailed diff --git a/tianshou/policy/imitation/discrete_crr.py b/tianshou/policy/imitation/discrete_crr.py index b182ead13..edbd25d08 100644 --- a/tianshou/policy/imitation/discrete_crr.py +++ b/tianshou/policy/imitation/discrete_crr.py @@ -29,6 +29,8 @@ class DiscreteCRRPolicy(PGPolicy): you do not use the target network). Default to 0. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: Please refer to :class:`~tianshou.policy.PGPolicy` for more detailed diff --git a/tianshou/policy/imitation/gail.py b/tianshou/policy/imitation/gail.py new file mode 100644 index 000000000..434e12e60 --- /dev/null +++ b/tianshou/policy/imitation/gail.py @@ -0,0 +1,141 @@ +from typing import Any, Dict, List, Optional, Type + +import numpy as np +import torch +import torch.nn.functional as F + +from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch +from tianshou.policy import PPOPolicy + + +class GAILPolicy(PPOPolicy): + r"""Implementation of Generative Adversarial Imitation Learning. arXiv:1606.03476. + + :param torch.nn.Module actor: the actor network following the rules in + :class:`~tianshou.policy.BasePolicy`. (s -> logits) + :param torch.nn.Module critic: the critic network. (s -> V(s)) + :param torch.optim.Optimizer optim: the optimizer for actor and critic network. + :param dist_fn: distribution class for computing the action. + :type dist_fn: Type[torch.distributions.Distribution] + :param ReplayBuffer expert_buffer: the replay buffer contains expert experience. + :param torch.nn.Module disc_net: the discriminator network with input dim equals + state dim plus action dim and output dim equals 1. + :param torch.optim.Optimizer disc_optim: the optimizer for the discriminator + network. + :param int disc_update_num: the number of discriminator grad steps per model grad + step. Default to 4. + :param float discount_factor: in [0, 1]. Default to 0.99. + :param float eps_clip: :math:`\epsilon` in :math:`L_{CLIP}` in the original + paper. Default to 0.2. + :param float dual_clip: a parameter c mentioned in arXiv:1912.09729 Equ. 5, + where c > 1 is a constant indicating the lower bound. + Default to 5.0 (set None if you do not want to use it). + :param bool value_clip: a parameter mentioned in arXiv:1811.02553 Sec. 4.1. + Default to True. + :param bool advantage_normalization: whether to do per mini-batch advantage + normalization. Default to True. + :param bool recompute_advantage: whether to recompute advantage every update + repeat according to https://arxiv.org/pdf/2006.05990.pdf Sec. 3.5. + Default to False. + :param float vf_coef: weight for value loss. Default to 0.5. + :param float ent_coef: weight for entropy loss. Default to 0.01. + :param float max_grad_norm: clipping gradients in back propagation. Default to + None. + :param float gae_lambda: in [0, 1], param for Generalized Advantage Estimation. + Default to 0.95. + :param bool reward_normalization: normalize estimated values to have std close + to 1, also normalize the advantage to Normal(0, 1). Default to False. + :param int max_batchsize: the maximum size of the batch when computing GAE, + depends on the size of available memory and the memory cost of the model; + should be as large as possible within the memory constraint. Default to 256. + :param bool action_scaling: whether to map actions from range [-1, 1] to range + [action_spaces.low, action_spaces.high]. Default to True. + :param str action_bound_method: method to bound action to range [-1, 1], can be + either "clip" (for simply clipping the action), "tanh" (for applying tanh + squashing) for now, or empty string for no bounding. Default to "clip". + :param Optional[gym.Space] action_space: env's action space, mandatory if you want + to use option "action_scaling" or "action_bound_method". Default to None. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). + :param bool deterministic_eval: whether to use deterministic action instead of + stochastic action sampled by the policy. Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). + + .. seealso:: + + Please refer to :class:`~tianshou.policy.PPOPolicy` for more detailed + explanation. + """ + + def __init__( + self, + actor: torch.nn.Module, + critic: torch.nn.Module, + optim: torch.optim.Optimizer, + dist_fn: Type[torch.distributions.Distribution], + expert_buffer: ReplayBuffer, + disc_net: torch.nn.Module, + disc_optim: torch.optim.Optimizer, + disc_update_num: int = 4, + eps_clip: float = 0.2, + dual_clip: Optional[float] = None, + value_clip: bool = False, + advantage_normalization: bool = True, + recompute_advantage: bool = False, + **kwargs: Any, + ) -> None: + super().__init__( + actor, critic, optim, dist_fn, eps_clip, dual_clip, value_clip, + advantage_normalization, recompute_advantage, **kwargs + ) + self.disc_net = disc_net + self.disc_optim = disc_optim + self.disc_update_num = disc_update_num + self.expert_buffer = expert_buffer + self.action_dim = actor.output_dim + + def process_fn( + self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray + ) -> Batch: + """Pre-process the data from the provided replay buffer. + + Used in :meth:`update`. Check out :ref:`process_fn` for more information. + """ + # update reward + with torch.no_grad(): + batch.rew = to_numpy(-F.logsigmoid(-self.disc(batch)).flatten()) + return super().process_fn(batch, buffer, indices) + + def disc(self, batch: Batch) -> torch.Tensor: + obs = to_torch(batch.obs, device=self.disc_net.device) # type: ignore + act = to_torch(batch.act, device=self.disc_net.device) # type: ignore + return self.disc_net(torch.cat([obs, act], dim=1)) # type: ignore + + def learn( # type: ignore + self, batch: Batch, batch_size: int, repeat: int, **kwargs: Any + ) -> Dict[str, List[float]]: + # update discriminator + losses = [] + acc_pis = [] + acc_exps = [] + bsz = len(batch) // self.disc_update_num + for b in batch.split(bsz, merge_last=True): + logits_pi = self.disc(b) + exp_b = self.expert_buffer.sample(bsz)[0] + logits_exp = self.disc(exp_b) + loss_pi = -F.logsigmoid(-logits_pi).mean() + loss_exp = -F.logsigmoid(logits_exp).mean() + loss_disc = loss_pi + loss_exp + self.disc_optim.zero_grad() + loss_disc.backward() + self.disc_optim.step() + losses.append(loss_disc.item()) + acc_pis.append((logits_pi < 0).float().mean().item()) + acc_exps.append((logits_exp > 0).float().mean().item()) + # update policy + res = super().learn(batch, batch_size, repeat, **kwargs) + res["loss/disc"] = losses + res["stats/acc_pi"] = acc_pis + res["stats/acc_exp"] = acc_exps + return res diff --git a/tianshou/policy/modelbased/icm.py b/tianshou/policy/modelbased/icm.py index 5a723c10b..66ab1bbc4 100644 --- a/tianshou/policy/modelbased/icm.py +++ b/tianshou/policy/modelbased/icm.py @@ -17,6 +17,8 @@ class ICMPolicy(BasePolicy): :param torch.optim.Optimizer optim: a torch.optim for optimizing the model. :param float lr_scale: the scaling factor for ICM learning. :param float forward_loss_weight: the weight for forward model loss. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelbased/psrl.py b/tianshou/policy/modelbased/psrl.py index 3caab0d63..8e7473adc 100644 --- a/tianshou/policy/modelbased/psrl.py +++ b/tianshou/policy/modelbased/psrl.py @@ -18,6 +18,8 @@ class PSRLModel(object): of rewards, with shape (n_state, n_action). :param float discount_factor: in [0, 1]. :param float epsilon: for precision control in value iteration. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). """ def __init__( diff --git a/tianshou/policy/modelfree/a2c.py b/tianshou/policy/modelfree/a2c.py index 2ad5bb3b2..b218cbf81 100644 --- a/tianshou/policy/modelfree/a2c.py +++ b/tianshou/policy/modelfree/a2c.py @@ -146,9 +146,6 @@ def learn( # type: ignore vf_losses.append(vf_loss.item()) ent_losses.append(ent_loss.item()) losses.append(loss.item()) - # update learning rate if lr_scheduler is given - if self.lr_scheduler is not None: - self.lr_scheduler.step() return { "loss": losses, diff --git a/tianshou/policy/modelfree/c51.py b/tianshou/policy/modelfree/c51.py index e49b2d697..3ebc1cfa8 100644 --- a/tianshou/policy/modelfree/c51.py +++ b/tianshou/policy/modelfree/c51.py @@ -25,6 +25,8 @@ class C51Policy(DQNPolicy): you do not use the target network). Default to 0. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/ddpg.py b/tianshou/policy/modelfree/ddpg.py index 0a779c661..0637d05ab 100644 --- a/tianshou/policy/modelfree/ddpg.py +++ b/tianshou/policy/modelfree/ddpg.py @@ -32,6 +32,8 @@ class DDPGPolicy(BasePolicy): Default to "clip". :param Optional[gym.Space] action_space: env's action space, mandatory if you want to use option "action_scaling" or "action_bound_method". Default to None. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/discrete_sac.py b/tianshou/policy/modelfree/discrete_sac.py index 33e06da30..2a626a722 100644 --- a/tianshou/policy/modelfree/discrete_sac.py +++ b/tianshou/policy/modelfree/discrete_sac.py @@ -28,6 +28,8 @@ class DiscreteSACPolicy(SACPolicy): alpha is automatically tuned. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/dqn.py b/tianshou/policy/modelfree/dqn.py index d03c3e3cb..593de15fd 100644 --- a/tianshou/policy/modelfree/dqn.py +++ b/tianshou/policy/modelfree/dqn.py @@ -26,6 +26,8 @@ class DQNPolicy(BasePolicy): :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. :param bool is_double: use double dqn. Default to True. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/fqf.py b/tianshou/policy/modelfree/fqf.py index 054781a7a..9eee122d3 100644 --- a/tianshou/policy/modelfree/fqf.py +++ b/tianshou/policy/modelfree/fqf.py @@ -27,6 +27,8 @@ class FQFPolicy(QRDQNPolicy): you do not use the target network). :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/iqn.py b/tianshou/policy/modelfree/iqn.py index 502dd693d..74b8d78d9 100644 --- a/tianshou/policy/modelfree/iqn.py +++ b/tianshou/policy/modelfree/iqn.py @@ -26,6 +26,8 @@ class IQNPolicy(QRDQNPolicy): you do not use the target network). :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/npg.py b/tianshou/policy/modelfree/npg.py index ce91fdb6e..e3ab3087c 100644 --- a/tianshou/policy/modelfree/npg.py +++ b/tianshou/policy/modelfree/npg.py @@ -127,10 +127,6 @@ def learn( # type: ignore vf_losses.append(vf_loss.item()) kls.append(kl.item()) - # update learning rate if lr_scheduler is given - if self.lr_scheduler is not None: - self.lr_scheduler.step() - return { "loss/actor": actor_losses, "loss/vf": vf_losses, diff --git a/tianshou/policy/modelfree/pg.py b/tianshou/policy/modelfree/pg.py index 9149a383b..1557c1ad6 100644 --- a/tianshou/policy/modelfree/pg.py +++ b/tianshou/policy/modelfree/pg.py @@ -44,7 +44,6 @@ def __init__( reward_normalization: bool = False, action_scaling: bool = True, action_bound_method: str = "clip", - lr_scheduler: Optional[torch.optim.lr_scheduler.LambdaLR] = None, deterministic_eval: bool = False, **kwargs: Any, ) -> None: @@ -55,7 +54,6 @@ def __init__( ) self.actor = model self.optim = optim - self.lr_scheduler = lr_scheduler self.dist_fn = dist_fn assert 0.0 <= discount_factor <= 1.0, "discount factor should be in [0, 1]" self._gamma = discount_factor @@ -137,8 +135,5 @@ def learn( # type: ignore loss.backward() self.optim.step() losses.append(loss.item()) - # update learning rate if lr_scheduler is given - if self.lr_scheduler is not None: - self.lr_scheduler.step() return {"loss": losses} diff --git a/tianshou/policy/modelfree/ppo.py b/tianshou/policy/modelfree/ppo.py index fe5aa2fa6..3c19daf1e 100644 --- a/tianshou/policy/modelfree/ppo.py +++ b/tianshou/policy/modelfree/ppo.py @@ -152,9 +152,6 @@ def learn( # type: ignore vf_losses.append(vf_loss.item()) ent_losses.append(ent_loss.item()) losses.append(loss.item()) - # update learning rate if lr_scheduler is given - if self.lr_scheduler is not None: - self.lr_scheduler.step() return { "loss": losses, diff --git a/tianshou/policy/modelfree/qrdqn.py b/tianshou/policy/modelfree/qrdqn.py index ea4913f62..39dde3d4a 100644 --- a/tianshou/policy/modelfree/qrdqn.py +++ b/tianshou/policy/modelfree/qrdqn.py @@ -23,6 +23,8 @@ class QRDQNPolicy(DQNPolicy): you do not use the target network). :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/rainbow.py b/tianshou/policy/modelfree/rainbow.py index 9028258d7..773abddc4 100644 --- a/tianshou/policy/modelfree/rainbow.py +++ b/tianshou/policy/modelfree/rainbow.py @@ -23,6 +23,8 @@ class RainbowPolicy(C51Policy): you do not use the target network). Default to 0. :param bool reward_normalization: normalize the reward to Normal(0, 1). Default to False. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/sac.py b/tianshou/policy/modelfree/sac.py index fc89cf318..5f17427a7 100644 --- a/tianshou/policy/modelfree/sac.py +++ b/tianshou/policy/modelfree/sac.py @@ -5,7 +5,7 @@ import torch from torch.distributions import Independent, Normal -from tianshou.data import Batch, ReplayBuffer, to_torch_as +from tianshou.data import Batch, ReplayBuffer from tianshou.exploration import BaseNoise from tianshou.policy import DDPGPolicy @@ -42,6 +42,8 @@ class SACPolicy(DDPGPolicy): Default to "clip". :param Optional[gym.Space] action_space: env's action space, mandatory if you want to use option "action_scaling" or "action_bound_method". Default to None. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: @@ -121,16 +123,9 @@ def forward( # type: ignore # apply correction for Tanh squashing when computing logprob from Gaussian # You can check out the original SAC paper (arXiv 1801.01290): Eq 21. # in appendix C to get some understanding of this equation. - if self.action_scaling and self.action_space is not None: - action_scale = to_torch_as( - (self.action_space.high - self.action_space.low) / 2.0, act - ) - else: - action_scale = 1.0 # type: ignore squashed_action = torch.tanh(act) - log_prob = log_prob - torch.log( - action_scale * (1 - squashed_action.pow(2)) + self.__eps - ).sum(-1, keepdim=True) + log_prob = log_prob - torch.log((1 - squashed_action.pow(2)) + + self.__eps).sum(-1, keepdim=True) return Batch( logits=logits, act=squashed_action, @@ -174,6 +169,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: if self._is_auto_alpha: log_prob = obs_result.log_prob.detach() + self._target_entropy + # please take a look at issue #258 if you'd like to change this line alpha_loss = -(self._log_alpha * log_prob).mean() self._alpha_optim.zero_grad() alpha_loss.backward() diff --git a/tianshou/policy/modelfree/td3.py b/tianshou/policy/modelfree/td3.py index 8ad31db06..003e09968 100644 --- a/tianshou/policy/modelfree/td3.py +++ b/tianshou/policy/modelfree/td3.py @@ -40,6 +40,8 @@ class TD3Policy(DDPGPolicy): Default to "clip". :param Optional[gym.Space] action_space: env's action space, mandatory if you want to use option "action_scaling" or "action_bound_method". Default to None. + :param lr_scheduler: a learning rate scheduler that adjusts the learning rate in + optimizer in each policy.update(). Default to None (no lr_scheduler). .. seealso:: diff --git a/tianshou/policy/modelfree/trpo.py b/tianshou/policy/modelfree/trpo.py index 2803a2df1..00688af69 100644 --- a/tianshou/policy/modelfree/trpo.py +++ b/tianshou/policy/modelfree/trpo.py @@ -146,10 +146,6 @@ def learn( # type: ignore step_sizes.append(step_size.item()) kls.append(kl.item()) - # update learning rate if lr_scheduler is given - if self.lr_scheduler is not None: - self.lr_scheduler.step() - return { "loss/actor": actor_losses, "loss/vf": vf_losses, diff --git a/tianshou/trainer/__init__.py b/tianshou/trainer/__init__.py index 11b3a95ef..8f1361bec 100644 --- a/tianshou/trainer/__init__.py +++ b/tianshou/trainer/__init__.py @@ -1,16 +1,34 @@ """Trainer package.""" -# isort:skip_file - -from tianshou.trainer.utils import test_episode, gather_info -from tianshou.trainer.onpolicy import onpolicy_trainer -from tianshou.trainer.offpolicy import offpolicy_trainer -from tianshou.trainer.offline import offline_trainer +from tianshou.trainer.base import BaseTrainer +from tianshou.trainer.offline import ( + OfflineTrainer, + offline_trainer, + offline_trainer_iter, +) +from tianshou.trainer.offpolicy import ( + OffpolicyTrainer, + offpolicy_trainer, + offpolicy_trainer_iter, +) +from tianshou.trainer.onpolicy import ( + OnpolicyTrainer, + onpolicy_trainer, + onpolicy_trainer_iter, +) +from tianshou.trainer.utils import gather_info, test_episode __all__ = [ + "BaseTrainer", "offpolicy_trainer", + "offpolicy_trainer_iter", + "OffpolicyTrainer", "onpolicy_trainer", + "onpolicy_trainer_iter", + "OnpolicyTrainer", "offline_trainer", + "offline_trainer_iter", + "OfflineTrainer", "test_episode", "gather_info", ] diff --git a/tianshou/trainer/base.py b/tianshou/trainer/base.py new file mode 100644 index 000000000..60525f67b --- /dev/null +++ b/tianshou/trainer/base.py @@ -0,0 +1,426 @@ +import time +from abc import ABC, abstractmethod +from collections import defaultdict, deque +from typing import Any, Callable, DefaultDict, Dict, Optional, Tuple, Union + +import numpy as np +import tqdm + +from tianshou.data import Collector, ReplayBuffer +from tianshou.policy import BasePolicy +from tianshou.trainer.utils import gather_info, test_episode +from tianshou.utils import BaseLogger, LazyLogger, MovAvg, deprecation, tqdm_config + + +class BaseTrainer(ABC): + """An iterator base class for trainers procedure. + + Returns an iterator that yields a 3-tuple (epoch, stats, info) of train results + on every epoch. + + :param learning_type str: type of learning iterator, available choices are + "offpolicy", "onpolicy" and "offline". + :param policy: an instance of the :class:`~tianshou.policy.BasePolicy` class. + :param Collector train_collector: the collector used for training. + :param Collector test_collector: the collector used for testing. If it's None, + then no testing will be performed. + :param int max_epoch: the maximum number of epochs for training. The training + process might be finished before reaching ``max_epoch`` if ``stop_fn`` + is set. + :param int step_per_epoch: the number of transitions collected per epoch. + :param int repeat_per_collect: the number of repeat time for policy learning, + for example, set it to 2 means the policy needs to learn each given batch + data twice. + :param int episode_per_test: the number of episodes for one policy evaluation. + :param int batch_size: the batch size of sample data, which is going to feed in + the policy network. + :param int step_per_collect: the number of transitions the collector would + collect before the network update, i.e., trainer will collect + "step_per_collect" transitions and do some policy network update repeatedly + in each epoch. + :param int episode_per_collect: the number of episodes the collector would + collect before the network update, i.e., trainer will collect + "episode_per_collect" episodes and do some policy network update repeatedly + in each epoch. + :param function train_fn: a hook called at the beginning of training in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function test_fn: a hook called at the beginning of testing in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function save_best_fn: a hook called when the undiscounted average mean + reward in evaluation phase gets better, with the signature + ``f(policy: BasePolicy) -> None``. It was ``save_fn`` previously. + :param function save_checkpoint_fn: a function to save training process, with + the signature ``f(epoch: int, env_step: int, gradient_step: int) -> None``; + you can save whatever you want. + :param bool resume_from_log: resume env_step/gradient_step and other metadata + from existing tensorboard log. Default to False. + :param function stop_fn: a function with signature ``f(mean_rewards: float) -> + bool``, receives the average undiscounted returns of the testing result, + returns a boolean which indicates whether reaching the goal. + :param function reward_metric: a function with signature + ``f(rewards: np.ndarray with shape (num_episode, agent_num)) -> np.ndarray + with shape (num_episode,)``, used in multi-agent RL. We need to return a + single scalar for each episode's result to monitor training in the + multi-agent RL setting. This function specifies what is the desired metric, + e.g., the reward of agent 1 or the average reward over all agents. + :param BaseLogger logger: A logger that logs statistics during + training/testing/updating. Default to a logger that doesn't log anything. + :param bool verbose: whether to print the information. Default to True. + :param bool test_in_train: whether to test in the training phase. + Default to True. + """ + + @staticmethod + def gen_doc(learning_type: str) -> str: + """Document string for subclass trainer.""" + step_means = f'The "step" in {learning_type} trainer means ' + if learning_type != "offline": + step_means += "an environment step (a.k.a. transition)." + else: # offline + step_means += "a gradient step." + + trainer_name = learning_type.capitalize() + "Trainer" + + return f"""An iterator class for {learning_type} trainer procedure. + + Returns an iterator that yields a 3-tuple (epoch, stats, info) of + train results on every epoch. + + {step_means} + + Example usage: + + :: + + trainer = {trainer_name}(...) + for epoch, epoch_stat, info in trainer: + print("Epoch:", epoch) + print(epoch_stat) + print(info) + do_something_with_policy() + query_something_about_policy() + make_a_plot_with(epoch_stat) + display(info) + + - epoch int: the epoch number + - epoch_stat dict: a large collection of metrics of the current epoch + - info dict: result returned from :func:`~tianshou.trainer.gather_info` + + You can even iterate on several trainers at the same time: + + :: + + trainer1 = {trainer_name}(...) + trainer2 = {trainer_name}(...) + for result1, result2, ... in zip(trainer1, trainer2, ...): + compare_results(result1, result2, ...) + """ + + def __init__( + self, + learning_type: str, + policy: BasePolicy, + max_epoch: int, + batch_size: int, + train_collector: Optional[Collector] = None, + test_collector: Optional[Collector] = None, + buffer: Optional[ReplayBuffer] = None, + step_per_epoch: Optional[int] = None, + repeat_per_collect: Optional[int] = None, + episode_per_test: Optional[int] = None, + update_per_step: Union[int, float] = 1, + update_per_epoch: Optional[int] = None, + step_per_collect: Optional[int] = None, + episode_per_collect: Optional[int] = None, + train_fn: Optional[Callable[[int, int], None]] = None, + test_fn: Optional[Callable[[int, Optional[int]], None]] = None, + stop_fn: Optional[Callable[[float], bool]] = None, + save_best_fn: Optional[Callable[[BasePolicy], None]] = None, + save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, + resume_from_log: bool = False, + reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, + logger: BaseLogger = LazyLogger(), + verbose: bool = True, + test_in_train: bool = True, + save_fn: Optional[Callable[[BasePolicy], None]] = None, + ): + if save_fn: + deprecation( + "save_fn in trainer is marked as deprecated and will be " + "removed in the future. Please use save_best_fn instead." + ) + assert save_best_fn is None + save_best_fn = save_fn + + self.policy = policy + self.buffer = buffer + + self.train_collector = train_collector + self.test_collector = test_collector + + self.logger = logger + self.start_time = time.time() + self.stat: DefaultDict[str, MovAvg] = defaultdict(MovAvg) + self.best_reward = 0.0 + self.best_reward_std = 0.0 + self.start_epoch = 0 + self.gradient_step = 0 + self.env_step = 0 + self.max_epoch = max_epoch + self.step_per_epoch = step_per_epoch + + # either on of these two + self.step_per_collect = step_per_collect + self.episode_per_collect = episode_per_collect + + self.update_per_step = update_per_step + self.repeat_per_collect = repeat_per_collect + + self.episode_per_test = episode_per_test + + self.batch_size = batch_size + + self.train_fn = train_fn + self.test_fn = test_fn + self.stop_fn = stop_fn + self.save_best_fn = save_best_fn + self.save_checkpoint_fn = save_checkpoint_fn + + self.reward_metric = reward_metric + self.verbose = verbose + self.test_in_train = test_in_train + self.resume_from_log = resume_from_log + + self.is_run = False + self.last_rew, self.last_len = 0.0, 0 + + self.epoch = self.start_epoch + self.best_epoch = self.start_epoch + self.stop_fn_flag = False + self.iter_num = 0 + + def reset(self) -> None: + """Initialize or reset the instance to yield a new iterator from zero.""" + self.is_run = False + self.env_step = 0 + if self.resume_from_log: + self.start_epoch, self.env_step, self.gradient_step = \ + self.logger.restore_data() + + self.last_rew, self.last_len = 0.0, 0 + self.start_time = time.time() + if self.train_collector is not None: + self.train_collector.reset_stat() + + if self.train_collector.policy != self.policy: + self.test_in_train = False + elif self.test_collector is None: + self.test_in_train = False + + if self.test_collector is not None: + assert self.episode_per_test is not None + self.test_collector.reset_stat() + test_result = test_episode( + self.policy, self.test_collector, self.test_fn, self.start_epoch, + self.episode_per_test, self.logger, self.env_step, self.reward_metric + ) + self.best_epoch = self.start_epoch + self.best_reward, self.best_reward_std = \ + test_result["rew"], test_result["rew_std"] + if self.save_best_fn: + self.save_best_fn(self.policy) + + self.epoch = self.start_epoch + self.stop_fn_flag = False + self.iter_num = 0 + + def __iter__(self): # type: ignore + self.reset() + return self + + def __next__(self) -> Union[None, Tuple[int, Dict[str, Any], Dict[str, Any]]]: + """Perform one epoch (both train and eval).""" + self.epoch += 1 + self.iter_num += 1 + + if self.iter_num > 1: + + # iterator exhaustion check + if self.epoch >= self.max_epoch: + raise StopIteration + + # exit flag 1, when stop_fn succeeds in train_step or test_step + if self.stop_fn_flag: + raise StopIteration + + # set policy in train mode + self.policy.train() + + epoch_stat: Dict[str, Any] = dict() + # perform n step_per_epoch + with tqdm.tqdm( + total=self.step_per_epoch, desc=f"Epoch #{self.epoch}", **tqdm_config + ) as t: + while t.n < t.total and not self.stop_fn_flag: + data: Dict[str, Any] = dict() + result: Dict[str, Any] = dict() + if self.train_collector is not None: + data, result, self.stop_fn_flag = self.train_step() + t.update(result["n/st"]) + if self.stop_fn_flag: + t.set_postfix(**data) + break + else: + assert self.buffer, "No train_collector or buffer specified" + result["n/ep"] = len(self.buffer) + result["n/st"] = int(self.gradient_step) + t.update() + + self.policy_update_fn(data, result) + t.set_postfix(**data) + + if t.n <= t.total and not self.stop_fn_flag: + t.update() + + if not self.stop_fn_flag: + self.logger.save_data( + self.epoch, self.env_step, self.gradient_step, self.save_checkpoint_fn + ) + # test + if self.test_collector is not None: + test_stat, self.stop_fn_flag = self.test_step() + if not self.is_run: + epoch_stat.update(test_stat) + + if not self.is_run: + epoch_stat.update({k: v.get() for k, v in self.stat.items()}) + epoch_stat["gradient_step"] = self.gradient_step + epoch_stat.update( + { + "env_step": self.env_step, + "rew": self.last_rew, + "len": int(self.last_len), + "n/ep": int(result["n/ep"]), + "n/st": int(result["n/st"]), + } + ) + info = gather_info( + self.start_time, self.train_collector, self.test_collector, + self.best_reward, self.best_reward_std + ) + return self.epoch, epoch_stat, info + else: + return None + + def test_step(self) -> Tuple[Dict[str, Any], bool]: + """Perform one testing step.""" + assert self.episode_per_test is not None + assert self.test_collector is not None + stop_fn_flag = False + test_result = test_episode( + self.policy, self.test_collector, self.test_fn, self.epoch, + self.episode_per_test, self.logger, self.env_step, self.reward_metric + ) + rew, rew_std = test_result["rew"], test_result["rew_std"] + if self.best_epoch < 0 or self.best_reward < rew: + self.best_epoch = self.epoch + self.best_reward = float(rew) + self.best_reward_std = rew_std + if self.save_best_fn: + self.save_best_fn(self.policy) + if self.verbose: + print( + f"Epoch #{self.epoch}: test_reward: {rew:.6f} ± {rew_std:.6f}," + f" best_reward: {self.best_reward:.6f} ± " + f"{self.best_reward_std:.6f} in #{self.best_epoch}" + ) + if not self.is_run: + test_stat = { + "test_reward": rew, + "test_reward_std": rew_std, + "best_reward": self.best_reward, + "best_reward_std": self.best_reward_std, + "best_epoch": self.best_epoch + } + else: + test_stat = {} + if self.stop_fn and self.stop_fn(self.best_reward): + stop_fn_flag = True + + return test_stat, stop_fn_flag + + def train_step(self) -> Tuple[Dict[str, Any], Dict[str, Any], bool]: + """Perform one training step.""" + assert self.episode_per_test is not None + assert self.train_collector is not None + stop_fn_flag = False + if self.train_fn: + self.train_fn(self.epoch, self.env_step) + result = self.train_collector.collect( + n_step=self.step_per_collect, n_episode=self.episode_per_collect + ) + if result["n/ep"] > 0 and self.reward_metric: + rew = self.reward_metric(result["rews"]) + result.update(rews=rew, rew=rew.mean(), rew_std=rew.std()) + self.env_step += int(result["n/st"]) + self.logger.log_train_data(result, self.env_step) + self.last_rew = result["rew"] if result["n/ep"] > 0 else self.last_rew + self.last_len = result["len"] if result["n/ep"] > 0 else self.last_len + data = { + "env_step": str(self.env_step), + "rew": f"{self.last_rew:.2f}", + "len": str(int(self.last_len)), + "n/ep": str(int(result["n/ep"])), + "n/st": str(int(result["n/st"])), + } + if result["n/ep"] > 0: + if self.test_in_train and self.stop_fn and self.stop_fn(result["rew"]): + assert self.test_collector is not None + test_result = test_episode( + self.policy, self.test_collector, self.test_fn, self.epoch, + self.episode_per_test, self.logger, self.env_step + ) + if self.stop_fn(test_result["rew"]): + stop_fn_flag = True + self.best_reward = test_result["rew"] + self.best_reward_std = test_result["rew_std"] + else: + self.policy.train() + + return data, result, stop_fn_flag + + def log_update_data(self, data: Dict[str, Any], losses: Dict[str, Any]) -> None: + """Log losses to current logger.""" + for k in losses.keys(): + self.stat[k].add(losses[k]) + losses[k] = self.stat[k].get() + data[k] = f"{losses[k]:.3f}" + self.logger.log_update_data(losses, self.gradient_step) + + @abstractmethod + def policy_update_fn(self, data: Dict[str, Any], result: Dict[str, Any]) -> None: + """Policy update function for different trainer implementation. + + :param data: information in progress bar. + :param result: collector's return value. + """ + + def run(self) -> Dict[str, Union[float, str]]: + """Consume iterator. + + See itertools - recipes. Use functions that consume iterators at C speed + (feed the entire iterator into a zero-length deque). + """ + try: + self.is_run = True + deque(self, maxlen=0) # feed the entire iterator into a zero-length deque + info = gather_info( + self.start_time, self.train_collector, self.test_collector, + self.best_reward, self.best_reward_std + ) + finally: + self.is_run = False + + return info diff --git a/tianshou/trainer/offline.py b/tianshou/trainer/offline.py index d2f85bc2a..82d9aa32a 100644 --- a/tianshou/trainer/offline.py +++ b/tianshou/trainer/offline.py @@ -1,131 +1,117 @@ -import time -from collections import defaultdict -from typing import Callable, Dict, Optional, Union +from typing import Any, Callable, Dict, Optional, Union import numpy as np -import tqdm from tianshou.data import Collector, ReplayBuffer from tianshou.policy import BasePolicy -from tianshou.trainer import gather_info, test_episode -from tianshou.utils import BaseLogger, LazyLogger, MovAvg, tqdm_config +from tianshou.trainer.base import BaseTrainer +from tianshou.utils import BaseLogger, LazyLogger -def offline_trainer( - policy: BasePolicy, - buffer: ReplayBuffer, - test_collector: Optional[Collector], - max_epoch: int, - update_per_epoch: int, - episode_per_test: int, - batch_size: int, - test_fn: Optional[Callable[[int, Optional[int]], None]] = None, - stop_fn: Optional[Callable[[float], bool]] = None, - save_fn: Optional[Callable[[BasePolicy], None]] = None, - save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, - resume_from_log: bool = False, - reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, - logger: BaseLogger = LazyLogger(), - verbose: bool = True, -) -> Dict[str, Union[float, str]]: - """A wrapper for offline trainer procedure. - - The "step" in offline trainer means a gradient step. +class OfflineTrainer(BaseTrainer): + """Create an iterator class for offline training procedure. :param policy: an instance of the :class:`~tianshou.policy.BasePolicy` class. - :param Collector test_collector: the collector used for testing. If it's None, then - no testing will be performed. + :param buffer: an instance of the :class:`~tianshou.data.ReplayBuffer` class. + This buffer must be populated with experiences for offline RL. + :param Collector test_collector: the collector used for testing. If it's None, + then no testing will be performed. :param int max_epoch: the maximum number of epochs for training. The training - process might be finished before reaching ``max_epoch`` if ``stop_fn`` is set. + process might be finished before reaching ``max_epoch`` if ``stop_fn`` is + set. :param int update_per_epoch: the number of policy network updates, so-called gradient steps, per epoch. :param episode_per_test: the number of episodes for one policy evaluation. :param int batch_size: the batch size of sample data, which is going to feed in the policy network. - :param function test_fn: a hook called at the beginning of testing in each epoch. - It can be used to perform custom additional operations, with the signature ``f( - num_epoch: int, step_idx: int) -> None``. - :param function save_fn: a hook called when the undiscounted average mean reward in - evaluation phase gets better, with the signature ``f(policy: BasePolicy) -> - None``. - :param function save_checkpoint_fn: a function to save training process, with the - signature ``f(epoch: int, env_step: int, gradient_step: int) -> None``; you can - save whatever you want. Because offline-RL doesn't have env_step, the env_step - is always 0 here. - :param bool resume_from_log: resume gradient_step and other metadata from existing - tensorboard log. Default to False. + :param function test_fn: a hook called at the beginning of testing in each + epoch. + It can be used to perform custom additional operations, with the signature + ``f(num_epoch: int, step_idx: int) -> None``. + :param function save_best_fn: a hook called when the undiscounted average mean + reward in evaluation phase gets better, with the signature + ``f(policy: BasePolicy) -> None``. It was ``save_fn`` previously. + :param function save_checkpoint_fn: a function to save training process, + with the signature ``f(epoch: int, env_step: int, gradient_step: int) -> + None``; you can save whatever you want. Because offline-RL doesn't have + env_step, the env_step is always 0 here. + :param bool resume_from_log: resume gradient_step and other metadata from + existing tensorboard log. Default to False. :param function stop_fn: a function with signature ``f(mean_rewards: float) -> bool``, receives the average undiscounted returns of the testing result, returns a boolean which indicates whether reaching the goal. - :param function reward_metric: a function with signature ``f(rewards: np.ndarray - with shape (num_episode, agent_num)) -> np.ndarray with shape (num_episode,)``, - used in multi-agent RL. We need to return a single scalar for each episode's - result to monitor training in the multi-agent RL setting. This function - specifies what is the desired metric, e.g., the reward of agent 1 or the - average reward over all agents. - :param BaseLogger logger: A logger that logs statistics during updating/testing. - Default to a logger that doesn't log anything. + :param function reward_metric: a function with signature ``f(rewards: + np.ndarray with shape (num_episode, agent_num)) -> np.ndarray with shape + (num_episode,)``, used in multi-agent RL. We need to return a single scalar + for each episode's result to monitor training in the multi-agent RL + setting. This function specifies what is the desired metric, e.g., the + reward of agent 1 or the average reward over all agents. + :param BaseLogger logger: A logger that logs statistics during + updating/testing. Default to a logger that doesn't log anything. :param bool verbose: whether to print the information. Default to True. - - :return: See :func:`~tianshou.trainer.gather_info`. """ - start_epoch, gradient_step = 0, 0 - if resume_from_log: - start_epoch, _, gradient_step = logger.restore_data() - stat: Dict[str, MovAvg] = defaultdict(MovAvg) - start_time = time.time() - if test_collector is not None: - test_c: Collector = test_collector - test_collector.reset_stat() - test_result = test_episode( - policy, test_c, test_fn, start_epoch, episode_per_test, logger, - gradient_step, reward_metric + __doc__ = BaseTrainer.gen_doc("offline") + "\n".join(__doc__.split("\n")[1:]) + + def __init__( + self, + policy: BasePolicy, + buffer: ReplayBuffer, + test_collector: Optional[Collector], + max_epoch: int, + update_per_epoch: int, + episode_per_test: int, + batch_size: int, + test_fn: Optional[Callable[[int, Optional[int]], None]] = None, + stop_fn: Optional[Callable[[float], bool]] = None, + save_best_fn: Optional[Callable[[BasePolicy], None]] = None, + save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, + resume_from_log: bool = False, + reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, + logger: BaseLogger = LazyLogger(), + verbose: bool = True, + **kwargs: Any, + ): + super().__init__( + learning_type="offline", + policy=policy, + buffer=buffer, + test_collector=test_collector, + max_epoch=max_epoch, + update_per_epoch=update_per_epoch, + step_per_epoch=update_per_epoch, + episode_per_test=episode_per_test, + batch_size=batch_size, + test_fn=test_fn, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + save_checkpoint_fn=save_checkpoint_fn, + resume_from_log=resume_from_log, + reward_metric=reward_metric, + logger=logger, + verbose=verbose, + **kwargs, ) - best_epoch = start_epoch - best_reward, best_reward_std = test_result["rew"], test_result["rew_std"] - if save_fn: - save_fn(policy) - for epoch in range(1 + start_epoch, 1 + max_epoch): - policy.train() - with tqdm.trange(update_per_epoch, desc=f"Epoch #{epoch}", **tqdm_config) as t: - for _ in t: - gradient_step += 1 - losses = policy.update(batch_size, buffer) - data = {"gradient_step": str(gradient_step)} - for k in losses.keys(): - stat[k].add(losses[k]) - losses[k] = stat[k].get() - data[k] = f"{losses[k]:.3f}" - logger.log_update_data(losses, gradient_step) - t.set_postfix(**data) - logger.save_data(epoch, 0, gradient_step, save_checkpoint_fn) - # test - if test_collector is not None: - test_result = test_episode( - policy, test_c, test_fn, epoch, episode_per_test, logger, - gradient_step, reward_metric - ) - rew, rew_std = test_result["rew"], test_result["rew_std"] - if best_epoch < 0 or best_reward < rew: - best_epoch, best_reward, best_reward_std = epoch, rew, rew_std - if save_fn: - save_fn(policy) - if verbose: - print( - f"Epoch #{epoch}: test_reward: {rew:.6f} ± {rew_std:.6f}, best_rew" - f"ard: {best_reward:.6f} ± {best_reward_std:.6f} in #{best_epoch}" - ) - if stop_fn and stop_fn(best_reward): - break + def policy_update_fn( + self, data: Dict[str, Any], result: Optional[Dict[str, Any]] = None + ) -> None: + """Perform one off-line policy update.""" + assert self.buffer + self.gradient_step += 1 + losses = self.policy.update(self.batch_size, self.buffer) + data.update({"gradient_step": str(self.gradient_step)}) + self.log_update_data(data, losses) - if test_collector is None and save_fn: - save_fn(policy) - if test_collector is None: - return gather_info(start_time, None, None, 0.0, 0.0) - else: - return gather_info( - start_time, None, test_collector, best_reward, best_reward_std - ) +def offline_trainer(*args, **kwargs) -> Dict[str, Union[float, str]]: # type: ignore + """Wrapper for offline_trainer run method. + + It is identical to ``OfflineTrainer(...).run()``. + + :return: See :func:`~tianshou.trainer.gather_info`. + """ + return OfflineTrainer(*args, **kwargs).run() + + +offline_trainer_iter = OfflineTrainer diff --git a/tianshou/trainer/offpolicy.py b/tianshou/trainer/offpolicy.py index 9b8727b24..e7be852a7 100644 --- a/tianshou/trainer/offpolicy.py +++ b/tianshou/trainer/offpolicy.py @@ -1,193 +1,132 @@ -import time -from collections import defaultdict -from typing import Callable, Dict, Optional, Union +from typing import Any, Callable, Dict, Optional, Union import numpy as np -import tqdm from tianshou.data import Collector from tianshou.policy import BasePolicy -from tianshou.trainer import gather_info, test_episode -from tianshou.utils import BaseLogger, LazyLogger, MovAvg, tqdm_config +from tianshou.trainer.base import BaseTrainer +from tianshou.utils import BaseLogger, LazyLogger -def offpolicy_trainer( - policy: BasePolicy, - train_collector: Collector, - test_collector: Optional[Collector], - max_epoch: int, - step_per_epoch: int, - step_per_collect: int, - episode_per_test: int, - batch_size: int, - update_per_step: Union[int, float] = 1, - train_fn: Optional[Callable[[int, int], None]] = None, - test_fn: Optional[Callable[[int, Optional[int]], None]] = None, - stop_fn: Optional[Callable[[float], bool]] = None, - save_fn: Optional[Callable[[BasePolicy], None]] = None, - save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, - resume_from_log: bool = False, - reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, - logger: BaseLogger = LazyLogger(), - verbose: bool = True, - test_in_train: bool = True, -) -> Dict[str, Union[float, str]]: - """A wrapper for off-policy trainer procedure. - - The "step" in trainer means an environment step (a.k.a. transition). +class OffpolicyTrainer(BaseTrainer): + """Create an iterator wrapper for off-policy training procedure. :param policy: an instance of the :class:`~tianshou.policy.BasePolicy` class. :param Collector train_collector: the collector used for training. - :param Collector test_collector: the collector used for testing. If it's None, then - no testing will be performed. + :param Collector test_collector: the collector used for testing. If it's None, + then no testing will be performed. :param int max_epoch: the maximum number of epochs for training. The training - process might be finished before reaching ``max_epoch`` if ``stop_fn`` is set. + process might be finished before reaching ``max_epoch`` if ``stop_fn`` is + set. :param int step_per_epoch: the number of transitions collected per epoch. - :param int step_per_collect: the number of transitions the collector would collect - before the network update, i.e., trainer will collect "step_per_collect" - transitions and do some policy network update repeatedly in each epoch. + :param int step_per_collect: the number of transitions the collector would + collect before the network update, i.e., trainer will collect + "step_per_collect" transitions and do some policy network update repeatedly + in each epoch. :param episode_per_test: the number of episodes for one policy evaluation. - :param int batch_size: the batch size of sample data, which is going to feed in the - policy network. - :param int/float update_per_step: the number of times the policy network would be - updated per transition after (step_per_collect) transitions are collected, - e.g., if update_per_step set to 0.3, and step_per_collect is 256, policy will - be updated round(256 * 0.3 = 76.8) = 77 times after 256 transitions are - collected by the collector. Default to 1. - :param function train_fn: a hook called at the beginning of training in each epoch. - It can be used to perform custom additional operations, with the signature ``f( - num_epoch: int, step_idx: int) -> None``. - :param function test_fn: a hook called at the beginning of testing in each epoch. - It can be used to perform custom additional operations, with the signature ``f( - num_epoch: int, step_idx: int) -> None``. - :param function save_fn: a hook called when the undiscounted average mean reward in - evaluation phase gets better, with the signature ``f(policy: BasePolicy) -> - None``. - :param function save_checkpoint_fn: a function to save training process, with the - signature ``f(epoch: int, env_step: int, gradient_step: int) -> None``; you can - save whatever you want. - :param bool resume_from_log: resume env_step/gradient_step and other metadata from - existing tensorboard log. Default to False. + :param int batch_size: the batch size of sample data, which is going to feed in + the policy network. + :param int/float update_per_step: the number of times the policy network would + be updated per transition after (step_per_collect) transitions are + collected, e.g., if update_per_step set to 0.3, and step_per_collect is 256 + , policy will be updated round(256 * 0.3 = 76.8) = 77 times after 256 + transitions are collected by the collector. Default to 1. + :param function train_fn: a hook called at the beginning of training in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function test_fn: a hook called at the beginning of testing in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function save_best_fn: a hook called when the undiscounted average mean + reward in evaluation phase gets better, with the signature + ``f(policy: BasePolicy) -> None``. It was ``save_fn`` previously. + :param function save_checkpoint_fn: a function to save training process, with + the signature ``f(epoch: int, env_step: int, gradient_step: int) -> None``; + you can save whatever you want. + :param bool resume_from_log: resume env_step/gradient_step and other metadata + from existing tensorboard log. Default to False. :param function stop_fn: a function with signature ``f(mean_rewards: float) -> bool``, receives the average undiscounted returns of the testing result, returns a boolean which indicates whether reaching the goal. - :param function reward_metric: a function with signature ``f(rewards: np.ndarray - with shape (num_episode, agent_num)) -> np.ndarray with shape (num_episode,)``, - used in multi-agent RL. We need to return a single scalar for each episode's - result to monitor training in the multi-agent RL setting. This function - specifies what is the desired metric, e.g., the reward of agent 1 or the - average reward over all agents. + :param function reward_metric: a function with signature + ``f(rewards: np.ndarray with shape (num_episode, agent_num)) -> + np.ndarray with shape (num_episode,)``, used in multi-agent RL. We need to + return a single scalar for each episode's result to monitor training in the + multi-agent RL setting. This function specifies what is the desired metric, + e.g., the reward of agent 1 or the average reward over all agents. :param BaseLogger logger: A logger that logs statistics during training/testing/updating. Default to a logger that doesn't log anything. :param bool verbose: whether to print the information. Default to True. - :param bool test_in_train: whether to test in the training phase. Default to True. - - :return: See :func:`~tianshou.trainer.gather_info`. + :param bool test_in_train: whether to test in the training phase. + Default to True. """ - start_epoch, env_step, gradient_step = 0, 0, 0 - if resume_from_log: - start_epoch, env_step, gradient_step = logger.restore_data() - last_rew, last_len = 0.0, 0 - stat: Dict[str, MovAvg] = defaultdict(MovAvg) - start_time = time.time() - train_collector.reset_stat() - test_in_train = test_in_train and ( - train_collector.policy == policy and test_collector is not None - ) - if test_collector is not None: - test_c: Collector = test_collector # for mypy - test_collector.reset_stat() - test_result = test_episode( - policy, test_c, test_fn, start_epoch, episode_per_test, logger, env_step, - reward_metric + __doc__ = BaseTrainer.gen_doc("offpolicy") + "\n".join(__doc__.split("\n")[1:]) + + def __init__( + self, + policy: BasePolicy, + train_collector: Collector, + test_collector: Optional[Collector], + max_epoch: int, + step_per_epoch: int, + step_per_collect: int, + episode_per_test: int, + batch_size: int, + update_per_step: Union[int, float] = 1, + train_fn: Optional[Callable[[int, int], None]] = None, + test_fn: Optional[Callable[[int, Optional[int]], None]] = None, + stop_fn: Optional[Callable[[float], bool]] = None, + save_best_fn: Optional[Callable[[BasePolicy], None]] = None, + save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, + resume_from_log: bool = False, + reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, + logger: BaseLogger = LazyLogger(), + verbose: bool = True, + test_in_train: bool = True, + **kwargs: Any, + ): + super().__init__( + learning_type="offpolicy", + policy=policy, + train_collector=train_collector, + test_collector=test_collector, + max_epoch=max_epoch, + step_per_epoch=step_per_epoch, + step_per_collect=step_per_collect, + episode_per_test=episode_per_test, + batch_size=batch_size, + update_per_step=update_per_step, + train_fn=train_fn, + test_fn=test_fn, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + save_checkpoint_fn=save_checkpoint_fn, + resume_from_log=resume_from_log, + reward_metric=reward_metric, + logger=logger, + verbose=verbose, + test_in_train=test_in_train, + **kwargs, ) - best_epoch = start_epoch - best_reward, best_reward_std = test_result["rew"], test_result["rew_std"] - if save_fn: - save_fn(policy) - for epoch in range(1 + start_epoch, 1 + max_epoch): - # train - policy.train() - with tqdm.tqdm( - total=step_per_epoch, desc=f"Epoch #{epoch}", **tqdm_config - ) as t: - while t.n < t.total: - if train_fn: - train_fn(epoch, env_step) - result = train_collector.collect(n_step=step_per_collect) - if result["n/ep"] > 0 and reward_metric: - rew = reward_metric(result["rews"]) - result.update(rews=rew, rew=rew.mean(), rew_std=rew.std()) - env_step += int(result["n/st"]) - t.update(result["n/st"]) - logger.log_train_data(result, env_step) - last_rew = result['rew'] if result["n/ep"] > 0 else last_rew - last_len = result['len'] if result["n/ep"] > 0 else last_len - data = { - "env_step": str(env_step), - "rew": f"{last_rew:.2f}", - "len": str(int(last_len)), - "n/ep": str(int(result["n/ep"])), - "n/st": str(int(result["n/st"])), - } - if result["n/ep"] > 0: - if test_in_train and stop_fn and stop_fn(result["rew"]): - test_result = test_episode( - policy, test_c, test_fn, epoch, episode_per_test, logger, - env_step - ) - if stop_fn(test_result["rew"]): - if save_fn: - save_fn(policy) - logger.save_data( - epoch, env_step, gradient_step, save_checkpoint_fn - ) - t.set_postfix(**data) - return gather_info( - start_time, train_collector, test_collector, - test_result["rew"], test_result["rew_std"] - ) - else: - policy.train() - for _ in range(round(update_per_step * result["n/st"])): - gradient_step += 1 - losses = policy.update(batch_size, train_collector.buffer) - for k in losses.keys(): - stat[k].add(losses[k]) - losses[k] = stat[k].get() - data[k] = f"{losses[k]:.3f}" - logger.log_update_data(losses, gradient_step) - t.set_postfix(**data) - if t.n <= t.total: - t.update() - logger.save_data(epoch, env_step, gradient_step, save_checkpoint_fn) - # test - if test_collector is not None: - test_result = test_episode( - policy, test_c, test_fn, epoch, episode_per_test, logger, env_step, - reward_metric - ) - rew, rew_std = test_result["rew"], test_result["rew_std"] - if best_epoch < 0 or best_reward < rew: - best_epoch, best_reward, best_reward_std = epoch, rew, rew_std - if save_fn: - save_fn(policy) - if verbose: - print( - f"Epoch #{epoch}: test_reward: {rew:.6f} ± {rew_std:.6f}, best_rew" - f"ard: {best_reward:.6f} ± {best_reward_std:.6f} in #{best_epoch}" - ) - if stop_fn and stop_fn(best_reward): - break + def policy_update_fn(self, data: Dict[str, Any], result: Dict[str, Any]) -> None: + """Perform off-policy updates.""" + assert self.train_collector is not None + for _ in range(round(self.update_per_step * result["n/st"])): + self.gradient_step += 1 + losses = self.policy.update(self.batch_size, self.train_collector.buffer) + self.log_update_data(data, losses) - if test_collector is None and save_fn: - save_fn(policy) - if test_collector is None: - return gather_info(start_time, train_collector, None, 0.0, 0.0) - else: - return gather_info( - start_time, train_collector, test_collector, best_reward, best_reward_std - ) +def offpolicy_trainer(*args, **kwargs) -> Dict[str, Union[float, str]]: # type: ignore + """Wrapper for OffPolicyTrainer run method. + + It is identical to ``OffpolicyTrainer(...).run()``. + + :return: See :func:`~tianshou.trainer.gather_info`. + """ + return OffpolicyTrainer(*args, **kwargs).run() + + +offpolicy_trainer_iter = OffpolicyTrainer diff --git a/tianshou/trainer/onpolicy.py b/tianshou/trainer/onpolicy.py index 251c55637..a2234e710 100644 --- a/tianshou/trainer/onpolicy.py +++ b/tianshou/trainer/onpolicy.py @@ -1,209 +1,149 @@ -import time -from collections import defaultdict -from typing import Callable, Dict, Optional, Union +from typing import Any, Callable, Dict, Optional, Union import numpy as np -import tqdm from tianshou.data import Collector from tianshou.policy import BasePolicy -from tianshou.trainer import gather_info, test_episode -from tianshou.utils import BaseLogger, LazyLogger, MovAvg, tqdm_config - - -def onpolicy_trainer( - policy: BasePolicy, - train_collector: Collector, - test_collector: Optional[Collector], - max_epoch: int, - step_per_epoch: int, - repeat_per_collect: int, - episode_per_test: int, - batch_size: int, - step_per_collect: Optional[int] = None, - episode_per_collect: Optional[int] = None, - train_fn: Optional[Callable[[int, int], None]] = None, - test_fn: Optional[Callable[[int, Optional[int]], None]] = None, - stop_fn: Optional[Callable[[float], bool]] = None, - save_fn: Optional[Callable[[BasePolicy], None]] = None, - save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, - resume_from_log: bool = False, - reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, - logger: BaseLogger = LazyLogger(), - verbose: bool = True, - test_in_train: bool = True, -) -> Dict[str, Union[float, str]]: - """A wrapper for on-policy trainer procedure. - - The "step" in trainer means an environment step (a.k.a. transition). +from tianshou.trainer.base import BaseTrainer +from tianshou.utils import BaseLogger, LazyLogger + + +class OnpolicyTrainer(BaseTrainer): + """Create an iterator wrapper for on-policy training procedure. :param policy: an instance of the :class:`~tianshou.policy.BasePolicy` class. :param Collector train_collector: the collector used for training. - :param Collector test_collector: the collector used for testing. If it's None, then - no testing will be performed. + :param Collector test_collector: the collector used for testing. If it's None, + then no testing will be performed. :param int max_epoch: the maximum number of epochs for training. The training - process might be finished before reaching ``max_epoch`` if ``stop_fn`` is set. + process might be finished before reaching ``max_epoch`` if ``stop_fn`` is + set. :param int step_per_epoch: the number of transitions collected per epoch. - :param int repeat_per_collect: the number of repeat time for policy learning, for - example, set it to 2 means the policy needs to learn each given batch data - twice. + :param int repeat_per_collect: the number of repeat time for policy learning, + for example, set it to 2 means the policy needs to learn each given batch + data twice. :param int episode_per_test: the number of episodes for one policy evaluation. - :param int batch_size: the batch size of sample data, which is going to feed in the - policy network. - :param int step_per_collect: the number of transitions the collector would collect - before the network update, i.e., trainer will collect "step_per_collect" - transitions and do some policy network update repeatedly in each epoch. - :param int episode_per_collect: the number of episodes the collector would collect - before the network update, i.e., trainer will collect "episode_per_collect" - episodes and do some policy network update repeatedly in each epoch. - :param function train_fn: a hook called at the beginning of training in each epoch. - It can be used to perform custom additional operations, with the signature ``f( - num_epoch: int, step_idx: int) -> None``. - :param function test_fn: a hook called at the beginning of testing in each epoch. - It can be used to perform custom additional operations, with the signature ``f( - num_epoch: int, step_idx: int) -> None``. - :param function save_fn: a hook called when the undiscounted average mean reward in - evaluation phase gets better, with the signature ``f(policy: BasePolicy) -> - None``. - :param function save_checkpoint_fn: a function to save training process, with the - signature ``f(epoch: int, env_step: int, gradient_step: int) -> None``; you can - save whatever you want. - :param bool resume_from_log: resume env_step/gradient_step and other metadata from - existing tensorboard log. Default to False. + :param int batch_size: the batch size of sample data, which is going to feed in + the policy network. + :param int step_per_collect: the number of transitions the collector would + collect before the network update, i.e., trainer will collect + "step_per_collect" transitions and do some policy network update repeatedly + in each epoch. + :param int episode_per_collect: the number of episodes the collector would + collect before the network update, i.e., trainer will collect + "episode_per_collect" episodes and do some policy network update repeatedly + in each epoch. + :param function train_fn: a hook called at the beginning of training in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function test_fn: a hook called at the beginning of testing in each + epoch. It can be used to perform custom additional operations, with the + signature ``f(num_epoch: int, step_idx: int) -> None``. + :param function save_best_fn: a hook called when the undiscounted average mean + reward in evaluation phase gets better, with the signature + ``f(policy: BasePolicy) -> None``. It was ``save_fn`` previously. + :param function save_checkpoint_fn: a function to save training process, + with the signature ``f(epoch: int, env_step: int, gradient_step: int) + -> None``; you can save whatever you want. + :param bool resume_from_log: resume env_step/gradient_step and other metadata + from existing tensorboard log. Default to False. :param function stop_fn: a function with signature ``f(mean_rewards: float) -> bool``, receives the average undiscounted returns of the testing result, returns a boolean which indicates whether reaching the goal. - :param function reward_metric: a function with signature ``f(rewards: np.ndarray - with shape (num_episode, agent_num)) -> np.ndarray with shape (num_episode,)``, - used in multi-agent RL. We need to return a single scalar for each episode's - result to monitor training in the multi-agent RL setting. This function - specifies what is the desired metric, e.g., the reward of agent 1 or the - average reward over all agents. + :param function reward_metric: a function with signature + ``f(rewards: np.ndarray with shape (num_episode, agent_num)) -> + np.ndarray with shape (num_episode,)``, used in multi-agent RL. + We need to return a single scalar for each episode's result to monitor + training in the multi-agent RL setting. This function specifies what is the + desired metric, e.g., the reward of agent 1 or the average reward over + all agents. :param BaseLogger logger: A logger that logs statistics during training/testing/updating. Default to a logger that doesn't log anything. :param bool verbose: whether to print the information. Default to True. - :param bool test_in_train: whether to test in the training phase. Default to True. - - :return: See :func:`~tianshou.trainer.gather_info`. + :param bool test_in_train: whether to test in the training phase. Default to + True. .. note:: Only either one of step_per_collect and episode_per_collect can be specified. """ - start_epoch, env_step, gradient_step = 0, 0, 0 - if resume_from_log: - start_epoch, env_step, gradient_step = logger.restore_data() - last_rew, last_len = 0.0, 0 - stat: Dict[str, MovAvg] = defaultdict(MovAvg) - start_time = time.time() - train_collector.reset_stat() - test_in_train = test_in_train and ( - train_collector.policy == policy and test_collector is not None - ) - - if test_collector is not None: - test_c: Collector = test_collector # for mypy - test_collector.reset_stat() - test_result = test_episode( - policy, test_c, test_fn, start_epoch, episode_per_test, logger, env_step, - reward_metric + + __doc__ = BaseTrainer.gen_doc("onpolicy") + "\n".join(__doc__.split("\n")[1:]) + + def __init__( + self, + policy: BasePolicy, + train_collector: Collector, + test_collector: Optional[Collector], + max_epoch: int, + step_per_epoch: int, + repeat_per_collect: int, + episode_per_test: int, + batch_size: int, + step_per_collect: Optional[int] = None, + episode_per_collect: Optional[int] = None, + train_fn: Optional[Callable[[int, int], None]] = None, + test_fn: Optional[Callable[[int, Optional[int]], None]] = None, + stop_fn: Optional[Callable[[float], bool]] = None, + save_best_fn: Optional[Callable[[BasePolicy], None]] = None, + save_checkpoint_fn: Optional[Callable[[int, int, int], None]] = None, + resume_from_log: bool = False, + reward_metric: Optional[Callable[[np.ndarray], np.ndarray]] = None, + logger: BaseLogger = LazyLogger(), + verbose: bool = True, + test_in_train: bool = True, + **kwargs: Any, + ): + super().__init__( + learning_type="onpolicy", + policy=policy, + train_collector=train_collector, + test_collector=test_collector, + max_epoch=max_epoch, + step_per_epoch=step_per_epoch, + repeat_per_collect=repeat_per_collect, + episode_per_test=episode_per_test, + batch_size=batch_size, + step_per_collect=step_per_collect, + episode_per_collect=episode_per_collect, + train_fn=train_fn, + test_fn=test_fn, + stop_fn=stop_fn, + save_best_fn=save_best_fn, + save_checkpoint_fn=save_checkpoint_fn, + resume_from_log=resume_from_log, + reward_metric=reward_metric, + logger=logger, + verbose=verbose, + test_in_train=test_in_train, + **kwargs, ) - best_epoch = start_epoch - best_reward, best_reward_std = test_result["rew"], test_result["rew_std"] - if save_fn: - save_fn(policy) - - for epoch in range(1 + start_epoch, 1 + max_epoch): - # train - policy.train() - with tqdm.tqdm( - total=step_per_epoch, desc=f"Epoch #{epoch}", **tqdm_config - ) as t: - while t.n < t.total: - if train_fn: - train_fn(epoch, env_step) - result = train_collector.collect( - n_step=step_per_collect, n_episode=episode_per_collect - ) - if result["n/ep"] > 0 and reward_metric: - rew = reward_metric(result["rews"]) - result.update(rews=rew, rew=rew.mean(), rew_std=rew.std()) - env_step += int(result["n/st"]) - t.update(result["n/st"]) - logger.log_train_data(result, env_step) - last_rew = result['rew'] if result["n/ep"] > 0 else last_rew - last_len = result['len'] if result["n/ep"] > 0 else last_len - data = { - "env_step": str(env_step), - "rew": f"{last_rew:.2f}", - "len": str(int(last_len)), - "n/ep": str(int(result["n/ep"])), - "n/st": str(int(result["n/st"])), - } - if result["n/ep"] > 0: - if test_in_train and stop_fn and stop_fn(result["rew"]): - test_result = test_episode( - policy, test_c, test_fn, epoch, episode_per_test, logger, - env_step - ) - if stop_fn(test_result["rew"]): - if save_fn: - save_fn(policy) - logger.save_data( - epoch, env_step, gradient_step, save_checkpoint_fn - ) - t.set_postfix(**data) - return gather_info( - start_time, train_collector, test_collector, - test_result["rew"], test_result["rew_std"] - ) - else: - policy.train() - losses = policy.update( - 0, - train_collector.buffer, - batch_size=batch_size, - repeat=repeat_per_collect - ) - train_collector.reset_buffer(keep_statistics=True) - step = max( - [1] + [len(v) for v in losses.values() if isinstance(v, list)] - ) - gradient_step += step - for k in losses.keys(): - stat[k].add(losses[k]) - losses[k] = stat[k].get() - data[k] = f"{losses[k]:.3f}" - logger.log_update_data(losses, gradient_step) - t.set_postfix(**data) - if t.n <= t.total: - t.update() - logger.save_data(epoch, env_step, gradient_step, save_checkpoint_fn) - # test - if test_collector is not None: - test_result = test_episode( - policy, test_c, test_fn, epoch, episode_per_test, logger, env_step, - reward_metric - ) - rew, rew_std = test_result["rew"], test_result["rew_std"] - if best_epoch < 0 or best_reward < rew: - best_epoch, best_reward, best_reward_std = epoch, rew, rew_std - if save_fn: - save_fn(policy) - if verbose: - print( - f"Epoch #{epoch}: test_reward: {rew:.6f} ± {rew_std:.6f}, best_rew" - f"ard: {best_reward:.6f} ± {best_reward_std:.6f} in #{best_epoch}" - ) - if stop_fn and stop_fn(best_reward): - break - - if test_collector is None and save_fn: - save_fn(policy) - - if test_collector is None: - return gather_info(start_time, train_collector, None, 0.0, 0.0) - else: - return gather_info( - start_time, train_collector, test_collector, best_reward, best_reward_std + + def policy_update_fn( + self, data: Dict[str, Any], result: Optional[Dict[str, Any]] = None + ) -> None: + """Perform one on-policy update.""" + assert self.train_collector is not None + losses = self.policy.update( + 0, + self.train_collector.buffer, + batch_size=self.batch_size, + repeat=self.repeat_per_collect, ) + self.train_collector.reset_buffer(keep_statistics=True) + step = max([1] + [len(v) for v in losses.values() if isinstance(v, list)]) + self.gradient_step += step + self.log_update_data(data, losses) + + +def onpolicy_trainer(*args, **kwargs) -> Dict[str, Union[float, str]]: # type: ignore + """Wrapper for OnpolicyTrainer run method. + + It is identical to ``OnpolicyTrainer(...).run()``. + + :return: See :func:`~tianshou.trainer.gather_info`. + """ + return OnpolicyTrainer(*args, **kwargs).run() + + +onpolicy_trainer_iter = OnpolicyTrainer diff --git a/tianshou/trainer/utils.py b/tianshou/trainer/utils.py index 9bb841248..585fdf23e 100644 --- a/tianshou/trainer/utils.py +++ b/tianshou/trainer/utils.py @@ -35,8 +35,8 @@ def test_episode( def gather_info( start_time: float, - train_c: Optional[Collector], - test_c: Optional[Collector], + train_collector: Optional[Collector], + test_collector: Optional[Collector], best_reward: float, best_reward_std: float, ) -> Dict[str, Union[float, str]]: @@ -57,20 +57,20 @@ def gather_info( * ``best_reward`` the best reward over the test results; * ``duration`` the total elapsed time. """ - duration = time.time() - start_time + duration = max(0, time.time() - start_time) model_time = duration result: Dict[str, Union[float, str]] = { "duration": f"{duration:.2f}s", "train_time/model": f"{model_time:.2f}s", } - if test_c is not None: - model_time = duration - test_c.collect_time - test_speed = test_c.collect_step / test_c.collect_time + if test_collector is not None: + model_time = max(0, duration - test_collector.collect_time) + test_speed = test_collector.collect_step / test_collector.collect_time result.update( { - "test_step": test_c.collect_step, - "test_episode": test_c.collect_episode, - "test_time": f"{test_c.collect_time:.2f}s", + "test_step": test_collector.collect_step, + "test_episode": test_collector.collect_episode, + "test_time": f"{test_collector.collect_time:.2f}s", "test_speed": f"{test_speed:.2f} step/s", "best_reward": best_reward, "best_result": f"{best_reward:.2f} ± {best_reward_std:.2f}", @@ -78,17 +78,19 @@ def gather_info( "train_time/model": f"{model_time:.2f}s", } ) - if train_c is not None: - model_time -= train_c.collect_time - if test_c is not None: - train_speed = train_c.collect_step / (duration - test_c.collect_time) + if train_collector is not None: + model_time = max(0, model_time - train_collector.collect_time) + if test_collector is not None: + train_speed = train_collector.collect_step / ( + duration - test_collector.collect_time + ) else: - train_speed = train_c.collect_step / duration + train_speed = train_collector.collect_step / duration result.update( { - "train_step": train_c.collect_step, - "train_episode": train_c.collect_episode, - "train_time/collector": f"{train_c.collect_time:.2f}s", + "train_step": train_collector.collect_step, + "train_episode": train_collector.collect_episode, + "train_time/collector": f"{train_collector.collect_time:.2f}s", "train_time/model": f"{model_time:.2f}s", "train_speed": f"{train_speed:.2f} step/s", } diff --git a/tianshou/utils/__init__.py b/tianshou/utils/__init__.py index 25ceda186..8acd06c4a 100644 --- a/tianshou/utils/__init__.py +++ b/tianshou/utils/__init__.py @@ -4,9 +4,19 @@ from tianshou.utils.logger.base import BaseLogger, LazyLogger from tianshou.utils.logger.tensorboard import BasicLogger, TensorboardLogger from tianshou.utils.logger.wandb import WandbLogger +from tianshou.utils.lr_scheduler import MultipleLRSchedulers from tianshou.utils.statistics import MovAvg, RunningMeanStd +from tianshou.utils.warning import deprecation __all__ = [ - "MovAvg", "RunningMeanStd", "tqdm_config", "BaseLogger", "TensorboardLogger", - "BasicLogger", "LazyLogger", "WandbLogger" + "MovAvg", + "RunningMeanStd", + "tqdm_config", + "BaseLogger", + "TensorboardLogger", + "BasicLogger", + "LazyLogger", + "WandbLogger", + "deprecation", + "MultipleLRSchedulers", ] diff --git a/tianshou/utils/logger/tensorboard.py b/tianshou/utils/logger/tensorboard.py index 469d32765..843ff012e 100644 --- a/tianshou/utils/logger/tensorboard.py +++ b/tianshou/utils/logger/tensorboard.py @@ -1,10 +1,10 @@ -import warnings from typing import Any, Callable, Optional, Tuple from tensorboard.backend.event_processing import event_accumulator from torch.utils.tensorboard import SummaryWriter from tianshou.utils.logger.base import LOG_DATA_TYPE, BaseLogger +from tianshou.utils.warning import deprecation class TensorboardLogger(BaseLogger): @@ -17,6 +17,8 @@ class TensorboardLogger(BaseLogger): :param int update_interval: the log interval in log_update_data(). Default to 1000. :param int save_interval: the save interval in save_data(). Default to 1 (save at the end of each epoch). + :param bool write_flush: whether to flush tensorboard result after each + add_scalar operation. Default to True. """ def __init__( @@ -26,16 +28,19 @@ def __init__( test_interval: int = 1, update_interval: int = 1000, save_interval: int = 1, + write_flush: bool = True, ) -> None: super().__init__(train_interval, test_interval, update_interval) self.save_interval = save_interval + self.write_flush = write_flush self.last_save_step = -1 self.writer = writer def write(self, step_type: str, step: int, data: LOG_DATA_TYPE) -> None: for k, v in data.items(): self.writer.add_scalar(k, v, global_step=step) - self.writer.flush() # issue #482 + if self.write_flush: # issue 580 + self.writer.flush() # issue #482 def save_data( self, @@ -81,7 +86,8 @@ class BasicLogger(TensorboardLogger): """ def __init__(self, *args: Any, **kwargs: Any) -> None: - warnings.warn( - "Deprecated soon: BasicLogger has renamed to TensorboardLogger in #427." + deprecation( + "Class BasicLogger is marked as deprecated and will be removed soon. " + "Please use TensorboardLogger instead." ) super().__init__(*args, **kwargs) diff --git a/tianshou/utils/logger/wandb.py b/tianshou/utils/logger/wandb.py index f9c047c59..e63a7bc7f 100644 --- a/tianshou/utils/logger/wandb.py +++ b/tianshou/utils/logger/wandb.py @@ -2,7 +2,9 @@ import os from typing import Callable, Optional, Tuple -from tianshou.utils import BaseLogger +from torch.utils.tensorboard import SummaryWriter + +from tianshou.utils import BaseLogger, TensorboardLogger from tianshou.utils.logger.base import LOG_DATA_TYPE try: @@ -17,22 +19,22 @@ class WandbLogger(BaseLogger): This logger creates three panels with plots: train, test, and update. Make sure to select the correct access for each panel in weights and biases: - - ``train/env_step`` for train plots - - ``test/env_step`` for test plots - - ``update/gradient_step`` for update plots - Example of usage: :: - with wandb.init(project="My Project"): - logger = WandBLogger() - result = onpolicy_trainer(policy, train_collector, test_collector, - logger=logger) + logger = WandbLogger() + logger.load(SummaryWriter(log_path)) + result = onpolicy_trainer(policy, train_collector, test_collector, + logger=logger) :param int train_interval: the log interval in log_train_data(). Default to 1000. :param int test_interval: the log interval in log_test_data(). Default to 1. :param int update_interval: the log interval in log_update_data(). Default to 1000. + :param int save_interval: the save interval in save_data(). Default to 1 (save at + the end of each epoch). + :param bool write_flush: whether to flush tensorboard result after each + add_scalar operation. Default to True. :param str project: W&B project name. Default to "tianshou". :param str name: W&B run name. Default to None. If None, random name is assigned. :param str entity: W&B team/organization name. Default to None. @@ -46,7 +48,8 @@ def __init__( test_interval: int = 1, update_interval: int = 1000, save_interval: int = 1000, - project: str = 'tianshou', + write_flush: bool = True, + project: Optional[str] = None, name: Optional[str] = None, entity: Optional[str] = None, run_id: Optional[str] = None, @@ -55,7 +58,10 @@ def __init__( super().__init__(train_interval, test_interval, update_interval) self.last_save_step = -1 self.save_interval = save_interval + self.write_flush = write_flush self.restored = False + if project is None: + project = os.getenv("WANDB_PROJECT", "tianshou") self.wandb_run = wandb.init( project=project, @@ -63,14 +69,28 @@ def __init__( id=run_id, resume="allow", entity=entity, + sync_tensorboard=True, monitor_gym=True, config=config, # type: ignore ) if not wandb.run else wandb.run self.wandb_run._label(repo="tianshou") # type: ignore + self.tensorboard_logger: Optional[TensorboardLogger] = None + + def load(self, writer: SummaryWriter) -> None: + self.writer = writer + self.tensorboard_logger = TensorboardLogger( + writer, self.train_interval, self.test_interval, self.update_interval, + self.save_interval, self.write_flush + ) def write(self, step_type: str, step: int, data: LOG_DATA_TYPE) -> None: - data[step_type] = step - wandb.log(data) + if self.tensorboard_logger is None: + raise Exception( + "`logger` needs to load the Tensorboard Writer before " + "writing data. Try `logger.load(SummaryWriter(log_path))`" + ) + else: + self.tensorboard_logger.write(step_type, step, data) def save_data( self, diff --git a/tianshou/utils/lr_scheduler.py b/tianshou/utils/lr_scheduler.py new file mode 100644 index 000000000..36a08b207 --- /dev/null +++ b/tianshou/utils/lr_scheduler.py @@ -0,0 +1,42 @@ +from typing import Dict, List + +import torch + + +class MultipleLRSchedulers: + """A wrapper for multiple learning rate schedulers. + + Every time :meth:`~tianshou.utils.MultipleLRSchedulers.step` is called, + it calls the step() method of each of the schedulers that it contains. + Example usage: + :: + + scheduler1 = ConstantLR(opt1, factor=0.1, total_iters=2) + scheduler2 = ExponentialLR(opt2, gamma=0.9) + scheduler = MultipleLRSchedulers(scheduler1, scheduler2) + policy = PPOPolicy(..., lr_scheduler=scheduler) + """ + + def __init__(self, *args: torch.optim.lr_scheduler.LambdaLR): + self.schedulers = args + + def step(self) -> None: + """Take a step in each of the learning rate schedulers.""" + for scheduler in self.schedulers: + scheduler.step() + + def state_dict(self) -> List[Dict]: + """Get state_dict for each of the learning rate schedulers. + + :return: A list of state_dict of learning rate schedulers. + """ + return [s.state_dict() for s in self.schedulers] + + def load_state_dict(self, state_dict: List[Dict]) -> None: + """Load states from state_dict. + + :param List[Dict] state_dict: A list of learning rate scheduler + state_dict, in the same order as the schedulers. + """ + for (s, sd) in zip(self.schedulers, state_dict): + s.__dict__.update(sd) diff --git a/tianshou/utils/net/discrete.py b/tianshou/utils/net/discrete.py index a81e1c645..51d19b73b 100644 --- a/tianshou/utils/net/discrete.py +++ b/tianshou/utils/net/discrete.py @@ -160,7 +160,7 @@ class ImplicitQuantileNetwork(Critic): :param preprocess_net: a self-defined preprocess_net which output a flattened hidden state. - :param int action_dim: the dimension of action space. + :param int action_shape: a sequence of int for the shape of action. :param hidden_sizes: a sequence of int for constructing the MLP after preprocess_net. Default to empty sequence (where the MLP now contains only a single linear layer). @@ -254,7 +254,7 @@ class FullQuantileFunction(ImplicitQuantileNetwork): :param preprocess_net: a self-defined preprocess_net which output a flattened hidden state. - :param int action_dim: the dimension of action space. + :param int action_shape: a sequence of int for the shape of action. :param hidden_sizes: a sequence of int for constructing the MLP after preprocess_net. Default to empty sequence (where the MLP now contains only a single linear layer). diff --git a/tianshou/utils/warning.py b/tianshou/utils/warning.py new file mode 100644 index 000000000..93c5ccec3 --- /dev/null +++ b/tianshou/utils/warning.py @@ -0,0 +1,8 @@ +import warnings + +warnings.simplefilter("once", DeprecationWarning) + + +def deprecation(msg: str) -> None: + """Deprecation warning wrapper.""" + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) From abe26b9db47d41b1f495ad8cb5528700e151e1d3 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 20:27:57 +0200 Subject: [PATCH 15/47] Remove unused imports --- examples/box2d/{bdq_train.py => bdq_bipedal_discrete.py} | 6 +++--- test/discrete/test_bdq.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) rename examples/box2d/{bdq_train.py => bdq_bipedal_discrete.py} (96%) diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_bipedal_discrete.py similarity index 96% rename from examples/box2d/bdq_train.py rename to examples/box2d/bdq_bipedal_discrete.py index 22493623a..f457e5873 100644 --- a/examples/box2d/bdq_train.py +++ b/examples/box2d/bdq_bipedal_discrete.py @@ -8,8 +8,8 @@ import torch from torch.utils.tensorboard import SummaryWriter -from tianshou.data import Collector, PrioritizedVectorReplayBuffer, VectorReplayBuffer -from tianshou.env import DiscreteToContinuous, DummyVectorEnv, SubprocVectorEnv +from tianshou.data import Collector, VectorReplayBuffer +from tianshou.env import DiscreteToContinuous, SubprocVectorEnv from tianshou.policy import BDQPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils import TensorboardLogger @@ -19,7 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument('--task', type=str, default='BipedalWalkerHardcore-v3') + parser.add_argument('--task', type=str, default='BipedalWalker-v3') # network architecture parser.add_argument( '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 5df1e6d60..412426bf4 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -1,6 +1,4 @@ import argparse -import datetime -import os import pprint import gym From 89d9c6e17598585bca426866af0ada3d812fde42 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Wed, 27 Apr 2022 20:32:21 +0200 Subject: [PATCH 16/47] Merge commit 'abe26b9db47d41b1f495ad8cb5528700e151e1d3' --- examples/box2d/{bdq_train.py => bdq_bipedal_discrete.py} | 6 +++--- test/discrete/test_bdq.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) rename examples/box2d/{bdq_train.py => bdq_bipedal_discrete.py} (96%) diff --git a/examples/box2d/bdq_train.py b/examples/box2d/bdq_bipedal_discrete.py similarity index 96% rename from examples/box2d/bdq_train.py rename to examples/box2d/bdq_bipedal_discrete.py index 22493623a..f457e5873 100644 --- a/examples/box2d/bdq_train.py +++ b/examples/box2d/bdq_bipedal_discrete.py @@ -8,8 +8,8 @@ import torch from torch.utils.tensorboard import SummaryWriter -from tianshou.data import Collector, PrioritizedVectorReplayBuffer, VectorReplayBuffer -from tianshou.env import DiscreteToContinuous, DummyVectorEnv, SubprocVectorEnv +from tianshou.data import Collector, VectorReplayBuffer +from tianshou.env import DiscreteToContinuous, SubprocVectorEnv from tianshou.policy import BDQPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils import TensorboardLogger @@ -19,7 +19,7 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument('--task', type=str, default='BipedalWalkerHardcore-v3') + parser.add_argument('--task', type=str, default='BipedalWalker-v3') # network architecture parser.add_argument( '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 5df1e6d60..412426bf4 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -1,6 +1,4 @@ import argparse -import datetime -import os import pprint import gym From dba85b48276bebed7a767a31fb791a7576f3c53a Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Fri, 29 Apr 2022 13:24:57 +0200 Subject: [PATCH 17/47] Fix some linting issues --- examples/box2d/bdq_bipedal_discrete.py | 8 ++++---- test/continuous/test_sac_with_il.py | 23 +++-------------------- tianshou/env/gym_wrappers.py | 7 ++++--- tianshou/policy/imitation/cql.py | 6 ++++-- tianshou/policy/modelfree/bdq.py | 2 +- tianshou/utils/net/common.py | 17 +++++++++-------- 6 files changed, 25 insertions(+), 38 deletions(-) diff --git a/examples/box2d/bdq_bipedal_discrete.py b/examples/box2d/bdq_bipedal_discrete.py index f457e5873..5a92e4013 100644 --- a/examples/box2d/bdq_bipedal_discrete.py +++ b/examples/box2d/bdq_bipedal_discrete.py @@ -26,20 +26,20 @@ def get_args(): ) parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--action_per_branch', type=int, default=32) + parser.add_argument('--action_per_branch', type=int, default=25) # training hyperparameters parser.add_argument('--seed', type=int, default=0) parser.add_argument('--eps-test', type=float, default=0.) parser.add_argument('--eps-train', type=float, default=0.73) parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=5e-5) + parser.add_argument('--lr', type=float, default=1e-4) parser.add_argument('--gamma', type=float, default=0.99) parser.add_argument('--target-update-freq', type=int, default=1000) - parser.add_argument('--epoch', type=int, default=100) + parser.add_argument('--epoch', type=int, default=1000) parser.add_argument('--step-per-epoch', type=int, default=80000) parser.add_argument('--step-per-collect', type=int, default=16) parser.add_argument('--update-per-step', type=float, default=0.0625) - parser.add_argument('--batch-size', type=int, default=128) + parser.add_argument('--batch-size', type=int, default=512) parser.add_argument('--training-num', type=int, default=100) parser.add_argument('--test-num', type=int, default=10) # other diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index 310c16d62..e8885e9c6 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -23,13 +23,8 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v0') -<<<<<<< HEAD parser.add_argument('--reward_threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) -======= - parser.add_argument('--reward-threshold', type=float, default=None) - parser.add_argument('--seed', type=int, default=1) ->>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-3) parser.add_argument('--critic-lr', type=float, default=1e-3) @@ -72,19 +67,12 @@ def test_sac_with_il(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: -<<<<<<< HEAD default_reward_threshold = { "Pendulum-v1": -250, "CartPole-v0": 195, "NChain-v0": 3400 } args.reward_threshold = default_reward_threshold.get(args.task) -======= - default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} - args.reward_threshold = default_reward_threshold.get( - args.task, env.spec.reward_threshold - ) ->>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d # you can also use tianshou.env.SubprocVectorEnv # seed np.random.seed(args.seed) @@ -152,7 +140,7 @@ def test_sac_with_il(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_best_fn(policy): + def save_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -170,19 +158,14 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_best_fn=save_best_fn, + save_fn=save_fn, logger=logger ) assert stop_fn(result['best_reward']) # here we define an imitation collector with a trivial policy policy.eval() -<<<<<<< HEAD args.reward_threshold = -300 # lower the goal -======= - if args.task.startswith("Pendulum"): - args.reward_threshold -= 50 # lower the goal ->>>>>>> 7f23748347d6bf4aebce3931f7e57291012cd98d net = Actor( Net( args.state_shape, @@ -216,7 +199,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_best_fn=save_best_fn, + save_fn=save_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index e8692532e..c3bc6e29c 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -7,7 +7,8 @@ class DiscreteToContinuous(gym.ActionWrapper): Args: env (gym.Environment): gym envirionment with continous action space. - action_per_branch (int): number of discrete actions in each dimension of the action space. + action_per_branch (int): number of discrete actions in each dimension + of the action space. """ @@ -22,8 +23,8 @@ def __init__(self, env: gym.Env, action_per_branch: int) -> None: ) setattr(self.action_space, "n", num_branches) self.mesh = [] - for l, h in zip(low, high): - self.mesh.append(np.linspace(l, h, action_per_branch)) + for lo, hi in zip(low, high): + self.mesh.append(np.linspace(lo, hi, action_per_branch)) def action(self, act: np.ndarray) -> np.ndarray: # modify act diff --git a/tianshou/policy/imitation/cql.py b/tianshou/policy/imitation/cql.py index 521e3f715..b43502880 100644 --- a/tianshou/policy/imitation/cql.py +++ b/tianshou/policy/imitation/cql.py @@ -212,10 +212,12 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: if len(obs.shape) > 2: tmp_obs = obs.unsqueeze(1) \ .repeat(1, self.num_repeat_actions, 1, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-2], obs.shape[-1]) + .view(batch_size * self.num_repeat_actions, + obs.shape[-2], obs.shape[-1]) tmp_obs_next = obs_next.unsqueeze(1) \ .repeat(1, self.num_repeat_actions, 1, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-2], obs.shape[-1]) + .view(batch_size * self.num_repeat_actions, + obs.shape[-2], obs.shape[-1]) else: tmp_obs = obs.unsqueeze(1) \ .repeat(1, self.num_repeat_actions, 1) \ diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index c3c8adbf7..4d36f60c2 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -114,7 +114,7 @@ def process_fn( def forward( self, batch: Batch, - state: Optional[Union[dict, Batch, np.ndarray]] = None, + state: Optional[Union[Dict, Batch, np.ndarray]] = None, model: str = "model", input: str = "obs", **kwargs: Any, diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 8cae5726c..248f721b3 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -316,13 +316,14 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, class BDQNet(nn.Module): """Branching dual Q network. - Network for the BDQPolicy, it uses a common network module, a value module and action "branches" one for each dimension. - It allows for a linear scaling of Q-value the output w.r.t. the number of dimensions in the action space. - For more info please refer to: arXiv:1711.08946. - + Network for the BDQPolicy, it uses a common network module, a value module + and action "branches" one for each dimension.It allows for a linear scaling + of Q-value the output w.r.t. the number of dimensions in the action space. + For more info please refer to: arXiv:1711.08946. :param state_shape: int or a sequence of int of the shape of state. :param action_shape: int or a sequence of int of the shape of action. - :param action_peer_branch: int or a sequence of int of the number of actions in each dimension. + :param action_peer_branch: int or a sequence of int of the number of actions in + each dimension. :param common_hidden_sizes: shape of the common MLP network passed in as a list. :param value_hidden_sizes: shape of the value MLP network passed in as a list. :param action_hidden_sizes: shape of the action MLP network passed in as a list. @@ -346,9 +347,9 @@ def __init__( state_shape: Union[int, Sequence[int]], action_shape: Union[int, Sequence[int]] = 0, action_per_branch: int = 2, - common_hidden_sizes: list[int] = [], - value_hidden_sizes: list[int] = [], - action_hidden_sizes: list[int] = [], + common_hidden_sizes: List[int] = [], + value_hidden_sizes: List[int] = [], + action_hidden_sizes: List[int] = [], norm_layer: Optional[ModuleType] = None, activation: Optional[ModuleType] = nn.ReLU, device: Union[str, int, torch.device] = "cpu", From af6b5dca839a2cbc97c983afb21b085545e88a1e Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Fri, 29 Apr 2022 08:40:19 -0400 Subject: [PATCH 18/47] revert all unrelated things --- test/continuous/test_ddpg.py | 16 +++++++-------- test/continuous/test_npg.py | 12 +++++------ test/continuous/test_ppo.py | 30 ++++++++++++++++------------ test/continuous/test_sac_with_il.py | 21 ++++++++++--------- test/continuous/test_td3.py | 12 +++++------ test/continuous/test_trpo.py | 12 +++++------ test/modelbased/test_psrl.py | 12 +++++------ test/offline/gather_cartpole_data.py | 12 ++++------- test/offline/gather_pendulum_data.py | 12 +++++------ test/offline/test_bcq.py | 13 ++++++------ test/offline/test_cql.py | 11 +++++----- test/offline/test_discrete_bcq.py | 2 +- test/offline/test_discrete_cql.py | 14 +++++-------- test/offline/test_discrete_crr.py | 12 +++++------ tianshou/env/__init__.py | 9 +++++++-- tianshou/utils/net/common.py | 22 ++++++++++---------- 16 files changed, 103 insertions(+), 119 deletions(-) diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index 33f0ea4ee..7e64d9ee1 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -20,7 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -54,12 +54,10 @@ def test_ddpg(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -114,7 +112,7 @@ def test_ddpg(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -132,7 +130,7 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/continuous/test_npg.py b/test/continuous/test_npg.py index 66be7cee7..b7ec50c82 100644 --- a/test/continuous/test_npg.py +++ b/test/continuous/test_npg.py @@ -21,7 +21,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--lr', type=float, default=1e-3) @@ -57,12 +57,10 @@ def test_npg(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_ppo.py b/test/continuous/test_ppo.py index dc1227ab6..e0858edf1 100644 --- a/test/continuous/test_ppo.py +++ b/test/continuous/test_ppo.py @@ -11,7 +11,7 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.env import DummyVectorEnv from tianshou.policy import PPOPolicy -from tianshou.trainer import onpolicy_trainer +from tianshou.trainer import OnpolicyTrainer from tianshou.utils import TensorboardLogger from tianshou.utils.net.common import ActorCritic, Net from tianshou.utils.net.continuous import ActorProb, Critic @@ -20,7 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--lr', type=float, default=1e-3) @@ -61,12 +61,10 @@ def test_ppo(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( @@ -131,7 +129,7 @@ def dist(*logits): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer, save_interval=args.save_interval) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -159,7 +157,7 @@ def save_checkpoint_fn(epoch, env_step, gradient_step): print("Fail to restore policy and optim.") # trainer - result = onpolicy_trainer( + trainer = OnpolicyTrainer( policy, train_collector, test_collector, @@ -170,15 +168,21 @@ def save_checkpoint_fn(epoch, env_step, gradient_step): args.batch_size, episode_per_collect=args.episode_per_collect, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger, resume_from_log=args.resume, save_checkpoint_fn=save_checkpoint_fn ) - assert stop_fn(result['best_reward']) + + for epoch, epoch_stat, info in trainer: + print(f"Epoch: {epoch}") + print(epoch_stat) + print(info) + + assert stop_fn(info["best_reward"]) if __name__ == '__main__': - pprint.pprint(result) + pprint.pprint(info) # Let's watch its performance! env = gym.make(args.task) policy.eval() diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index e8885e9c6..fcaaad0c9 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -23,7 +23,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v0') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -67,12 +67,10 @@ def test_sac_with_il(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # seed np.random.seed(args.seed) @@ -140,7 +138,7 @@ def test_sac_with_il(args=get_args()): writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): + def save_best_fn(policy): torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) def stop_fn(mean_rewards): @@ -158,14 +156,15 @@ def stop_fn(mean_rewards): args.batch_size, update_per_step=args.update_per_step, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) # here we define an imitation collector with a trivial policy policy.eval() - args.reward_threshold = -300 # lower the goal + if args.task.startswith("Pendulum"): + args.reward_threshold -= 50 # lower the goal net = Actor( Net( args.state_shape, @@ -199,7 +198,7 @@ def stop_fn(mean_rewards): args.test_num, args.batch_size, stop_fn=stop_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) assert stop_fn(result['best_reward']) diff --git a/test/continuous/test_td3.py b/test/continuous/test_td3.py index 5f078e6a9..ac557ba12 100644 --- a/test/continuous/test_td3.py +++ b/test/continuous/test_td3.py @@ -20,7 +20,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-4) @@ -56,12 +56,10 @@ def test_td3(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/continuous/test_trpo.py b/test/continuous/test_trpo.py index 3511ca0a7..cc8b39f61 100644 --- a/test/continuous/test_trpo.py +++ b/test/continuous/test_trpo.py @@ -21,7 +21,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--lr', type=float, default=1e-3) @@ -60,12 +60,10 @@ def test_trpo(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/modelbased/test_psrl.py b/test/modelbased/test_psrl.py index 7405ad5c3..3a3023005 100644 --- a/test/modelbased/test_psrl.py +++ b/test/modelbased/test_psrl.py @@ -16,7 +16,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='NChain-v0') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=50000) parser.add_argument('--epoch', type=int, default=5) @@ -46,12 +46,10 @@ def test_psrl(args=get_args()): ) test_envs = envpool.make_gym(args.task, num_envs=args.test_num, seed=args.seed) if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"NChain-v0": 3400} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) print("reward threshold:", args.reward_threshold) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n diff --git a/test/offline/gather_cartpole_data.py b/test/offline/gather_cartpole_data.py index e56795bd9..2e01723f3 100644 --- a/test/offline/gather_cartpole_data.py +++ b/test/offline/gather_cartpole_data.py @@ -22,7 +22,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='CartPole-v0') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=1) parser.add_argument('--eps-test', type=float, default=0.05) parser.add_argument('--eps-train', type=float, default=0.1) @@ -61,14 +61,10 @@ def gather_data(): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 190, - "NChain-v0": 3400 - } + default_reward_threshold = {"CartPole-v0": 190} args.reward_threshold = default_reward_threshold.get( - args.task - ) # lower the goal? + args.task, env.spec.reward_threshold + ) # train_envs = gym.make(args.task) # you can also use tianshou.env.SubprocVectorEnv train_envs = DummyVectorEnv( diff --git a/test/offline/gather_pendulum_data.py b/test/offline/gather_pendulum_data.py index 1f0a14518..f60ec3696 100644 --- a/test/offline/gather_pendulum_data.py +++ b/test/offline/gather_pendulum_data.py @@ -23,7 +23,7 @@ def expert_file_name(): def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[128, 128]) @@ -70,12 +70,10 @@ def gather_data(): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) # you can also use tianshou.env.SubprocVectorEnv # train_envs = gym.make(args.task) train_envs = DummyVectorEnv( diff --git a/test/offline/test_bcq.py b/test/offline/test_bcq.py index 4210726f5..dccb2ec90 100644 --- a/test/offline/test_bcq.py +++ b/test/offline/test_bcq.py @@ -26,7 +26,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v1') - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument('--seed', type=int, default=0) parser.add_argument('--hidden-sizes', type=int, nargs='*', default=[64]) parser.add_argument('--actor-lr', type=float, default=1e-3) @@ -75,12 +75,11 @@ def test_bcq(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -1100, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) # too low? + # too low? + default_reward_threshold = {"Pendulum-v0": -1100, "Pendulum-v1": -1100} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_cql.py b/test/offline/test_cql.py index 59cfe1b1f..6d52bca7a 100644 --- a/test/offline/test_cql.py +++ b/test/offline/test_cql.py @@ -80,12 +80,11 @@ def test_cql(args=get_args()): args.action_shape = env.action_space.shape or env.action_space.n args.max_action = env.action_space.high[0] # float if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -1100, - "CartPole-v0": 195, - "NChain-v0": 3400 - } # too low? - args.reward_threshold = default_reward_threshold.get(args.task) + # too low? + default_reward_threshold = {"Pendulum-v0": -1200, "Pendulum-v1": -1200} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) args.state_dim = args.state_shape[0] args.action_dim = args.action_shape[0] diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index a2e11f741..4c8f15da0 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -25,7 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument('--reward-threshold', type=float, default=None) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-4) diff --git a/test/offline/test_discrete_cql.py b/test/offline/test_discrete_cql.py index fae843375..eca810fb6 100644 --- a/test/offline/test_discrete_cql.py +++ b/test/offline/test_discrete_cql.py @@ -24,9 +24,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument( - '--reward_threshold', type=float, default=None - ) # lower the goal + parser.add_argument("--reward-threshold", type=float, default=None) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.001) parser.add_argument("--lr", type=float, default=3e-3) @@ -58,12 +56,10 @@ def test_discrete_cql(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 170, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"CartPole-v0": 170} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) diff --git a/test/offline/test_discrete_crr.py b/test/offline/test_discrete_crr.py index 4f0aedead..9f47b32e7 100644 --- a/test/offline/test_discrete_crr.py +++ b/test/offline/test_discrete_crr.py @@ -25,7 +25,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument("--task", type=str, default="CartPole-v0") - parser.add_argument('--reward_threshold', type=float, default=None) + parser.add_argument("--reward-threshold", type=float, default=None) parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--lr", type=float, default=7e-4) parser.add_argument("--gamma", type=float, default=0.99) @@ -54,12 +54,10 @@ def test_discrete_crr(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 180, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) + default_reward_threshold = {"CartPole-v0": 180} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) diff --git a/tianshou/env/__init__.py b/tianshou/env/__init__.py index f72181535..3df537865 100644 --- a/tianshou/env/__init__.py +++ b/tianshou/env/__init__.py @@ -15,6 +15,11 @@ pass __all__ = [ - "BaseVectorEnv", "DummyVectorEnv", "SubprocVectorEnv", "ShmemVectorEnv", - "RayVectorEnv", "PettingZooEnv", "DiscreteToContinuous" + "BaseVectorEnv", + "DummyVectorEnv", + "SubprocVectorEnv", + "ShmemVectorEnv", + "RayVectorEnv", + "PettingZooEnv", + "DiscreteToContinuous", ] diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 248f721b3..2cbef52d7 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -257,17 +257,17 @@ def forward( obs = obs.unsqueeze(-2) obs = self.fc1(obs) self.nn.flatten_parameters() - # if state is None: - obs, (hidden, cell) = self.nn(obs) - # else: - # # we store the stack data in [bsz, len, ...] format - # # but pytorch rnn needs [len, bsz, ...] - # obs, (hidden, cell) = self.nn( - # obs, ( - # state["hidden"].transpose(0, 1).contiguous(), - # state["cell"].transpose(0, 1).contiguous() - # ) - # ) + if state is None: + obs, (hidden, cell) = self.nn(obs) + else: + # we store the stack data in [bsz, len, ...] format + # but pytorch rnn needs [len, bsz, ...] + obs, (hidden, cell) = self.nn( + obs, ( + state["hidden"].transpose(0, 1).contiguous(), + state["cell"].transpose(0, 1).contiguous() + ) + ) obs = self.fc2(obs[:, -1]) # please ensure the first dim is batch size: [bsz, len, ...] return obs, { From 1b705d0e4f806751812c9995794fa0192f7cd0b3 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Fri, 29 Apr 2022 08:41:59 -0400 Subject: [PATCH 19/47] revert again --- test/continuous/test_ddpg.py | 1 - test/continuous/test_sac_with_il.py | 2 +- test/offline/test_discrete_bcq.py | 7 ------- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/test/continuous/test_ddpg.py b/test/continuous/test_ddpg.py index 7e64d9ee1..cc9aafe5d 100644 --- a/test/continuous/test_ddpg.py +++ b/test/continuous/test_ddpg.py @@ -48,7 +48,6 @@ def get_args(): def test_ddpg(args=get_args()): - torch.set_num_threads(1) # we just need only one thread for NN env = gym.make(args.task) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n diff --git a/test/continuous/test_sac_with_il.py b/test/continuous/test_sac_with_il.py index fcaaad0c9..a204e55e8 100644 --- a/test/continuous/test_sac_with_il.py +++ b/test/continuous/test_sac_with_il.py @@ -24,7 +24,7 @@ def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--task', type=str, default='Pendulum-v0') parser.add_argument('--reward-threshold', type=float, default=None) - parser.add_argument('--seed', type=int, default=0) + parser.add_argument('--seed', type=int, default=1) parser.add_argument('--buffer-size', type=int, default=20000) parser.add_argument('--actor-lr', type=float, default=1e-3) parser.add_argument('--critic-lr', type=float, default=1e-3) diff --git a/test/offline/test_discrete_bcq.py b/test/offline/test_discrete_bcq.py index 4c8f15da0..51380fb62 100644 --- a/test/offline/test_discrete_bcq.py +++ b/test/offline/test_discrete_bcq.py @@ -66,13 +66,6 @@ def test_discrete_bcq(args=get_args()): test_envs = DummyVectorEnv( [lambda: gym.make(args.task) for _ in range(args.test_num)] ) - if args.reward_threshold is None: - default_reward_threshold = { - "Pendulum-v1": -250, - "CartPole-v0": 195, - "NChain-v0": 3400 - } - args.reward_threshold = default_reward_threshold.get(args.task) # seed np.random.seed(args.seed) torch.manual_seed(args.seed) From 74be2564c62b3dc73a59667170f32c18226e8f78 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Fri, 29 Apr 2022 08:58:21 -0400 Subject: [PATCH 20/47] update --- ...bdq_bipedal_discrete.py => bipedal_bdq.py} | 65 +++++++++---------- test/discrete/test_bdq.py | 62 +++++++++--------- 2 files changed, 59 insertions(+), 68 deletions(-) rename examples/box2d/{bdq_bipedal_discrete.py => bipedal_bdq.py} (67%) diff --git a/examples/box2d/bdq_bipedal_discrete.py b/examples/box2d/bipedal_bdq.py similarity index 67% rename from examples/box2d/bdq_bipedal_discrete.py rename to examples/box2d/bipedal_bdq.py index 5a92e4013..6d4d8d44c 100644 --- a/examples/box2d/bdq_bipedal_discrete.py +++ b/examples/box2d/bipedal_bdq.py @@ -19,42 +19,39 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument('--task', type=str, default='BipedalWalker-v3') + parser.add_argument("--task", type=str, default="BipedalWalker-v3") # network architecture parser.add_argument( - '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] + "--common-hidden-sizes", type=int, nargs="*", default=[512, 256] ) - parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--action_per_branch', type=int, default=25) + parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[128]) + parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[128]) + parser.add_argument("--action-per-branch", type=int, default=25) # training hyperparameters - parser.add_argument('--seed', type=int, default=0) - parser.add_argument('--eps-test', type=float, default=0.) - parser.add_argument('--eps-train', type=float, default=0.73) - parser.add_argument('--buffer-size', type=int, default=100000) - parser.add_argument('--lr', type=float, default=1e-4) - parser.add_argument('--gamma', type=float, default=0.99) - parser.add_argument('--target-update-freq', type=int, default=1000) - parser.add_argument('--epoch', type=int, default=1000) - parser.add_argument('--step-per-epoch', type=int, default=80000) - parser.add_argument('--step-per-collect', type=int, default=16) - parser.add_argument('--update-per-step', type=float, default=0.0625) - parser.add_argument('--batch-size', type=int, default=512) - parser.add_argument('--training-num', type=int, default=100) - parser.add_argument('--test-num', type=int, default=10) + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--eps-test", type=float, default=0.) + parser.add_argument("--eps-train", type=float, default=0.73) + parser.add_argument("--buffer-size", type=int, default=100000) + parser.add_argument("--lr", type=float, default=1e-4) + parser.add_argument("--gamma", type=float, default=0.99) + parser.add_argument("--target-update-freq", type=int, default=1000) + parser.add_argument("--epoch", type=int, default=1000) + parser.add_argument("--step-per-epoch", type=int, default=80000) + parser.add_argument("--step-per-collect", type=int, default=16) + parser.add_argument("--update-per-step", type=float, default=0.0625) + parser.add_argument("--batch-size", type=int, default=512) + parser.add_argument("--training-num", type=int, default=100) + parser.add_argument("--test-num", type=int, default=10) # other - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) return parser.parse_args() def test_bdq(args=get_args()): - if args.task == 'Humanoid-v3': - args.reward_treshold = 3000 - env = gym.make(args.task) env = DiscreteToContinuous(env, args.action_per_branch) @@ -111,17 +108,15 @@ def test_bdq(args=get_args()): train_collector.collect(n_step=args.batch_size * args.training_num) # log current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") - log_path = os.path.join(args.logdir, 'bdq', args.task, current_time) + log_path = os.path.join(args.logdir, "bdq", args.task, current_time) writer = SummaryWriter(log_path) logger = TensorboardLogger(writer) - def save_fn(policy): - torch.save(policy.state_dict(), os.path.join(log_path, 'policy.pth')) + def save_best_fn(policy): + torch.save(policy.state_dict(), os.path.join(log_path, "policy.pth")) def stop_fn(mean_rewards): - return mean_rewards >= getattr( - env, "spec.reward_threshold", args.reward_treshold - ) + return mean_rewards >= getattr(env.spec.reward_threshold) def train_fn(epoch, env_step): # exp decay eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) @@ -144,12 +139,12 @@ def test_fn(epoch, env_step): # stop_fn=stop_fn, train_fn=train_fn, test_fn=test_fn, - save_fn=save_fn, + save_best_fn=save_best_fn, logger=logger ) - # assert stop_fn(result['best_reward']) - if __name__ == '__main__': + # assert stop_fn(result["best_reward"]) + if __name__ == "__main__": pprint.pprint(result) # Let's watch its performance! policy.eval() @@ -161,5 +156,5 @@ def test_fn(epoch, env_step): print(f"Final reward: {rews.mean()}, length: {lens.mean()}") -if __name__ == '__main__': +if __name__ == "__main__": test_bdq(get_args()) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 412426bf4..5e4278ed2 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -15,47 +15,43 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument('--task', type=str, default='BipedalWalker-v3') + parser.add_argument("--task", type=str, default="BipedalWalker-v3") # network architecture parser.add_argument( - '--common_hidden-sizes', type=int, nargs='*', default=[512, 256] + "--common-hidden-sizes", type=int, nargs="*", default=[512, 256] ) - parser.add_argument('--action_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--value_hidden-sizes', type=int, nargs='*', default=[128]) - parser.add_argument('--action_per_branch', type=int, default=32) + parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[128]) + parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[128]) + parser.add_argument("--action-per-branch", type=int, default=32) # training hyperparameters - parser.add_argument('--seed', type=int, default=1626) - parser.add_argument('--eps-test', type=float, default=0.05) - parser.add_argument('--eps-train', type=float, default=0.1) - parser.add_argument('--buffer-size', type=int, default=20000) - parser.add_argument('--lr', type=float, default=1e-3) - parser.add_argument('--gamma', type=float, default=0.9) - parser.add_argument('--n-step', type=int, default=3) - parser.add_argument('--target-update-freq', type=int, default=320) - parser.add_argument('--epoch', type=int, default=20) - parser.add_argument('--step-per-epoch', type=int, default=10000) - parser.add_argument('--step-per-collect', type=int, default=10) - parser.add_argument('--update-per-step', type=float, default=0.1) - parser.add_argument('--batch-size', type=int, default=64) - parser.add_argument('--training-num', type=int, default=10) - parser.add_argument('--test-num', type=int, default=100) - parser.add_argument('--logdir', type=str, default='log') - parser.add_argument('--render', type=float, default=0.) - parser.add_argument('--prioritized-replay', action="store_true", default=False) - parser.add_argument('--alpha', type=float, default=0.6) - parser.add_argument('--beta', type=float, default=0.4) + parser.add_argument("--seed", type=int, default=1626) + parser.add_argument("--eps-test", type=float, default=0.05) + parser.add_argument("--eps-train", type=float, default=0.1) + parser.add_argument("--buffer-size", type=int, default=20000) + parser.add_argument("--lr", type=float, default=1e-3) + parser.add_argument("--gamma", type=float, default=0.9) + parser.add_argument("--n-step", type=int, default=3) + parser.add_argument("--target-update-freq", type=int, default=320) + parser.add_argument("--epoch", type=int, default=20) + parser.add_argument("--step-per-epoch", type=int, default=10000) + parser.add_argument("--step-per-collect", type=int, default=10) + parser.add_argument("--update-per-step", type=float, default=0.1) + parser.add_argument("--batch-size", type=int, default=64) + parser.add_argument("--training-num", type=int, default=10) + parser.add_argument("--test-num", type=int, default=100) + parser.add_argument("--logdir", type=str, default="log") + parser.add_argument("--render", type=float, default=0.) + parser.add_argument("--prioritized-replay", action="store_true", default=False) + parser.add_argument("--alpha", type=float, default=0.6) + parser.add_argument("--beta", type=float, default=0.4) parser.add_argument( - '--device', type=str, default='cuda' if torch.cuda.is_available() else 'cpu' + "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) args = parser.parse_known_args()[0] return args - return parser.parse_args() def test_bdq(args=get_args()): - if args.task == 'Humanoid-v3': - args.reward_treshold = 3000 - env = gym.make(args.task) env = DiscreteToContinuous(env, args.action_per_branch) @@ -131,8 +127,8 @@ def test_fn(epoch, env_step): test_fn=test_fn, ) - # assert stop_fn(result['best_reward']) - if __name__ == '__main__': + # assert stop_fn(result["best_reward"]) + if __name__ == "__main__": pprint.pprint(result) # Let's watch its performance! policy.eval() @@ -144,5 +140,5 @@ def test_fn(epoch, env_step): print(f"Final reward: {rews.mean()}, length: {lens.mean()}") -if __name__ == '__main__': +if __name__ == "__main__": test_bdq(get_args()) From 1c5c2fb157e3d045855c193398fa098bbabb8ca4 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Fri, 29 Apr 2022 15:46:11 +0200 Subject: [PATCH 21/47] Change name of env wrapper to ContinuousToDiscrete --- examples/box2d/bipedal_bdq.py | 12 ++++++------ test/discrete/test_bdq.py | 8 ++++---- tianshou/env/__init__.py | 4 ++-- tianshou/env/gym_wrappers.py | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 6d4d8d44c..99f2fd6f0 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -9,7 +9,7 @@ from torch.utils.tensorboard import SummaryWriter from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import DiscreteToContinuous, SubprocVectorEnv +from tianshou.env import ContinuousToDiscrete, SubprocVectorEnv from tianshou.policy import BDQPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils import TensorboardLogger @@ -53,7 +53,7 @@ def get_args(): def test_bdq(args=get_args()): env = gym.make(args.task) - env = DiscreteToContinuous(env, args.action_per_branch) + env = ContinuousToDiscrete(env, args.action_per_branch) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n @@ -62,18 +62,18 @@ def test_bdq(args=get_args()): print("Actions shape:", args.action_shape) print("Actions per branch:", args.action_per_branch) - # train_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + # train_envs = ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) # you can also use tianshou.env.SubprocVectorEnv train_envs = SubprocVectorEnv( [ - lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num) ] ) - # test_envs = DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + # test_envs = ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) test_envs = SubprocVectorEnv( [ - lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.test_num) ] ) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 5e4278ed2..cbb88375d 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -6,7 +6,7 @@ import torch from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import DiscreteToContinuous, SubprocVectorEnv +from tianshou.env import ContinuousToDiscrete, SubprocVectorEnv from tianshou.policy import BDQPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils.net.common import BDQNet @@ -53,7 +53,7 @@ def get_args(): def test_bdq(args=get_args()): env = gym.make(args.task) - env = DiscreteToContinuous(env, args.action_per_branch) + env = ContinuousToDiscrete(env, args.action_per_branch) args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n @@ -64,13 +64,13 @@ def test_bdq(args=get_args()): train_envs = SubprocVectorEnv( [ - lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num) ] ) test_envs = SubprocVectorEnv( [ - lambda: DiscreteToContinuous(gym.make(args.task), args.action_per_branch) + lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.test_num) ] ) diff --git a/tianshou/env/__init__.py b/tianshou/env/__init__.py index 3df537865..10030a877 100644 --- a/tianshou/env/__init__.py +++ b/tianshou/env/__init__.py @@ -1,6 +1,6 @@ """Env package.""" -from tianshou.env.gym_wrappers import DiscreteToContinuous +from tianshou.env.gym_wrappers import ContinuousToDiscrete from tianshou.env.venvs import ( BaseVectorEnv, DummyVectorEnv, @@ -21,5 +21,5 @@ "ShmemVectorEnv", "RayVectorEnv", "PettingZooEnv", - "DiscreteToContinuous", + "ContinuousToDiscrete", ] diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index c3bc6e29c..83d94d579 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -2,7 +2,7 @@ import numpy as np -class DiscreteToContinuous(gym.ActionWrapper): +class ContinuousToDiscrete(gym.ActionWrapper): """Gym environment wrapper to take discrete action in a continous environment. Args: From 605f8b6e783b3b916d817bc52ae5d12c2340e82d Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Fri, 29 Apr 2022 16:27:13 +0200 Subject: [PATCH 22/47] Fix magic number, now its an argument --- examples/box2d/bipedal_bdq.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 99f2fd6f0..2faa30cff 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -31,6 +31,7 @@ def get_args(): parser.add_argument("--seed", type=int, default=0) parser.add_argument("--eps-test", type=float, default=0.) parser.add_argument("--eps-train", type=float, default=0.73) + parser.add_argument("--eps-decay", type=float, default=5e-6) parser.add_argument("--buffer-size", type=int, default=100000) parser.add_argument("--lr", type=float, default=1e-4) parser.add_argument("--gamma", type=float, default=0.99) @@ -119,7 +120,7 @@ def stop_fn(mean_rewards): return mean_rewards >= getattr(env.spec.reward_threshold) def train_fn(epoch, env_step): # exp decay - eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) + eps = max(args.eps_train * (1 - args.eps_decay)**env_step, args.eps_test) policy.set_eps(eps) def test_fn(epoch, env_step): From f92df57807d6fd80e03180e9723c4999e2a1f596 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Fri, 29 Apr 2022 16:39:56 +0200 Subject: [PATCH 23/47] BDQPolicy -> BranchingDQNPolicy, BDQNet -> BranchingNet --- examples/box2d/bipedal_bdq.py | 8 ++--- test/discrete/test_bdq.py | 10 +++---- tianshou/policy/__init__.py | 4 +-- tianshou/policy/modelfree/bdq.py | 51 ++++++++------------------------ tianshou/utils/net/common.py | 4 +-- 5 files changed, 25 insertions(+), 52 deletions(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 2faa30cff..15952a101 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -10,10 +10,10 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.env import ContinuousToDiscrete, SubprocVectorEnv -from tianshou.policy import BDQPolicy +from tianshou.policy import BranchingDQNPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils import TensorboardLogger -from tianshou.utils.net.common import BDQNet +from tianshou.utils.net.common import BranchingNet def get_args(): @@ -84,7 +84,7 @@ def test_bdq(args=get_args()): train_envs.seed(args.seed) test_envs.seed(args.seed) # model - net = BDQNet( + net = BranchingNet( args.state_shape, args.action_shape, args.action_per_branch, @@ -94,7 +94,7 @@ def test_bdq(args=get_args()): device=args.device, ).to(args.device) optim = torch.optim.Adam(net.parameters(), lr=args.lr) - policy = BDQPolicy( + policy = BranchingDQNPolicy( net, optim, args.gamma, target_update_freq=args.target_update_freq ) # collector diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index cbb88375d..dc8280f05 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -7,9 +7,9 @@ from tianshou.data import Collector, VectorReplayBuffer from tianshou.env import ContinuousToDiscrete, SubprocVectorEnv -from tianshou.policy import BDQPolicy +from tianshou.policy import BranchingDQNPolicy from tianshou.trainer import offpolicy_trainer -from tianshou.utils.net.common import BDQNet +from tianshou.utils.net.common import BranchingNet def get_args(): @@ -81,7 +81,7 @@ def test_bdq(args=get_args()): train_envs.seed(args.seed) test_envs.seed(args.seed) # model - net = BDQNet( + net = BranchingNet( args.state_shape, args.action_shape, args.action_per_branch, @@ -91,10 +91,10 @@ def test_bdq(args=get_args()): device=args.device, ).to(args.device) optim = torch.optim.Adam(net.parameters(), lr=args.lr) - policy = BDQPolicy( + policy = BranchingDQNPolicy( net, optim, args.gamma, target_update_freq=args.target_update_freq ) - # collector + # collector train_collector = Collector( policy, train_envs, diff --git a/tianshou/policy/__init__.py b/tianshou/policy/__init__.py index 01d660c56..0d2b2f878 100644 --- a/tianshou/policy/__init__.py +++ b/tianshou/policy/__init__.py @@ -4,7 +4,7 @@ from tianshou.policy.base import BasePolicy from tianshou.policy.random import RandomPolicy from tianshou.policy.modelfree.dqn import DQNPolicy -from tianshou.policy.modelfree.bdq import BDQPolicy +from tianshou.policy.modelfree.bdq import BranchingDQNPolicy from tianshou.policy.modelfree.c51 import C51Policy from tianshou.policy.modelfree.rainbow import RainbowPolicy from tianshou.policy.modelfree.qrdqn import QRDQNPolicy @@ -34,7 +34,7 @@ "BasePolicy", "RandomPolicy", "DQNPolicy", - "BDQPolicy", + "BranchingDQNPolicy", "C51Policy", "RainbowPolicy", "QRDQNPolicy", diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 4d36f60c2..4e2889973 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -5,10 +5,10 @@ import torch from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch_as -from tianshou.policy import BasePolicy +from tianshou.policy import DQNPolicy -class BDQPolicy(BasePolicy): +class BranchingDQNPolicy(DQNPolicy): """Implementation of the Branching dual Q network arXiv:1711.08946. :param torch.nn.Module model: a model following the rules in @@ -33,39 +33,15 @@ def __init__( model: torch.nn.Module, optim: torch.optim.Optimizer, discount_factor: float = 0.99, + estimation_step: int = 1, target_update_freq: int = 0, reward_normalization: bool = False, is_double: bool = True, **kwargs: Any, ) -> None: - super().__init__(**kwargs) - self.model = model - self.optim = optim - self.eps = 0.0 - assert 0.0 <= discount_factor <= 1.0, "discount factor should be in [0, 1]" - self._gamma = discount_factor - self._target = target_update_freq > 0 - self._freq = target_update_freq - self._iter = 0 - if self._target: - self.model_old = deepcopy(self.model) - self.model_old.eval() - self._rew_norm = reward_normalization - self._is_double = is_double - - def set_eps(self, eps: float) -> None: - """Set the eps for epsilon-greedy exploration.""" - self.eps = eps - - def train(self, mode: bool = True) -> "BDQPolicy": - """Set the module in training mode, except for the target network.""" - self.training = mode - self.model.train(mode) - return self - - def sync_weight(self) -> None: - """Synchronize the weight for the target network.""" - self.model_old.load_state_dict(self.model.state_dict()) + super().__init__(model, optim, discount_factor, estimation_step, + target_update_freq, reward_normalization, is_double) + assert estimation_step == 1, "N-step bigger than one is not supported by BDQ" def _target_q(self, batch: Batch) -> torch.Tensor: result = self(batch, input="obs_next") @@ -75,11 +51,11 @@ def _target_q(self, batch: Batch) -> torch.Tensor: else: target_q = result.logits if self._is_double: - act = self(batch, input="obs_next").act + act = np.expand_dims(self(batch, input="obs_next").act, -1) + act = torch.from_numpy(act).to(target_q.get_device()) else: - act = target_q.max(dim=-1).indices.cpu() - - return np.squeeze(np.take_along_axis(target_q, np.expand_dims(act, -1), -1)) + act = target_q.max(-1).indices.unsqueeze(-1) + return torch.gather(target_q, -1, act) def _compute_return( self, @@ -91,7 +67,7 @@ def _compute_return( rew = batch.rew with torch.no_grad(): target_q_torch = self._target_q(batch) # (bsz, ?) - target_q = to_numpy(target_q_torch) + target_q = to_numpy(target_q_torch).squeeze() end_flag = buffer.done.copy() end_flag[buffer.unfinished_index()] = True end_flag = end_flag[indice] @@ -107,7 +83,7 @@ def _compute_return( def process_fn( self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray ) -> Batch: - """Compute the return for BDQ targets.""" + """Compute the 1-step return for BDQ targets.""" batch = self._compute_return(batch, buffer, indices) return batch @@ -179,6 +155,3 @@ def exploration_noise(self, act: Union[np.ndarray, Batch], rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] return act - - def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: - return act diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index 2cbef52d7..f66543155 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -313,10 +313,10 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, return self.net(obs=obs.cuda(), *args, **kwargs) -class BDQNet(nn.Module): +class BranchingNet(nn.Module): """Branching dual Q network. - Network for the BDQPolicy, it uses a common network module, a value module + Network for the BranchingDQNPolicy, it uses a common network module, a value module and action "branches" one for each dimension.It allows for a linear scaling of Q-value the output w.r.t. the number of dimensions in the action space. For more info please refer to: arXiv:1711.08946. From 65a03eb985820fc45a8f957637cedd5d4025652d Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Mon, 9 May 2022 14:58:49 +0200 Subject: [PATCH 24/47] Accommodate for one-dimensional discrete action space --- tianshou/env/gym_wrappers.py | 1 + tianshou/policy/modelfree/bdq.py | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 83d94d579..7dcee0fed 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -25,6 +25,7 @@ def __init__(self, env: gym.Env, action_per_branch: int) -> None: self.mesh = [] for lo, hi in zip(low, high): self.mesh.append(np.linspace(lo, hi, action_per_branch)) + self.mesh = np.array(self.mesh) def action(self, act: np.ndarray) -> np.ndarray: # modify act diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 4e2889973..d23ad213a 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -1,4 +1,3 @@ -from copy import deepcopy from typing import Any, Dict, Optional, Union import numpy as np @@ -6,6 +5,7 @@ from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch_as from tianshou.policy import DQNPolicy +from tianshou.utils.net.common import BranchingNet class BranchingDQNPolicy(DQNPolicy): @@ -30,7 +30,7 @@ class BranchingDQNPolicy(DQNPolicy): def __init__( self, - model: torch.nn.Module, + model: BranchingNet, optim: torch.optim.Optimizer, discount_factor: float = 0.99, estimation_step: int = 1, @@ -42,6 +42,8 @@ def __init__( super().__init__(model, optim, discount_factor, estimation_step, target_update_freq, reward_normalization, is_double) assert estimation_step == 1, "N-step bigger than one is not supported by BDQ" + self.max_action_num = self.model.action_per_branch + self.num_branches = self.model.num_branches def _target_q(self, batch: Batch) -> torch.Tensor: result = self(batch, input="obs_next") @@ -55,7 +57,7 @@ def _target_q(self, batch: Batch) -> torch.Tensor: act = torch.from_numpy(act).to(target_q.get_device()) else: act = target_q.max(-1).indices.unsqueeze(-1) - return torch.gather(target_q, -1, act) + return torch.gather(target_q, -1, act).squeeze() def _compute_return( self, @@ -67,12 +69,13 @@ def _compute_return( rew = batch.rew with torch.no_grad(): target_q_torch = self._target_q(batch) # (bsz, ?) - target_q = to_numpy(target_q_torch).squeeze() + target_q = to_numpy(target_q_torch) end_flag = buffer.done.copy() end_flag[buffer.unfinished_index()] = True end_flag = end_flag[indice] - _target_q = rew + gamma * np.mean(target_q, -1) * (1 - end_flag) - target_q = np.repeat(_target_q[..., None], target_q.shape[-1], axis=-1) + mean_target_q = np.mean(target_q, -1) if len(target_q.shape) > 1 else target_q + _target_q = rew + gamma * mean_target_q * (1 - end_flag) + target_q = np.repeat(_target_q[..., None], self.num_branches, axis=-1) target_q = np.repeat(target_q[..., None], self.max_action_num, axis=-1) batch.returns = to_torch_as(target_q, target_q_torch) @@ -114,11 +117,7 @@ def forward( obs = batch[input] obs_next = obs.obs if hasattr(obs, "obs") else obs logits, hidden = model(obs_next, state=state, info=batch.info) - if not hasattr(self, "max_action_num"): - self.max_action_num = logits.shape[-1] - act = to_numpy(logits.max(dim=-1)[1].squeeze()) - if len(act.shape) == 1: - act = np.expand_dims(act, 0) + act = to_numpy(logits.max(dim=-1)[1]) return Batch(logits=logits, act=act, state=hidden) def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: @@ -135,7 +134,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: returns = returns * act_mask td_error = (returns - act_q) loss = (td_error.pow(2).sum(-1).mean(-1) * weight).mean() - batch.weight = td_error.sum(-1).sum(-1) # prio-buffer + # batch.weight = td_error.sum(-1).sum(-1) # prio-buffer loss.backward() self.optim.step() self._iter += 1 @@ -144,8 +143,6 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: def exploration_noise(self, act: Union[np.ndarray, Batch], batch: Batch) -> Union[np.ndarray, Batch]: if isinstance(act, np.ndarray) and not np.isclose(self.eps, 0.0): - if len(act.shape) == 1: - act = np.expand_dims(act, 0) bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps rand_act = np.random.randint( @@ -155,3 +152,7 @@ def exploration_noise(self, act: Union[np.ndarray, Batch], rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] return act + + def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: + # Important, used by collector + return act \ No newline at end of file From 2590ce3b1b6729bcb8b3223dbfb5a98eded6259d Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Mon, 9 May 2022 15:00:42 +0200 Subject: [PATCH 25/47] Test bdq on pendulum environment --- examples/box2d/bipedal_bdq.py | 4 ++-- test/discrete/test_bdq.py | 40 +++++++++++++++++++++----------- tianshou/policy/modelfree/bdq.py | 8 ++++--- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 15952a101..eea0d7ad8 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -33,7 +33,7 @@ def get_args(): parser.add_argument("--eps-train", type=float, default=0.73) parser.add_argument("--eps-decay", type=float, default=5e-6) parser.add_argument("--buffer-size", type=int, default=100000) - parser.add_argument("--lr", type=float, default=1e-4) + parser.add_argument("--lr", type=float, default=1e-5) parser.add_argument("--gamma", type=float, default=0.99) parser.add_argument("--target-update-freq", type=int, default=1000) parser.add_argument("--epoch", type=int, default=1000) @@ -41,7 +41,7 @@ def get_args(): parser.add_argument("--step-per-collect", type=int, default=16) parser.add_argument("--update-per-step", type=float, default=0.0625) parser.add_argument("--batch-size", type=int, default=512) - parser.add_argument("--training-num", type=int, default=100) + parser.add_argument("--training-num", type=int, default=20) parser.add_argument("--test-num", type=int, default=10) # other parser.add_argument("--logdir", type=str, default="log") diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index dc8280f05..1b0445f59 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -15,35 +15,37 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument("--task", type=str, default="BipedalWalker-v3") + parser.add_argument("--task", type=str, default="Pendulum-v0") + parser.add_argument('--reward-threshold', type=float, default=None) # network architecture parser.add_argument( "--common-hidden-sizes", type=int, nargs="*", default=[512, 256] ) parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[128]) parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[128]) - parser.add_argument("--action-per-branch", type=int, default=32) + parser.add_argument("--action-per-branch", type=int, default=40) # training hyperparameters parser.add_argument("--seed", type=int, default=1626) parser.add_argument("--eps-test", type=float, default=0.05) - parser.add_argument("--eps-train", type=float, default=0.1) + parser.add_argument("--eps-train", type=float, default=0.76) + parser.add_argument("--eps-decay", type=float, default=1e-5) parser.add_argument("--buffer-size", type=int, default=20000) - parser.add_argument("--lr", type=float, default=1e-3) + parser.add_argument("--lr", type=float, default=5e-4) parser.add_argument("--gamma", type=float, default=0.9) parser.add_argument("--n-step", type=int, default=3) - parser.add_argument("--target-update-freq", type=int, default=320) - parser.add_argument("--epoch", type=int, default=20) - parser.add_argument("--step-per-epoch", type=int, default=10000) + parser.add_argument("--target-update-freq", type=int, default=1000) + parser.add_argument("--epoch", type=int, default=200) + parser.add_argument("--step-per-epoch", type=int, default=80000) parser.add_argument("--step-per-collect", type=int, default=10) parser.add_argument("--update-per-step", type=float, default=0.1) - parser.add_argument("--batch-size", type=int, default=64) + parser.add_argument("--batch-size", type=int, default=128) parser.add_argument("--training-num", type=int, default=10) - parser.add_argument("--test-num", type=int, default=100) + parser.add_argument("--test-num", type=int, default=10) parser.add_argument("--logdir", type=str, default="log") parser.add_argument("--render", type=float, default=0.) - parser.add_argument("--prioritized-replay", action="store_true", default=False) - parser.add_argument("--alpha", type=float, default=0.6) - parser.add_argument("--beta", type=float, default=0.4) + # parser.add_argument("--prioritized-replay", action="store_true", default=False) + # parser.add_argument("--alpha", type=float, default=0.6) + # parser.add_argument("--beta", type=float, default=0.4) parser.add_argument( "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) @@ -58,6 +60,12 @@ def test_bdq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + if args.reward_threshold is None: + default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} + args.reward_threshold = default_reward_threshold.get( + args.task, env.spec.reward_threshold + ) + print("Observations shape:", args.state_shape) print("Actions shape:", args.action_shape) print("Actions per branch:", args.action_per_branch) @@ -94,7 +102,7 @@ def test_bdq(args=get_args()): policy = BranchingDQNPolicy( net, optim, args.gamma, target_update_freq=args.target_update_freq ) - # collector + # collector train_collector = Collector( policy, train_envs, @@ -106,12 +114,15 @@ def test_bdq(args=get_args()): train_collector.collect(n_step=args.batch_size * args.training_num) def train_fn(epoch, env_step): # exp decay - eps = max(args.eps_train * (1 - 5e-6)**env_step, args.eps_test) + eps = max(args.eps_train * (1 - args.eps_decay)**env_step, args.eps_test) policy.set_eps(eps) def test_fn(epoch, env_step): policy.set_eps(args.eps_test) + def stop_fn(mean_rewards): + return mean_rewards >= args.reward_threshold + # trainer result = offpolicy_trainer( policy, @@ -125,6 +136,7 @@ def test_fn(epoch, env_step): update_per_step=args.update_per_step, train_fn=train_fn, test_fn=test_fn, + stop_fn=stop_fn, ) # assert stop_fn(result["best_reward"]) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index d23ad213a..552477a9f 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -39,8 +39,10 @@ def __init__( is_double: bool = True, **kwargs: Any, ) -> None: - super().__init__(model, optim, discount_factor, estimation_step, - target_update_freq, reward_normalization, is_double) + super().__init__( + model, optim, discount_factor, estimation_step, target_update_freq, + reward_normalization, is_double + ) assert estimation_step == 1, "N-step bigger than one is not supported by BDQ" self.max_action_num = self.model.action_per_branch self.num_branches = self.model.num_branches @@ -155,4 +157,4 @@ def exploration_noise(self, act: Union[np.ndarray, Batch], def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: # Important, used by collector - return act \ No newline at end of file + return act From aabe4a289938af2b1f3a643575f2ca34c406d7fa Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Mon, 9 May 2022 16:47:14 +0200 Subject: [PATCH 26/47] Run local contrib tests --- test/discrete/test_bdq.py | 7 +------ tianshou/env/gym_wrappers.py | 6 +++--- tianshou/policy/modelfree/bdq.py | 5 +++-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 1b0445f59..e2b9559c7 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -32,9 +32,8 @@ def get_args(): parser.add_argument("--buffer-size", type=int, default=20000) parser.add_argument("--lr", type=float, default=5e-4) parser.add_argument("--gamma", type=float, default=0.9) - parser.add_argument("--n-step", type=int, default=3) parser.add_argument("--target-update-freq", type=int, default=1000) - parser.add_argument("--epoch", type=int, default=200) + parser.add_argument("--epoch", type=int, default=10) parser.add_argument("--step-per-epoch", type=int, default=80000) parser.add_argument("--step-per-collect", type=int, default=10) parser.add_argument("--update-per-step", type=float, default=0.1) @@ -42,10 +41,6 @@ def get_args(): parser.add_argument("--training-num", type=int, default=10) parser.add_argument("--test-num", type=int, default=10) parser.add_argument("--logdir", type=str, default="log") - parser.add_argument("--render", type=float, default=0.) - # parser.add_argument("--prioritized-replay", action="store_true", default=False) - # parser.add_argument("--alpha", type=float, default=0.6) - # parser.add_argument("--beta", type=float, default=0.4) parser.add_argument( "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 7dcee0fed..eeb52f5c6 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -22,10 +22,10 @@ def __init__(self, env: gym.Env, action_per_branch: int) -> None: [action_per_branch] * num_branches ) setattr(self.action_space, "n", num_branches) - self.mesh = [] + mesh = [] for lo, hi in zip(low, high): - self.mesh.append(np.linspace(lo, hi, action_per_branch)) - self.mesh = np.array(self.mesh) + mesh.append(np.linspace(lo, hi, action_per_branch)) + self.mesh = np.array(mesh) def action(self, act: np.ndarray) -> np.ndarray: # modify act diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 552477a9f..8605fa123 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -47,7 +47,8 @@ def __init__( self.max_action_num = self.model.action_per_branch self.num_branches = self.model.num_branches - def _target_q(self, batch: Batch) -> torch.Tensor: + def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: + batch = buffer[indices] # batch.obs_next: s_{t+n} result = self(batch, input="obs_next") if self._target: # target_Q = Q_old(s_, argmax(Q_new(s_, *))) @@ -70,7 +71,7 @@ def _compute_return( ) -> Batch: rew = batch.rew with torch.no_grad(): - target_q_torch = self._target_q(batch) # (bsz, ?) + target_q_torch = self._target_q(buffer, indice) # (bsz, ?) target_q = to_numpy(target_q_torch) end_flag = buffer.done.copy() end_flag[buffer.unfinished_index()] = True From 05fcf50e35179d342da53fbe8a02b086c05869bb Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 10:23:22 +0200 Subject: [PATCH 27/47] fix code format and resolve linter complaints --- examples/box2d/bipedal_bdq.py | 6 ++++-- test/discrete/test_bdq.py | 6 ++++-- tianshou/env/gym_wrappers.py | 6 +++--- tianshou/utils/net/common.py | 15 +++++++-------- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index eea0d7ad8..7004d4258 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -58,9 +58,11 @@ def test_bdq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + args.num_branches = args.action_shape if isinstance( + args.action_shape, int) else args.action_shape[0] print("Observations shape:", args.state_shape) - print("Actions shape:", args.action_shape) + print("Num branches:", args.num_branches) print("Actions per branch:", args.action_per_branch) # train_envs = ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) @@ -86,7 +88,7 @@ def test_bdq(args=get_args()): # model net = BranchingNet( args.state_shape, - args.action_shape, + args.num_branches, args.action_per_branch, args.common_hidden_sizes, args.value_hidden_sizes, diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index e2b9559c7..d97bf3344 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -54,6 +54,8 @@ def test_bdq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n + args.num_branches = args.action_shape if isinstance( + args.action_shape, int) else args.action_shape[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} @@ -62,7 +64,7 @@ def test_bdq(args=get_args()): ) print("Observations shape:", args.state_shape) - print("Actions shape:", args.action_shape) + print("Num branches:", args.num_branches) print("Actions per branch:", args.action_per_branch) train_envs = SubprocVectorEnv( @@ -86,7 +88,7 @@ def test_bdq(args=get_args()): # model net = BranchingNet( args.state_shape, - args.action_shape, + args.num_branches, args.action_per_branch, args.common_hidden_sizes, args.value_hidden_sizes, diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index eeb52f5c6..0b73e6c4f 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -7,9 +7,9 @@ class ContinuousToDiscrete(gym.ActionWrapper): Args: env (gym.Environment): gym envirionment with continous action space. - action_per_branch (int): number of discrete actions in each dimension + action_per_branch (int): number of discrete actions in each dimension of the action space. - + """ def __init__(self, env: gym.Env, action_per_branch: int) -> None: @@ -21,7 +21,7 @@ def __init__(self, env: gym.Env, action_per_branch: int) -> None: self.action_space = gym.spaces.MultiDiscrete( [action_per_branch] * num_branches ) - setattr(self.action_space, "n", num_branches) + self.action_space.n = num_branches mesh = [] for lo, hi in zip(low, high): mesh.append(np.linspace(lo, hi, action_per_branch)) diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index f66543155..e21033050 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -315,14 +315,14 @@ def forward(self, obs: Union[np.ndarray, torch.Tensor], *args: Any, class BranchingNet(nn.Module): """Branching dual Q network. - - Network for the BranchingDQNPolicy, it uses a common network module, a value module + + Network for the BranchingDQNPolicy, it uses a common network module, a value module and action "branches" one for each dimension.It allows for a linear scaling - of Q-value the output w.r.t. the number of dimensions in the action space. - For more info please refer to: arXiv:1711.08946. + of Q-value the output w.r.t. the number of dimensions in the action space. + For more info please refer to: arXiv:1711.08946. :param state_shape: int or a sequence of int of the shape of state. :param action_shape: int or a sequence of int of the shape of action. - :param action_peer_branch: int or a sequence of int of the number of actions in + :param action_peer_branch: int or a sequence of int of the number of actions in each dimension. :param common_hidden_sizes: shape of the common MLP network passed in as a list. :param value_hidden_sizes: shape of the value MLP network passed in as a list. @@ -345,7 +345,7 @@ class BranchingNet(nn.Module): def __init__( self, state_shape: Union[int, Sequence[int]], - action_shape: Union[int, Sequence[int]] = 0, + num_branches: int = 0, action_per_branch: int = 2, common_hidden_sizes: List[int] = [], value_hidden_sizes: List[int] = [], @@ -356,8 +356,7 @@ def __init__( ) -> None: super().__init__() self.device = device - self.num_branches = action_shape if type(action_shape - ) is int else action_shape[0] + self.num_branches = num_branches self.action_per_branch = action_per_branch # common network common_input_dim = int(np.prod(state_shape)) From 480b064f284c0dd6effba9cb3efcb850a7a37331 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 10:58:34 +0200 Subject: [PATCH 28/47] fix code format and resolve linter complaints --- examples/box2d/bipedal_bdq.py | 4 ++-- test/discrete/test_bdq.py | 4 ++-- tianshou/policy/modelfree/bdq.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 7004d4258..3fddc8dd4 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -58,8 +58,8 @@ def test_bdq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n - args.num_branches = args.action_shape if isinstance( - args.action_shape, int) else args.action_shape[0] + args.num_branches = args.action_shape if isinstance(args.action_shape, + int) else args.action_shape[0] print("Observations shape:", args.state_shape) print("Num branches:", args.num_branches) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index d97bf3344..5a923f34a 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -54,8 +54,8 @@ def test_bdq(args=get_args()): args.state_shape = env.observation_space.shape or env.observation_space.n args.action_shape = env.action_space.shape or env.action_space.n - args.num_branches = args.action_shape if isinstance( - args.action_shape, int) else args.action_shape[0] + args.num_branches = args.action_shape if isinstance(args.action_shape, + int) else args.action_shape[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 8605fa123..e4b1d2bd9 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -44,8 +44,8 @@ def __init__( reward_normalization, is_double ) assert estimation_step == 1, "N-step bigger than one is not supported by BDQ" - self.max_action_num = self.model.action_per_branch - self.num_branches = self.model.num_branches + self.max_action_num = model.action_per_branch + self.num_branches = model.num_branches def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: batch = buffer[indices] # batch.obs_next: s_{t+n} From 8d78b88838d436533a5844ebe23928b9a29cda36 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 11:14:30 +0200 Subject: [PATCH 29/47] Add BranchingDQN (BDQ) entry --- README.md | 1 + docs/api/tianshou.policy.rst | 5 +++++ docs/index.rst | 1 + 3 files changed, 7 insertions(+) diff --git a/README.md b/README.md index aaf610549..9af26a350 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ - [Deep Q-Network (DQN)](https://storage.googleapis.com/deepmind-media/dqn/DQNNaturePaper.pdf) - [Double DQN](https://arxiv.org/pdf/1509.06461.pdf) - [Dueling DQN](https://arxiv.org/pdf/1511.06581.pdf) +- [Branching DQN](https://arxiv.org/pdf/1711.08946.pdf) - [Categorical DQN (C51)](https://arxiv.org/pdf/1707.06887.pdf) - [Rainbow DQN (Rainbow)](https://arxiv.org/pdf/1710.02298.pdf) - [Quantile Regression DQN (QRDQN)](https://arxiv.org/pdf/1710.10044.pdf) diff --git a/docs/api/tianshou.policy.rst b/docs/api/tianshou.policy.rst index a0d9bed99..a8057978f 100644 --- a/docs/api/tianshou.policy.rst +++ b/docs/api/tianshou.policy.rst @@ -25,6 +25,11 @@ DQN Family :undoc-members: :show-inheritance: +.. autoclass:: tianshou.policy.BranchingDQNPolicy + :members: + :undoc-members: + :show-inheritance: + .. autoclass:: tianshou.policy.C51Policy :members: :undoc-members: diff --git a/docs/index.rst b/docs/index.rst index 6a82e6d52..99358e119 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,6 +12,7 @@ Welcome to Tianshou! * :class:`~tianshou.policy.DQNPolicy` `Deep Q-Network `_ * :class:`~tianshou.policy.DQNPolicy` `Double DQN `_ * :class:`~tianshou.policy.DQNPolicy` `Dueling DQN `_ +* :class:`~tianshou.policy.BranchingDQNPolicy` `Branching DQN `_ * :class:`~tianshou.policy.C51Policy` `Categorical DQN `_ * :class:`~tianshou.policy.RainbowPolicy` `Rainbow DQN `_ * :class:`~tianshou.policy.QRDQNPolicy` `Quantile Regression DQN `_ From 1f09c6d04262d485477154e5f86a78ab68f27e7a Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 16:57:49 +0200 Subject: [PATCH 30/47] Add BDQ bipedal result --- examples/box2d/README.md | 7 +++++++ examples/box2d/bipedal_bdq.py | 2 +- examples/box2d/results/bdq/BipedalWalker.png | Bin 0 -> 89371 bytes 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 examples/box2d/results/bdq/BipedalWalker.png diff --git a/examples/box2d/README.md b/examples/box2d/README.md index f438b2a4b..f42f19ad9 100644 --- a/examples/box2d/README.md +++ b/examples/box2d/README.md @@ -4,3 +4,10 @@ - If the done penalty is not removed, it converges much slower than before, about 200 epochs (20M env steps) to reach the same performance (\~200 reward) ![](results/sac/BipedalHardcore.png) + + +# BipedalWalker-BDQ + +- To demonstrate the cpabilities of the BDQ to scale up to big discrete action spaces, we run it on a discretized version of the BipedalWalker-v3 environment, where the number of possible actions in each dimension is 25, for a total of 25^4 = 390 625 possible actions. A usaual DQN architecture would use 25^4 output neurons for the Q-network, thus scaling exponentially with the number of action space dimensions, while the Branching architecture scales linearly and uses only 25*4 output neurons. + +![](results/bdq/BipedalWalker.png) \ No newline at end of file diff --git a/examples/box2d/bipedal_bdq.py b/examples/box2d/bipedal_bdq.py index 3fddc8dd4..bb9d4d213 100644 --- a/examples/box2d/bipedal_bdq.py +++ b/examples/box2d/bipedal_bdq.py @@ -33,7 +33,7 @@ def get_args(): parser.add_argument("--eps-train", type=float, default=0.73) parser.add_argument("--eps-decay", type=float, default=5e-6) parser.add_argument("--buffer-size", type=int, default=100000) - parser.add_argument("--lr", type=float, default=1e-5) + parser.add_argument("--lr", type=float, default=1e-4) parser.add_argument("--gamma", type=float, default=0.99) parser.add_argument("--target-update-freq", type=int, default=1000) parser.add_argument("--epoch", type=int, default=1000) diff --git a/examples/box2d/results/bdq/BipedalWalker.png b/examples/box2d/results/bdq/BipedalWalker.png new file mode 100644 index 0000000000000000000000000000000000000000..ee4b24042c702f9a7f598ad9d65e1818c60d7f24 GIT binary patch literal 89371 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 ))W_}9Ns@&DcP%6VdbMb2Wwe0 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 Oj=S!9*UsSXNXPX?Wc-ilU@XQHW|!a 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 R6~%tytiGup?zHpu{{yOI`eXnA literal 0 HcmV?d00001 From fcb0c76bee8f94258600c5e2425b5c4af086da0c Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 18:19:08 +0200 Subject: [PATCH 31/47] Add type: ignore, and v1 for Pendulum --- test/discrete/test_bdq.py | 2 +- tianshou/env/gym_wrappers.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 5a923f34a..3f6ccd381 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -15,7 +15,7 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument("--task", type=str, default="Pendulum-v0") + parser.add_argument("--task", type=str, default="Pendulum-v1") parser.add_argument('--reward-threshold', type=float, default=None) # network architecture parser.add_argument( diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 0b73e6c4f..c40969594 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -15,13 +15,13 @@ class ContinuousToDiscrete(gym.ActionWrapper): def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) self.action_per_branch = action_per_branch - low = env.action_space.low - high = env.action_space.high - num_branches = env.action_space.shape[0] + low = env.action_space.low # type: ignore + high = env.action_space.high # type: ignore + num_branches = env.action_space.shape[0] # type: ignore self.action_space = gym.spaces.MultiDiscrete( [action_per_branch] * num_branches ) - self.action_space.n = num_branches + self.action_space.n = num_branches # type: ignore mesh = [] for lo, hi in zip(low, high): mesh.append(np.linspace(lo, hi, action_per_branch)) From 0bc2d20678a7b584c9877d301c5b2d2f7a3fbd73 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 18:23:18 +0200 Subject: [PATCH 32/47] Fix lint two spaces comment error --- tianshou/env/gym_wrappers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index c40969594..b4f9f05dd 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -15,13 +15,13 @@ class ContinuousToDiscrete(gym.ActionWrapper): def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) self.action_per_branch = action_per_branch - low = env.action_space.low # type: ignore - high = env.action_space.high # type: ignore - num_branches = env.action_space.shape[0] # type: ignore + low = env.action_space.low # type: ignore + high = env.action_space.high # type: ignore + num_branches = env.action_space.shape[0] # type: ignore self.action_space = gym.spaces.MultiDiscrete( [action_per_branch] * num_branches ) - self.action_space.n = num_branches # type: ignore + self.action_space.n = num_branches # type: ignore mesh = [] for lo, hi in zip(low, high): mesh.append(np.linspace(lo, hi, action_per_branch)) From 0f5a8c32635844e71688d2d7663358ed107d4290 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 18:33:18 +0200 Subject: [PATCH 33/47] Resolve docstyle error --- tianshou/env/gym_wrappers.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index b4f9f05dd..2ec07862e 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -5,11 +5,9 @@ class ContinuousToDiscrete(gym.ActionWrapper): """Gym environment wrapper to take discrete action in a continous environment. - Args: - env (gym.Environment): gym envirionment with continous action space. - action_per_branch (int): number of discrete actions in each dimension - of the action space. - + param gym.Environment env: gym envirionment with continous action space. + param int action_per_branch: number of discrete actions in each dimension + of the action space. """ def __init__(self, env: gym.Env, action_per_branch: int) -> None: From 7ee89393dae9955d9944419e102bd934135d79d6 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 18:40:50 +0200 Subject: [PATCH 34/47] Resolve docstyle error: indentation --- tianshou/utils/net/common.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tianshou/utils/net/common.py b/tianshou/utils/net/common.py index ce73c0b89..1fc58f768 100644 --- a/tianshou/utils/net/common.py +++ b/tianshou/utils/net/common.py @@ -380,18 +380,18 @@ class BranchingNet(nn.Module): :param value_hidden_sizes: shape of the value MLP network passed in as a list. :param action_hidden_sizes: shape of the action MLP network passed in as a list. :param norm_layer: use which normalization before activation, e.g., - ``nn.LayerNorm`` and ``nn.BatchNorm1d``. Default to no normalization. - You can also pass a list of normalization modules with the same length - of hidden_sizes, to use different normalization module in different - layers. Default to no normalization. + ``nn.LayerNorm`` and ``nn.BatchNorm1d``. Default to no normalization. + You can also pass a list of normalization modules with the same length + of hidden_sizes, to use different normalization module in different + layers. Default to no normalization. :param activation: which activation to use after each layer, can be both - the same activation for all layers if passed in nn.Module, or different - activation for different Modules if passed in a list. Default to - nn.ReLU. + the same activation for all layers if passed in nn.Module, or different + activation for different Modules if passed in a list. Default to + nn.ReLU. :param device: specify the device when the network actually runs. Default - to "cpu". + to "cpu". :param bool softmax: whether to apply a softmax layer over the last layer's - output. + output. """ def __init__( From ae5709a66a732effa4d32d5ef320bcc55f8c6632 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sat, 14 May 2022 19:11:01 +0200 Subject: [PATCH 35/47] Fix torch.to(device) error --- tianshou/policy/modelfree/bdq.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index e4b1d2bd9..e85392f2c 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -57,7 +57,9 @@ def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: target_q = result.logits if self._is_double: act = np.expand_dims(self(batch, input="obs_next").act, -1) - act = torch.from_numpy(act).to(target_q.get_device()) + act = torch.from_numpy(act) + if not target_q.get_device() < 0: # TODO better? + act = act.to(target_q.get_device()) else: act = target_q.max(-1).indices.unsqueeze(-1) return torch.gather(target_q, -1, act).squeeze() @@ -128,7 +130,9 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self.sync_weight() self.optim.zero_grad() weight = batch.pop("weight", 1.0) - act = torch.tensor(batch.act).to(batch.returns.get_device()) + act = torch.tensor(batch.act) + if not batch.returns.get_device() < 0: # TODO better? + act = act.to(batch.returns.get_device()) q = self(batch).logits act_mask = torch.zeros_like(q) act_mask = act_mask.scatter_(-1, act.unsqueeze(-1), 1) From 8d565ca4a3fe868406cd83f1d786a26247216cac Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 16:51:47 -0400 Subject: [PATCH 36/47] polish --- docs/api/tianshou.env.rst | 8 ++++++++ test/discrete/test_bdq.py | 10 ++++------ tianshou/env/gym_wrappers.py | 17 +++++++---------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/docs/api/tianshou.env.rst b/docs/api/tianshou.env.rst index 77713f411..bf0c8e064 100644 --- a/docs/api/tianshou.env.rst +++ b/docs/api/tianshou.env.rst @@ -49,6 +49,14 @@ RayVectorEnv Wrapper ------- +ContinuousToDiscrete +~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: tianshou.env.ContinuousToDiscrete + :members: + :undoc-members: + :show-inheritance: + VectorEnvWrapper ~~~~~~~~~~~~~~~~ diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 3f6ccd381..a46de42ca 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -6,7 +6,7 @@ import torch from tianshou.data import Collector, VectorReplayBuffer -from tianshou.env import ContinuousToDiscrete, SubprocVectorEnv +from tianshou.env import ContinuousToDiscrete, DummyVectorEnv from tianshou.policy import BranchingDQNPolicy from tianshou.trainer import offpolicy_trainer from tianshou.utils.net.common import BranchingNet @@ -53,9 +53,7 @@ def test_bdq(args=get_args()): env = ContinuousToDiscrete(env, args.action_per_branch) args.state_shape = env.observation_space.shape or env.observation_space.n - args.action_shape = env.action_space.shape or env.action_space.n - args.num_branches = args.action_shape if isinstance(args.action_shape, - int) else args.action_shape[0] + args.num_branches = env.action_space.shape[0] if args.reward_threshold is None: default_reward_threshold = {"Pendulum-v0": -250, "Pendulum-v1": -250} @@ -67,13 +65,13 @@ def test_bdq(args=get_args()): print("Num branches:", args.num_branches) print("Actions per branch:", args.action_per_branch) - train_envs = SubprocVectorEnv( + train_envs = DummyVectorEnv( [ lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.training_num) ] ) - test_envs = SubprocVectorEnv( + test_envs = DummyVectorEnv( [ lambda: ContinuousToDiscrete(gym.make(args.task), args.action_per_branch) for _ in range(args.test_num) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 2ec07862e..0d5a2c400 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -5,21 +5,19 @@ class ContinuousToDiscrete(gym.ActionWrapper): """Gym environment wrapper to take discrete action in a continous environment. - param gym.Environment env: gym envirionment with continous action space. - param int action_per_branch: number of discrete actions in each dimension - of the action space. + :param gym.Environment env: gym envirionment with continous action space. + :param int action_per_branch: number of discrete actions in each dimension + of the action space. """ def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) - self.action_per_branch = action_per_branch - low = env.action_space.low # type: ignore - high = env.action_space.high # type: ignore - num_branches = env.action_space.shape[0] # type: ignore + act_space: gym.spaces.Box = env.action_space # type: ignore + low, high = act_space.low, act_space.high + num_branches = act_space.shape[0] self.action_space = gym.spaces.MultiDiscrete( [action_per_branch] * num_branches ) - self.action_space.n = num_branches # type: ignore mesh = [] for lo, hi in zip(low, high): mesh.append(np.linspace(lo, hi, action_per_branch)) @@ -27,5 +25,4 @@ def __init__(self, env: gym.Env, action_per_branch: int) -> None: def action(self, act: np.ndarray) -> np.ndarray: # modify act - act = np.array([self.mesh[i][a] for i, a in enumerate(act)]) - return act + return np.array([self.mesh[i][a] for i, a in enumerate(act)]) From 29a01b83eb8d77d4cca399a55f357385cee028d5 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 17:01:21 -0400 Subject: [PATCH 37/47] fix spelling error --- tianshou/env/gym_wrappers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index 0d5a2c400..e999bf6a6 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -3,18 +3,18 @@ class ContinuousToDiscrete(gym.ActionWrapper): - """Gym environment wrapper to take discrete action in a continous environment. + """Gym environment wrapper to take discrete action in a continuous environment. - :param gym.Environment env: gym envirionment with continous action space. + :param gym.Env env: gym environment with continuous action space. :param int action_per_branch: number of discrete actions in each dimension of the action space. """ def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) - act_space: gym.spaces.Box = env.action_space # type: ignore - low, high = act_space.low, act_space.high - num_branches = act_space.shape[0] + assert(isinstance(env.action_space, gym.spaces.Box)) + low, high = env.action_space.low, env.action_space.high + num_branches = env.action_space.shape[0] self.action_space = gym.spaces.MultiDiscrete( [action_per_branch] * num_branches ) From db193a52192a2c7c5909f54c7ae45af8deb514fc Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 17:12:01 -0400 Subject: [PATCH 38/47] fix lint --- tianshou/env/gym_wrappers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tianshou/env/gym_wrappers.py b/tianshou/env/gym_wrappers.py index e999bf6a6..f63bc9e2e 100644 --- a/tianshou/env/gym_wrappers.py +++ b/tianshou/env/gym_wrappers.py @@ -12,7 +12,7 @@ class ContinuousToDiscrete(gym.ActionWrapper): def __init__(self, env: gym.Env, action_per_branch: int) -> None: super().__init__(env) - assert(isinstance(env.action_space, gym.spaces.Box)) + assert isinstance(env.action_space, gym.spaces.Box) low, high = env.action_space.low, env.action_space.high num_branches = env.action_space.shape[0] self.action_space = gym.spaces.MultiDiscrete( From baec43faf2bae3a4ea7c6d2e3b9a572a439d4d9e Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sun, 15 May 2022 00:07:22 +0200 Subject: [PATCH 39/47] Tuned hyperparameters for BDQ test --- test/discrete/test_bdq.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index a46de42ca..1969830b8 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -15,7 +15,7 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument("--task", type=str, default="Pendulum-v1") + parser.add_argument("--task", type=str, default="Pendulum-v0") parser.add_argument('--reward-threshold', type=float, default=None) # network architecture parser.add_argument( @@ -26,13 +26,13 @@ def get_args(): parser.add_argument("--action-per-branch", type=int, default=40) # training hyperparameters parser.add_argument("--seed", type=int, default=1626) - parser.add_argument("--eps-test", type=float, default=0.05) + parser.add_argument("--eps-test", type=float, default=0.01) parser.add_argument("--eps-train", type=float, default=0.76) - parser.add_argument("--eps-decay", type=float, default=1e-5) + parser.add_argument("--eps-decay", type=float, default=1e-4) parser.add_argument("--buffer-size", type=int, default=20000) - parser.add_argument("--lr", type=float, default=5e-4) + parser.add_argument("--lr", type=float, default=1e-3) parser.add_argument("--gamma", type=float, default=0.9) - parser.add_argument("--target-update-freq", type=int, default=1000) + parser.add_argument("--target-update-freq", type=int, default=200) parser.add_argument("--epoch", type=int, default=10) parser.add_argument("--step-per-epoch", type=int, default=80000) parser.add_argument("--step-per-collect", type=int, default=10) From 8bb0ba7563b2edcaff2df29f412de541893e47cd Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sun, 15 May 2022 00:08:32 +0200 Subject: [PATCH 40/47] Pendulum-v1 not v0 --- test/discrete/test_bdq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 1969830b8..60335f038 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -15,7 +15,7 @@ def get_args(): parser = argparse.ArgumentParser() # task - parser.add_argument("--task", type=str, default="Pendulum-v0") + parser.add_argument("--task", type=str, default="Pendulum-v1") parser.add_argument('--reward-threshold', type=float, default=None) # network architecture parser.add_argument( From df757561fdb17abbe369edd5e73e6091f13e91d9 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 19:09:28 -0400 Subject: [PATCH 41/47] make test faster --- test/discrete/test_bdq.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 60335f038..7aade1517 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -19,10 +19,10 @@ def get_args(): parser.add_argument('--reward-threshold', type=float, default=None) # network architecture parser.add_argument( - "--common-hidden-sizes", type=int, nargs="*", default=[512, 256] + "--common-hidden-sizes", type=int, nargs="*", default=[64, 64] ) - parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[128]) - parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[128]) + parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[64]) + parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[64]) parser.add_argument("--action-per-branch", type=int, default=40) # training hyperparameters parser.add_argument("--seed", type=int, default=1626) @@ -41,6 +41,7 @@ def get_args(): parser.add_argument("--training-num", type=int, default=10) parser.add_argument("--test-num", type=int, default=10) parser.add_argument("--logdir", type=str, default="log") + parser.add_argument('--render', type=float, default=0.) parser.add_argument( "--device", type=str, default="cuda" if torch.cuda.is_available() else "cpu" ) From cc8157584624519786fd3817d167afa1c66d42d6 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 21:36:20 -0400 Subject: [PATCH 42/47] simplify cql code --- test/discrete/test_bdq.py | 4 +--- tianshou/policy/imitation/cql.py | 21 +++++---------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/test/discrete/test_bdq.py b/test/discrete/test_bdq.py index 7aade1517..604fd886b 100644 --- a/test/discrete/test_bdq.py +++ b/test/discrete/test_bdq.py @@ -18,9 +18,7 @@ def get_args(): parser.add_argument("--task", type=str, default="Pendulum-v1") parser.add_argument('--reward-threshold', type=float, default=None) # network architecture - parser.add_argument( - "--common-hidden-sizes", type=int, nargs="*", default=[64, 64] - ) + parser.add_argument("--common-hidden-sizes", type=int, nargs="*", default=[64, 64]) parser.add_argument("--action-hidden-sizes", type=int, nargs="*", default=[64]) parser.add_argument("--value-hidden-sizes", type=int, nargs="*", default=[64]) parser.add_argument("--action-per-branch", type=int, default=40) diff --git a/tianshou/policy/imitation/cql.py b/tianshou/policy/imitation/cql.py index b43502880..672b7cad6 100644 --- a/tianshou/policy/imitation/cql.py +++ b/tianshou/policy/imitation/cql.py @@ -209,22 +209,11 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: batch_size * self.num_repeat_actions, act.shape[-1] ).uniform_(-self.min_action, self.max_action).to(self.device) - if len(obs.shape) > 2: - tmp_obs = obs.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1, 1) \ - .view(batch_size * self.num_repeat_actions, - obs.shape[-2], obs.shape[-1]) - tmp_obs_next = obs_next.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1, 1) \ - .view(batch_size * self.num_repeat_actions, - obs.shape[-2], obs.shape[-1]) - else: - tmp_obs = obs.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-1]) - tmp_obs_next = obs_next.unsqueeze(1) \ - .repeat(1, self.num_repeat_actions, 1) \ - .view(batch_size * self.num_repeat_actions, obs.shape[-1]) + obs_len = len(obs.shape) + repeat_size = [1, self.num_repeat_actions] + [1] * (obs_len - 1) + view_size = [batch_size * self.num_repeat_actions] + list(obs.shape[1:]) + tmp_obs = obs.unsqueeze(1).repeat(*repeat_size).view(*view_size) + tmp_obs_next = obs_next.unsqueeze(1).repeat(*repeat_size).view(*view_size) # tmp_obs & tmp_obs_next: (batch_size * num_repeat, state_dim) current_pi_value1, current_pi_value2 = self.calc_pi_values(tmp_obs, tmp_obs) From b6d7a9e4068d2ca82a6d6cd76644f6992288c1c2 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sat, 14 May 2022 21:49:11 -0400 Subject: [PATCH 43/47] sync --- tianshou/policy/modelfree/bdq.py | 13 ++++++------- tianshou/policy/modelfree/dqn.py | 7 +++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index e85392f2c..8beb3d4c0 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -139,7 +139,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: act_q = q * act_mask returns = batch.returns returns = returns * act_mask - td_error = (returns - act_q) + td_error = returns - act_q loss = (td_error.pow(2).sum(-1).mean(-1) * weight).mean() # batch.weight = td_error.sum(-1).sum(-1) # prio-buffer loss.backward() @@ -147,8 +147,11 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self._iter += 1 return {"loss": loss.item()} - def exploration_noise(self, act: Union[np.ndarray, Batch], - batch: Batch) -> Union[np.ndarray, Batch]: + def exploration_noise( + self, + act: Union[np.ndarray, Batch], + batch: Batch, + ) -> Union[np.ndarray, Batch]: if isinstance(act, np.ndarray) and not np.isclose(self.eps, 0.0): bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps @@ -159,7 +162,3 @@ def exploration_noise(self, act: Union[np.ndarray, Batch], rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] return act - - def map_action(self, act: Union[Batch, np.ndarray]) -> Union[Batch, np.ndarray]: - # Important, used by collector - return act diff --git a/tianshou/policy/modelfree/dqn.py b/tianshou/policy/modelfree/dqn.py index 593de15fd..a87192b6a 100644 --- a/tianshou/policy/modelfree/dqn.py +++ b/tianshou/policy/modelfree/dqn.py @@ -177,8 +177,11 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self._iter += 1 return {"loss": loss.item()} - def exploration_noise(self, act: Union[np.ndarray, Batch], - batch: Batch) -> Union[np.ndarray, Batch]: + def exploration_noise( + self, + act: Union[np.ndarray, Batch], + batch: Batch, + ) -> Union[np.ndarray, Batch]: if isinstance(act, np.ndarray) and not np.isclose(self.eps, 0.0): bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps From 47a23768fdd12a855267d8eea29c8e2aee564658 Mon Sep 17 00:00:00 2001 From: Anas BELFADIL <56280198+BFAnas@users.noreply.github.com> Date: Sun, 15 May 2022 13:15:13 +0200 Subject: [PATCH 44/47] Update tianshou/policy/modelfree/bdq.py Co-authored-by: Jiayi Weng --- tianshou/policy/modelfree/bdq.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 8beb3d4c0..b95a8ebce 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -57,9 +57,7 @@ def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: target_q = result.logits if self._is_double: act = np.expand_dims(self(batch, input="obs_next").act, -1) - act = torch.from_numpy(act) - if not target_q.get_device() < 0: # TODO better? - act = act.to(target_q.get_device()) + act = to_torch_as(act, target_q) else: act = target_q.max(-1).indices.unsqueeze(-1) return torch.gather(target_q, -1, act).squeeze() From 3b40b471af3a12cc27156dab3f82be86c7af3500 Mon Sep 17 00:00:00 2001 From: BELFADIL BELFADIL Date: Sun, 15 May 2022 13:37:40 +0200 Subject: [PATCH 45/47] Revert to_torch_as, to resolve type error --- tianshou/policy/modelfree/bdq.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index b95a8ebce..53d9b59f6 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -57,7 +57,9 @@ def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: target_q = result.logits if self._is_double: act = np.expand_dims(self(batch, input="obs_next").act, -1) - act = to_torch_as(act, target_q) + act = torch.from_numpy(act) + if not target_q.get_device() < 0: # TODO better? + act = act.to(target_q.get_device()) else: act = target_q.max(-1).indices.unsqueeze(-1) return torch.gather(target_q, -1, act).squeeze() @@ -129,7 +131,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self.optim.zero_grad() weight = batch.pop("weight", 1.0) act = torch.tensor(batch.act) - if not batch.returns.get_device() < 0: # TODO better? + if not batch.returns.get_device() < 0: act = act.to(batch.returns.get_device()) q = self(batch).logits act_mask = torch.zeros_like(q) From 8060866a1037578f2f2a462c1416cc910c290080 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sun, 15 May 2022 08:58:40 -0400 Subject: [PATCH 46/47] add no_type_check for to_* --- tianshou/data/utils/converter.py | 9 ++++++--- tianshou/policy/base.py | 2 +- tianshou/policy/imitation/base.py | 4 ++-- tianshou/policy/imitation/bcq.py | 8 ++------ tianshou/policy/imitation/cql.py | 4 +--- tianshou/policy/imitation/discrete_bcq.py | 5 +---- tianshou/policy/imitation/gail.py | 6 +++--- tianshou/policy/modelbased/icm.py | 2 +- 8 files changed, 17 insertions(+), 23 deletions(-) diff --git a/tianshou/data/utils/converter.py b/tianshou/data/utils/converter.py index e23143b0d..ed705e204 100644 --- a/tianshou/data/utils/converter.py +++ b/tianshou/data/utils/converter.py @@ -1,7 +1,7 @@ import pickle from copy import deepcopy from numbers import Number -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, Optional, Union, no_type_check import h5py import numpy as np @@ -10,6 +10,7 @@ from tianshou.data.batch import Batch, _parse_value +@no_type_check def to_numpy(x: Any) -> Union[Batch, np.ndarray]: """Return an object without torch.Tensor.""" if isinstance(x, torch.Tensor): # most often case @@ -30,6 +31,7 @@ def to_numpy(x: Any) -> Union[Batch, np.ndarray]: return np.asanyarray(x) +@no_type_check def to_torch( x: Any, dtype: Optional[torch.dtype] = None, @@ -39,14 +41,14 @@ def to_torch( if isinstance(x, np.ndarray) and issubclass( x.dtype.type, (np.bool_, np.number) ): # most often case - x = torch.from_numpy(x).to(device) # type: ignore + x = torch.from_numpy(x).to(device) if dtype is not None: x = x.type(dtype) return x elif isinstance(x, torch.Tensor): # second often case if dtype is not None: x = x.type(dtype) - return x.to(device) # type: ignore + return x.to(device) elif isinstance(x, (np.number, np.bool_, Number)): return to_torch(np.asanyarray(x), dtype, device) elif isinstance(x, (dict, Batch)): @@ -59,6 +61,7 @@ def to_torch( raise TypeError(f"object {x} cannot be converted to torch.") +@no_type_check def to_torch_as(x: Any, y: torch.Tensor) -> Union[Batch, torch.Tensor]: """Return an object without np.ndarray. diff --git a/tianshou/policy/base.py b/tianshou/policy/base.py index 325a85b62..893905d63 100644 --- a/tianshou/policy/base.py +++ b/tianshou/policy/base.py @@ -339,7 +339,7 @@ def compute_episodic_return( assert np.isclose(gae_lambda, 1.0) v_s_ = np.zeros_like(rew) else: - v_s_ = to_numpy(v_s_.flatten()) # type: ignore + v_s_ = to_numpy(v_s_.flatten()) v_s_ = v_s_ * BasePolicy.value_mask(buffer, indices) v_s = np.roll(v_s_, 1) if v_s is None else to_numpy(v_s.flatten()) diff --git a/tianshou/policy/imitation/base.py b/tianshou/policy/imitation/base.py index 20c6a6212..211c093b8 100644 --- a/tianshou/policy/imitation/base.py +++ b/tianshou/policy/imitation/base.py @@ -54,11 +54,11 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: if self.action_type == "continuous": # regression act = self(batch).act act_target = to_torch(batch.act, dtype=torch.float32, device=act.device) - loss = F.mse_loss(act, act_target) # type: ignore + loss = F.mse_loss(act, act_target) elif self.action_type == "discrete": # classification act = F.log_softmax(self(batch).logits, dim=-1) act_target = to_torch(batch.act, dtype=torch.long, device=act.device) - loss = F.nll_loss(act, act_target) # type: ignore + loss = F.nll_loss(act, act_target) loss.backward() self.optim.step() return {"loss": loss.item()} diff --git a/tianshou/policy/imitation/bcq.py b/tianshou/policy/imitation/bcq.py index 89facd7d5..883400dff 100644 --- a/tianshou/policy/imitation/bcq.py +++ b/tianshou/policy/imitation/bcq.py @@ -104,9 +104,7 @@ def forward( """Compute action over the given batch data.""" # There is "obs" in the Batch # obs_group: several groups. Each group has a state. - obs_group: torch.Tensor = to_torch( # type: ignore - batch.obs, device=self.device - ) + obs_group: torch.Tensor = to_torch(batch.obs, device=self.device) act_group = [] for obs in obs_group: # now obs is (state_dim) @@ -132,9 +130,7 @@ def sync_weight(self) -> None: def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: # batch: obs, act, rew, done, obs_next. (numpy array) # (batch_size, state_dim) - batch: Batch = to_torch( # type: ignore - batch, dtype=torch.float, device=self.device - ) + batch: Batch = to_torch(batch, dtype=torch.float, device=self.device) obs, act = batch.obs, batch.act batch_size = obs.shape[0] diff --git a/tianshou/policy/imitation/cql.py b/tianshou/policy/imitation/cql.py index 672b7cad6..7d9cea927 100644 --- a/tianshou/policy/imitation/cql.py +++ b/tianshou/policy/imitation/cql.py @@ -160,9 +160,7 @@ def process_fn( return batch def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: - batch: Batch = to_torch( # type: ignore - batch, dtype=torch.float, device=self.device, - ) + batch: Batch = to_torch(batch, dtype=torch.float, device=self.device) obs, act, rew, obs_next = batch.obs, batch.act, batch.rew, batch.obs_next batch_size = obs.shape[0] diff --git a/tianshou/policy/imitation/discrete_bcq.py b/tianshou/policy/imitation/discrete_bcq.py index 95b5dea5f..1f713b536 100644 --- a/tianshou/policy/imitation/discrete_bcq.py +++ b/tianshou/policy/imitation/discrete_bcq.py @@ -113,10 +113,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: current_q = result.q_value[np.arange(len(target_q)), batch.act] act = to_torch(batch.act, dtype=torch.long, device=target_q.device) q_loss = F.smooth_l1_loss(current_q, target_q) - i_loss = F.nll_loss( - F.log_softmax(imitation_logits, dim=-1), - act # type: ignore - ) + i_loss = F.nll_loss(F.log_softmax(imitation_logits, dim=-1), act) reg_loss = imitation_logits.pow(2).mean() loss = q_loss + i_loss + self._weight_reg * reg_loss diff --git a/tianshou/policy/imitation/gail.py b/tianshou/policy/imitation/gail.py index 434e12e60..b85f52dba 100644 --- a/tianshou/policy/imitation/gail.py +++ b/tianshou/policy/imitation/gail.py @@ -108,9 +108,9 @@ def process_fn( return super().process_fn(batch, buffer, indices) def disc(self, batch: Batch) -> torch.Tensor: - obs = to_torch(batch.obs, device=self.disc_net.device) # type: ignore - act = to_torch(batch.act, device=self.disc_net.device) # type: ignore - return self.disc_net(torch.cat([obs, act], dim=1)) # type: ignore + obs = to_torch(batch.obs, device=self.disc_net.device) + act = to_torch(batch.act, device=self.disc_net.device) + return self.disc_net(torch.cat([obs, act], dim=1)) def learn( # type: ignore self, batch: Batch, batch_size: int, repeat: int, **kwargs: Any diff --git a/tianshou/policy/modelbased/icm.py b/tianshou/policy/modelbased/icm.py index 66ab1bbc4..97fcde2e1 100644 --- a/tianshou/policy/modelbased/icm.py +++ b/tianshou/policy/modelbased/icm.py @@ -105,7 +105,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self.optim.zero_grad() act_hat = batch.policy.act_hat act = to_torch(batch.act, dtype=torch.long, device=act_hat.device) - inverse_loss = F.cross_entropy(act_hat, act).mean() # type: ignore + inverse_loss = F.cross_entropy(act_hat, act).mean() forward_loss = batch.policy.mse_loss.mean() loss = ( (1 - self.forward_loss_weight) * inverse_loss + From 5b6cd1236d7011bd77f6f159a5a3b13975f08616 Mon Sep 17 00:00:00 2001 From: Jiayi Weng Date: Sun, 15 May 2022 09:08:15 -0400 Subject: [PATCH 47/47] use to_torch in bdq --- tianshou/policy/modelfree/bdq.py | 34 +++++++------------------------- tianshou/policy/modelfree/dqn.py | 2 -- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/tianshou/policy/modelfree/bdq.py b/tianshou/policy/modelfree/bdq.py index 53d9b59f6..b02514c02 100644 --- a/tianshou/policy/modelfree/bdq.py +++ b/tianshou/policy/modelfree/bdq.py @@ -3,7 +3,7 @@ import numpy as np import torch -from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch_as +from tianshou.data import Batch, ReplayBuffer, to_numpy, to_torch, to_torch_as from tianshou.policy import DQNPolicy from tianshou.utils.net.common import BranchingNet @@ -57,9 +57,7 @@ def _target_q(self, buffer: ReplayBuffer, indices: np.ndarray) -> torch.Tensor: target_q = result.logits if self._is_double: act = np.expand_dims(self(batch, input="obs_next").act, -1) - act = torch.from_numpy(act) - if not target_q.get_device() < 0: # TODO better? - act = act.to(target_q.get_device()) + act = to_torch(act, dtype=torch.long, device=target_q.device) else: act = target_q.max(-1).indices.unsqueeze(-1) return torch.gather(target_q, -1, act).squeeze() @@ -92,8 +90,7 @@ def process_fn( self, batch: Batch, buffer: ReplayBuffer, indices: np.ndarray ) -> Batch: """Compute the 1-step return for BDQ targets.""" - batch = self._compute_return(batch, buffer, indices) - return batch + return self._compute_return(batch, buffer, indices) def forward( self, @@ -103,21 +100,6 @@ def forward( input: str = "obs", **kwargs: Any, ) -> Batch: - """Compute action over the given batch data. - - :param float eps: in [0, 1], for epsilon-greedy exploration method. - - :return: A :class:`~tianshou.data.Batch` which has 3 keys: - - * ``act`` the action. - * ``logits`` the network's raw output. - * ``state`` the hidden state. - - .. seealso:: - - Please refer to :meth:`~tianshou.policy.BasePolicy.forward` for - more detailed explanation. - """ model = getattr(self, model) obs = batch[input] obs_next = obs.obs if hasattr(obs, "obs") else obs @@ -130,9 +112,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: self.sync_weight() self.optim.zero_grad() weight = batch.pop("weight", 1.0) - act = torch.tensor(batch.act) - if not batch.returns.get_device() < 0: - act = act.to(batch.returns.get_device()) + act = to_torch(batch.act, dtype=torch.long, device=batch.returns.device) q = self(batch).logits act_mask = torch.zeros_like(q) act_mask = act_mask.scatter_(-1, act.unsqueeze(-1), 1) @@ -141,7 +121,7 @@ def learn(self, batch: Batch, **kwargs: Any) -> Dict[str, float]: returns = returns * act_mask td_error = returns - act_q loss = (td_error.pow(2).sum(-1).mean(-1) * weight).mean() - # batch.weight = td_error.sum(-1).sum(-1) # prio-buffer + batch.weight = td_error.sum(-1).sum(-1) # prio-buffer loss.backward() self.optim.step() self._iter += 1 @@ -156,8 +136,8 @@ def exploration_noise( bsz = len(act) rand_mask = np.random.rand(bsz) < self.eps rand_act = np.random.randint( - 0, self.max_action_num, (bsz, act.shape[-1]) - ) # [0, 1] + low=0, high=self.max_action_num, size=(bsz, act.shape[-1]) + ) if hasattr(batch.obs, "mask"): rand_act += batch.obs.mask act[rand_mask] = rand_act[rand_mask] diff --git a/tianshou/policy/modelfree/dqn.py b/tianshou/policy/modelfree/dqn.py index a87192b6a..e36b7f582 100644 --- a/tianshou/policy/modelfree/dqn.py +++ b/tianshou/policy/modelfree/dqn.py @@ -138,8 +138,6 @@ def forward( ... ) - :param float eps: in [0, 1], for epsilon-greedy exploration method. - :return: A :class:`~tianshou.data.Batch` which has 3 keys: * ``act`` the action.