【问题标题】:How to load a large h5 file in memory?如何在内存中加载一个大的 h5 文件?
【发布时间】:2021-02-15 03:11:42
【问题描述】:

我在 HDFS 中有一个带有 5 维 numpy 数组的大型 h5 文件。文件大小约为 130Gb。我在加载文件时遇到内存问题,即使机器有 256Gb RAM,进程也会被 OOM 错误杀死。如何以块的形式写入文件并以块的形式加载回来?我环顾四周,发现 h5py 提供了像这样对数据集进行分块的方法,但是如何以块的形式加载数据呢?如果文件驻留在 HDFS 中,它也可以工作吗?

dset = f.create_dataset("Images2", (100,480,640), 'f', chunks=True)

想法是批量加载文件以减少 I/O 时间以及内存问题。任何帮助将不胜感激。

【问题讨论】:

  • 即使没有块,您也可以加载切片,例如dset[33]dset[22:55]h5py 文档中对此进行了说明。

标签: numpy hdfs hdf5 h5py chunking


【解决方案1】:

上面的答案和cmets中提到了两个相似(但不同)的h5py I/O概念:

  • HDF5 分块 用于启用分块 I/O 以提高性能。如果您在尝试读取内存不足的大型数据集时遇到 OOM 错误,则分块可能无济于事
  • NumPy 风格切片 用于从驱动器读取数据切片到内存(或将数据切片写入驱动器)。在读取非常大的文件时,切片是避免 OOM 错误的关键。
  • 另外,当创建非常大的数据集时,通常需要使 它可调整大小。您可以分配一个初始大小,然后使用“.resize()”方法来增加磁盘上的大小。

我写了一个简单的例子来展示如何同时使用切片和分块。它一次将 100 张图像加载到可调整大小的数据集中。然后它会关闭文件并重新打开(只读)以一次将 100 张图像读取到 NumPy 数组中。

有效的分块需要适当的大小/形状,并且取决于您的阵列形状和 I/O 需求。我在示例中设置了块大小/形状以匹配我正在写入/读取的 100 个图像数组的大小。

这个例子应该让你开始。您需要修改以使用 5 维数组/数据集。

import numpy as np
import h5py

with h5py.File('SO_64645940.h5','w') as h5w:
    img_ds = h5w.create_dataset('Images', shape=(100,480,640), dtype='f', maxshape=(None,480,640),chunks=(10,480,640))

    next_img_row = 0    
    arr = np.random.random(100*480*640).reshape(100,480,640)
    for cnt in range(1,10):
#        print(cnt,img_ds.len(),next_img_row)
        if img_ds.len() == next_img_row :
            img_ds.resize(100*cnt,axis=0)
            print('new ds size=',img_ds.len())
        h5w['Images'][next_img_row:next_img_row+100] = arr
        next_img_row += 100
    
    
with h5py.File('SO_64645940.h5','r') as h5r:
     for cnt in range(10):
         print('get slice#',str(cnt))
         img_arr = h5r['Images'][cnt*100:(cnt+1)*100] 

【讨论】:

    【解决方案2】:

    HDF5 中的分块意味着数据不是连续存储的,而是分块存储的。 在此处查看信息:https://docs.h5py.org/en/stable/high/dataset.html#chunked-storage --> 所以这对你的问题没有帮助。

    解决方案可能是您自己构建一个函数来分块加载数据。 例如,我以这种方式将数据分块:

    def get_chunked(data, chunk_size=100):
        for i in give_chunk(len(data), chunk_size):
            chunked_array = data[i]
            yield chunked_array
    
    def give_chunk(length, chunk_size):
        it = iter(range(length))
        while True:
            chunk = list(itertools.islice(it, chunk_size))
            if not chunk:
                break
            yield chunk
    

    要将数据写入 HDF5,您可以先创建数据集,然后通过切片明智地写入数据块,请参阅 h5py 文档:https://docs.h5py.org/en/stable/high/dataset.html#reading-writing-data

    关于HDF5的基础知识我真的可以推荐这本书:https://www.oreilly.com/library/view/python-and-hdf5/9781491944981/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-29
      • 2019-08-03
      • 2015-09-09
      • 2020-03-19
      • 1970-01-01
      • 1970-01-01
      • 2014-10-22
      • 1970-01-01
      相关资源
      最近更新 更多