数据pipeline优化
之前训练的时候只是把图像数据保存在磁盘上,通过torchvision Dataloader
方式进行批量加载。最近遇到一个问题,就是批量加载ImageNet
数据时发现程序运行很慢,但是cpu/gpu
的使用率并不高,查询过后发现是遇到了磁盘io
的瓶颈
除了使用更好的硬件(比如用固态硬盘替代机械硬盘)来解决问题外,在网上还找到了不少的软件优化方法:
- 打开
dataloade pin_memory
- 替换数据预处理库
- 使用
lmdb
加快磁盘到cpu
内存的io
- 使用
prefetcher
加快cpu
内存到gpu
内存的io
- 使用
dali
加速数据预处理 - 其他
data pipeline
通常在gpu
上训练深度网络模型,数据从磁盘到gpu
的整个过程大体可分为如下步骤:
- 从磁盘加载数据到
cpu
; - 在
cpu
上进行数据预处理; - 从
cpu
加载数据到gpu
; - 在
gpu
上进行深度模型训练。
pin_memory
使用torchvision Dataloader
时,可以打开pin_memory
设置,其目的是将处理后的数据放入到内存锁页区,更方便加载到gpu
,从而提高训练速度
当计算机的内存充足的时候,设置
pin_memory=True
。当系统卡住,或者交换内存使用过多的时候,设置pin_memory=False
。因为pin_memory
与电脑硬件性能有关,pytorch
开发者不能确保每一个炼丹玩家都有高端设备,因此pin_memory
默认为False
数据预处理库
目前torchvision
默认使用PIL
进行图像处理,为了加速数据处理速度,可以使用其他后端进行处理
- Pillow。安装后可以直接替代
PIL
作为torchvision
后端 - imgaug。提供了丰富的图像处理操作
- albumentations-team/albumentations。综合了多个图像处理库(
torchvision/imgaug/opencv
),实现最快的图像操作
lmdb
最简单的方式就是先把所有训练都读入到cpu
内存上,不过这种方式需要大内存,大部分的训练环境都不符合这个条件。lmdb拥有类似的实现方式,首先在磁盘上将所有数据保存为单个文件,然后通过内存映射的方式访问文件,因为文件内寻址的开销非常小,使用指针运算就能实现,从而能够提高数据加载速度
相关实现:
prefetcher
prefetcher
是一个数据预取器,通过并行传输的方式,将数据提前从cpu
内存传输到gpu
内存中,以此来提高训练速度
注意:使用prefetcher
时要确保打开了pin_memory
设置
相关实现:
dali
dali是nvidia
开发的一个加速数据预处理的gpu
加速库。如果要使用dali
进行加速,那么需要重新构建数据加载流程
其他
在调查过程中,发现ImageNet
的数据大小不一,并且相对于网络要求的输入大小而言都比较大,所以可以预先进行图像缩放,然后再进行训练,这样也能够有效的提高训练速度
相关阅读
- pin_memory
- Pytorch中,将Dataloader的pin_memory设置为True会提高训练速度吗?
- TypeError: can't pickle Environment objects when num_workers > 0 for LSUN #689
- What’s the best way to load large data?
- TypeError: can't pickle Environment objects #526
- [Dataloader] ‘Shuffle=True’ makes IO slow
- PyTorch 60.读写LMDB数据库
- Dose data_prefetcher() really speed up training? #304
- 如何给你PyTorch里的Dataloader打鸡血
- 在用pytorch 多gpu的时候,如何使cpu满负荷运载,加快图片的载入速度?
- Using DALI in PyTorch
- 英伟达DALI加速技巧:让数据预处理速度比原生PyTorch快4倍