加载预训练模型应设 include_top=false 以移除原分类头,接自定义 globalaveragepooling2d+dense 层;冻结 base_model 部分层后 compile 再训练;预处理须用对应 model.preprocess_input 而非 rescale=1/255;class_mode 必须与输出层激活函数及 loss 匹配。

用 tf.keras.applications 加载预训练模型时,别直接调用 model.predict()
迁移学习的第一步是复用已训练好的特征提取器,但很多人一上来就对整个模型做 predict(),结果发现输出维度不对、梯度无法回传,或者训练时 loss 不下降。这是因为默认加载的模型包含顶层分类头(比如 ImageNet 的 1000 类),而你的任务很可能只有几类,且需要微调。
正确做法是显式禁用顶层,并冻结部分层:
- 用
include_top=False参数加载模型,例如tf.keras.applications.ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3)) - 后续接自定义的
GlobalAveragePooling2D+Dense层,输出维度设为你任务的类别数 - 冻结前若干层(如 ResNet50 的前 100 层)再编译训练,否则小数据集上极易过拟合
冻结与解冻层时,trainable 属性必须在 compile() 前设置
常见错误是:先 model.compile(),再改某层的 trainable = True,结果发现该层权重根本不更新。TensorFlow 在 compile() 时会固化计算图和可训练变量列表,之后改 trainable 属性不会自动重新注册梯度路径。
实操顺序必须是:
- 构建完整模型(含自定义 head)
- 对 base_model 中想冻结的层批量设
layer.trainable = False - 调用
model.compile() - 训练若干 epoch 后,若需微调,再设
base_model.trainable = True,并 重新 compile(尤其 learning_rate 要调低,比如 1e-5)
ImageDataGenerator 的 rescale 和预训练模型的预处理函数不能混用
ResNet、EfficientNet 等模型在训练时用了特定归一化方式:ResNet 用的是「减均值」(RGB 各通道减 [103.939, 116.779, 123.68]),而 ImageDataGenerator(rescale=1./255) 是简单缩放到 [0,1]。两者混用会导致输入分布严重偏移,模型几乎不收敛。
解决方案只有两个,二选一:
- 弃用
ImageDataGenerator,改用tf.keras.applications.resnet50.preprocess_input(或其他对应模型的 preprocess_input)封装进tf.data.Dataset.map() - 若坚持用
ImageDataGenerator,则rescale设为None,并在flow_from_directory()后手动调用 preprocess 函数(注意它要求输入是 uint8,范围 [0,255])
验证集准确率卡在某个值不动?检查 class_mode 和 label 编码是否匹配
用 ImageDataGenerator.flow_from_directory() 时,如果目录结构是 train/cat/, train/dog/,但模型输出层是 Dense(1, activation='sigmoid'),而你设了 class_mode='categorical',就会因 label 维度不匹配导致 silent fail——loss 计算出错但不报异常,acc 停滞在 0.5 或其他固定值。
对应关系必须一致:
-
class_mode='categorical'→ 输出层用Dense(N, activation='softmax'),loss 用'categorical_crossentropy' -
class_mode='binary'→ 输出层用Dense(1, activation='sigmoid'),loss 用'binary_crossentropy' - 若用
tf.data,确保 label 是 int(binary)或 one-hot(categorical),不要混用字符串或 float 标签
最易被忽略的是:当从二分类切到多分类时,只改了输出层,忘了同步改 class_mode 和 loss,模型就一直在“假装学习”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











