用于读取行的最佳 HDF5 数据集块形状

2025-03-05 09:15:00
admin
原创
81
摘要:问题描述:我有一个合理大小(压缩后为 18GB)的 HDF5 数据集,并且希望优化读取行的速度。形状为 (639038, 10000)。我将多次读取位于数据集中的选定行(例如 ~1000 行)。因此,我不能使用 x:(x+1000) 来切片行。使用 h5py 从内存不足的 HDF5 读取行已经很慢了,因为我必...

问题描述:

我有一个合理大小(压缩后为 18GB)的 HDF5 数据集,并且希望优化读取行的速度。形状为 (639038, 10000)。我将多次读取位于数据集中的选定行(例如 ~1000 行)。因此,我不能使用 x:(x+1000) 来切片行。

使用 h5py 从内存不足的 HDF5 读取行已经很慢了,因为我必须传递一个排序列表并诉诸花哨的索引。有没有办法避免花哨的索引,或者有没有更好的块形状/大小可以使用?

我读过一些经验法则,例如 1MB-10MB 的块大小和选择与我所读内容一致的形状。但是,构建大量具有不同块形状的 HDF5 文件进行测试在计算上非常昂贵,而且速度非常慢。

对于每选择约 1,000 行,我都会立即将它们相加,得到一个长度为 10,000 的数组。我当前的数据集如下所示:

'10000': {'chunks': (64, 1000),
          'compression': 'lzf',
          'compression_opts': None,
          'dtype': dtype('float32'),
          'fillvalue': 0.0,
          'maxshape': (None, 10000),
          'shape': (639038, 10000),
          'shuffle': False,
          'size': 2095412704}

我已经尝试过的:

  • 重写块形状为(128,10000)的数据集(我计算其大小约为5MB)的速度非常慢。

  • 我查看了 dask.array 进行优化,但由于~1,000 行很容易装入内存,所以我没有看到任何好处。


解决方案 1:

找到正确的块缓存大小

首先我想讨论一些一般性的东西。了解每个单独的块只能作为一个整体进行读取或写入非常重要。h5py 的标准块缓存大小可以避免过多的磁盘 I/O,默认情况下仅为 1 MB,在许多情况下应该增加,这将在后面讨论。

举个例子:

  • 我们有一个形状为 (639038, 10000) 的数据集,float32(未压缩时为 25,5 GB)

  • 我们希望按列写入数据dset[:,i]=arr,按行读取数据arr=dset[i,:]

  • 对于这种类型的工作,我们选择了一个完全错误的块形状,即(1,10000)

在这种情况下,读取速度不会太差(尽管块大小有点小),因为我们只读取我们正在使用的数据。但是当我们在该数据集上写入时会发生什么?如果我们访问一列,则会写入每个块的一个浮点数。这意味着我们实际上在每次迭代中写入整个数据集(25.5 GB),并且每隔一次读取整个数据集。这是因为如果您修改一个块,如果它没有缓存,您必须先读取它(我假设这里的块缓存大小低于 25.5 GB)。

那么我们可以在这里改进什么呢?在这种情况下,我们必须在写入/读取速度和块缓存使用的内存之间做出妥协。

一个能提供良好读写速度的假设:

  • 我们选择块大小为(100, 1000)

  • 如果我们想要迭代第一个维度,我们至少需要(10006390384 ->2,55 GB)的缓存以避免如上所述的额外 IO 开销和(100100004 -> 0,4 MB)。

  • 因此,在这个例子中,我们应该提供至少 2.6 GB 的块数据缓存。

结论
没有普遍正确的块大小或形状,它在很大程度上取决于要使用哪个任务。在不考虑块缓存的情况下,切勿选择块大小或形状。就随机读/写而言,RAM 比最快的 SSD 快几个数量级。

关于你的问题,
我只会读取随机行,不适当的块缓存大小才是你的真正问题。

将以下代码与您的版本的性能进行比较:

import h5py as h5
import time
import numpy as np

