【发布时间】:2021-03-09 18:13:44
【问题描述】:
上下文
在训练神经网络时,我意识到当我增加数据集的大小(不改变批处理大小)时,每批花费的时间会增加。重要的是,我需要为每个数据点获取 20 个.npy 文件,这个数字不取决于数据集的大小。
问题
训练从 2s/iteration 到 10s/iteration...
没有明显的理由说明培训需要更长的时间。但是,我设法找到了瓶颈。这似乎与 .npy 文件的加载有关。
要重现此行为,您可以运行以下小脚本来生成 10,000 个虚拟 .npy 文件:
def path(i):
return os.sep.join(('../datasets/test', str(i)))
def create_dummy_files(N=10000):
for i in range(N):
x = np.random.random((100, 100))
np.save(path(random.getrandbits(128)), x)
然后你可以运行以下两个脚本,自己比较一下:
-
随机选择并加载 20 个
.npy文件的第一个脚本:L = os.listdir('../datasets/test') S = random.sample(L, 20) for s in S: np.load(path(s)) # <- timed this -
第二个版本,其中选择并加载了 20 个
.npy'sequential' 文件。L = os.listdir('../datasets/test') i = 100 S = L[i: i + 20] for s in S: np.load(path(s)) # <- timed this
我测试了两个脚本并分别运行了 100 次(在第二个脚本中,我使用迭代计数作为 i 的值,因此相同的文件不会加载两次)。我用time.time() 调用包裹了np.load(path(s)) 行。 我没有计时采样,只有加载。结果如下:
我假设这些时间与加载脚本时 CPU 的活动有关。但是,它并不能解释这种差距。为什么这两个结果如此不同?文件的索引方式有什么关系吗?
编辑:我在随机示例脚本中打印了 S,复制了 20 个文件名的列表,然后使用 S 作为字面定义的列表再次运行它。它所花费的时间与“顺序”脚本相当。这意味着它与文件在 fs 或任何内容中不连续无关。似乎随机采样被计入计时器,然而时间定义为:
t = time.time()
np.load(path(s))
print(time.time() - t)
我也尝试用cProfile 包装np.load(独家):同样的结果。
【问题讨论】:
-
i=100应该是随机的。这样,您就可以测量操作系统是否识别出您一遍又一遍地读取相同的 20 个文件。提示:确实如此,这就是文件系统缓存的用途。 -
我确实尝试不使用迭代
i作为起点两次(在第二个版本中)获取相同的文件。但是我很傻,没有正确地做到这一点! (见下文)。非常感谢@tevemadar
标签: python numpy time cprofile