Pytorch数据加载的效率一直让人头痛,此前我介绍过两个方法,实际使用后数据加载的速度还是不够快,我陆续做了一些尝试,这里做个简单的总结和分析。
1、定位问题
在优化数据加载前,应该先确定是否需要优化数据加载。数据读取并不需要更快,够快就好。一般的,显存占用率很高,利用率却很低的时候,通常会怀疑是数据加载太慢导致,但不是唯一原因,比如模型内大量的循环也会导致GPU利用率低。可以尝试固定数据看看是否可以提高GPU利用率。
确定数据加载需优化后,需要判断是数据加载的哪一部分慢。整个数据处理的流程如下:
- 读取图片数据(IO,可能存在IO瓶颈)
- 解码数据(一般是numpy格式,可能存在计算性能瓶颈)
- 数据增强(可能存在计算性能瓶颈)
- 类型变换(CPU->GPU,,可能存在数据拷贝瓶颈)
为节省阅读时间,先给结论,数据加载慢主要是由于计算性能的瓶颈,而不是IO瓶颈和数据拷贝瓶颈(测试数据为1920x1080的大图,小图片可能结论不同)。为优化加载速度应该从两个方向下手:
- 更快的图片解码
- 更快的数据增强
- 更强性能的设备,如使用GPU进行数据解码和增强(DALI库)
下面是具体的实验分析,测试环境和数据如下:
- CPU: Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz (正常负载,利用率小于30%)
- GPU: V100 (正常负载,利用率小于30%)
- 数据集数据840张,尺寸为1920x1080
- batch size = 64
- 无特别说明下num_workers=2
- 迭代10个epoch(13x10个迭代次数)
2. Baseline
不进行任何额外优化下的速度如下:
其中:
- 无任何额外操作的输出图片为原始大小(1920x1080)
- 归一化的具体操作为:
x = x.permute(0, 3, 1, 2).float().div(255)
- 转GPU的具体操作为:
x = x.cuda()
- resize为opencv的resize,插值方式为
cv2.INTER_LINEAR
- 数据增强的操作使用Numpy和Opencv,包括:
- random resize
- random crop
- random filp
- random HSV
可以明显的看出耗时主要发生在数据读取和数据增强部分,而CPU到GPU的数据转换等耗时较少。
需要注意的一个地方是【crop(8960x540)、转GPU、归一化】和【转GPU、归一化】的耗时差不多,crop的耗时很小,且crop后图片较小,使得转GPU的操作也变快了,最终二者的耗时差不多。
分析将分为以下几个部分: DataLoader 图片读取 * 数据增强
此外由于【CPU转GPU、数据的归一化转秩】和【DataLoader】比较相关,会一起分析。
3. DataLoader
(1) num_workers