参考链接:Speeding up DQN on PyTorch: how to solve Pong in 30 minutes | by Max Lapan | Medium

Intro
前段时间我实现了文章Rainbow: Combining Improvements in Deep Reinforcement Learning using PyTorch和我的名为PTAN的小型强化学习库中的所有模型。如果你好奇,这里有八个系统的代码。
为了调试和测试它,我使用了Atari套件中的Pong游戏,主要是因为它的简单性、快速收敛性和超参数鲁棒性:你可以将回放缓存尺寸缩小10到100倍,它仍然会很好地收敛。这对于无法访问谷歌员工拥有的计算资源的深度强化学习爱好者来说非常有帮助。在代码的实现和调试过程中,我需要运行大约100-200次优化,因此,一次运行需要多长时间并不重要:2-3天或一个小时。
尽管如此,你始终应该在这里保持平衡:尝试尽可能多地压缩性能,您可能会引入错误,这将使已经很复杂的调试和实现过程变得非常复杂。所以,在Rainbow论文上的所有系统都实现之后,我问自己一个问题:是否有可能使我的实现更快,不仅能够在Pong上训练,而且能够挑战其余的游戏,这至少需要50M帧进行训练,如SeaQuest、River Raid、Breakout等。
由于我的计算资源非常有限,只有两个1080Ti + 一个1080,(在现在已经非常有限了),唯一的办法就是让代码更快。
Initial numbers
作为起点,我采用了具有以下超参数的经典DQN版本:
应用于环境的包装器对于速度和收敛都非常重要(前段时间,我浪费了两天时间试图在工作代码中找到一个错误,该错误仅仅因为缺少"Fire at reset"包装器而拒绝收敛。所以,我前段时间从OpenAI基准项目中使用的包装器列表:
在GTX 1080Ti上运行的初始代码版本显示训练期间每秒154次观察的速度,并且根据初始随机种子可以在60到90分钟解决Pong。这就是我们的出发点。从这个角度来看,RL论文通常使用的100M帧需要我们耐心等待7.5天。

Change 1: larger batch size + several steps
我们通常用于加速深度学习训练的第一个想法是更大的批量。 它适用于深度强化学习领域,但这里需要小心。 在正常的监督学习案例中,一个简单的规则“大批量更好”通常是正确的:您只需增加您的批量,直到您的 GPU 内存允许,并且更大的批量通常意味着将在单位时间内处理更多的样本,这要归功于巨大的 GPU 并行性。
强化学习案例略有不同。 在训练期间,两件事同时发生:
当代理探索环境并了解其行为的结果时,训练数据正在发生变化。 例如,在射击游戏中,您的代理可以随机运行一段时间,被怪物击中,在训练缓冲区中只有“死亡无处不在”的悲惨经历。 但过了一会儿,代理会发现他有一个可以使用的武器。 这种新体验可以极大地改变我们用于训练的数据。
RL 收敛通常建立在训练和探索之间的脆弱平衡上。 如果我们只是在不调整其他选项的情况下增加批量大小,我们很容易过度拟合当前数据(对于上面的射击游戏示例,您的代理可能会开始认为“死得年轻”是最大程度减少痛苦的唯一选择,并且永远无法发现它 已)。
因此,在 02_play_steps.py 中,我们在每个训练循环中执行多个步骤,并使用批次大小乘以该步骤数。 但是我们需要小心这个步数参数。 更多的步骤意味着更大的批量大小,这应该会导致更快的训练,但同时在训练之间做很多步骤可以用从旧网络获得的样本填充我们的缓冲区。
为了找到最佳位置,我使用随机种子(您需要同时通过 numpy 和 pytorch)修复了训练过程,并针对各个步骤对其进行了训练。
收敛动态几乎相同(见下图),但速度增加在 4 步左右饱和,因此,我决定坚持这个数字进行进一步的实验。
好的,我们的性能提升了 47%。

Change 2: play and train in separate processes
在这一步中,我们将检查我们的训练循环,它基本上包含以下步骤的重复:
前两步的目的是用来自环境的样本(观察、动作、奖励和下一次观察)填充重放缓冲区。 最后两步是训练我们的网络。
上述步骤及其与环境、GPU 上的 DQN 和重放缓冲区的通信的说明如下图所示。

正如我们所看到的,环境仅被第一步使用,我们训练的上半部分和下半部分之间的唯一连接是我们的回放缓存。由于这种数据独立性,我们可以并行运行两个进程:
这两个活动应该同步运行,以保持我们在上一节中讨论的训练/探索平衡。
这个想法是在03_parallel.py中实现的,并且正在使用torch.multiprocessing模块来并行玩游戏和训练仍然能够与GPU同时工作。为了尽量减少其他类中的修改,只有第一步(环境通信)放在单独的过程中。使Queue类将获得的观察结果传输到训练循环。

这个新版本的基准测试显示令人印象深刻的395帧/秒,与之前的版本相比增加了74%,与代码的原始版本相比增加了156%。
Change 3: async cuda transfers
Change 4: latest Atari wrappers
Summary
Speeding up DQN on PyTorch: how to solve Pong in 30 minutes
原文:https://www.cnblogs.com/lucifer1997/p/15201408.html