我该如何在GPU上有效地并行化AlphaZero?

3
我正在实现AlphaZero的一个版本(AlphaGo最新的演变形态),并将其应用于其他领域。
该算法的关键是对状态空间(CPU)进行蒙特卡罗树搜索,并与神经网络在评估模式下的“直觉”(概率)相互交错(GPU)。然后使用MCTS结果来训练神经网络。
我已经通过启动多个进程并使每个进程构建自己的树来实现CPU执行的并行化。这很有效,但现在导致了GPU瓶颈! (nvidia-smi显示GPU始终为100%)
我设计了两种策略来并行化GPU评估,但它们都存在问题。
1. 每个进程仅评估其自己树中的批次。在我的最初的天真实现中,这意味着批量大小为1。但是,通过重构一些代码并添加“虚拟损失”以防止(但并不完全阻止)选择同一节点两次,我们可以得到较大的1-4批处理数据。这里的问题是我们不能允许太长时间的延迟,否则准确性会受到影响,因此小批量处理非常关键。
2. 将批次发送到中央“神经网络工作线程”以进行组合和评估。这可以在32个或更多的大批次中完成,因此GPU可以非常有效地使用。这里的问题是树工人会将CUDA张量进行'round-trip'发送,而PyTorch不支持此操作。如果先克隆它们,则支持此方法,但所有这些常量副本使该方法比第一种方法慢。
我在考虑可能有一个巧妙的批处理方案可以使第一种方法生效。使用多个GPU也可以加速第一种方法,但是我想要的并行性不受PyTorch的本机支持。也许只保留NN工作器中的所有张量并仅发送id可以改善第二种方法,但困难在于如何有效地同步以获得大批量,而不让CPU线程等待太久。
在他们各自的论文中,我几乎找不到关于AlphaZero或AlphaGo Zero是如何并行化的信息。但我能在网上找到一些有限的信息,这些信息帮助我改进了第一种方法。
如果有任何建议,尤其是我忽略掉某些点或方法,我将不胜感激。
1个回答

1
使用TensorFlow Serving作为示例,预测服务可以在不同的进程中运行,运行一个服务来接收来自工作进程(运行MCTS进程并向预测服务发送预测请求)的请求。我们可以保留从套接字地址到套接字本身的字典。
预测服务可以读取每个查询体及其标头(对于每个查询不同),我们可以将这些标头放入队列中。等待最多100毫秒或当前批次大于批处理大小时,进行预测运算。 GPU给出结果后,我们遍历结果,并且由于顺序与队列中的标头相同,我们可以根据每个标头(可以从上面保留的字典中查找)通过套接字发送回响应。
由于每个查询都带有不同的标头,因此您不能错过请求、响应和套接字。虽然您可以使用GPU卡运行TensorFlow Serving,但同时运行多个工作进程以保持批量足够大以获得更高的吞吐量。
我还在此存储库中找到了一种批处理机制: https://github.com/richemslie/galvanise_zero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接