将Pandas列转换为Keras神经网络的Numpy数组

时间:2017-10-15 01:06:38

标签: python pandas numpy neural-network keras

我正在学习如何创建CNN模型,并认为Kaggle举办了一场有趣的比赛来帮助我学习它。

他们提供了一个类似JSON的大型(BSON)文件,大约50GB,我正在尝试处理。我正在尝试使用Keras模块训练卷积神经网络。在文件中,我迭代地读取具有(180,180,3)的阵列结构的图像数据。整个文件包含大约7,000,000个图像,因此最终的数组结构看起来像(7000000,180,180,3)。但是,我无法将所有这些数据读入内存,因此我的目标是一次读取100,000个图像以适应神经网络,保存模型的权重,删除数组以释放内存,然后继续将接下来的100,000个图像读入新阵列,以重新拟合先前训练的模型。我会迭代地这样做,直到我到达最后一张图片。

我最初尝试使用' np.append()'来迭代地将每个图像阵列附加在一起,但是,这花了很多时间,因为我只通过了25,000个图像,从而产生了一个数组结构(25000,180,180,3),在10小时内,由于尺寸的原因,它在末端附近非常慢。

然后我尝试使用pandas数据帧结构使用不同的方法。我将每个(1,180,180,3)阵列附加到每个单元格中。我能够使用这种方法在大约20分钟内迭代100,000张图像(大部分代码都是通过Kaggle提供的 -  https://www.kaggle.com/inversion/processing-bson-files)但我在下面进行了修改:

# Simple data processing
from bson.json_util import dumps
data = bson.decode_file_iter(open('train.bson', 'rb'))

prod_to_category = dict()

i = 0
j = 1000

# Loop through dataset
for c, d in enumerate(data):
    product_id = d['_id']
    category_id = d['category_id'] # This won't be in Test data
    prod_to_category[product_id] = category_id
    i+=1

    # Create a counter to check how many records have been iterated through
    if (i == 1):
        print (i, "records loaded")
        print(picture_1.shape)
        j+=1000
    for e, pic in enumerate(d['imgs']):

    # Reshape the array and append image array data
        if (i == 0):
            picture_1 = np.reshape(imread(io.BytesIO(pic['picture'])), (1,180,180,3))
            get = pd.DataFrame({'A': [product_id], 'B': [category_id], 'C':[picture_1]})
            frames = get

            break
        else:
            picture_2 = np.reshape(imread(io.BytesIO(pic['picture'])), (1,180,180,3))
            get2 = pd.DataFrame({'A': [product_id], 'B': [category_id], 'C':[picture_2]})
            frames = frames.append(get2)

            break

所以大熊猫数据框的标题,'帧' ,看起来像这样。请注意,在此示例中假装我将循环完全停在100,000条记录:

enter image description here

如何将整个列' C'转换为Numpy结构数组(100000,如此),将每个单元看起来都有一个数组结构(1,180,180,3)。 180,180,3)那么我可以将它喂入我的神经网络吗?最好不要使用for循环来执行此操作。

我已经在网上看了很多东西,但却找不到如何做到这一点。一旦我搞清楚了,我应该能够用一个包含100,000个图像的新阵列重新训练我的网络,并一遍又一遍地执行此操作,直到我将所有七百万个图像都安装到我的模型中。我对这种东西真的很陌生,所以任何其他帮助或建议都会非常感激。

2 个答案:

答案 0 :(得分:7)

编辑:如果您正在寻找一个简单的Pandas功能,那么答案就会过度,但我会在这里留下答案,以防其他人帮助其他人对Keras进行记忆外训练。

你一定要考虑使用HDF5。这是一种压缩文件格式,允许您以分层方式存储数据,并有选择地加载数据。可以把它想象成一个带有文件夹结构的zip文件。如果您使用的是Python,则可以使用h5pylink to h5py documentation,如果您拥有$$或访问Safari Bookshelf,则可以使用非常密集且有用的O'Reilly book公共图书馆)。

手动创建包含数据的HDF5文件

要使用h5py,您将创建一个HDF5文件并迭代地向其添加数据。您必须对数据进行一次传递以对其进行压缩(创建HDF5结构,并遍历每个图像以将其添加到HDF5文件中)。您可能希望自己将其分成HDF5文件中的N个图像批次,但这并非绝对必要(见下文)。您可以使用您选择的云提供程序在本地计算机上或高内存计算实例上执行此操作。

