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

Keras模型训练验证准确率高,保存加载后评估预测准确率异常低

问题根因

所有异常的核心触发点是 BatchNormalization(BN)层的状态在训练/推理切换、模型序列化重载时出现不一致,和数据加载、随机种子、优化器配置无关:

  1. 训练过程中显示的高验证准确率为虚高值:部分TensorFlow/Keras版本下,当BN层处于trainable=True状态时,model.fit()执行到验证环节不会正确把BN切到推理模式,BN会用当前验证batch的均值、方差做归一化,相当于模型在验证阶段拿到了当前batch的统计信息,算出来的准确率远高于真实推理精度。
  2. 保存重载后输出恒定值0.5左右:MobileNetV3Small的BN层默认momentum=0.99,对alpha=0.125的超小模型、小批量训练场景,滑动均值、滑动方差更新速度极慢,训练结束后滑动统计量几乎还是初始值。模型重载后会默认切到正确的推理模式,BN用未收敛的滑动统计量做归一化,输出直接塌缩到sigmoid激活的初始输出附近(0.5上下)。
  3. 修改momentum后仍存在精度差:你修改BN参数的时机错误——在模型compile()之后遍历修改层属性,改动不会被Keras的计算图捕获,只有部分BN层生效,训练和推理的计算逻辑不统一;同时验证集生成器默认开启shuffle,评估时会出现数据标签错位,进一步拉低准确率。
修复步骤

按以下顺序调整代码即可完全复现一致的训练、评估、预测精度:

  • 第一步:在compile前统一调整BN配置
    不要在compile之后修改任何层的属性,所有BN层参数调整必须在模型构建完成后、compile前执行,覆盖所有BN层(包括主干和自定义头部分):
    base_model = keras.applications.MobileNetV3Small(
        input_shape=INPUT_SHAPE,
        alpha=0.125,
        include_top=False,
        weights=None,
        dropout_rate=0.2
    )
    x = keras.layers.Flatten()(base_model.output)
    preds = keras.layers.Dense(1, activation="sigmoid")(x)
    model = keras.Model(inputs=base_model.input, outputs=preds)
    
    # 遍历模型所有层调整BN配置,不要只遍历base_model
    for layer in model.layers:
        if isinstance(layer, keras.layers.BatchNormalization):
            layer.momentum = 0.9 # 小模型、小batch场景下比默认0.99更稳定
            layer.trainable = True
    
    # 所有层属性调整完成后再compile,显式指定学习率不要用隐式默认值
    model.compile(
        loss="binary_crossentropy",
        optimizer=keras.optimizers.RMSprop(learning_rate=1e-4),
        metrics=["binary_accuracy"]
    )
    
  • 第二步:修正数据生成器配置
    验证、测试集生成器必须关闭shuffle,避免评估时数据和标签错位:
    validation_generator = validation_datagen.flow_from_directory(
        os.path.join(DATA_ROOT, 'val'),
        target_size=(56,56),
        batch_size=128,
        class_mode="binary",
        shuffle=False, # 强制关闭验证集乱序
        seed=42
    )
    
  • 第三步:训练结束后先切推理模式再评估、保存
    训练完成后不要直接保存或评估,显式将模型切到推理模式并重新compile,强制BN、Dropout层使用推理逻辑,确认评估精度正常后再保存权重:
    # 训练完成后切推理模式
    model.trainable = False
    # 重新compile让trainable状态生效,不会丢失已训练的权重
    model.compile(
        loss="binary_crossentropy",
        metrics=["binary_accuracy"]
    )
    # 先跑评估确认真实精度,这时候的结果和predict结果完全对齐
    val_loss, val_acc = model.evaluate(validation_generator, verbose=1)
    # 精度确认无误后保存权重,不要直接保存整模型,减少序列化状态丢失风险
    model.save_weights(SAVE_DIR)
    
  • 第四步:模型重载逻辑对齐
    重载模型时,先按照和训练时完全一致的代码构建模型结构、调整BN参数、compile,再加载保存的权重,加载完成后同样切到推理模式再做评估或预测,结果和训练结束时的精度完全一致。
之前方案无效的原因
  • 替换数据加载方式、固定随机种子不解决BN层状态不同步的核心问题,自然没有效果。
  • 在compile之后修改BN的momentum参数,改动没有被Keras计算图捕获,部分层仍使用旧配置,训练和推理逻辑不统一,所以精度差始终存在。
  • 训练时看到的0.94验证准确率是BN在训练模式下的虚高值,不是模型的真实泛化能力,切到推理模式后的结果才是真实精度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:51:21