保存到hdf5的速度非常慢(Python冻结)

8 浏览
0 Comments

保存到hdf5的速度非常慢(Python冻结)

我正在尝试将瓶颈值保存到一个新创建的hdf5文件中。

瓶颈值以大小为(120,10,10,2048)的批次形式出现。

保存一个批次就占用了超过16GB的空间,而且Python似乎在那个批次上冻结了。根据最近的发现(见更新部分),似乎hdf5占用大内存是可以接受的,但冻结部分似乎是一个故障。

我只想测试目的,只保存前2个批次,并且只保存训练数据集(再次强调,这是一个测试运行),但我甚至无法通过第一个批次。它只是在第一个批次处停滞不前,不会循环到下一个迭代。如果我尝试检查hdf5,资源管理器会变得迟钝,Python会冻结。如果我试图关闭Python(即使没有检查hdf5文件),Python无法正确关闭,它会强制重新启动。

以下是相关的代码和数据:

总共的数据点大约有90,000个,以每批120个的形式发布。

瓶颈形状是(120,10,10,2048)

我尝试保存数据集的方式如下:

with h5py.File(hdf5_path, mode='w') as hdf5:
                hdf5.create_dataset("train_bottle", train_shape, np.float32)
                hdf5.create_dataset("train_labels", (len(train.filenames), params['bottle_labels']),np.uint8)
                hdf5.create_dataset("validation_bottle", validation_shape, np.float32)
                hdf5.create_dataset("validation_labels",
                                              (len(valid.filenames),params['bottle_labels']),np.uint8)
 #上述第一部分工作正常
                current_iteration = 0
                print('created_datasets')
                for x, y in train:
                    number_of_examples = len(train.filenames) # 图像数
                    prediction = model.predict(x)
                    labels = y
                    print(prediction.shape) # (120,10,10,2048)
                    print(y.shape) # (120, 12)
                    print('start',current_iteration*params['batch_size']) # 0
                    print('end',(current_iteration+1) * params['batch_size']) # 120
                    hdf5["train_bottle"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = prediction
                    hdf5["train_labels"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = labels
                    current_iteration += 1
                    print(current_iteration)
                    if current_iteration == 3:
                       break

这是打印语句的输出:

(90827, 10, 10, 2048) # 打印(train_shape)
(6831, 10, 10, 2048)  # 打印(validation_shape)
created_datasets
(120, 10, 10, 2048)  # 打印(prediction.shape)
(120, 12)           # label.shape
start 0             # 批次开始
end 120             # 批次结束
# 在这里停滞不前,没有打印`print(current_iteration)`

它在这里停滞了一段时间(超过20分钟),而hdf5文件的大小慢慢增长(现在大约20GB),然后我强制终止。实际上,我甚至无法通过任务管理器强制终止,我必须重新启动操作系统才能真正终止Python。

更新

在我的代码中稍作调整后,发现了一个奇怪的错误/行为。

相关部分如下:

          hdf5["train_bottle"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = prediction
                hdf5["train_labels"][current_iteration*params['batch_size']: (current_iteration+1) * params['batch_size'],...] = labels

如果我运行这两行中的任意一行,我的脚本将按预期进行迭代,并自动中断。所以如果我运行其中之一,就不会冻结。而且速度相当快,不到一分钟。

如果我运行第一行('train_bottle'),即使只有几个批次,我的内存占用也会达到约69-72GB。如果我尝试更多批次,内存仍然是一样的。所以我猜测train_bottle根据我分配给数据集的大小参数决定了存储空间,而不是实际填充时。

所以尽管有72GB的内存,但运行得相当快(不到一分钟)。

如果我运行第二行train_labels,我的内存占用几兆字节。

迭代没有问题,中断语句也被执行。

然而,现在问题来了,如果我尝试同时运行这两行(在我的情况下需要保存'train_bottle'和'train_labels'两者),我会在第一次迭代上冻结,并且不会继续到第二次迭代,即使过了20分钟。Hdf5文件在慢慢增长,但如果我尝试访问它,Windows资源管理器会变得非常慢,我无法关闭Python - 我必须重新启动操作系统。

所以我不确定在同时运行这两行时有什么问题 - 如果我运行内存占用较大的train_data行,一切都完美地在一分钟内结束。

0
0 Comments

这篇文章主要讨论了保存数据到hdf5文件的速度慢的问题,并给出了解决方法。具体来说,作者通过使用提供的代码,并按照建议进行了修改,然后测试了hdf5和np.save()的速度。作者的配置是:SSD硬盘为Samsung 960 EVO,CPU为i7-7700K,内存为2133 MHz 16GB,操作系统为Windows 10。测试结果显示,使用HDF5的速度为1339.5 MB/s,而使用np.save()的速度为924.9 MB/s(不使用压缩)。此外,作者还提到,有一位用户在使用lzf-Filter时遇到了问题,如果读者也遇到了这个问题,可以在Windows 10上使用conda分发的python3和pip安装的软件包来运行作者提供的jupyter notebook。最佳的保存/加载大型数组的方法取决于各种因素(最重要的是可实现的压缩比)。在许多情况下,可以通过大幅度地超越HDF5(只有单线程压缩过滤器)来提高性能。此外,吞吐量也可能有很大的差异。使用哪种SSD?它是满的还是空的?数组有多大?(许多SSD有一个快速的SLC-Cache)...

0
0 Comments

问题原因:保存数据到HDF5文件时非常慢,导致Python卡住。即使HDF5的性能只有np.load()和np.save()的1/5到1/7,但目前没有其他工具或框架能够与其竞争。

解决方法:使用np.load()和np.save()函数直接加载和保存数据,可以获得最快的性能。如果你有足够的DDR内存并且想要极快的数据加载和保存性能,请使用这两个函数。只有使用PCIe SSD才能超越这种解决方案的性能。即使如此,你也需要将np.save()和np.load()与HDF5进行比较,以保持一致。例如,将HDF5函数替换为np.save(),通过这个例子,我可以在我的SATA3 SSD上获得完整的带宽(大约MB/s),几乎没有CPU使用率。但大多数情况下,这并不推荐,因为你几乎失去了HDF5的所有优势(只写或读取文件的部分,压缩)。

作者建议不需要争论np.load()和np.save()和HDF5哪个更快,只需要将HDF5函数替换为np.save()。作者的测试结果显示,np.save()函数的带宽为2.3GBps(18Gbps),是HDF5性能的8倍以上。作者相信你的计算机比他的更快,所以可能达到4~5GBps的速度。请尝试一下,只需要将dset_train_bottle()函数替换为np.save()即可。期待你的测试结果。这并不是一个很大的工作量。

0
0 Comments

问题出现的原因:

- h5py在没有指定chunkshape的情况下会自动为你创建chunked dataset。但是由于h5py无法知道你如何读取或写入数据集,这经常会导致性能问题。

- 默认的chunk-cache-size为1MB。如果你只写入chunk的一部分,并且该chunk无法适应缓存(使用1MB的chunk-cache-size),整个chunk将被读入内存,修改后再写回磁盘。如果发生多次这样的操作,性能将远远超出HDD/SSD的顺序IO速度。

解决方法:

- 设置一个较大的chunk-cache-size,确保能够读取或写入整个chunk。

- 根据需要修改代码,只在第一维度上读取或写入数据。

- 使用with语句打开HDF5文件时,确保不要多次调用该块,这将关闭并重新打开文件,删除chunk-cache。

- 根据需求确定合适的chunk大小。

文章内容如下:

写入数据到HDF5文件

如果你在没有指定chunkshape的情况下写入chunked dataset,h5py会自动为你创建chunkshape。然而,由于h5py无法知道你如何读取或写入数据集,这经常会导致性能问题。

此外,默认的chunk-cache-size为1MB。如果你只写入chunk的一部分,并且该chunk无法适应缓存(使用1MB的chunk-cache-size),整个chunk将被读入内存,修改后再写回磁盘。如果发生多次这样的操作,性能将远远超出HDD/SSD的顺序IO速度。

以下示例假设你只在第一维度上读取或写入数据。如果不是这样,需要根据自己的需求进行修改。

import numpy as np
import tables #register blosc
import h5py as h5
import h5py_cache as h5c
import time
batch_size=120
train_shape=(90827, 10, 10, 2048)
hdf5_path='Test.h5'
# 设置一个较大的chunk-cache-size,确保能够读取或写入整个chunk
f = h5c.File(hdf5_path, 'w',chunk_cache_mem_size=1024**2*200) #200 MB cache size
# 创建dataset时指定chunks参数,以便进行整块读取或写入
dset_train_bottle = f.create_dataset("train_bottle", shape=train_shape,dtype=np.float32,chunks=(10, 10, 10, 2048),compression=32001,compression_opts=(0, 0, 0, 0, 9, 1, 1), shuffle=False)
prediction=np.array(np.arange(120*10*10*2048),np.float32).reshape(120,10,10,2048)
t1=time.time()
# 测试2GB数据的写入性能
for i in range(20):
    dset_train_bottle[i*batch_size:(i+1)*batch_size,:,:,:]=prediction
f.close()
print(time.time()-t1)
print("MB/s: " + str(2000/(time.time()-t1)))

编辑:

在循环中创建数据花费了很多时间,因此我在测量时间之前先创建了数据。这样至少可以达到900MB/s的吞吐量(受CPU限制)。对于真实数据和较低的压缩比,你应该可以轻松达到硬盘的顺序IO速度。

使用with语句打开HDF5文件时,如果错误地多次调用该块,会导致性能下降,因为这将关闭并重新打开文件,删除chunk-cache。

关于确定合适的chunk大小,建议参考以下链接:

- [https://stackoverflow.com/a/48405220/4045774](https://stackoverflow.com/a/48405220/4045774)

- [https://stackoverflow.com/a/44961222/4045774](https://stackoverflow.com/a/44961222/4045774)

以上方法应该可以解决问题。如果还有其他建议,请提供相关链接。chunking是我不太熟悉的内容,我会在处理其他事情之后阅读相关资料。非常感谢你详细的回答。我需要再运行一些测试来确保(希望明天能完成)。谢谢你!

0