例如,假设您定义了一个load_images()函数,该函数将从start_indexend_index获取一定数量的图像,并返回嵌套np.array()的{ {1}}对象(我会留给你定义,但看起来你已经有了这个,或者至少有一些非常接近的东西)。然后,您将数据加载到HDF5文件中,如下所示:

np.array()

使用燃料

我推荐使用库fuel,它旨在组织/压缩/存储大型数据集,以便在Keras,Theano和Lasagne中使用。它基本上和上面做的一样,但有更多的选择。要使用它,你会:

  • 定义fuel dataset(基本上是一个存根类)
  • 定义fuel downloader(一种获取数据的方式 - 可以在本地使用,因为您已经拥有它)
  • 定义fuel converter(将迭代数据并将其添加到HDF5文件的内容,类似于上面的代码段)

Documentation gives a toy example using H5PYDataset class,这基本上就是你所遵循的。)

然后运行image_set_1 = load_images(path_to_bson, start_index, end_index) with h5py.File(output_path, mode="w") as h5file: h5file.create_dataset("image_set_1", data=image_set_1) 实用程序下载数据集,然后fuel-download <name-of-dataset>运行转换器。

最终结果是一个HDF5文件,它以有组织的方式包含您的数据,现在您可以通过多种方式访问​​和采样数据。例如,您可以创建一个DataStream来创建任意迭代器,并将其传递给iteration scheme,您可以在其中指定自己的自定义批量大小,随机或按顺序采样,或根据特定样本进行采样批量“计划”。 (请参阅文档中的DataStreams。)

示例:假设您的数据集有100,000张图像。燃料转换器会将所有100,000张图像填充到HDF5文件中(使用您定义的任何方案 - 也许您希望根据任务组织它们,或者您可能希望将它们全部保持平坦。由您决定。)一旦您运行转换器,您的数据是燃料数据集。然后你可能会说,我想用洗牌顺序训练我的神经网络 - 然后你会使用ShuffledScheme。然后明天你可能会说,我想按顺序迭代图像 - 然后你会使用SequentialScheme。然后你可能会说,我想指定每个批次使用的图像 - 然后你使用BatchScheme。这就是燃料给你的灵活性。

使用Keras HDF5Matrix

最后一个选项是使用Keras内置的utilite来处理HDF5文件:HDF5Matrix。该工作流程看起来类似于上面提到的HDF5工作流程(只需通过所有数据将其压缩成HDF5文件),但您现在可以直接从Keras中选择性地加载部分数据。这将更有利于您在HDF5文件中按批次分组图像,并且您的工作流程如下所示:

  • 使用fuel-convert <name-of-datset>
  • 加载batch1
  • 使用batch1
  • 训练模型
  • 使用keras.HDF5Matrix()
  • 加载batch2
  • 使用batch2
  • 训练模型
  • 等...

自己编写这些内容相当简单(有几个可用于各种数据集的示例,以及other examples available for other data sets on Github)。

或者,您可以将更大的数据块(或全部)加载为非常大的numpy数组,并使用keras.HDF5Matrix()start参数进行end调用以限制您正在加载的数据量。不过,这也需要重塑你的numpy数据。

最终建议

我的总体建议是使用fuel。我已经成功地将它用于一些非常大的数据集和内存外训练方案。

答案 1 :(得分:3)

您可以使用.tolist()

# example data
N = 20000
cdata = np.random.random(N).reshape(10, 20, 20, 5)
adata = [True] * len(cdata)
df = pd.DataFrame({"A":adata, "C":cdata.tolist()})

df.head()
      A                                                  C
0  True  [[[0.18399037775743088, 0.6762324340882544, 0....
1  True  [[[0.9030084241016858, 0.4060105756597291, 0.4...
2  True  [[[0.2659580640570838, 0.8247979431136298, 0.6...
3  True  [[[0.9626035946363627, 0.16487112072561239, 0....
4  True  [[[0.034946598341842106, 0.17646725825025167, ...

c = np.array(df.C.tolist())

c.shape 
# (10, 20, 20, 5)