PyTorch DataLoader出现‘too many open files’错误排查求助
这个问题我之前在旧版本PyTorch里碰到过,结合你的代码和环境来看,大概率是PyTorch 0.3.x多进程数据加载机制的文件描述符泄漏bug导致的,给你几个针对性的解决方案:
1. 先降低num_workers验证问题根源
首先可以把num_workers设为0或者1,关闭多进程加载,看看错误是否消失:
playloader = torch.utils.data.DataLoader(ds, batch_size=PLAY_BATCH_SIZE, shuffle=False, num_workers=0)
当num_workers=0时,数据加载会在主进程中完成,不会创建子进程,也就不会触发多进程带来的资源继承/泄漏问题。如果这样错误消失,就可以确认问题出在多进程加载的逻辑上。
2. 让每个worker独立加载数据集
你的当前代码是在主进程加载完json数据后传给Dataset,在旧版本PyTorch的多进程模式下,子进程会继承主进程的内存状态,可能附带一些隐式的资源句柄。可以修改Dataset,让每个worker进程自己读取json文件:
class IceShipDataset(Dataset): BAND1='band_1' BAND2='band_2' IMAGE='image' @staticmethod def get_band_img(sample,band): pic_size=75 img=np.array(sample[band]) img.resize(pic_size,pic_size) return img def __init__(self, json_path, transform=None): # 每个worker初始化时独立读取文件 with open(json_path,'r') as f: data=f.read() self.data=json.loads(data) self.transform=transform def __len__(self): return len(self.data) def __getitem__(self, idx): sample=self.data[idx] band1_img=IceShipDataset.get_band_img(sample,self.BAND1) band2_img=IceShipDataset.get_band_img(sample,self.BAND2) img=np.stack([band1_img,band2_img],2) sample[self.IMAGE]=img if self.transform is not None: sample=self.transform(sample) return sample
然后修改Dataset的初始化代码:
ds=IceShipDataset('train.json')
这样每个worker进程会独立完成文件读取和数据加载,避免继承主进程的潜在资源泄漏。
3. 升级PyTorch版本(最根本的解决方案)
PyTorch 0.3.0是非常老旧的版本,后续的0.4.x及以上版本修复了大量多进程数据加载的bug,包括文件描述符泄漏这类问题。如果你的项目允许,强烈建议升级到较新的稳定版本,从根源上避免这类旧版本的遗留问题。
问题原因分析
在PyTorch 0.3.x的多进程DataLoader实现中,当设置num_workers>0时,系统会通过fork创建子进程,子进程会继承主进程的所有文件描述符(即使主进程已经显式关闭文件,也可能存在隐式残留的描述符)。再加上旧版本DataLoader本身的资源管理缺陷,会导致大量文件描述符被占用,最终触发too many open files错误。
内容的提问来源于stack exchange,提问作者Yoni Keren

