Pytorch训练速度更快的十七种方法

来源:

不久前,Reddit 上一个帖子热度爆了。最主题的内容是关于如何加速 PyTorch 训练。作者是来自苏黎世联邦理工学院的计算机科学硕士生 LORENZ KUHN,文章向我们介绍了在使用 PyTorch 的深度模型时省力、最有效的17种方法。
Pytorch训练速度更快的十七种方法_第1张图片

1.考虑换一种学习率变化的方法

Leslie N. Smith 等人在论文《Cyclical Learning Rates for Training Neural Networks》、《Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates 》中提出的学习率(周期性)学习计划以及 1Cycle 学习计划。之后,fast.ai 的 Jeremy Howard 和 Sylvain Guggere 进行了推广。下图是 1Cycle 学习计划的图示:
Pytorch训练速度更快的十七种方法_第2张图片
Sylva 写到:1Cycle 包括的步幅,每个步幅是从下面的学习率到幅幅的学习,或者是回到等高率的学习率。然后,这个周期的长度应该略低于总的低级数。

与传统的情况相比,在最好的情况下,该时间表实现了的时间表(Smith-下集56高效学习率在图像中)。例如,1Cycle 策略网络训练上ResNet,训练重复次数为原来的1/10,但模型性能仍能比肩原论文中的水平。在的体系结构和优化器中,这种时间表看起来经常得表现得很好。

Pytorch 已经实现了这种方法:「torch.optim.lr_scheduler.CyclicLR」和「torch.optim.lr_scheduler.OneCycleLR」。

参考文档:https://pytorch.org/docs/stable/optim.html

2.在DataLoader中使用多个worker和页锁定内存

当使用 torch.utils.data.DataLoader 时,设置 num_workers > 0,而不是默认值 0,同时设置 pin_memory=True,而不是默认 False。

  • 参考文档:https://pytorch.org/docs/stable/data.html

加速 NVIDIA 的高级 CUDA 深度学习算法软件工程师 Szymon Micacz 工人和页锁定(固定内存)在中国时代中实现了倍增的。 GPU 的数量增加了四倍,小于或小于这个数量的减少速度。请注意,增加 num_workers 将增加 CPU 占用。

3. batchsize调到最大

把批处理调到最大是一个训练有争议的观点。一般来说,如果在 GPU 内存允许的范围内将批处理调到最大,你的速度会增加。但是,你也必须调整其他超参数,比如学习率。一个比较好用的经验是,批量大小加倍时,学习率也要加倍。
OpenAI 的论文《大批量训练的经验模型》很好地在多少不同的中文本中使用了多少批次的收敛步骤。使用不同的批次进行了一些实验(也使用了多个 1Cycle 大小的策略进行讨论)。最终,他将批次大小由 64 倍的 512 倍,实现 4 倍的加速。

4.使用自动混合精度AMP

pytorch1.6版本包括对pytorch的自动混合精度训练的本地实现,AMP会自动选择那些运算是fp16哪些fp32,这样精度既可以加快训练速度,又可以减少内存。(note:tensorrt8 中的感知量化也是同理)

#AMP 

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()

5.考虑使用另外一种优化器

AdamW是一种具有权重衰减的Adam。

6.cudNN基准

如果模型架构一直没变,输入大小保持不变
可参考我另外一篇博文

import torch
torch.backends.cudnn.benchmark = True

7.小心cpu和GPU之间频繁数据传输

大家都知道内存读取和cpu处理速度有差距,所以才会出现三级cache,同理,将数据从cpu放到GPU上的开销也是很大的。

8.使用梯度/激活 checkpointing

Checkpointing 的工作原理是用计算换内存,并不存储整个计算图的所有中间激活用于 backward pass,而是重新计算这些激活。我们可以将其应用于模型的任何部分。

9.使用梯度积累

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

# 梯度积累
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 accumula

10.使用分布式数据并行多GPU训练

加速分布式训练可能有很多方法,但是简单的方法是使用 torch.nn.DistributedDataParallel 而不是 torch.nn.DataParallel。这样一来,每个 GPU 将由一个专用的 CPU 核心驱动,避免了 DataParallel 的 GIL 问题。

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

梯度设置为. zero_grad(set_to_none=True) 而不是 .zero_grad()。这样做可以让内存分配器处理梯度,而不是将它们设置为 0。正如文档中所说,将梯度设置为 None 会产生适度的加速,但不要期待奇迹出现。注意,这样做也有缺点,详细信息请查看文档。

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

torch.tensor()总是会复制数据,如果tensor转np,使用torch.as_tensor()或torch.from_numpy()来避免复制数据

13.必要时打开调试工具

PyTorch 提供了很多调试工具,例如 autograd.profiler、autograd.grad_check、autograd.anomaly_detection。请确保当你需要调试时再打开调试器,不需要时要及时关掉,因为调试器会降低你的训练速度。

14.使用梯度裁剪

关于避免 RNN 中的梯度爆炸的问题,已经有一些实验和理论证实,梯度裁剪(gradient = min(gradient, threshold))可以加速收敛。HuggingFace 的 Transformer 实现就是一个非常清晰的例子,说明了如何使用梯度裁剪。本文中提到的其他一些方法,如 AMP 也可以用。
在 PyTorch 中可以使用 torch.nn.utils.clip_grad_norm_来实现。

15.在batchnorm之前关闭bias

这是因为bn自带γ和β,会与bias重复

16.在验证期间关闭梯度计算

import torch
torch.no_grad()

17.使用输入和batch归一化

你可能感兴趣的:(深度学习,算法,计算机视觉,视觉检测)