|
深度学习干活时,经常碰上那种破事:数据是一大堆小文件。比如做图像识别,训练集里几百万张图片,每张才几十KB;搞自然语言处理,语料库拆成无数个小文本文件。这种时候,硬盘IO就成了瓶颈,GPU再猛也得干等着数据喂,急死个人。
那么,咋整才能让数据读取快起来?下面唠几个实在的法子。
第一招:打包成专用格式
别让程序直接读散装小文件了,太慢。把它们打包成连续存放的大文件,比如TFRecord(TensorFlow用)、HDF5、或者LMDB这些。原理就是把一堆小文件拼成一个大文件,同时生成一个索引文件记录每个小文件在大文件里的位置和长度。读取的时候,顺着大文件连续读,硬盘磁头不用来回跳,速度能翻好几倍。这就好比运沙子,别一粒一粒搬,装成一大袋扛着走。
第二招:搞个缓存
有些数据反复用,比如训练时每个epoch都遍历一遍数据集。可以在内存里划块地方当缓存,把最近用过的数据放进去。下次再要,直接从内存拿,比读硬盘快百倍不止。如果内存不够大,可以设个缓存队列,或者用速度快的固态硬盘当二级缓存。内存好比桌上的书,伸手就拿到;硬盘是书架上的书,得走过去取。
第三招:预处理和预加载
训练开始前,把数据预处理干净,比如图片缩放、归一化,然后存成处理后的格式。训练时省掉预处理时间。还可以在GPU算这一批数据时,后台线程提前把下一批数据从硬盘读到内存里,这叫预加载。GPU忙它的,读数据的活也在同时干,两不耽误。
第四招:调整数据读取的并发数
深度学习框架读数据通常用多线程或多进程。并发数不是越多越好,设太多了,硬盘扛不住,线程之间抢资源反而更慢。得根据CPU核心数、硬盘类型(机械盘还是固态盘)慢慢试,找个最合适的并发数。比如用固态盘,并发可以调高些;机械盘并发高了就卡。
第五招:用更快的存储硬件
归根结底,硬件是基础。把数据集放到固态硬盘上,速度比机械硬盘快得多。如果条件允许,上NVMe固态,更快。对于超大规模的训练,可以用内存盘,或者高速网络存储,但那个成本就高了。
第六招:数据压缩
在打包大文件时,可以对每个小文件做无损压缩,减少总体积。读的时候解压,虽然多了一步计算,但IO压力小了,总体可能更快。尤其是文本类数据,压缩效果很明显。
总结一下
核心思想就两个:一是减少硬盘寻址次数,用打包大文件的方法;二是减少等待时间,用缓存、预加载、调整并发这些招。实际应用中,往往是几种方法组合着用。先拿部分数据做实验,看瓶颈到底在哪儿,再对症下药。调好了,数据读取嗖嗖的,GPU就能满负荷跑起来,训练时间大大缩短。
|
|