为什么只有在不修复 HDF5 弃用警告时才能处理大文件?
Why can I process a large file only when I don't fix HDF5 deprecation warning?
收到 H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead.
warning 后,我将代码更改为:
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
工作正常,除了发出的警告..
为什么我的代码有效?
让我解释一下您的代码在做什么,以及为什么会出现内存错误。首先是一些 HDF5/h5py 基础知识。 (h5py 文档是一个很好的起点。查看此处:h5py QuickStart)
foo = f['foo']
和 foo = f.get('foo')
都是 return 一个名为 'foo' 的 h5py 数据集对象。(注意:更常见的是将其视为 foo = f['foo']
,但是get()
方法没有问题。)数据集对象 与 NumPy 数组不同。数据集的行为类似于 NumPy 数组;两者都有形状和数据类型,并支持数组式切片。但是,当您访问数据集对象时,您不会将所有数据读入内存。因此,它们需要更少的内存来访问。这在处理大型数据集时很重要!
这条语句 return 是一个 Numpy 数组:data_foo = f.get('foo').value
。首选方法是 data_foo = f['foo'][:]
。 (NumPy 切片符号是从数据集对象 return NumPy 数组的方法。正如您所发现的,.value
已被弃用。)
这也是 return 一个 Numpy 数组:data_foo = foo[()]
(假设 foo 定义如上)。
因此,当您输入此等式 data_foo = np.array(foo[()])
时,您是从另一个数组创建一个新的 NumPy 数组(foo[()]
是输入对象)。我怀疑您的进程被终止是因为创建 (8192, 3, 1080, 1920) 数组副本的内存量超出了您的系统资源。该语句适用于小 datasets/arrays。但是,这不是好的做法。
下面是一个展示如何使用不同方法的示例(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,:,:,:]
收到 H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead.
warning 后,我将代码更改为:
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
工作正常,除了发出的警告..
为什么我的代码有效?
让我解释一下您的代码在做什么,以及为什么会出现内存错误。首先是一些 HDF5/h5py 基础知识。 (h5py 文档是一个很好的起点。查看此处:h5py QuickStart)
foo = f['foo']
和 foo = f.get('foo')
都是 return 一个名为 'foo' 的 h5py 数据集对象。(注意:更常见的是将其视为 foo = f['foo']
,但是get()
方法没有问题。)数据集对象 与 NumPy 数组不同。数据集的行为类似于 NumPy 数组;两者都有形状和数据类型,并支持数组式切片。但是,当您访问数据集对象时,您不会将所有数据读入内存。因此,它们需要更少的内存来访问。这在处理大型数据集时很重要!
这条语句 return 是一个 Numpy 数组:data_foo = f.get('foo').value
。首选方法是 data_foo = f['foo'][:]
。 (NumPy 切片符号是从数据集对象 return NumPy 数组的方法。正如您所发现的,.value
已被弃用。)
这也是 return 一个 Numpy 数组:data_foo = foo[()]
(假设 foo 定义如上)。
因此,当您输入此等式 data_foo = np.array(foo[()])
时,您是从另一个数组创建一个新的 NumPy 数组(foo[()]
是输入对象)。我怀疑您的进程被终止是因为创建 (8192, 3, 1080, 1920) 数组副本的内存量超出了您的系统资源。该语句适用于小 datasets/arrays。但是,这不是好的做法。
下面是一个展示如何使用不同方法的示例(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,:,:,:]