微调需加载完整模型而非仅权重,正确冻结bn层并设training=true,学习率降3–10倍,验证旧指标防灾难性遗忘,保存用save_format='tf'并传custom_objects。

加载旧模型时权重没更新,训练像从头开始
TensorFlow 默认保存的是完整图结构 + 权重(tf.keras.models.load_model),但微调必须复用旧权重、只改部分层。如果直接新建模型再 load_weights,容易漏掉优化器状态或 batch norm 的 running stats。
- 用
tf.keras.models.load_model加载整个模型(含架构、权重、优化器状态),而不是仅用model.load_weights - 确保保存时用了
save_format='tf'(默认),避免 HDF5 格式在自定义层/符号张量下出问题 - 加载后立刻检查
model.trainable_weights数量是否与原始训练一致;若变少,说明某些层被意外设为不可训练
冻结部分层后 loss 不下降,梯度为 0
冻结不等于“跳过计算”,而是让梯度不更新该层参数。但如果冻结了 BatchNormalization 层,它的 training=False 状态会导致推理模式计算,running_mean / running_var 不更新,进而影响后续层梯度传播。
- 对 BN 层,冻结时设
layer.trainable = False后,**仍需在训练时显式传training=True**(如model(x, training=True)),否则 BN 行为异常 - 用
model.layers[i].trainable = False冻结后,必须调用model.compile(...)重新构建计算图,否则旧的 trainable 状态不会生效 - 验证是否真冻结:打印
[w.name for w in model.trainable_weights],确认不需要更新的变量不在列表中
增量数据和旧数据分布差异大,微调后准确率反而下降
微调不是“加点新样本就训几轮”,本质是领域适配。若新数据噪声高、标注不一致或类别偏移明显,直接 resume 训练会污染原有知识。
- 先做小规模验证:用旧验证集跑一次微调后的模型,acc 下降超 2% 就要停——说明灾难性遗忘已发生
- 学习率必须比原训练小 3–10 倍(如原用 1e-3,微调改用 1e-4),否则旧权重被剧烈扰动
- 考虑用
tf.keras.callbacks.EarlyStopping监控旧验证集指标,而非只看新数据 loss
保存微调后模型,部署时报错 “Unknown layer” 或 shape mismatch
常见于用了自定义预处理层(如 tf.keras.layers.Rescaling)、或在模型里嵌了非序列化对象(如 Python 函数、外部文件路径)。
- 保存前用
model.save('path', save_format='tf'),不要用model.to_json() + load_weights—— 后者丢掉自定义层逻辑 - 若用了
tf.keras.layers.Lambda,确保 lambda 函数体可序列化(不能引用闭包变量、不能含 print 等副作用) - 加载时若报 “Unknown layer”,检查是否漏了
custom_objects=...参数,且 key 必须和定义时类名完全一致(大小写敏感)










