2017-07-15 56 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

相關問題