pytorch加速

Pytorch 加速方案

1. 数据

(0) dataloader
  • num_workers与batch_size调到合适值,并非越大越快(注意后者也影响模型性能)(需要在实验中找到最快的取值)
  • eval/test时shuffle=False
  • 内存够大的情况下,dataloader的pin_memory设为True。对特别小的数据集如 MNIST 设置 pin_memory=False 反而更快一些。
(1) 预处理提速
  • 尽量减少每次读取数据时的预处理操作,可以考虑把一些固定的操作,例如 resize ,事先处理好保存下来,训练的时候直接拿来用
  • Linux上将预处理搬到GPU上加速:

  • 数据预取:prefetch_generator(方法)让读数据的worker能在运算时预读数据,而默认是数据清空时才读

(2) IO 提速
(3) 借助硬件
  • 借助内存:直接载到内存里面,或者把把内存映射成磁盘好了
  • 借助固态:把读取速度慢的机械硬盘换成 NVME 固态吧~
(4) 训练策略
(5) 代码层面
  • torch.backends.cudnn.benchmark = True
  • Do numpy-like operations on the GPU wherever you can
  • Free up memory usingdeldel及时删除不用的中间变量,节约GPU存储。
  • Avoid unnecessary transfer of data from the GPU
  • Use pinned memory, and use non_blocking=False to parallelize data transfer and GPU number crunching

2. model

  1. float16代替默认的float32运算(方法参考,搜索”fp16”可以看到需要修改之处,包括model、optimizer、backward、learning rate)

  2. 优化器以及对应参数的选择,如learning rate,不过它对性能的影响似乎更重要【占坑】

  3. 少用循环,多用向量化操作

  4. 经典操作尽量用别人优化好的,别自己写

  5. 数据很多时少用append,虽然使用很方便,不过它每次都会重新分配空间?所以数据很大的话,光一次append就要几秒(测过),可以先分配好整个容器大小,每次用索引去修改内容,这样一步只要0.0x秒

  6. 固定对模型影响不大的部分参数,还能节约显存,可以用 detach() 切断反向传播,注意若仅仅给变量设置 required_grad=False 还是会计算梯度的

  7. eval/test 的时候,加上 model.eval() 和 torch.no_grad(),前者固定 batch-normalization 和 dropout 但是会影响性能,后者关闭 autograd

  8. 提高程序并行度,例如 我想 train 时对每个 epoch 都能 test 一下以追踪模型性能变化,但是 test 时间成本太高要一个小时,所以写了个 socket,设一个127.0.0.1 的端口,每次 train 完一个 epoch 就发个UDP过去,那个进程就可以自己 test,同时原进程可以继续 train 下一个 epoch(对 这是自己想的诡异方法hhh)

  9. torch.backends.cudnn.benchmark设为True,可以让cudnn根据当前训练各项config寻找优化算法,但这本身需要时间,所以input size在训练时会频繁变化的话,建议设为False

  10. 使用inplace操作可节约 GPU 存储,如

    x = torch.nn.functional.relu(x, inplace=True)
  11. 减少CPU和GPU之间的数据传输。例如, 如果你想知道一个 epoch 中每个 mini-batch 的 loss 和准确率,先将它们累积在 GPU 中等一个 epoch 结束之后一起传输回 CPU 会比每个 mini-batch 都进行一次 GPU 到 CPU 的传输更快。

  12. 使用半精度浮点数half()会有一定的速度提升,具体效率依赖于GPU型号。需要小心数值精度过低带来的稳定性问题。时常使用 assert tensor.size() == (N, D, H, W)作为调试手段,确保张量维度和你设想中一致。

  13. 除了标记 y 外,尽量少使用一维张量,使用n*1的二维张量代替,可以避免一些意想不到的一维张量计算结果。

  14. 统计代码各部分耗时

with torch.autograd.profiler.profile(enabled=True, use_cuda=False) as profile:
    ...
    print(profile)

或者在命令行运行:

python -m torch.utils.bottleneck main.py

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!