You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Keras在单个epoch中多次调用model.fit进行训练

问题描述

使用Keras训练模型时因数据量过大导致内存不足,希望单个epoch通过多次model.fit调用完成训练,现有代码框架如下:

for epoche in range(nbEpoches):
    for index_df in range(len(list_of_dataFrames)):
        dataFrame = load_dataFrame(list_of_dataFrames, index_df) # 仅将当前DF加载到内存
        X_train, Y_train, X_test, Y_test = calc_train_arrays(dataFrame)
        model.fit(
            X_train, Y_train,
            validation_data=(X_test, Y_test),
            # ... 需要配置的参数
            batch_size=batch_size,
        )

其中X_train和X_test是形状为(数千, 35至200, 54+)的numpy数组,必须通过多批次适配GPU显存、动态加载DataFrame适配内存,因此被迫在同一个epoch内多次调用fit。

需求:

  1. 如何正确配置model.fit参数实现上述单epoch多fit调用的训练方式?
  2. 使用输出形状为(batch_size, 35+, 54+)的生成器并指定steps_per_epoch是否可行?

之前的尝试:

  • 仅在约2万样本的单个DataFrame上训练,模型泛化性差;
  • 每个DataFrame训练一个epoch,模型出现“互相遗忘”的情况。

解决方案

一、单epoch内多次调用model.fit的正确配置

要实现单epoch多fit调用,核心是保留模型优化器状态,让每次fit成为当前全局epoch的一部分,具体配置如下:

  1. 核心参数设置
    外层循环控制全局epoch,每次内层循环的fit都设置epochs=1,且不重新编译模型(Keras默认会保留优化器的梯度、学习率等状态)。调整后的代码:

    for epoch in range(nbEpoches):
        print(f"===== 全局 Epoch {epoch+1}/{nbEpoches} =====")
        # 遍历所有DataFrame,作为当前全局epoch的训练批次
        for index_df in range(len(list_of_dataFrames)):
            dataFrame = load_dataFrame(list_of_dataFrames, index_df)
            X_train, Y_train, X_test, Y_test = calc_train_arrays(dataFrame)
            model.fit(
                X_train, Y_train,
                validation_data=(X_test, Y_test),
                batch_size=batch_size,
                epochs=1,
                verbose=1,  # 按需设置日志输出级别
                shuffle=True  # 每个DataFrame内部打乱样本
            )
        # 全局epoch结束后可统一评估
        val_loss, val_acc = model.evaluate(X_total_val, Y_total_val, batch_size=batch_size)
        print(f"全局 Epoch {epoch+1} 验证损失: {val_loss}, 准确率: {val_acc}")
    
  2. 解决“遗忘”问题
    之前每个DataFrame单独训练一个epoch导致遗忘,本质是模型在小数据集上过拟合后,权重被下一个数据集的梯度覆盖。现在单epoch遍历所有DataFrame,让模型每个全局epoch都接触全量数据,避免单数据集的权重偏移。

  3. 验证集优化
    建议使用统一的全局验证集,而非每个DataFrame的独立验证集,避免每次fit的验证结果波动过大,更准确反映模型泛化能力。

二、使用生成器+steps_per_epoch的方案(更推荐)

这种方案更贴合Keras设计规范,无需手动循环DataFrame,自动处理动态加载和批次训练:

  1. 实现自定义Sequence生成器
    继承keras.utils.Sequence(比普通生成器更稳定,支持多进程),动态加载DataFrame并生成批次:

    from keras.utils import Sequence
    import numpy as np
    
    class DataGenerator(Sequence):
        def __init__(self, df_paths, batch_size, is_train=True):
            self.df_paths = df_paths
            self.batch_size = batch_size
            self.is_train = is_train
            # 预建立样本与DataFrame的映射,避免重复加载
            self.sample_map = []
            for df_idx, path in enumerate(df_paths):
                # 仅加载DataFrame元数据(如样本数量),不加载完整数据
                df_meta = load_df_metadata(path)
                self.sample_map.extend([(df_idx, i) for i in range(df_meta['num_samples'])])
            # 训练集打乱样本顺序
            if self.is_train:
                import random
                random.shuffle(self.sample_map)
    
        def __len__(self):
            # 计算每个epoch的总步数
            return len(self.sample_map) // self.batch_size
    
        def __getitem__(self, idx):
            batch_samples = self.sample_map[idx*self.batch_size : (idx+1)*self.batch_size]
            current_df = None
            current_df_idx = -1
            X_batch, Y_batch = [], []
            
            for df_idx, sample_idx in batch_samples:
                if df_idx != current_df_idx:
                    # 释放上一个DataFrame内存,加载当前DataFrame
                    current_df = None
                    current_df = load_dataFrame(self.df_paths[df_idx])
                    current_df_idx = df_idx
                # 从DataFrame提取单个样本(根据你的预处理逻辑调整)
                X, Y = get_single_sample(current_df, sample_idx, self.is_train)
                X_batch.append(X)
                Y_batch.append(Y)
            
            return np.array(X_batch), np.array(Y_batch)
    
  2. 生成器训练代码

    # 创建训练/验证生成器
    train_gen = DataGenerator(train_df_paths, batch_size=batch_size, is_train=True)
    val_gen = DataGenerator(val_df_paths, batch_size=batch_size, is_train=False)
    
    # 启动训练
    model.fit(
        train_gen,
        validation_data=val_gen,
        epochs=nbEpoches,
        steps_per_epoch=len(train_gen),  # Sequence会自动计算,可选省略
        use_multiprocessing=True,  # 开启多进程加速数据加载
        workers=4
    )
    
  3. 方案优势

    • 自动完成全量数据遍历,避免“遗忘”问题;
    • 支持多进程加载,提升数据读取效率;
    • 内置样本打乱逻辑,每个epoch样本顺序不同,泛化性更好;
    • 代码更简洁,无需手动管理fit调用流程。

三、额外优化建议

  • 预处理缓存:将每个DataFrame预处理后的numpy数组保存到磁盘,下次直接读取,减少重复计算;
  • 学习率调度:使用ReduceLROnPlateau回调,根据验证集性能动态调整学习率,缓解过拟合;
  • 梯度累积:若GPU显存仍不足,可手动累加梯度,每隔N批次更新一次权重(通过自定义训练循环实现)。

内容的提问来源于stack exchange,提问作者vuvu 700

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:19:54