前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >PyTorch深度学习模型训练加速指南2021

PyTorch深度学习模型训练加速指南2021

作者头像
AI算法与图像处理
发布于 2021-01-20 07:01:42
发布于 2021-01-20 07:01:42
1.4K00
代码可运行
举报
运行总次数:0
代码可运行

导读

简要介绍在PyTorch中加速深度学习模型训练的一些最小改动、影响最大的方法。我既喜欢效率又喜欢ML,所以我想我也可以把它写下来。

比如说,你正在PyTorch中训练一个深度学习模型。你能做些什么让你的训练更快结束?

在这篇文章中,我将概述一些在PyTorch中加速深度学习模型训练时改动最小,影响最大的方法。对于每种方法,我会简要总结其思想,并估算预期的加速度,并讨论一些限制。我将着重于传达最重要的部分,并为每个部分给出额外的一些资源。大多数情况下,我会专注于可以直接在PyTorch中进行的更改,而不需要引入额外的库,并且我将假设你正在使用GPU训练模型。

1. 考虑使用另外一种学习率策略

你选择的学习率对收敛速度以及模型的泛化性能有很大的影响。

循环学习率和1Cycle学习率策略都是Leslie N. Smith提出的方法,然后由fast.ai推广。本质上,1Cycle学习率策略看起来像这样:

Sylvain写道:

