从 RAM 中更快地学习 Breakout - 第 2 部分





5.00/5 (1投票)
在本文中,我们将探讨通过稍微不同的方式访问RAM,如何改进我们的学习效果。
在上一篇文章中,我们继续探索通过训练一个基于游戏使用的128字节RAM内容的智能体来学习Atari Breakout环境。虽然取得了一些学习成果,但结果不如我们在早期文章中从像素学习时那么令人印象深刻。
让我们看看是否可以通过稍微不同的方式处理输入特征来获得更好的结果。
如Atari学习环境(ALE)论文的附录A中所述,“Atari 2600游戏程序员通常不将这些位作为单个值使用,而是作为4位或8位字的一部分使用。对单个位进行线性函数逼近可以捕捉到这些多位字的值。”
从单个位学习
鉴于各种数字可能使用不同的方案编码在RAM中(例如,前四个位中的一个值,后四个位中的第二个值),我们可以尝试从1024位学习,而不是将它们视为128字节值。
这是我用于从位学习的代码。它提供了一个自定义的观察包装器,该包装器使用NumPy的unpackbits
函数将传入的128字节观察值分解为1024字节的观察值(每个字节的值为0或1)。它还使用一个大的缓冲区和一个小的学习率,遵循了我不太成功的、使用较高学习率的尝试。
import numpy as np
import gym
import ray
from gym.spaces import Box
from gym import ObservationWrapper
from ray import tune
from ray.rllib.agents.dqn import DQNTrainer
from ray.tune.registry import register_env
class BytesToBits(ObservationWrapper):
def __init__(self, env):
super().__init__(env)
self.observation_space = Box(low=0, high=1, shape=(1024,), dtype=np.uint8)
def observation(self, obs):
return np.unpackbits(obs)
def env_creator(env_config):
env = gym.make('Breakout-ramDeterministic-v4')
env = BytesToBits(env)
return env
register_env("ram_bits_breakout", env_creator)
ENV = "ram_bits_breakout"
TARGET_REWARD = 200
TRAINER = DQNTrainer
ray.shutdown()
ray.init(include_webui=False, ignore_reinit_error=True)
tune.run(
TRAINER,
stop={"episode_reward_mean": TARGET_REWARD},
config={
env: ENV,
monitor: True,
evaluation_num_episodes: 25,
double_q: True,
hiddens: [1024],
num_workers: 0,
num_gpus: 1,
target_network_update_freq: 12_000,
lr: 5E-6,
adam_epsilon: 1E-5,
learning_starts: 150_000,
buffer_size: 1_500_000,
}
)
这个包装后的环境仍然需要很长时间才能让智能体学习,但它比直接从字节学习好得多。这个环境用了12,779次迭代,耗时26.1小时才达到目标分数200。
进度如下所示
我建议您尝试不同的设置,如果您取得了一些成功,请在评论中分享您的发现。
例如,我尝试使用位和字节的串联进行训练。这并不太顺利,也许是因为通常来说,所有特征都应该归一化到大致相同的尺度。我训练了18.3小时后停止了,此时它的平均分数为仅19.48(与仅使用位的版本在相同时间后的86.17相比)。
在下一篇,也是本系列最后一篇文章中,我们将探讨稍微高级的主题:最小化我们的Breakout游戏智能体的“抖动”,以及执行超参数的网格搜索。