【问题标题】:Keras fit_generator and fit results are differentKeras fit_generator 和 fit 结果不同
【发布时间】:2019-03-07 02:17:36
【问题描述】:

我正在使用人脸图像数据集训练卷积神经网络。该数据集有 10,000 张尺寸为 700 x 700 的图像。我的模型有 12 层。我正在使用生成器函数将图像读入 Keras fit_generator 函数,如下所示。

train_file_names ==> 包含训练实例文件名的 Python 列表
train_class_labels ==> one-hot 编码类标签的 Numpy 数组([0, 1, 0], [0, 0, 1] 等)
train_data ==> 训练实例的 Numpy 数组
train_steps_epoch ==> 16(批量大小为 400,我有 6400 个训练实例。因此,单次遍历整个数据集需要 16 次迭代)
批量大小 ==> 400
call_made ==> 当生成器到达训练实例结束时,它会重置索引以在下一个 epoch 从第一个索引加载数据。

我将此生成器作为参数传递给 keras 'fit_generator' 函数,以便为每个时期生成新的一批数据。

val_data, val_class_labels ==> 验证数据 numpy 数组
纪元 ==> 纪元数

使用 Keras fit_generator

model.fit_generator(generator=train_generator, steps_per_epoch=train_steps_per_epoch, epochs=epochs, use_multiprocessing=False, validation_data=[val_data, val_class_labels], verbose=True, callbacks=[history, model_checkpoint], shuffle=True, initial_epoch=0) 

代码

def train_data_generator(self):     
    index_start = index_end = 0 
    temp = 0
    calls_made = 0

    while temp < train_steps_per_epoch:
        index_end = index_start + batch_size
        for temp1 in range(index_start, index_end):
            index = 0
            # Read image
            img = cv2.imread(str(TRAIN_DIR / train_file_names[temp1]), cv2.IMREAD_GRAYSCALE).T
            train_data[index]  = cv2.resize(img, (self.ROWS, self.COLS), interpolation=cv2.INTER_CUBIC)
            index += 1       
        yield train_data, self.train_class_labels[index_start:index_end]
        calls_made += 1
        if calls_made == train_steps_per_epoch:
            index_start = 0
            temp = 0
            calls_made = 0
        else:
            index_start = index_end
            temp += 1  
        gc.collect()

fit_generator 的输出

86/300 纪元
16/16 [===============================] - 16s 1s/step - loss: 1.5739 - acc: 0.2991 - val_loss : 12.0076 - val_acc: 0.2110
87/300 纪元
16/16 [==============================] - 16s 1s/step - loss: 1.6010 - acc: 0.2549 - val_loss : 11.6689 - val_acc: 0.2016
88/300 纪元
16/16 [==============================] - 16s 1s/step - loss: 1.5750 - acc: 0.2391 - val_loss : 10.2663 - val_acc: 0.2004
89/300 纪元
16/16 [===============================] - 16s 1s/step - loss: 1.5526 - acc: 0.2641 - val_loss : 11.8809 - val_acc: 0.2249
纪元 90/300
16/16 [==============================] - 16s 1s/step - loss: 1.5867 - acc: 0.2602 - val_loss : 12.0392 - val_acc: 0.2010
91/300 纪元
16/16 [==============================] - 16s 1s/step - loss: 1.5524 - acc: 0.2609 - val_loss : 12.0254 - val_acc: 0.2027

我的问题是,在使用上述生成器函数的“fit_generator”时,我的模型损失根本没有改善,验证准确性非常差。但是当我使用下面的 keras 'fit' 函数时,模型损失减少并且验证准确度要好得多。

在不使用生成器的情况下使用 Keras 拟合函数

model.fit(self.train_data, self.train_class_labels, batch_size=self.batch_size, epochs=self.epochs, validation_data=[self.val_data, self.val_class_labels], verbose=True, callbacks=[history, model_checkpoint])    

使用拟合函数训练时的输出

