在处理不适合 RAM 的数据时,Keras fit_generator 是最好的选择吗?

Is Keras fit_generator the best thing to use when handling data that does not fit in RAM?

我正在努力构建一个可以分类 Knots 的分类器。目前我有一个包含 "unknots"、100,000 "plus trefoil" 和 100,000 "minus trefoil".

的 100,000 张图像的数据集

在过去的 4 天里,我一直在尝试让一个分类器处理这个大型数据集。到目前为止我遇到的问题列表是:

1) 数据集不适合 CPU 主内存:通过使用 PyTables 和 Hdf5 制作一些 EArrays 并将它们追加到磁盘上来解决这个问题。所以现在我有一个 1.2Gb 的文件,它是数据集。

2) 即使 Keras 中一个非常简单的神经网络在 模型编译 之后也会达到 100% GPU (nvidia k80) 内存使用...甚至不适合模型然而。我读到这是由于 Keras 后端在编译时自动分配了接近 100% 的可用资源:我也修复了这个问题。

3) 修复错误 1 ​​和 2 后,我仍然从 Keras fit_generator() 获得奇怪的准确性。

问题:

1) 我所描述的使用 PyTables 将小型 numpy 数组合并为一个大型 EArray 的方法是否是制作非常大(300,000 张图像 128x128,总大小 = 1.2Gb)数据集的好方法?

2) 在 Keras 中是否应该在 train_on_batch 之上使用拟合生成器?他们 return 最终 loss/accuracy 分数会有显着差异吗?

3) 如果我想用 hdf5 文件中的 50 张图像批量训练神经网络,并且在每个训练时期之后,从主内存中删除网络刚刚训练的图像,那么我的生成器方法有什么问题?

import tables
hdf5_path = "300K_Knot_data.hdf5"
extendable_hdf5_file = tables.open_file(hdf5_path, mode='r')

def imageLoader(files, batch_size):

    L = len(files.root.train_data)

    #this line is just to make the generator infinite, keras needs that    
    while True:

        batch_start = 0
        batch_end = batch_size

        while batch_start < L:
            limit = min(batch_end, L)
            X = files.root.train_data[batch_start:limit]
            X = np.reshape(X, (X.shape[0],128,128,3))
            X = X/255
            Y = files.root.train_label[batch_start:limit]

            yield (X,Y) #a tuple with two numpy arrays with batch_size samples     

            batch_start += batch_size   
            batch_end += batch_size

img_rows, img_cols = 128,128
###################################
# TensorFlow wizardry
config = tf.ConfigProto()

# Don't pre-allocate memory; allocate as-needed
config.gpu_options.allow_growth = True

# Only allow a total of half the GPU memory to be allocated
config.gpu_options.per_process_gpu_memory_fraction = 0.5

# Create a session with the above options specified.
K.tensorflow_backend.set_session(tf.Session(config=config))
###################################

model = Sequential()
model.add(Conv2D(64, (3,3), input_shape=(img_rows,img_cols,3)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(96, (3,3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(128, (3,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2)))


model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(3))
model.add(Activation('softmax', name='preds'))


#lr was originally 0.01

model.compile(loss='categorical_crossentropy',
optimizer=keras.optimizers.Adagrad(lr=0.01, epsilon=None, decay=0.0),metrics= 
['accuracy'])

# fits the model on batches with real-time data augmentation:

model.fit_generator(imageLoader(extendable_hdf5_file, 50),
                steps_per_epoch=240000 / 50, epochs=50)

这是拟合模型的输出:

抱歉,如果这不是 post 的正确位置。 我的研究顾问不在城里,我花了相当多的时间试图解决这个问题,我只需要一些意见,因为我在互联网上找不到合适的解决方案,或者似乎无法全神贯注于我的想法确实找到足够好的方式以很好的方式实现它。我不是一个新程序员,但在 python.

方面相对缺乏经验

我认为您定义生成器的方式很好。它似乎没有任何问题。虽然,目前使用 Sequence class 是推荐的方式,特别是因为它在进行多处理时更安全。但是,使用生成器很好,而且它仍然被大量使用。

关于奇怪的准确率数字,你提到它在 3000 步时是 100%,然后下降到 33%。我有以下诊断建议:

1) 将学习率降低到例如 3e-31e-31-e4。我建议使用像 AdagradRMSpropAdam 这样的自适应优化器。我推荐 RMSprop 使用默认参数;不要先改变任何参数,而是试验它并根据你得到的反馈做出改变(如果损失减少非常缓慢然后增加学习率一点;如果它增加或稳定然后降低学习率,虽然这些不是明确的规则。您必须进行试验并同时考虑验证损失)。使用自适应优化器可以减少使用像 ReduceLearningRateOnPlateu 这样的回调的需要(至少在你有充分的理由使用它之前不需要)。

2) 如果可能的话,将整个数据分成 train/validation/test 组(或至少 train/validation)。 60/20/20 或 70/15/15 的比率是最常用的比率。但是请确保这三个集合中的每个集合中的 类 都具有相同的代表性(即每个集合中的 "unknots"、"plus trefoil"、"minus trefoil" 的数量大致相同).请注意,它们的分布也应该大致相同。例如,您不应该为验证和测试集挑选简单的。通常在打乱整个数据后进行选择(即确保它们没有按任何特定顺序排列)会起作用。创建验证集可帮助您确保您在训练过程中看到的进展是真实的,并且模型不会过度拟合训练数据。

您需要定义一个新的验证生成器并传递验证数据(即加载包含验证数据的文件),就像您处理训练数据一样。然后用适当的值设置 fit_generator 方法的 validation_datavalidation_steps 参数。

3) 在激活之前或之后使用批量归一化 still debatable. Though, some people claim 如果将其放在激活之后或正好在下一层之前,效果会更好。您也可以尝试一下。

4) 如果您没有将 GPU 用于其他用途,请使用其全部容量(即不要限制其 RAM 使用)。并使用 2 的幂(即 64、128、256 等)的批处理大小,因为它有助于 GPU 内存分配并可能加快速度。考虑到您拥有的样本数量,128 或 256 似乎是不错的选择。

5) 如果一个时期的训练需要很多时间,那么考虑使用 ModelCheckpoint and EarlyStopping 回调。