多进程最佳实践
来源:互联网 发布:淘宝如何设置一件代发 编辑:程序博客网 时间:2024/05/20 22:01
torch.multiprocessing
是Pythonmultiprocessing
的替代品。它支持完全相同的操作,但扩展了它以便通过multiprocessing.Queue
发送的所有张量将其数据移动到共享内存中,并且只会向其他进程发送一个句柄。
Note
当
Variable
发送到另一个进程时,Variable.data
和Variable.grad.data
都将被共享。
这允许实现各种训练方法,如Hogwild,A3C或需要异步操作的任何其他方法。
共享CUDA张量
仅在Python 3中使用spawn
或forkserver
启动方法才支持在进程之间共享CUDA张量。Python 2中的multiprocessing
只能使用fork
创建子进程,并且不被CUDA运行时所支持。
Warning
CUDA API要求导出到其他进程的分配,只要它们被使用就要一直保持有效。您应该小心,确保您共享的CUDA张量只要有必要就不要超出范围。这不是共享模型参数的问题,但传递其他类型的数据应该小心。注意,此限制不适用于共享CPU内存。
参考:使用 nn.DataParallel 替代 multiprocessing
最佳实践和提示
避免和抵制死锁
当一个新进程被产生时,有很多事情可能会出错,最常见的死锁原因是后台线程。如果有任何线程持有锁或导入模块,并且fork
被调用,则子进程很可能处于损坏的状态,并以不同的方式死锁或失败。注意,即使您没有,Python内置的库也可能会这样做 —— 不需要看得比multiprocessing
更远。multiprocessing.Queue
实际上是一个非常复杂的类,它产生用于序列化,发送和接收对象的多个线程,它们也可能引起上述问题。如果您发现自己处于这种情况,请尝试使用multiprocessing.queues.SimpleQueue
,这不会使用任何其他线程。
我们正在竭尽全力把它设计得更简单,并确保这些死锁不会发生,但有些事情无法控制。如果有任何问题您无法一时无法解决,请尝试在论坛上提出,我们将看看是否可以解决问题。
重用经过队列的缓冲区
记住每次将Tensor
放入multiprocessing.Queue
时,必须将其移动到共享内存中。如果它已经被共享,它是一个无效的操作,否则会产生一个额外的内存副本,这会减缓整个进程。即使你有一个进程池来发送数据到一个进程,使它返回缓冲区 —— 这几乎是免费的,并且允许你在发送下一个batch时避免产生副本。
异步多进程训练(例如Hogwild)
使用torch.multiprocessing
,可以异步地训练模型,参数可以一直共享,也可以定期同步。在第一种情况下,我们建议发送整个模型对象,而在后者中,我们建议只发送state_dict()
。
我们建议使用multiprocessing.Queue
来在进程之间传递各种PyTorch对象。例如, 当使用fork启动方法时,可能会继承共享内存中的张量和存储器,但这是非常容易出错的,应谨慎使用,而且只能由高级用户使用。队列虽然有时是一个较不优雅的解决方案,但基本上能在所有情况下正常工作。
Warning 你应该注意有关全局语句,它们没有被
if __name__ == '__main__'
保护。如果使用与fork
不同的启动方法,则它们将在所有子进程中执行。
Hogwild
在examples repository中可以找到具体的Hogwild实现,可以展示代码的整体结构。下面也有一个小例子:
import torch.multiprocessing as mpfrom model import MyModeldef train(model): # Construct data_loader, optimizer, etc. for data, labels in data_loader: optimizer.zero_grad() loss_fn(model(data), labels).backward() optimizer.step() # This will update the shared parametersif __name__ == '__main__': num_processes = 4 model = MyModel() # NOTE: this is required for the ``fork`` method to work model.share_memory() processes = [] for rank in range(num_processes): p = mp.Process(target=train, args=(model,)) p.start() processes.append(p) for p in processes: p.join()
- 多进程最佳实践
- 多屏幕最佳实践
- hibernate 一对多 最佳实践
- JAVA调用外部进程最佳实践版组件
- 最佳实践
- 最佳实践
- 最佳实践
- hibernate 多对多 最佳实践
- RecyclerView 多类型Adapter的最佳实践
- HBase最佳实践 – 多租户机制
- ANT十五大最佳实践
- C 编程最佳实践
- J2EE 最佳实践
- 【笔记】EJb最佳实践
- JUnit最佳实践
- ANT十五大最佳实践
- JUnit最佳实践
- ANT十五大最佳实践
- 数据字典管理表空间 & 本地管理表空间 转换
- poj 1321
- 【公告】关于开启用户注册及登录手机短信验证的通知
- 机器学习笔记(十一)特征选择和稀疏学习
- 史上最全Html和CSS布局技巧
- 多进程最佳实践
- linux进程间通信之管道
- 苹果开发者账号中,测试机器列表达到100台上限,如何删除一些设备、添加新设备?
- unit13
- LeetCode435. Non-overlapping Intervals题解
- 从持续集成到弹性缩扩容:一个容器案例落地问题的思考(2017-04-12 陈俊凯 高可用架构)
- Python 学习成长记(三)---- Python 基本用法简介
- 虚函数和纯虚函数的区别
- 彻底理解ThreadLocal