def ReadingAndWriting():
    File_Name_HDF5='Test.h5'

    #shape = (639038, 10000)
    shape = (639038, 1000)
    chunk_shape=(100, 1000)
    Array=np.array(np.random.rand(shape[0]),np.float32)

    #We are using 4GB of chunk_cache_mem here ("rdcc_nbytes")
    f = h5.File(File_Name_HDF5, 'w',rdcc_nbytes =1024**2*4000,rdcc_nslots=1e7)
    d = f.create_dataset('Test', shape ,dtype=np.float32,chunks=chunk_shape,compression="lzf")

    #Writing columns
    t1=time.time()
    for i in range(0,shape[1]):
        d[:,i:i+1]=np.expand_dims(Array, 1)

    f.close()
    print(time.time()-t1)

    # Reading random rows
    # If we read one row there are actually 100 read, but if we access a row
    # which is already in cache we would see a huge speed up.
    f = h5.File(File_Name_HDF5,'r',rdcc_nbytes=1024**2*4000,rdcc_nslots=1e7)
    d = f["Test"]
    for j in range(0,639):
        t1=time.time()
        # With more iterations it will be more likely that we hit a already cached row
        inds=np.random.randint(0, high=shape[0]-1, size=1000)
        for i in range(0,inds.shape[0]):
            Array=np.copy(d[inds[i],:])
        print(time.time()-t1)
    f.close()

最简单的花式切片

我在评论中写道,在最近的版本中我看不到这种行为。我错了。比较以下内容:

def Writing():File_Name_HDF5='Test.h5'

#shape = (639038, 10000)
shape = (639038, 1000)
chunk_shape=(100, 1000)
Array=np.array(np.random.rand(shape[0]),np.float32)

# Writing_1 normal indexing
###########################################
f = h5c.File(File_Name_HDF5, 'w',chunk_cache_mem_size=1024**2*4000)
d = f.create_dataset('Test', shape ,dtype=np.float32,chunks=chunk_shape,compression="lzf")

t1=time.time()
for i in range(shape[1]):
    d[:,i:i+1]=np.expand_dims(Array, 1)

f.close()
print(time.time()-t1)

# Writing_2 simplest form of fancy indexing
###########################################
f = h5.File(File_Name_HDF5, 'w',rdcc_nbytes =1024**2*4000,rdcc_nslots=1e7)
d = f.create_dataset('Test', shape ,dtype=np.float32,chunks=chunk_shape,compression="lzf")

#Writing columns
t1=time.time()
for i in range(shape[1]):
    d[:,i]=Array

f.close()
print(time.time()-t1)

这使得我的硬盘上第一个版本耗时 34 秒,第二个版本耗时 78 秒。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2757  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1693  
  在全球化的浪潮下,企业的业务范围不断拓展,跨文化协作变得愈发普遍。不同文化背景的团队成员在合作过程中,由于语言、价值观、工作习惯等方面的差异,往往会面临诸多沟通挑战。而产品生命周期管理(PLM)系统作为企业管理产品全生命周期的重要工具,如何有效支持跨文化协作成为了关键问题。通过合理运用沟通策略,PLM系统能够在跨文化团...
plm是什么软件   15  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色,其中文档版本控制是确保产品数据准确性、完整性和可追溯性的关键环节。有效的文档版本控制能够避免因版本混乱导致的错误、重复工作以及沟通不畅等问题,提升企业整体的运营效率和产品质量。接下来,我们将深入探讨 PLM 系统实现文档版本控制的 6...
plm是什么意思   19  
  PLM(产品生命周期管理)项目管理旨在通过有效整合流程、数据和人员,优化产品从概念到退役的整个生命周期。在这个过程中,敏捷测试成为确保产品质量、加速交付的关键环节。敏捷测试强调快速反馈、持续改进以及与开发的紧密协作,对传统的测试流程提出了新的挑战与机遇。通过对测试流程的优化,能够更好地适应PLM项目的动态变化,提升产品...
plm管理系统   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用