我有数百万张图像保存在 HDF5 文件中,我想尽快以随机顺序读取这些图像。我比较了顺序(按字母顺序)与随机顺序的读取时间。我发现随机排序时间比顺序读取时间要长得多。如何提高随机顺序读取性能?代码和配置文件时间线如下所示:
with h5py.File("/slowdata/caid_2024/GenImage_compressed.h5") as hf:
keys = list(hf.keys())
from random import shuffle
sleep(0.1)
for i, key in enumerate(keys):
if i == 16:
break
np.array(hf[key])
# Random order now
shuffle(keys)
sleep(0.1)
for i, key in enumerate(keys):
if i == 16:
break
np.array(hf[key])
sleep(0.1)
我无法解释为什么您在分析器中看到如此大的差异。我不认为 I/O 性能会因读取数据集的顺序而出现显着差异。为了证实这一点,我构建了一个简单的测试来模仿您的代码,并且发现变化很小。我的代码在最后 HDF5 数据集不是按顺序访问的,因此按创建顺序读取没有任何优势。此外,数据集名称(也称为键)按字母顺序返回,而不是创建顺序。换句话说,数据集
Alpha
在
Zulu
之前返回,即使 Zulu
是先创建的。所以,你无法真正控制创建顺序的阅读。也就是说,h5py/HDF5
I/O 性能由许多因素控制:
处理非常大的数据集时最重要的因素是分块 I/O(如果启用它,并且块大小设置适当)。np.array(hf[key])
从数据集中创建 NumPy 数组。首选方法是
hf[key][()]
。我对这两种方法进行了基准测试。首选方式是稍微快一点(6-10%),但显示出相同的随机行为与字母行为。 最后是我的测试代码的性能统计。请注意,随机读取顺序实际上比按字母顺序读取要快一些。这可能是由于缓存 I/O 造成的。我需要有关您的文件和数据集的更多详细信息,以诊断您看到差异的原因。
dataset shape = 256, 256, 10_000
H5 size: 39 GB
WITHOUT CHUNKED I/O
Time to create file: 373.49 sec
read peformance:
As written using np.array(hfr[key]):
Time to read datasets alphabetically: 407.66 sec
Time to read datasets randomly: 355.97 sec
Modified to use hfr[key][()]:
Time to read datasets alphabetically: 360.67 sec
Time to read datasets randomly: 333.69 sec
代码如下。
img_w, img_h, img_cnt = 256, 256, 10_000
ds_cnt = 16
start = time.time()
with h5py.File("SO_78500597.h5","w") as hfw:
for i in range(ds_cnt):
rgb_val = int((255/ds_cnt)*i)
hfw.create_dataset(f'image_{i:02}', data=np.full((img_w, img_h, img_cnt), rgb_val, dtype=int))
print(f"Time to create file: {(time.time()-start):.2f} sec")
with h5py.File("SO_78500597.h5") as hfr:
keys = list(hfr.keys())
print(keys)
from random import shuffle
start = time.time()
for i, key in enumerate(keys):
if i == 16:
break
#np.array(hfr[key])
arr = hfr[key][()]
print(f"Time to read datasets alphabetically: {(time.time()-start):.2f} sec")
# Random order now
shuffle(keys)
start = time.time()
for i, key in enumerate(keys):
if i == 16:
break
#np.array(hfr[key])
arr = hfr[key][()]
print(f"Time to read datasets randomly: {(time.time()-start):.2f} sec")