首页 > 解决方案 > 为什么只有在不修复 HDF5 弃用警告时才能处理大文件?

问题描述

收到H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead. 警告后,我将代码更改为:

import h5py
import numpy as np 

f = h5py.File('myfile.hdf5', mode='r')
foo = f['foo']
bar = f['bar']
N, C, H, W = foo.shape. # (8192, 3, 1080, 1920)
data_foo = np.array(foo[()]) # [()] equivalent to .value

当我试图读取一个(不是那么大的)图像文件时,我Killed: 9在终端上得到了一个,我的进程被杀死了,因为它在代码的最后一行消耗了太多的内存,尽管我在那里有过时的评论. .

但是,我的原始代码:

f = h5py.File('myfile.hdf5', mode='r')
data_foo = f.get('foo').value
# script's logic after that worked, process not killed

工作得很好,除了发出的警告..

为什么我的代码有效?

标签: pythonarraysnumpymachine-learninghdf5

解决方案


让我解释一下您的代码在做什么,以及为什么会出现内存错误。首先是一些 HDF5/h5py 基础知识。(h5py 文档是一个很好的起点。在这里查看:h5py QuickStart

foo = f['foo']并且foo = f.get('foo')都返回一个名为 'foo' 的 h5py 数据集对象。(注意:更常见的是将此视为foo = f['foo'],但该get()方法没有任何问题。)数据集对象NumPy 数组不同。数据集的行为类似于 NumPy 数组;两者都具有形状和数据类型,并支持数组样式的切片。但是,当您访问数据集对象时,您不会将所有数据读入内存。因此,它们需要更少的内存来访问。这在处理大型数据集时很重要!

此语句返回一个 Numpy 数组:data_foo = f.get('foo').value. 首选方法是data_foo = f['foo'][:]。(NumPy 切片表示法是从数据集对象返回 NumPy 数组的方法。正如您所发现的,.value它已被弃用。)
这也返回一个 Numpy 数组:(data_foo = foo[()]假设 foo 定义如上)。
因此,当您输入此等式时,data_foo = np.array(foo[()])您正在从另一个数组(foo[()]是输入对象)创建一个新的 NumPy 数组。我怀疑您的进程已被杀死,因为创建 (8192, 3, 1080, 1920) 数组副本的内存量超出了您的系统资源。该语句适用于小型数据集/数组。但是,这不是一个好习惯。

这是一个示例来展示如何使用不同的方法(h5py 数据集对象与 NumPy 数组)。

h5f = h5py.File('myfile.hdf5', mode='r')

# This returns a h5py object:
foo_ds = h5f['foo']
# You can slice to get elements like this:
foo_slice1 = foo_ds[0,:,:,:] # first row
foo_slice2 = foo_ds[-1,:,:,:] # last row

# This is the recommended method to get a Numpy array of the entire dataset:
foo_arr = h5f['foo'][:]
# or, referencing h5py dataset object above
foo_arr = foo_ds[:] 
# you can also create an array with a slice
foo_slice1 = h5f['foo'][0,:,:,:] 
# is the same as (from above):
foo_slice1 = foo_ds[0,:,:,:] 

推荐阅读