25/300 纪元
6400/6400 [===============================] - 20s 3ms/步 - 损失:0.0207 - acc: 0.9939 - val_loss : 4.1009 - val_acc: 0.4916
26/300 纪元
6400/6400 [===============================] - 20s 3ms/步 - 损失:0.0197 - acc: 0.9948 - val_loss : 2.4758 - val_acc: 0.5568
27/300 纪元
6400/6400 [===============================] - 20s 3ms/步 - 损失:0.0689 - acc: 0.9800 - val_loss : 1.2843 - val_acc: 0.7361
28/300 纪元
6400/6400 [==============================] - 20s 3ms/步 - 损失:0.0207 - acc: 0.9947 - val_loss : 5.6979 - val_acc: 0.4560
29/300 纪元
6400/6400 [===============================] - 20s 3ms/步 - 损失:0.0353 - acc: 0.9908 - val_loss : 1.0801 - val_acc: 0.7817
时代 30/300
6400/6400 [===============================] - 20s 3ms/step - 损失:0.0362 - acc: 0.9896 - val_loss : 3.7851 - val_acc: 0.5173
时代 31/300
6400/6400 [===============================] - 20s 3ms/step - loss: 0.0481 - acc: 0.9896 - val_loss : 1.1152 - val_acc: 0.7795
时代 32/300
6400/6400 [===============================] - 20s 3ms/步 - 损失:0.0106 - acc: 0.9969 - val_loss : 1.4803 - val_acc: 0.7372

【问题讨论】:

  • 请修正代码中的缩进。它目前的呈现方式,它不是有效的 Python/没有多大意义。您是否验证过训练数据生成器以正确的顺序和正确的标签输出相同的图像?
  • 我重新提出了我的问题。让我知道是否还有其他需要更改的地方。是的,数据生成器以正确的顺序输出图像。我再次测试了它。我正在按预期读取数据。
  • 您是否验证了生成器在多个批次中都能正常工作?
  • 是的,我做到了。我手动调用了生成器并检查了数据。它正在按预期生成输出。
  • 不是答案,但您必须执行img = img / 255.0 以确保它学习。否则数字太大,默认学习率不会发生任何事情。

标签: python-3.x tensorflow keras deep-learning generator


【解决方案1】:

您必须确保您的数据生成器在 epoch 之间打乱数据。我建议您在循环之外创建一个可能的索引列表,使用 random.shuffle 对其进行随机化,然后在循环内对其进行迭代。

来源:https://github.com/keras-team/keras/issues/2389 和自己的经历。

【讨论】:

  • 我不认为我的方法是错误的,因为它与 fit 函数一起使用。我的生成器实现有问题。到现在都想不通是什么。当我使用 python 进行测试并且它运行良好但使用 Keras 时,它的行为方式很奇怪。
【解决方案2】:

这很可能是由于您的数据生成器中缺少数据混洗。我遇到了同样的问题。我改变了 shuffle=True 但没有成功。然后我在我的自定义生成器中集成了一个 shuffle。这是 Keras 文档建议的自定义生成器:

class Generator(Sequence):
    # Class is a dataset wrapper for better training performance
    def __init__(self, x_set, y_set, batch_size=256):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size

    def __len__(self):
        return math.ceil(self.x.shape[0] / self.batch_size)

    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) * self.batch_size]
        return batch_x, batch_y

这是里面的随机播放:

class Generator(Sequence):
    # Class is a dataset wrapper for better training performance
    def __init__(self, x_set, y_set, batch_size=256):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size
        self.indices = np.arange(self.x.shape[0])

    def __len__(self):
        return math.ceil(self.x.shape[0] / self.batch_size)

    def __getitem__(self, idx):
        inds = self.indices[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_x = self.x[inds]
        batch_y = self.y[inds]
        return batch_x, batch_y
    
    def on_epoch_end(self):
        np.random.shuffle(self.indices)

然后模型很好地收敛了。 fculinovic 的积分。

【讨论】:

  • 感谢您的回答。可悲的是,我不再使用这种方法,因此无法对其进行测试。希望这对某人有所帮助。
  • @SudheerRaja 你能解决你的问题还是你刚刚改变了方法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 2019-10-01
  • 2020-12-25
  • 1970-01-01
  • 2019-10-19
  • 2018-03-01
相关资源
最近更新 更多