Keras的`model.fit_generator()`与`model.fit()`的行为不同

时间:2017-08-29 16:42:59

标签: python keras generator

我有一个巨大的数据集,我需要以生成器的形式提供给Keras,因为它不适合内存。但是,使用fit_generator,我无法复制.black { padding: 12px 20px; margin: 0 auto; box-sizing: border-box; text-align: center; display: inline-block; background-color: black; color: white; border-style: solid; } .white { padding: 12px 20px; margin: 0 auto; box-sizing: border-box; text-align: center; display: inline-block; }常规培训期间获得的结果。每个时代也要持续更长时间。

我实现了一个最小的例子。也许有人可以告诉我问题所在。

<div id="bet-and-chance-input-boxes">
  <input class="black" value="text" autocomplete="off">
  <input readonly value="text" class="black" placeholder="" name="bet" autocomplete="off">
</div>

<div id="bet-and-chance-input-boxes">
  <input class="white" id="userbet" value="text" autocomplete="off">
  <input readonly class="white" value="text" placeholder="" name="" autocomplete="off">
</div>

在我的计算机上,model.fit总是在第10个纪元完成时失去import random import numpy from keras.layers import Dense from keras.models import Sequential random.seed(23465298) numpy.random.seed(23465298) no_features = 5 no_examples = 1000 def get_model(): network = Sequential() network.add(Dense(8, input_dim=no_features, activation='relu')) network.add(Dense(1, activation='sigmoid')) network.compile(loss='binary_crossentropy', optimizer='adam') return network def get_data(): example_input = [[float(f_i == e_i % no_features) for f_i in range(no_features)] for e_i in range(no_examples)] example_target = [[float(t_i % 2)] for t_i in range(no_examples)] return example_input, example_target def data_gen(all_inputs, all_targets, batch_size=10): input_batch = numpy.zeros((batch_size, no_features)) target_batch = numpy.zeros((batch_size, 1)) while True: for example_index, each_example in enumerate(zip(all_inputs, all_targets)): each_input, each_target = each_example wrapped = example_index % batch_size input_batch[wrapped] = each_input target_batch[wrapped] = each_target if wrapped == batch_size - 1: yield input_batch, target_batch if __name__ == "__main__": input_data, target_data = get_data() g = data_gen(input_data, target_data, batch_size=10) model = get_model() model.fit(input_data, target_data, epochs=15, batch_size=10) # 15 * (1000 / 10) * 10 # model.fit_generator(g, no_examples // 10, epochs=15) # 15 * (1000 / 10) * 10 而在此之后。 2-3秒。

然而,方法model.fit的运行时间要长得多,并且在不同损失(0.6939)的情况下完成上一个纪元。

我一般不明白为什么两种方法的结果都不同。这可能看起来不是很大差异,但我需要确保具有相同网络的相同数据产生相同的结果,独立于传统培训或使用生成器。

更新:@Alex R.为部分原始问题提供了答案(一些性能问题以及每次运行时更改结果)。然而,由于核心问题仍然存在,我只是相应地调整了问题和标题。

7 个答案:

答案 0 :(得分:4)

我不明白批量较大时损失是如何不稳定的,因为较大批次的波动应该较小。但是,查看Keras documentationfit()例程如下:

fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None, validation_split=0.0, 
    validation_data=None, shuffle=True, class_weight=None, sample_weight=None, 
    initial_epoch=0)

具有默认batch_size=32epochs=10fit_generator()看起来像是:

fit_generator(self, generator, steps_per_epoch, epochs=1, verbose=1,
              callbacks=None, validation_data=None, validation_steps=None, 
              class_weight=None, max_queue_size=10, workers=1,
              use_multiprocessing=False, initial_epoch=0)

特别是&#34; step_per_epoch&#34;定义如下:

  

steps_per_epoch:要产生的步骤(样本批次)的总数   来自发电机,然后宣布一个纪元完成并启动   下一个时代。它通常应该等于唯一的数量   数据集的样本除以批量大小。

因此对于初学者来说,与fit()例程相比,听起来你的fit_generator正在接收大量的样本。 See here for more details.

答案 1 :(得分:2)

批量大小

  • fit中,您使用的是标准批量大小= 32.
  • fit_generator中,您使用批量大小= 10。

Keras可能会在每批次之后运行重量更新,因此,如果您使用不同大小的批次,则两种方法之间可能会出现不同的渐变。一旦有不同的重量更新,两种型号都不会再次相遇。

尝试使用batch_size=10,或使用batch_size=32生成器。

种子问题?

您是否为每种情况创建了一个get_model()的新模型?

如果是这样,两个模型中的权重都不同,当然两种模型的结果都不同。 (好的,你已经设定了种子,但如果你正在使用张量流,也许你正面临this issue

但从长远来看,他们会有所收敛。两者之间的差异似乎并不大。

检查数据

如果您不确定您的生成器是否产生与您预期相同的数据,请对其进行简单循环并打印/比较/检查它产生的数据:

for i in range(numberOfBatches):
    x,y = g.next() #or next(g)
    #print or compare x,y here. 

答案 2 :(得分:1)

请确保在发生器中对批次进行混洗。

此讨论建议您在迭代器https://github.com/keras-team/keras/issues/2389中启用随机播放。我遇到了同样的问题,这解决了。

答案 3 :(得分:0)

至于损失,这可能是由于已经讨论过的批量差异造成的。

至于培训时间的差异,model.fit_generator()允许您指定&#34;工人&#34;的数量。此参数指的是同时在数据集中的不同区域上训练模型的实例数。如果您的计算机体系结构已正确优化,您应该能够将workers参数更改为4或8,并且可以大幅缩短培训时间。

答案 4 :(得分:0)

希望我参加聚会不晚。我要添加的最重要的内容:

在Keras中,对于可以加载到内存中的较小数据集,使用fit()很好。但是实际上,对于大多数实际使用的情况,几乎所有数据集都很大,无法一次加载到内存中。

对于更大的数据集,我们必须使用fit_generator()

答案 5 :(得分:0)

fitfit.generator之间的区别不只是让人眼前一亮。无论Keras团队希望您做什么,这两种功能都是可以互换的相信。他们更新梯度的方式可能是其行为不同的原因。

无论如何,由于神经网络现实生活中的问题的性质,fit()的使用是徒劳的。如果可以使用fit()解决您的问题,那么它要么属于教室,要么属于试运行。否则,您可能需要更多的数据收集。

答案 6 :(得分:0)

确保每次生成器实际上返回不同的批次。我的发电机遇到了这个问题。 当您在while循环之前初始化批处理numpy占位符时,即使您可以在for循环中更改这些变量,也有可能初始化的变量在第一个for循环中仅更改一次。我的问题就是这样。我有一个结构类似的生成器,但是我在for循环之后返回了批次:Why is this python generator returning the same value everytime?

您可以使用以下代码段检查生成器是否正常工作:检查所有生成的批次是否确实不同:

g = data_gen(input_data, target_data, batch_size=10)
input_list = []
target_list = []
for _ in range(100):
    input, target = next(g)
    input_list.append(input)
    target_list.append(target)
inputs = np.concatenate(input_list, axis=0)   
targets = np.concatenate(target_list, axis=0)

all_different = True
for i in range(1, inputs.shape[0]):
    if np.array_equal(inputs[0], inputs[i]):
        all_different = False
print('All batches different') if all_different else print('Generator broken. Initialize your numpy arrays inside the while loop or yield input.copy, target.copy()')