You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于ImageDataGenerator的CNN分类k折交叉验证实现正确性咨询

嘿,我看了你的代码,发现几个关键问题会导致你的k-fold交叉验证没正确跑起来,咱们一步步捋清楚:

核心问题分析

  • 循环结构完全错位:你写的for i in range(2)只创建了不同fold的生成器,但模型训练的model.fit_generator()在循环外面,这意味着你实际只训练了最后一次循环生成的train_generatorvalidation_generator(也就是fold1),前面的fold0完全没用到,这完全失去了k-fold交叉验证的意义。必须把整个训练流程(包括模型初始化/加载、训练、评估)都放进for循环里,每个fold独立执行一次完整的训练-验证流程。

  • 模型初始化逻辑有问题:当前代码尝试先加载一个预存的saved.hdf5,但k-fold交叉验证中,每个fold的模型应该是独立初始化的(除非你是做模型微调且有特定需求)。如果第一个fold训练完覆盖了saved.hdf5,第二个fold加载的是第一个fold训练后的模型,这就不是独立的交叉验证了。正确的做法是,每个fold要么从头构建模型,要么加载同一个初始预训练模型(如果用迁移学习),而不是上一个fold训练后的模型。

  • 样本数变量未对应单个fold:你用的nb_train_samplenb_validation_sample看起来是全局的总样本数,但每个fold的训练/验证样本数应该是各自fold下的数量,否则steps_per_epochvalidation_steps会计算错误,导致训练时的步数不对。

  • 测试集预测未整合进交叉验证流程:你在循环里创建了test_generator,但没有在每个fold训练完后对测试集进行预测并保存结果。k-fold交叉验证通常需要每个fold训练的模型都对测试集做预测,最后把所有fold的预测结果整合起来计算平均性能(比如平均准确率、混淆矩阵等)。

修正后的代码示例

我调整了你的代码结构,把核心流程放进循环,并且处理了每个fold的独立模型和结果保存:

import numpy as np

# 定义每个fold的模型保存路径,避免互相覆盖
model_base_path = '../carPrediction/model/'
# 用来保存每个fold的测试集预测结果
all_test_predictions = []

for i in range(2):
    print('===== Training fold', i, '=====')
    
    # 1. 创建当前fold的生成器
    train_generator = train_datagen.flow_from_directory(
        TRAIN_CROPPED_PATH + f'fold{i}', 
        target_size=(image_size, image_size), 
        batch_size=batch_size, 
        class_mode='categorical', 
        seed=2019, 
        color_mode='rgb'
    )
    validation_generator = valid_datagen.flow_from_directory(
        VALID_CROPPED_PATH + f'fold{i}', 
        target_size=(image_size,image_size), 
        batch_size=batch_size, 
        class_mode='categorical', 
        seed=2019, 
        color_mode='rgb'
    )
    test_generator = test_datagen.flow_from_dataframe(
        dataframe=df_test, 
        directory=TEST_CROPPED_PATH, 
        x_col='img_file', 
        y_col=None, 
        target_size=(image_size,image_size), 
        color_mode='rgb', 
        class_mode=None, 
        batch_size=batch_size, 
        shuffle=False
    )
    
    # 2. 初始化当前fold的模型:要么从头构建,要么加载初始预训练模型
    # 这里假设你有一个build_model()函数用来创建你的CNN结构
    # 如果是迁移学习,就加载预训练模型并修改顶层
    model = build_model()  # 替换成你实际的模型构建代码
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    
    # 3. 设置当前fold的回调(注意模型路径要区分fold)
    patient = 2
    fold_model_path = model_base_path + f'saved_fold{i}.hdf5'
    callbacks1 = [
        EarlyStopping(monitor='val_loss', patience=patient, mode='min', verbose=1),
        ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=patient//2, min_lr=1e-5, verbose=1, mode='min'),
        ModelCheckpoint(filepath=fold_model_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min'),
    ]
    
    # 4. 获取当前fold的样本数(从generator里取更准确)
    nb_train_sample = train_generator.samples
    nb_validation_sample = validation_generator.samples
    
    # 5. 训练当前fold的模型
    history = model.fit_generator(
        train_generator, 
        steps_per_epoch=nb_train_sample // batch_size, 
        epochs=2,
        validation_data=validation_generator, 
        validation_steps=nb_validation_sample // batch_size,
        verbose=1, 
        callbacks=callbacks1
    )
    
    # 6. 用当前fold的最佳模型预测测试集
    best_model = load_model(fold_model_path)
    test_predictions = best_model.predict(test_generator, verbose=1)
    all_test_predictions.append(test_predictions)

# 7. 整合所有fold的预测结果,计算平均性能
mean_predictions = np.mean(all_test_predictions, axis=0)
# 这里可以根据mean_predictions计算准确率、混淆矩阵等

额外注意点

  • 如果你的k-fold是严格的分层抽样(保证每个fold里carA和carB的比例和整体一致),那你的文件夹结构是对的;如果不是,建议检查每个fold的类别分布是否均衡。
  • 如果你想用同一个初始模型(比如预训练的ResNet)做微调,那每个fold都要加载同一个初始权重,而不是上一个fold训练后的权重。
  • fit_generator()在新版本Keras里已经被fit()替代了,如果你的TensorFlow/Keras版本较新,建议改用model.fit(train_generator, ...),用法基本一致。

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

火山引擎 最新活动