蓝盟IT小贴士,来喽!
两周前,我在Pytorch Lightning上重建了一些深度学习代码。 预计将加速约1.5倍。 但是,培训、评估和测试任务的速度降低了1/4。 重构之后的神经网络需要几天。 因此,我想找出原因,尽量缩短训练时间。
就是这样的事。 我正在使用一些开源深度学习代码。 这些代码用于展示一些机器学习任务的最新体系结构。 但是,这些代码本身既没有清洁也没有优化。 注意到一些可以加速的地方,将代码重建为Pytorch代码,使训练速度加快了约3倍。
但是,我认为还有改善的余地。 Pytorch Lightning是一个非常好的工具。 由于删除了大量的模板代码并提供了一些优化方法,所以我们决定使用Lightning重建这些代码。
我希望代码能快约1.5倍,但我很惊讶,完成重构时,迭代时间从4秒变成了15秒,训练时间延长了将近3倍。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
问题在哪里?
首先,运行Lightning分析器以确定问题。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
他给了我一个起点。 大部分时间都花在运行epoch上了。 高级分析器没有给我更多的信息。
我想知道神经网络中是否错误地配置了超级参数。 我打乱了其中一些超参数,训练速度没有任何变化。
然后,对数据加载器进行了调整,发现更改作业数n_jobs会影响总培训时间。 但影响不是加快了计算速度,而是减慢了。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
随着作业数的变化,100个epoch所需的时间。
如果使用n_jobs=0完全禁用多点处理,迭代速度将比使用六个内核快将近两倍。 缺省情况下,Pytorch会在两个epoch之间遍历正在运行的进程(worker )并重新加载,因此需要重新加载数据集。
在我的例子中,数据集加载得非常慢。 将DataLoader的persistent_workers参数设置为True,以防止正在运行的进程被杀死,从而防止数据被重新加载。# #我的数据加载器参数
数据加载器(
train_dataset,batch_size=64,shuffle=真,num _工作器=n _工作器,
永久_工作器=真,管脚_内存=真,
)
因此,有两种可能性。
Pytorch Lightning kill将工作器放掉,不考虑持久性_工作器参数;
问题出在别的地方。
我在GitHub上创建了issue。 我希望Lightning团队意识这个问题。 接下来寻找问题的根源。
GitHub地址: https://github.com/pytorchlightning/py torch-lightning/issues/10389
探究问题的根源
Lightning效能分析工具与前后关联管理员一起工作,以计算特定图块所需的时间。 例如,您可以使用run_training_epoch来轻松搜索特定的性能分析工具操作。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
我开始调查Lightning源代码,开始调查导致循环(loops )变慢的指令。 Loop.run通过调用Loop.on_run_start和Loop.on_run_start来重新加载数据加载器。 如下图所示
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
Loop.run是指Loop.on_run_start…
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
Loop.on_run_start调用数据加载器
问题似乎确实是由在各个epoch上重新加载数据加载器引起的。 如果观察DataLoader的源代码,则如下所示。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
如果persistent_workers使用迭代数据加载器(如果_iterator `为None,则为_get_iterator ) )重新加载整个数据集。 可以肯定的是,Pytorch Lightning错误地重置了_iterator,从而导致了这个问题。为了证实这一发现,我用自定义的、仅重载的__iter__方法替换了数据加载器:
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
正如所料,迭代之后_iterator属性设置正确,但在下一个epoch开始之前重置为None。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
现在,只需要知道属性何时设置为None,就可以找出问题的根本原因。 尝试使用调试器,但由于多进程或CUDA的原因,程序崩溃。
Ernst写了一篇博客,详细说明了他发现这个bug的过程。 以下是博客原文。
两周前,我在Pytorch Lightning上重建了一些深度学习代码。 预计将加速约1.5倍。 但是,培训、评估和测试任务的速度降低了1/4。 重构之后的神经网络需要几天。 因此,我想找出原因,尽量缩短训练时间。
就是这样的事。 我正在使用一些开源深度学习代码。 这些代码用于展示一些机器学习任务的最新体系结构。 但是,这些代码本身既没有清洁也没有优化。 注意到一些可以加速的地方,将代码重建为Pytorch代码,使训练速度加快了约3倍。
但是,我认为还有改善的余地。 Pytorch Lightning是一个非常好的工具。 由于删除了大量的模板代码并提供了一些优化方法,所以我们决定使用Lightning重建这些代码。
我希望代码能快约1.5倍,但我很惊讶,完成重构时,迭代时间从4秒变成了15秒,训练时间延长了将近3倍。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
问题在哪里?
首先,运行Lightning分析器以确定问题。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
他给了我一个起点。 大部分时间都花在运行epoch上了。 高级分析器没有给我更多的信息。
我想知道神经网络中是否错误地配置了超级参数。 我打乱了其中一些超参数,训练速度没有任何变化。
然后,对数据加载器进行了调整,发现更改作业数n_jobs会影响总培训时间。 但影响不是加快了计算速度,而是减慢了。有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
随着作业数的变化,100个epoch所需的时间。
如果使用n_jobs=0完全禁用多点处理,迭代速度将比使用六个内核快将近两倍。 缺省情况下,Pytorch会在两个epoch之间遍历正在运行的进程(worker )并重新加载,因此需要重新加载数据集。
在我的例子中,数据集加载得非常慢。 将DataLoader的persistent_workers参数设置为True,以防止正在运行的进程被杀死,从而防止数据被重新加载。
# #我的数据加载器参数
数据加载器(
train_dataset,batch_size=64,shuffle=真,num _工作器=n _工作器,
永久_工作器=真,管脚_内存=真,
)
因此,有两种可能性。
Pytorch Lightning kill将工作器放掉,不考虑持久性_工作器参数;
问题出在别的地方。
我在GitHub上创建了issue。 我希望Lightning团队意识这个问题。 接下来寻找问题的根源。
GitHub地址: https://github.com/pytorchlightning/py torch-lightning/issues/10389
探究问题的根源
Lightning效能分析工具与前后关联管理员一起工作,以计算特定图块所需的时间。 例如,您可以使用run_training_epoch来轻松搜索特定的性能分析工具操作。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
我开始调查Lightning源代码,开始调查导致循环(loops )变慢的指令。 Loop.run通过调用Loop.on_run_start和Loop.on_run_start来重新加载数据加载器。 如下图所示
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增Loop.run是指Loop.on_run_start…
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
Loop.on_run_start调用数据加载器
问题似乎确实是由在各个epoch上重新加载数据加载器引起的。 如果观察DataLoader的源代码,则如下所示。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
如果persistent_workers使用迭代数据加载器(如果_iterator `为None,则为_get_iterator ) )重新加载整个数据集。 可以肯定的是,Pytorch Lightning错误地重置了_iterator,从而导致了这个问题。
为了证实这一发现,我用自定义的、仅重载的__iter__方法替换了数据加载器:
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
正如所料,迭代之后_iterator属性设置正确,但在下一个epoch开始之前重置为None。
有臭虫! 用Pytorch Lightning重构代码会更慢,修复后的速度会倍增
n_jobs=1,永久_工作器=真
现在,只需要知道属性何时设置为None,就可以找出问题的根本原因。 尝试使用调试器,但由于多进程或CUDA的原因,程序崩溃。
文/上海蓝盟 IT外包专家