2017-07-15 60 views
1

我试图通过生成器将1D numpy数组(平展图像)送入H5py数据文件以创建训练和验证矩阵。H5py - 使用生成器创建数据集 - ValueError:设置数组元素的序列

以下代码改编自溶液(找不到它现在),其中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还是其他?

+0

你必须写出块。 'NP。fromiter(...,dtype = np.int8)'产生一个数组 - 1d。所以即使它可以从一个生成器创建数组,它仍然会在将内容传递到文件之前创建内存中的所有内容。 – hpaulj

+0

@hpaulj与ali_m在本文中建议的方式如此相似? https://stackoverflow.com/questions/34531479/writing-a-large-hdf5-dataset-using-h5py 这似乎是相当不雅/曲...... 我用更简单的看'chunk'尝试'create_dataset'函数的属性,但不幸的是无法正常工作。 – aweeeezy

回答

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) 

启用分块可能与真正的大数据集的帮助,但我不这方面的经验。

+0

谢谢你的写作。 我设法得到了一个工作解决方案,我模拟了我在我的原始文章中粘贴的评论中所链接的ali_m的含义。我制作了一个生成函数,生成扁平图像的形状(chunk_size,len(img_array)),然后迭代调整h5数据集的大小,并为每个生成的块插入一个ndarray。 您的解决方案非常简单,可能更合适,因为h5的建议块大小为〜1MiB,略小于一幅图像的大小。虽然分块可能仍然有用,如果我稍后再下载图像。 – aweeeezy

相关问题