Python 从hdf到ndarray的numpy-快速方式

Python 从hdf到ndarray的numpy-快速方式,python,numpy,hdf5,h5py,Python,Numpy,Hdf5,H5py,我正在寻找一种快速的方法,将我的hdf文件集合设置为一个numpy数组,其中每一行都是图像的展开版本。我的确切意思是: 我的hdf文件除了存储其他信息外,还存储每帧的图像。每个文件包含51帧和512x424个图像。现在我有300多个hdf文件,我希望图像像素以每帧一个向量的形式存储,其中所有图像的所有帧都存储在一个numpy数组中。以下图片有助于理解: 到目前为止,我得到的是一个非常缓慢的方法,实际上我不知道如何使它更快。问题是,据我所想,我的最终数组调用太频繁了。因为我观察到第一批文件加载到

我正在寻找一种快速的方法,将我的hdf文件集合设置为一个numpy数组,其中每一行都是图像的展开版本。我的确切意思是:

我的hdf文件除了存储其他信息外,还存储每帧的图像。每个文件包含51帧和512x424个图像。现在我有300多个hdf文件,我希望图像像素以每帧一个向量的形式存储,其中所有图像的所有帧都存储在一个numpy数组中。以下图片有助于理解:

到目前为止,我得到的是一个非常缓慢的方法,实际上我不知道如何使它更快。问题是,据我所想,我的最终数组调用太频繁了。因为我观察到第一批文件加载到数组中的速度非常快,但速度下降得很快。(通过打印当前hdf文件的编号观察)

我当前的代码:

os.chdir(os.getcwd()+"\\datasets")

# predefine first row to use vstack later
numpy_data = np.ndarray((1,217088))

# search for all .hdf files
for idx, file in enumerate(glob.glob("*.hdf5")):
  f = h5py.File(file, 'r')
  # load all img data to imgs (=ndarray, but not flattened)
  imgs = f['img']['data'][:]

  # iterate over all frames (50)
  for frame in range(0, imgs.shape[0]):
    print("processing {}/{} (file/frame)".format(idx+1,frame+1))
    data = np.array(imgs[frame].flatten())
    numpy_data = np.vstack((numpy_data, data))

    # delete first row after another is one is stored
    if idx == 0 and frame == 0:
        numpy_data = np.delete(numpy_data, 0,0)

f.close()
为了进一步了解,我需要这个来学习决策树。因为我的hdf文件比RAM大,所以我认为转换成numpy阵列可以节省内存,因此更适合


谢谢你的每一个意见

我认为你不需要反复讨论

imgs = f['img']['data'][:]
并重塑每个二维阵列的形状。只是重塑整件事。如果我没弄错你的描述,
imgs
是一个3d阵列:(51512424)

应为2d等效项

如果必须循环,请不要使用
vstack
(或某种变体来构建更大的阵列)。一是速度慢,二是清理初始的“虚拟”条目很痛苦。使用列表附录,并在末尾堆叠一次

alist = []
for frame....
   alist.append(data)
data_array = np.vstack(alist)
vstack
(和family)将数组列表作为输入,因此它可以同时处理多个数组。列表追加在迭代完成时要快得多

我怀疑将事物放入一个数组是否会有所帮助。我不知道一个
hdf5
文件的大小与下载的数组大小有什么关系,但我希望它们的大小是相同的。因此,尝试将所有300个文件加载到内存中可能不起作用。那是什么,3G像素

对于单个文件,
h5py
提供了加载太大而无法装入内存的数组块的功能。这表明问题往往会反过来发展,文件保存的内容太多


我认为你不需要反复讨论

imgs = f['img']['data'][:]
并重塑每个二维阵列的形状。只是重塑整件事。如果我没弄错你的描述,
imgs
是一个3d阵列:(51512424)

应为2d等效项

如果必须循环,请不要使用
vstack
(或某种变体来构建更大的阵列)。一是速度慢,二是清理初始的“虚拟”条目很痛苦。使用列表附录,并在末尾堆叠一次

alist = []
for frame....
   alist.append(data)
data_array = np.vstack(alist)
vstack
(和family)将数组列表作为输入,因此它可以同时处理多个数组。列表追加在迭代完成时要快得多

我怀疑将事物放入一个数组是否会有所帮助。我不知道一个
hdf5
文件的大小与下载的数组大小有什么关系,但我希望它们的大小是相同的。因此,尝试将所有300个文件加载到内存中可能不起作用。那是什么,3G像素

对于单个文件,
h5py
提供了加载太大而无法装入内存的数组块的功能。这表明问题往往会反过来发展,文件保存的内容太多


您真的不想将所有图像加载到RAM中,而不使用单个HDF5文件吗?如果您不犯任何错误(不需要花哨的索引、不正确的块大小),访问HDF5文件可能会非常快。 如果你不想用这种方式,这是一种可能性:

os.chdir(os.getcwd()+"\\datasets")
img_per_file=51

# get all HDF5-Files
files=[]
for idx, file in enumerate(glob.glob("*.hdf5")):
    files.append(file)

# allocate memory for your final Array (change the datatype if your images have some other type)
numpy_data=np.empty((len(files)*img_per_file,217088),dtype=np.uint8)

# Now read all the data
ii=0
for i in range(0,len(files)):
    f = h5py.File(files[0], 'r')
    imgs = f['img']['data'][:]
    f.close()
    numpy_data[ii:ii+img_per_file,:]=imgs.reshape((img_per_file,217088))
    ii=ii+img_per_file
将数据写入单个HDF5文件将非常类似:

f_out=h5py.File(File_Name_HDF5_out,'w')
# create the dataset (change the datatype if your images have some other type)
dset_out = f_out.create_dataset(Dataset_Name_out, ((len(files)*img_per_file,217088), chunks=(1,217088),dtype='uint8')

# Now read all the data
ii=0
for i in range(0,len(files)):
    f = h5py.File(files[0], 'r')
    imgs = f['img']['data'][:]
    f.close()
    dset_out[ii:ii+img_per_file,:]=imgs.reshape((img_per_file,217088))
    ii=ii+img_per_file

f_out.close()
如果你只是不想访问整个图像后,区块大小应该是好的。如果没有,你必须根据自己的需要改变

访问HDF5文件时应执行的操作:

  • 使用适合您需要的块大小

  • 设置一个合适的块大小。这可以通过h5py低级api或h5py_缓存完成

  • 避免任何类型的花哨索引。如果数据集有n个维度,则以返回的数组也有n个维度的方式访问它

    # Chunk size is [50,50] and we iterate over the first dimension
    numpyArray=h5_dset[i,:] #slow
    numpyArray=np.squeeze(h5_dset[i:i+1,:]) #does the same but is much faster
    
编辑 这显示了如何将数据读取到memmaped numpy数组。我认为您的方法需要np.32格式的数据。


其他一切都可以保持不变。如果可行,我还建议使用SSD而不是硬盘。

您真的不想将所有图像加载到RAM中,而不使用单个HDF5文件吗?如果您不犯任何错误(不需要花哨的索引、不正确的块大小),访问HDF5文件可能会非常快。 如果你不想用这种方式,这是一种可能性:

os.chdir(os.getcwd()+"\\datasets")
img_per_file=51

# get all HDF5-Files
files=[]
for idx, file in enumerate(glob.glob("*.hdf5")):
    files.append(file)

# allocate memory for your final Array (change the datatype if your images have some other type)
numpy_data=np.empty((len(files)*img_per_file,217088),dtype=np.uint8)

# Now read all the data
ii=0
for i in range(0,len(files)):
    f = h5py.File(files[0], 'r')
    imgs = f['img']['data'][:]
    f.close()
    numpy_data[ii:ii+img_per_file,:]=imgs.reshape((img_per_file,217088))
    ii=ii+img_per_file
将数据写入单个HDF5文件将非常类似:

f_out=h5py.File(File_Name_HDF5_out,'w')
# create the dataset (change the datatype if your images have some other type)
dset_out = f_out.create_dataset(Dataset_Name_out, ((len(files)*img_per_file,217088), chunks=(1,217088),dtype='uint8')

# Now read all the data
ii=0
for i in range(0,len(files)):
    f = h5py.File(files[0], 'r')
    imgs = f['img']['data'][:]
    f.close()
    dset_out[ii:ii+img_per_file,:]=imgs.reshape((img_per_file,217088))
    ii=ii+img_per_file

f_out.close()
如果你只是不想访问整个图像后,区块大小应该是好的。如果没有,你必须根据自己的需要改变

访问HDF5文件时应执行的操作:

  • 使用适合您需要的块大小

  • 设置一个合适的块大小。这可以通过h5py低级api或h5py_缓存完成

  • 避免任何类型的花哨索引。如果数据集有n个维度,则以返回的数组也有n个维度的方式访问它

    # Chunk size is [50,50] and we iterate over the first dimension
    numpyArray=h5_dset[i,:] #slow
    numpyArray=np.squeeze(h5_dset[i:i+1,:]) #does the same but is much faster
    
编辑 这显示了如何将数据读取到memmaped numpy数组。我认为您的方法需要np.32格式的数据。


其他一切都可以保持不变。如果可行,我还建议使用SSD而不是硬盘。

您的算法一次需要多个帧吗?我猜速度的降低来自于对vstack的所有调用,您可能不需要做任何类似的事情。而且,我不确定如果idx==0和frame==0: