DataLoader 参数调优
一句话定位:训练/推理慢,很多时候不是 GPU 不够快,而是数据喂不上。DataLoader 调优的目标只有一个——让数据供给速度追上 GPU 消费速度,把 GPU 利用率从锯齿状拉成一条直线。
1. 三个核心参数
1 num_workers:并行加载子进程数
- 用多个子进程并行做数据读取与前处理(解析、解码、增强),与主进程的 GPU 计算重叠。
0表示在主进程加载,GPU 会被数据准备完全阻塞。- 过高的代价:每个 worker 是独立进程,会抢占 CPU 并各自持有一份内存(数据集对象、缓冲区),导致 CPU 争抢、内存暴涨甚至 OOM;进程间通信与序列化开销也随之上升。
- 经验取值:与可用 CPU 核数匹配(常见 4~8 或
核数/GPU数),需实测。
2 pin_memory:锁页内存
- 设为
True时,DataLoader 把 batch 放入锁页(page-locked / pinned)内存。 - 作用:锁页内存不会被操作系统换出,因此 Host→Device 拷贝可以走异步 DMA,与计算重叠(配合
non_blocking=True的.to(device))。非锁页内存的 H2D 拷贝需要先暂存到临时锁页缓冲,多一次拷贝且无法异步。 - 代价:占用不可换出的物理内存,过量使用会挤压系统内存。
3 prefetch_factor:每 worker 预取批数
- 每个 worker 提前准备的 batch 数(默认 2),即预取队列深度。
- 作用:掩盖 I/O 与前处理延迟——GPU 消费当前 batch 时,后续 batch 已在准备好的队列中,避免 GPU 等待(与 1.6 的异步预取是同一思想)。
- 代价:队列越深,内存占用越高。
2. 判断依据:GPU 利用率呈锯齿状
这是最实用的诊断信号:
- 用
nvidia-smi(或 dmon / Nsight)观察 GPU 利用率曲线,若呈锯齿状(忙一下→掉到低位→再忙),说明 GPU 周期性空等 → 数据供给不足,瓶颈在 CPU 侧的加载/前处理,而不是 GPU 算力。 - 此时正确动作是调
num_workers/prefetch_factor/pin_memory、优化前处理与数据格式(如换 Parquet/Arrow 减少解析开销,见 1.7),而不是换更强的卡。 - 反之若利用率持续接近满载,才应从 kernel/batch/并行策略入手(对应 3.3 瓶颈定位)。
参考:PyTorch 官方文档
torch.utils.data.DataLoader