【问题标题】:H5py - using generator to create dataset - ValueError: setting an array element with a sequenceH5py - 使用生成器创建数据集 - ValueError:使用序列设置数组元素
【发布时间】:2017-12-20 04:19:14
【问题描述】:

我正在尝试通过生成器将一维 numpy 数组(展平图像)输入 H5py 数据文件,以创建训练和验证矩阵。

以下代码改编自一个解决方案(现在找不到),其中 H5py 的 File 对象的 create_dataset 函数的 data 属性以调用 np.fromiter 的形式提供数据有一个生成器函数作为它的参数之一。

from scipy.misc import imread
import h5py
import numpy as np
import os

# Creating h5 data file
f = h5py.File('../data.h5', 'w')

# Source directory for image data
src = '/datasets/aic540/train/images/'

# Showing quantity and dimensionality of data
images = os.listdir(src)
ex_img = imread(src + images[0])
flat_img = ex_img.flatten()
print "# of images is {}".format(len(images))
print "image shape is {}".format(ex_img.shape)
print "flattened image shape is {}".format(flat_img.shape)

# Creating generator to feed in data to h5py's `create_dataset` function
gen = (imread(src + i).flatten().astype(np.int8) for i in os.listdir(src))

# Creating h5 dataset
f.create_dataset(name='training',
                 #shape=(59482, 1555200),
                 data=np.fromiter(gen, dtype=np.int8))

输出:

# of images is 59482
image shape is (540, 960, 3)
flattened image shape is (1555200,)
Traceback (most recent call last):
  File "process_images.py", line 30, in <module>
    data=np.fromiter(gen, dtype=np.int8))
ValueError: setting an array element with a sequence.

我在此上下文中搜索此错误时读到,问题在于np.fromiter() 需要一个列表而不是生成器函数(这似乎与名称“fromiter”所暗示的函数相反)——包装列表调用 list(gen) 中的生成器允许代码运行,但它当然会在调用 create_dataset 之前耗尽此列表扩展中的所有内存。

如何使用生成器将数据输入 H5py 数据文件?

如果我的方法完全错误,那么构建一个不适合内存的非常大的 numpy 矩阵的正确方法是什么——使用 H5py 还是其他方式?

【问题讨论】:

  • 你必须写块。 np.fromiter(..., dtype=np.int8) 创建一个数组 - 1d。因此,即使它可以从生成器生成数组,它仍然会在将整个内容传递给文件之前在内存中创建整个内容。
  • @hpaulj 与 ali_m 在这篇文章中建议的方式如此相似? stackoverflow.com/questions/34531479/… 看起来很不优雅/令人费解......我尝试使用 create_dataset 函数的看起来更简单的 chunk 属性,但不幸的是这不起作用。

标签: numpy generator h5py


【解决方案1】:

with a sequence 错误来自您尝试输入 fromiter 的内容,而不是生成器部分。

在 py3 中,range 类似于生成器:

In [15]: np.fromiter(range(3),dtype=int)
Out[15]: array([0, 1, 2])
In [16]: np.fromiter((2*x for x in range(3)),dtype=int)
Out[16]: array([0, 2, 4])

但如果我从一个二维数组(imread 产生,对吗?)开始,然后像你一样创建一个生成器表达式:

In [17]: gen = (np.ones((2,3)).flatten().astype(np.int8) for i in range(3))
In [18]: list(gen)
Out[18]: 
[array([1, 1, 1, 1, 1, 1], dtype=int8),
 array([1, 1, 1, 1, 1, 1], dtype=int8),
 array([1, 1, 1, 1, 1, 1], dtype=int8)]

我生成了一个数组列表。

In [19]: gen = (np.ones((2,3)).flatten().astype(np.int8) for i in range(3))
In [21]: np.fromiter(gen, np.int8)
...
ValueError: setting an array element with a sequence.

np.fromiter 从迭代器创建一维数组,该迭代器一次提供一个“数字”,而不是提供列表或数组的东西。

无论如何,npfromiter 创建一个完整的数组;不是某种发电机。没有什么比得上数组“生成器”了。


即使没有分块,您也可以通过“行”或其他切片将数据写入文件。

In [28]: f = h5py.File('test.h5', 'w')
In [29]: data = f.create_dataset(name='test',shape=(100,10))
In [30]: for i in range(100):
    ...:     data[i,:] = np.arange(i,i+10)
    ...:     
In [31]: data
Out[31]: <HDF5 dataset "test": shape (100, 10), type "<f4">

在您的情况下,等效于加载图像,对其进行整形,然后立即将其写入h5py 数据集。无需将所有图像收集在数组或列表中。

读取 10 行:

In [33]: data[:10,:]
Out[33]: 
array([[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.],
       [  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
       [  2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.],
       [  3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.],
       [  4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.],
       [  5.,   6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.],
       [  6.,   7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.],
       [  7.,   8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.],
       [  8.,   9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.],
       [  9.,  10.,  11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.]], dtype=float32)

启用分块可能有助于处理非常大的数据集,但我没有这方面的经验。

【讨论】:

  • 感谢您的来信。我设法获得了一个可行的解决方案,我模仿了 ali_m 在我粘贴在我的原始帖子下的评论中的链接中所建议的内容。我制作了一个生成器函数,该函数产生形状为 (chunk_size, len(img_array)) 的扁平图像的 ndarray,然后迭代地调整 h5 数据集的大小并为每个生成的块插入一个 ndarray。您的解决方案要简单得多,并且可能更合适,因为 h5 的推荐块大小约为 1MiB,略小于一张图像的大小。虽然如果我稍后对图像进行下采样,分块可能仍然有用。
猜你喜欢
  • 2011-06-08
  • 2018-08-04
  • 2019-08-04
相关资源
最近更新 更多