使用GeneratorDataset加载自定义数据集时,会根据num_parallel_workers来启动多线程或多线程来加载数据集,每个进程或者线程中都会尝试去打开数据集文件。
Linux一般默认允许同时打开的文件数为1024 ,当并发度过高 (num_parallel_workers)并且数据集文件较多,可能会导致出现 OSERROR: [Errno 24] Too many open files 。
此时可以在shell环境上执行ulimit -n 65535 来调整同时打开文件的阈值。
另外对Dataset对象进行“非常规”的操作,也有可能导致 Too many open files 错误。
1 import numpy as np
2 import mindspore.dataset as ds
3 import argparse
4 from mindspore import context
5 from datasets.online_adaptation_dataset import OnlineAdaptationDataset, OnlineAdaptationDatasetStorage
6
7 class MyAccessible:
8 def __init__(self):
9 self._data = np.random.sample((10, 2))
10 self._label = np.random.sample((10, 1))
11
12 def __getitem__(self, index):
13 return self._data[index], self._label[index]
14
15 def __len__(self):
16 return len(self._data)
17
18 class MyData:
19 def __init__(self, data):
20 self.data = data
21
22 def __getitem__(self, index):
23 return self.data.__getitem__(index)
24
25 if __name__ == '__main__':
26 parser = argparse.ArgumentParser(description='MindSpore LeNet Example')
27 parser.add_argument('--device_target', type=str, default="Ascend", choices=['Ascend', 'GPU', 'CPU'])
28
29 args = parser.parse_known_args()[0]
30 context.set_context(device_id=4, mode=context.PYNATIVE_MODE, device_target=args.device_target)
31 for i in range(10):
32 data = MyAccessible()
33 dataset = ds.GeneratorDataset(source=MyData(data), column_names=["data", "label"],num_parallel_workers=4, shuffle=True)
34 dataset = dataset.batch(batch_size=2)
35 import pdb;pdb.set_trace()
36 datas = iter(dataset)
37 print(next(datas))
38 datas = iter(dataset)
脚本中第36行使用iter()来创建迭代器对象后,在第37行中使用next(datas)读取迭代器中第一个元素,然后在第38行重复使用iter()来创建迭代器。
原因分析:
1. Mindspore提供了create_dict_iterator()和create_tuple_iterator(),分别返回dict迭代器和tuple迭代器,不建议直接使用iter()方法来生成迭代器。
create_dict_iterator()以及create_tuple_iterator(),可以设置num_epochs参数来控制迭代器的迭代次数,以及output_numpy参数来控制输出数据类型为numpy.ndarray或者Tensor。
2. 重复调用iter()会重复创建迭代器,而GeneratorDataset加载数据集时默认为多进程加载,每次打开的句柄在主进程停止前得不到释放,导致打开句柄数一直在增长。
解决方法:
第36行修改为
datas=dataset.create_tuple_iterator(num_epochs=1, output_numpy=True)
移除第38行