[1cycle由两个相同长度的步骤组成,一个是从较低的学习率到较高的学习率,另一个步骤是回到最低的学习速率。最大值应该是使用Learning Rate Finder选择的值,较低的值可以低十倍。然后,这个周期的长度应该略小于epochs的总数,并且,在训练的最后一部分,我们应该允许学习率减少超过最小值几个数量级。

在最好的情况下,与传统的学习率策略相比,这种策略可以实现巨大的加速 —— Smith称之为“超级收敛”。例如,使用1Cycle策略,在ImageNet上减少了ResNet-56训练迭代数的10倍,就可以匹配原始论文的性能。该策略似乎在通用架构和优化器之间运行得很好。

PyTorch实现了这两个方法,torch.optim.lr_scheduler.CyclicLRtorch.optim.lr_scheduler.OneCycleLR

这两个策略的一个缺点是它们引入了许多额外的超参数。为什么会这样呢?这似乎并不完全清楚,但一个可能的解释是,定期提高学习率有助于更快的穿越鞍点。

2. 在 DataLoader中使用多个workers和pinned memory

当使用torch.utils.data.DataLoader时,设置num_workers > 0,而不是等于0,设置pin_memory=True而不是默认值False。详细解释:https://pytorch.org/docs/stable/data.html。

Szymon Micacz通过使用4个workers和pinned memory,实现了单个训练epoch的2倍加速。

一个经验法则,选择workers的数量设置为可用GPU数量的4倍,更大或更小的workers数量会变慢。

注意,增加num_workers会增加CPU内存消耗。

3. 最大化batch size

这是一个颇有争议的观点。一般来说,然而,似乎使用GPU允许的最大的batch size可能会加速你的训练。注意,如果你修改了batch大小,你还必须调整其他超参数,例如学习率。这里的一个经验法则是,当你把batch数量翻倍时,学习率也要翻倍。

OpenAI有一篇很好的实证论文关于不同batch size需要的收敛步骤的数量。Daniel Huynh运行一些实验用不同batch大小(使用上面所讨论的1Cycle策略),从batch size 64到512他实现了4倍的加速。

然而,使用大batch的缺点之一是,它们可能会导致泛化能力比使用小batch的模型差。

4. 使用自动混合精度

PyTorch 1.6的发行版包含了对PyTorch进行自动混合精度训练的本地实现。这里的主要思想是,与在所有地方都使用单精度(FP32)相比,某些操作可以在半精度(FP16)下运行得更快,而且不会损失精度。然后,AMP自动决定应该以何种格式执行何种操作。这允许更快的训练和更小的内存占用。

AMP的使用看起来像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import torch
# Creates once at the beginning of training
scaler = torch.cuda.amp.GradScaler()

for data, label in data_iter:
   optimizer.zero_grad()
   # Casts operations to mixed precision
   with torch.cuda.amp.autocast():
      loss = model(data)

   # Scales the loss, and calls backward()
   # to create scaled gradients
   scaler.scale(loss).backward()

   # Unscales gradients and calls
   # or skips optimizer.step()
   scaler.step(optimizer)

   # Updates the scale for next iteration
   scaler.update()

在NVIDIA V100 GPU上对多个NLP和CV的benchmark进行测试,Huang和他的同事们发现使用AMP在FP32训练收益率常规大约2x,但最高可达5.5x。

目前,只有CUDA ops可以通过这种方式自动转换。

5. 考虑使用另外的优化器

AdamW是由fast.ai推广的具有权重衰减(而不是L2正则化)的Adam。现在可以在PyTorch中直接使用,torch.optim.AdamW。无论在误差还是训练时间上,AdamW都比Adam表现更好。

Adam和AdamW都可以很好地使用上面描述的1Cycle策略。

还有一些自带优化器最近受到了很多关注,最著名的是LARS和LAMB。

NVIDA的APEX实现了许多常见优化器的融合版本,如Adam。与Adam的PyTorch实现相比,这种实现避免了大量进出GPU内存的操作,从而使速度提高了5%。

6. 开启cudNN benchmarking

如果你的模型架构保持不变,你的输入大小保持不变,设置torch.backends.cudnn.benchmark = True可能是有益的。这使得cudNN能够测试许多不同的卷积计算方法,然后使用最快的方法。

对于加速的预期有一个粗略的参考,Szymon Migacz达到70%的forward的加速以及27%的forward和backward的加速。

这里需要注意的是,如果你像上面提到的那样将batch size最大化,那么这种自动调优可能会变得非常缓慢。

7. 注意CPU和GPU之间频繁的数据传输

小心使用tensor.cpu()tensor.cuda()频繁地将张量从GPU和CPU之间相互转换。对于.item().numpy()也是一样,用.detach()代替。

如果你正在创建一个新的张量,你也可以使用关键字参数device=torch.device('cuda:0')直接将它分配给你的GPU。

如果你确实需要传输数据,在传输后使用.to(non_blocking=True)可能会很有用,只要你没有任何同步点。

如果你真的需要,你可以试试Santosh Gupta的SpeedTorch,虽然不是很确定在什么情况下可以加速。

8. 使用gradient/activation检查点

直接引用文档中的话:

检查点的工作原理是用计算交换内存,并不是存储整个计算图的所有中间激活用于向后计算,检查点不保存中间的激活,而是在向后传递中重新计算它们。可以应用于模型的任何部分。 具体来说,在向前传递中,function会以torch.no_grad()的方式运行,也就是说,不存储中间激活。相反,正向传递保存输入和function的参数。在向后传递中,将检索保存的输入和function,并再次根据function计算向前传递,然后跟踪中间的激活,再使用这些激活值计算梯度。

因此,虽然这可能会略微增加给定batch大小的运行时间,但会显著减少内存占用。这反过来会允许你进一步增加你正在使用的batch大小,从而更好地利用GPU。

检查点的pytorch实现为torch.utils.checkpoint,需要想点办法才能实现的很好。

9. 使用梯度累加

增加batch大小的另一种方法是在调用optimizer.step()之前,在多个.backward()中累积梯度。

在Hugging Face的实现中,梯度累加可以实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
model.zero_grad()                                   # Reset gradients tensors
for i, (inputs, labels) in enumerate(training_set):
    predictions = model(inputs)                     # Forward pass
    loss = loss_function(predictions, labels)       # Compute loss function
    loss = loss / accumulation_steps                # Normalize our loss (if averaged)
    loss.backward()                                 # Backward pass
    if (i+1) % accumulation_steps == 0:             # Wait for several backward steps
        optimizer.step()                            # Now we can do an optimizer step
        model.zero_grad()                           # Reset gradients tensors
        if (i+1) % evaluation_steps == 0:           # Evaluate the model when we...
            evaluate_model()                        # ...have no gradients accumulated

这个方法主要是为了避开GPU内存限制。fastai论坛上的这个讨论:https://forums.fast.ai/t/accumulating-gradients/33219/28似乎表明它实际上可以加速训练,所以可能值得一试。

10. 对于多个GPU使用分布式数据并行

对于分布式训练加速,一个简单的方法是使用torch.nn.DistributedDataParallel而不是torch.nn.DataParallel。通过这样做,每个GPU将由一个专用的CPU核心驱动,避免了DataParallel的GIL问题。

11. 将梯度设为None而不是0

使用.zero_grad(set_to_none=True)而不是.zero_grad()。这样做会让内存分配器去处理梯度,而不是主动将它们设置为0。正如在文档中所说的那样,这会导致产生一个适度的加速,所以不要期待任何奇迹。

注意,这样做并不是没有副作用的!关于这一点的详细信息请查看文档。

12. 使用.as_tensor() 而不是 .tensor()

torch.tensor() 会拷贝数据,如果你有一个numpy数组,你想转为tensor,使用 torch.as_tensor() 或是 torch.from_numpy() 来避免拷贝数据。

13. 需要的时候打开调试工具

Pytorch提供了大量的有用的调试工具,如autograd.profiler,autograd.grad_check和autograd.anomaly_detection。在需要的时候使用它们,在不需要它们的时候关闭它们,因为它们会减慢你的训练。

14. 使用梯度剪裁

最初是用于RNNs避免爆炸梯度,有一些经验证据和一些理论支持认为剪裁梯度(粗略地说:gradient = min(gradient, threshold))可以加速收敛。Hugging Face的Transformer实现是关于如何使用梯度剪裁以及其他的一些方法如AMP的一个非常干净的例子。

在PyTorch中,这可以通过使用torch.nn.utils.clip_grad_norm_实现。我并不完全清楚哪个模型从梯度裁剪中获益多少,但它似乎对RNN、基于Transformer和ResNets架构以及一系列不同的优化器都非常有用。

15. 在BatchNorm之前不使用bias

这是一个非常简单的方法:在BatchNormalization 层之前不使用bias。对于二维卷积层,可以将关键字bias设为False: torch.nn.Conv2d(..., bias=False, ...)

你会保存一些参数,然而,与这里提到的其他一些方法相比,我对这个方法的加速期望相对较小。

16. 在验证的时候关闭梯度计算

这个很直接:在验证的时候使用 torch.no_grad()

17. 对输入和batch使用归一化

你可能已经这么做了,但你可能想再检查一下:

  • 你的输入归一化了吗?
  • 你是否在使用batch-normalization

来自评论的额外的技巧:使用 JIT融合point-wise的操作

如果你有point-wise的操作,你可以使用PyTorch JIT将它们合并成一个FusionGroup,这样就可以在单个核上启动,而不是像默认情况下那样在多个核上启动。你还可以节省一些内存的读写。

Szymon Migacz展示了如何使用@torch.jit脚本装饰器来融合GELU中的操作,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@torch.jit.script
def fused_gelu(x):
    return x * 0.5 * (1.0 + torch.erf(x / 1.41421))

在本例中,与未融合的版本相比,融合操作将导致fused_gelu的执行速度提高5倍。

一些相关的资源

上面列出的许多技巧来自Szymon Migacz的谈话,并发表在:https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html。

PyTorch Lightning的William Falcon有两篇文章:

https://towardsdatascience.com/9-tips-for-training-lightning-fast-neural-networks-in-pytorch-8e63a502f565

https://towardsdatascience.com/7-tips-for-squeezing-maximum-performance-from-pytorch-ca4a40951259

其中有加速训练的技巧。PyTorch Lightning已经处理了上面默认的一些点。

Hugging Face的Thomas Wolf有很多关于加速深度学习的有趣文章,其中特别关注语言模型。

Sylvain Gugger和Jeremy Howard也有一些文章:

关于学习率策略的:https://sgugger.github.io/the-1cycle-policy.html,

关于找最佳学习率的:https://sgugger.github.io/how-do-you-find-a-good-learning-rate.html

AdamW相关的:https://www.fast.ai/2018/07/02/adam-weight-decay/。

—END—

英文原文:https://efficientdl.com/faster-deep-learning-in-pytorch-a-guide/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI算法与图像处理 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
PyTorch神经网络的高效训练指南!
本文介绍在使用 PyTorch 高效训练深度学习模型的 17 种方法。该文所提方法,都是假设你在 GPU 环境下训练模型。关于pytorch-GPU的介绍可以参考文章:深度学习GPU环境配置及建模(Python)
算法进阶
2023/08/28
4620
PyTorch神经网络的高效训练指南!
让PyTorch训练速度更快,你需要掌握这17种方法
近日,Reddit 上一个帖子热度爆表。主题内容是关于怎样加速 PyTorch 训练。原文作者是来自苏黎世联邦理工学院的计算机科学硕士生 LORENZ KUHN,文章向我们介绍了在使用 PyTorch 训练深度模型时最省力、最有效的 17 种方法。
机器之心
2021/01/20
5670
如何用更少的内存训练你的PyTorch模型?深度学习GPU内存优化策略总结
在训练大规模深度学习模型时,GPU 内存往往成为关键瓶颈,尤其是面对大型语言模型(LLM)和视觉 Transformer 等现代架构时。由于大多数研究者和开发者难以获得配备海量 GPU 内存的高端计算集群,掌握高效的内存优化技术至关重要。本文将系统介绍多种优化策略,这些方法在组合应用的情况下,可将训练过程中的内存占用降低近 20 倍,而不会影响模型性能和预测精度。此外,大多数技术可以相互结合,以进一步提升内存效率。
CoovallyAIHub
2025/03/06
2010
如何用更少的内存训练你的PyTorch模型?深度学习GPU内存优化策略总结
优化PyTorch速度和内存效率的技巧汇总
深度学习模型的训练/推理过程涉及很多步骤。在有限的时间和资源条件下,每个迭代的速度越快,整个模型的预测性能就越快。我收集了几个PyTorch技巧,以最大化内存使用效率和最小化运行时间。为了更好地利用这些技巧,我们还需要理解它们如何以及为什么有效。
炼丹笔记
2022/10/27
2.5K0
优化PyTorch速度和内存效率的技巧汇总
一文详解Transformers的性能优化的8种方法
前言 自BERT出现以来,nlp领域已经进入了大模型的时代,大模型虽然效果好,但是毕竟不是人人都有着丰富的GPU资源,在训练时往往就捉襟见肘,出现显存out of memory的问题,或者训练时间非常非常的久,因此,这篇文章主要解决的问题就是如何在GPU资源受限的情况下训练transformers库上面的大模型。 这篇文章源自Vadim Irtlach大佬在kaggle的开源notebook,感谢原作者的分享,本nlp小白觉得受益良多,因此搬运到知乎分享给大家,已取得作者授权,大部分内容是照搬翻译过来的,小
zenRRan
2022/09/02
3.8K0
一文详解Transformers的性能优化的8种方法
深度学习性能飙升的秘密——GPU优化的小窍门
大家好,我是Echo_Wish,这篇文章将和大家聊聊深度学习中一个不可或缺的话题:如何优化GPU的使用,让你的训练任务快如闪电。如果你也曾因训练模型太慢,望着进度条抓狂,那么接下来的内容可能会帮到你。本文用简单明了的语言,并结合代码实例,分享一些GPU优化的小窍门,让你的深度学习任务效率翻倍。
Echo_Wish
2025/03/31
1790
深度学习性能飙升的秘密——GPU优化的小窍门
[源码分析] Facebook如何训练超大模型---(4)
我们在前文介绍过,微软 ZeRO 可以对一个万亿参数模型可以使用 8 路模型并行、64 路管道并行和 8 路数据并行在 4,096 个 NVIDIA A100 GPU 上进行扩展。而FSDP(Fully Sharded Data Parallel)是Facebook 深度借鉴微软ZeRO之后提出的PyTorch DDP升级版本,可以认为是对标微软 ZeRO,其本质是 parameter sharding。Parameter sharding 就是把模型参数等切分到各个GPU之上。我们会以 Google,微软和 Facebook 的论文,博客以及代码来进行学习分析。
罗西的思考
2022/05/09
1.6K0
[源码分析] Facebook如何训练超大模型---(4)
优化Pytorch模型训练的小技巧
在本文中,我将描述并展示4种不同的Pytorch训练技巧的代码,这些技巧是我个人发现的,用于改进我的深度学习模型的训练。
deephub
2021/03/29
1.8K0
优化Pytorch模型训练的小技巧
Python王牌加速库2:深度学习下的障碍期权定价
上一期推文中,我们使用了Numba和CuPy来运行蒙特卡罗模拟来确定亚式障碍期权的价格。
量化投资与机器学习微信公众号
2020/04/24
2.8K0
PyTorch重大更新:将支持自动混合精度训练!
混合精度训练(mixed precision training)可以让模型训练在尽量不降低性能的情形下提升训练速度,而且也可以降低显卡使用内存。目前主流的深度学习框架都开始支持混合精度训练。对于PyTorch,混合精度训练还主要是采用NVIDIA开源的apex库。但是,PyTorch将迎来重大更新,那就是提供内部支持的混合精度训练,而且是自动混合精度训练:
lujohn3li
2020/11/11
2.6K1
PyTorch重大更新:将支持自动混合精度训练!
拿什么拯救我的 4G 显卡
随着深度学习快速发展,同时伴随着模型参数的爆炸式增长,对显卡的显存容量提出了越来越高的要求,如何在单卡小容量显卡上面训练模型是一直以来大家关心的问题。
OpenMMLab 官方账号
2022/01/18
7400
拿什么拯救我的 4G 显卡
机器学习|从0开发大模型之模型预训练
继续写《从0开发大模型》系列文章,本文主要介绍预训练过程。 预训练是目的是让模型学习知识,需要将预处理的数据(《机器学习|从0开发大模型之数据预处理》)中生成的 pretrain_data.bin 文件的上下文全部学习到,那预训练怎么做呢?
用户1904552
2025/02/27
1330
机器学习|从0开发大模型之模型预训练
50个超强的Pytorch操作 ! ! !
介绍: torch.floor() 用于将张量元素向下取整,得到不超过每个元素的最大整数。
JOYCE_Leo16
2024/03/22
3630
【深度学习】与【PyTorch实战】
深度学习是机器学习的一个分支,主要通过多层神经网络进行数据特征的自动提取和建模。本文将通过PyTorch这个深度学习框架,从理论到实战,详细介绍深度学习的基本概念、模型构建、训练和评估的过程。我会包含实例和代码,以帮助理解。
小李很执着
2024/06/15
1260
【深度学习】与【PyTorch实战】
训练提速60%!只需5行代码,PyTorch 1.6即将原生支持自动混合精度训练。
PyTorch 1.6 nightly增加了一个子模块 amp ,支持自动混合精度训练。值得期待。来看看性能如何,相比Nvidia Apex 有哪些优势?
McGL
2020/09/03
1.2K0
Pytorch自动混合精度训练模板
GitHub 仓库地址:https://github.com/yanqiangmiffy/amp-pytorch
致Great
2023/08/25
3390
Pytorch自动混合精度训练模板
9个技巧让你的PyTorch模型训练变得飞快!
让我们面对现实吧,你的模型可能还停留在石器时代。我敢打赌你仍然使用32位精度或GASP甚至只在一个GPU上训练。
深度学习技术前沿公众号博主
2020/11/20
1.2K0
9个技巧让你的PyTorch模型训练变得飞快!
[源码解析] PyTorch分布式优化器(3)---- 模型并行
本系列介绍分布式优化器,分为三篇文章,分别是基石篇,DP/DDP/Horovod 之中数据并行的优化器,PyTorch 分布式优化器,按照深度递进。本文介绍PyTorch 分布式优化器和PipeDream之中的优化器,主要涉及模型并行(流水线并行)。
罗西的思考
2021/12/10
1.5K0
[源码解析] PyTorch分布式优化器(3)---- 模型并行
强大的PyTorch:10分钟让你了解深度学习领域新流行的框架
摘要: 今年一月份开源的PyTorch,因为它强大的功能,它现在已经成为深度学习领域新流行框架,它的强大源于它内部有很多内置的库。本文就着重介绍了其中几种有特色的库,它们能够帮你在深度学习领域更上一层楼。 PyTorch由于使用了强大的GPU加速的Tensor计算(类似numpy)和基于tape的autograd系统的深度神经网络。这使得今年一月份被开源的PyTorch成为了深度学习领域新流行框架,许多新的论文在发表过程中都加入了大多数人不理解的PyTorch代码。这篇文章我们就来讲述一下我对PyTor
小莹莹
2018/04/24
8610
强大的PyTorch:10分钟让你了解深度学习领域新流行的框架
《算力狂飙!万亿参数模型推理加速全攻略 》
家人们,如今 AI 界 “卷” 得那叫一个厉害,万亿参数模型如雨后春笋般不断涌现。这些模型虽然超级强大,但对算力的要求,简直就是 “无底洞”。想要让它们在实际应用中,又快又稳地运行,推理优化就成了关键!今天,小编就带着大家,一起探索万亿参数模型推理优化的秘籍,从混合精度计算到分布式显存调度,为大家奉上全链路加速指南!
小白的大数据之旅
2025/04/03
1040
《算力狂飙!万亿参数模型推理加速全攻略 》
推荐阅读
相关推荐
PyTorch神经网络的高效训练指南!
更多 >
LV.1
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文