当前位置: 首页 > 面试题库 >

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

汪跃
2023-03-14
问题内容

我有一个合理的大小(压缩后的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行很容易放入内存,所以我看不到任何好处。

问题答案:

找到正确的块缓存大小

首先,我想讨论一些一般性的事情。知道每个单独的块只能整体读取或写入非常重要。默认情况下,可以避免过多的磁盘I /
O的h5py的标准块高速缓存大小仅为默认值1 MB,并且在许多情况下应该增加该大小,稍后将对此进行讨论。

举个例子:

  • 我们有一个形状为(639038,10000),float32(未压缩的25.5 GB)的dset
  • 我们想按列写数据,dset[:,i]=arr并按行读数据arr=dset[i,:]
  • 我们为这种类型的工作选择了完全错误的块形状,即(1,10000)

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

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

假设将给出不错的读/写速度:

  • 我们选择(100,1000)的块大小
  • 如果我们要遍历第一维,则至少需要(1000 * 639038 * 4-> 2,55 GB)高速缓存,以避免如上所述的额外IO开销和(100 * 10000 * 4-> 0.4 MB) 。
  • 因此,在此示例中,我们至少应提供2.6 GB的块数据缓存。

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

关于您的问题, 我只会读取随机行,不正确的chunk-cache-size是您真正的问题。

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

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秒。



 类似资料:
  • 我是Cassandra的新手,我正在努力弄清楚如何存储数据,以便能够并行执行快速读取。我听说分区数据会给性能带来问题?是否可以并行读取同一分区中Cassandra表中的数据?

  • 问题内容: 假设我有一个处理100万个句子的任务。 对于每个句子,我都需要对其进行处理,而这与处理它们的顺序无关。 在我的Java程序中,我从我的主要工作分区中划分出一组期货,并带有一个可调用对象,该可调用对象定义了要在大量句子上完成的工作单元,并且我正在寻找一种优化线程数量的方法分配大量的句子来工作,然后重新组合每个线程的所有结果。 在我看到收益递减之前,我可以使用的最大线程数将使我在速度方面达

  • 问题内容: 从其他一些应用程序中,我正在获取XML文件。 我想逐个节点读取该XML文件,并将节点值存储在数据库中以备将来使用。 那么,使用Java读取XML文件和检索节点值的最佳方法/ API是什么? 问题答案: dom4j和jdom非常易于使用(暂时忽略“最佳”需求;))

  • fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets() 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread() 函数;相应地写入函数为 fwrite()。 对于 Windows 系统,使用 fread() 和 fwrite() 时应该以二进制的形式打开文件,具体原因我们已在《 文本文件和二进制文件到底有什么区别》一文中进行了说明。 fread() 函数用来从

  • 我是spark的新手,正在尝试使用java将avro数据加载到spark“dataset”(spark 1.6)。我在scala中看到了一些示例,但在java中没有看到。任何指向java示例的指针都会很有帮助。我试图创建一个javaRDD,然后将其转换为“dataset”。我相信一定有一条直截了当的路。

  • 本文向大家介绍Python读取数据集并消除数据中的空行方法,包括了Python读取数据集并消除数据中的空行方法的使用技巧和注意事项,需要的朋友参考一下 如下所示: 以上这篇Python读取数据集并消除数据中的空行方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。