【问题标题】:Randomly selected file take longer to load with numpy.load than sequential ones使用 numpy.load 随机选择的文件加载时间比顺序文件要长
【发布时间】: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)) 行。 我没有计时采样,只​​有加载。结果如下:

  • 随机加载(时间大致保持在 0.1s 和 0.4s 之间,平均为 0.25s):

  • 非随机加载(时间大致保持在 0.010s 和 0.014s 之间,平均为 0.01s):


我假设这些时间与加载脚本时 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


【解决方案1】:

我确实说过:

我测试了两个脚本并分别运行了 100 次(在第二个脚本中,我使用迭代计数作为 i 的值,因此相同的文件不会加载两次)

但是正如tevemadar 提到的那样

i 应该是随机的

我完全搞砸了第二个版本中选择不同文件的操作。我的代码将脚本计时 100 次,如下所示:

for i in trange(100):
   if rand:
      S = random.sample(L, 20)
   else:
      S = L[i: i+20] # <- every loop there's only 1 new file added in the selection, 
                     #    19 files will have already been cached in the previous fetch

对于第二个脚本,它应该是S = L[100*i, 100*i+20]

是的,在计时时,结果是可比的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 2015-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多