batchno 让PyTorch训练速度更快,你需要掌握这17种方法
作者| | LORENZ KUHN
来源|机器心脏编译
掌握这17种方法,以最省力的方式加快你的Pytorch深度学习训练。
最近,Reddit上的一篇帖子在排行榜上变得很受欢迎。题目是关于如何加快PyTorch的训练。原作者是苏黎世联邦理工学院计算机科学专业的硕士研究生LORENZ KUHN。文章向我们介绍了使用PyTorch训练深度模型时最省力、最有效的17种方法。
本文提出的所有方法都假设您在GPU环境中训练模型。详情如下。
加速PyTorch培训的17种方法
1.考虑改变学习进度
学习速率调度的选择对模型的收敛速度和泛化能力有很大影响。莱斯利·史密斯等人在《训练神经网络的循环学习速率》一文中,在“超收敛:使用大学习速率的神经网络的非常快速的训练”中,提出了周期性学习速率和1个循环学习速率调度。后来,fast.ai的杰瑞米·霍华德和西尔万·古格推广了它。下图说明了1周期学习率计划:
Sylvain写道:1循环由两个等长的步骤组成,一个步骤是从较低的学习率到较高的学习率,另一个步骤是回到最低的水平。最大值来自学习率查找器选择的值,较小的值可以低十倍。那么,这个周期的长度应该略小于纪元的总数,在训练的最后阶段,我们应该允许学习率比最小值小几个数量级。
与传统的学习速率调度相比,在最好的情况下,这种调度实现了极大的加速。例如,使用1Cycle策略在ImageNet数据集上训练ResNet-56,训练迭代次数减少到原来的1/10,但模型的性能仍能与原论文的水平相匹配。在常见的架构和优化器中,这种调度似乎表现良好。
Pytorch实现了这两种方法:“torch . optim . lr _ scheduler . cyclic lr”和“torch . optim . lr _ scheduler . onecycler”。
参考文件:https://pytorch.org/docs/stable/optim.html
2.在数据加载器中使用多个工作进程和页面来锁定内存
使用torch.utils.data.DataLoader时设置num _ workers >:0而不是默认值0,pin_memory=True而不是默认值False。
参考文件:https://pytorch.org/docs/stable/data.html
来自NVIDIA的CUDA深度学习算法高级软件工程师Szymon Micacz曾用4个worker和固定内存在单个纪元内实现了两倍的速度。人们选择工作者数量的经验法则是将其设置为可用GPU数量的四倍。如果大于或小于这个数,训练速度就会降低。请注意,增加num_workers将增加CPU内存消耗。
3.将批次调到最大
最大限度地调整批次是一个有争议的观点。一般来说,如果批处理被调整到GPU内存内的最大值,你的训练速度会更快。但是,您还必须调整其他超参数,如学习速率。一个有用的经验是,当批量翻倍时,学习率也会翻倍。
OpenAI的论文《大批量训练的帝国模型》很好地展示了不同批量需要多少步才能收敛。在“如何使用合适的批处理大小获得4倍的加速和更好的泛化”一文中,作者Daniel Huynh用不同的批处理大小进行了一些实验。最终,他将批量从64个增加到512个,实现了四倍的加速。
然而,使用大批量的缺点是,它可能导致比使用小批量更差的泛化能力。
4.使用自动混合精度
PyTorch 1.6版本包含了对py torch 1.6的自动混音精度训练的局部实现,这里我想说的是,相比于单精度,有些运算在半精度下运行更快,而不损失精度。放大器自动确定应该以何种精度执行何种操作。这样既能加快训练速度,又能减少记忆占用。
在最佳情况下,放大器的使用如下:
importtorch # Creates once at the beginning of training scaler= torch.cuda.amp.GradScalerfordata,data_iter中的标签:optimizer.zero_grad#将操作强制转换为混合精度with torch . cuda . amp . auto cast:loss = model
#缩放损失,并向后调用#创建缩放的梯度缩放器。缩放。向后的
#不缩放渐变并调用#或跳过optimizer . step scaler . step
#更新下次迭代的刻度。更新
5.考虑使用另一个优化器
AdamW是fast.ai推广的一种权重衰减的Adam,由torch.optim实现,PyTorch中的AdamW在误差和训练时间上似乎总是优于Adam。
Adam和AdamW可以很好的配合上面提到的1周期策略。
目前,有一些非局部优化器引起了极大的关注,其中最突出的是LARS和LAMB。NVIDA的APEX实现了一些常用优化器的融合版,比如Adam。与PyTorch中的Adam实现相比,该实现避免了与GPU内存的多次传输,速度提高了5%。
6.cudNN基准
如果您的模型架构保持不变并且输入大小保持不变,则设置torch . back ends . cud nn . benchmark = true。
7.小心中央处理器和图形处理器之间频繁的数据传输
当tensor.cpu频繁用于将张量从GPU转移到cpu时,成本非常昂贵。项目与相同。努皮。你可以用。请改为分离。
如果创建新的张量,可以使用关键字参数device=torch.device将其分配给GPU。
如果需要传输数据,可以使用。只要传输后没有同步点,设置为。
8.使用渐变/激活检查点
检查点的工作原理是用计算换取内存。不是存储整个计算图的所有中间激活用于反向传递,而是重新计算这些激活。我们可以将其应用于模型的任何部分。
具体来说,在向前传递中,该函数将作为torch.no_grad运行,并且不会存储任何中间激活。相反,输入元组和函数参数保存在正向传递中。在向后传递中,检索输入和函数,并再次对函数计算向前传递。然后跟踪中间激活,并使用这些激活值来计算梯度。
因此,尽管这可能会稍微增加给定批处理大小的运行时间,但它将显著减少内存占用。反过来,这将允许使用的批量进一步增加,从而提高GPU的利用率。
虽然checkpointing是通过torch.utils.checkpoint实现的,但要正确实现还需要一些思考和努力。Priya Goyal写了一个很好的教程来介绍检查点的关键方面。
Priya Goyal教程地址:
https://github . com/prigoyal/py torch _ memonger/blob/master/tutorial/Checkpointing _ for _ py torch _ models . ipynb
9.使用梯度累积
另一种增加批次大小的方法是在多个批次中累积梯度。在调用optimizer.step之前向后传递。
文章“在大型蝙蝠上训练神经网络:单图形处理器、多图形处理器和分布式设置的实用技巧”描述了如何使用梯度累积。梯度累积可以如下实现:
model.zero_grad # Reset gradients tensorsfor i, in enumerate:predictions = model # Forward passloss = loss_function # Compute loss functionloss = loss / accumulation_steps # Normalize our loss loss.backward # Backward passif % accumulation_steps == 0: # Wait for several backward stepsoptimizer.step # Now we can do an optimizer stepmodel.zero_grad # Reset gradients tensorsif % evaluation_steps == 0: # Evaluate the model when we...evaluate_model # ...have no gradients accumulate这种方法主要是为了避免GPU内存的限制而开发的。
10.使用分布式数据并行的多图形处理器训练
加速分布式训练的方法可能有很多,但简单的方法是用torch . nn . distributeddataparallel代替torch.nn.DataParallel这样,每个GPU都将由一个专用的CPU内核驱动,从而避免了dataparallel的GIL问题。
分发的培训文件地址:https://pytorch.org/tutorials/beginner/dist_overview.html
11.将渐变设置为无,而不是0
渐变设置为zero_grad ,而不是。零梯度。这样做允许内存分配器处理渐变,而不是将其设置为0。如文档中所述,将渐变设置为“无”将产生中等加速度,但不要期待奇迹。请注意,这有缺点。有关详细信息,请查看文档。
文件地址:https://pytorch.org/docs/stable/optim.html
12.使用。as_tensor而不是。时态
Torch.tensor总是复制数据。如果要转换numpy数组,请使用torch.as _时态或torch.from_numpy来避免复制数据。
13.如有必要,请打开调试工具
PyTorch提供了许多调试工具,如autograd.profiler、autograd.grad_check和autograd . exception _ detection。需要调试的时候请确保打开调试器,不需要的时候关闭调试器,因为调试器会降低你的训练速度。
14.使用渐变剪辑
关于RNN避免梯度爆炸的问题,一些实验和理论已经证明,梯度裁剪)可以加速收敛。HuggingFace的Transformer实现是如何使用渐变裁剪的一个非常清晰的例子。本文提到的其他方法,如AMP,也可以使用。
可以使用torch.nn.utils.clip_grad_norm_在PyTorch中实现。
15.在批处理前关闭偏置
在开始BatchNormalization图层之前关闭偏置图层。对于二维卷积层,bias关键字可以设置为false: torch.nn.conv2d.
16.验证期间关闭梯度计算
验证时关闭梯度计算,设置:torch.no_grad。
17.使用输入和批处理规范化
再次检查输入是否正常。是否使用批处理规范化?
原文链接:https://efficent dl . com/fast-deep-learning-in-py torch-a-guide/