自定义模型最后一层冻结及ResNet50权重替换与单层训练方案
解决方案:加载自定义权重并冻结最后一层以外的层
我来帮你一步步搞定这个问题,咱们拆成两个核心环节来操作:加载你的自定义权重到模型,然后冻结大部分层只训练最后一层。
1. 加载自定义权重到mini_XCEPTION模型
首先你得确保手里有训练好的权重文件(一般是.h5格式),先创建模型实例,再加载你的权重:
from tensorflow.keras.layers import Input, Conv2D, BatchNormalization, Activation, SeparableConv2D, MaxPooling2D, add, GlobalAveragePooling2D from tensorflow.keras.models import Model from tensorflow.keras.regularizers import l2 # 保留你原有的模型定义 def mini_XCEPTION(input_shape, num_classes, l2_regularization=0.01): regularization = l2(l2_regularization) # base img_input = Input(input_shape) x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(img_input) x = BatchNormalization()(x) x = Activation('relu')(x) x = Conv2D(8, (3, 3), strides=(1, 1), kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = Activation('relu')(x) # module 1 residual = Conv2D(16, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x) residual = BatchNormalization()(residual) x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = Activation('relu')(x) x = SeparableConv2D(16, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) x = add([x, residual]) # module 2 residual = Conv2D(32, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x) residual = BatchNormalization()(residual) x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = Activation('relu')(x) x = SeparableConv2D(32, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) x = add([x, residual]) # module 3 residual = Conv2D(64, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x) residual = BatchNormalization()(residual) x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = Activation('relu')(x) x = SeparableConv2D(64, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) x = add([x, residual]) # module 4 residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x) residual = BatchNormalization()(residual) x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = Activation('relu')(x) x = SeparableConv2D(128, (3, 3), padding='same', kernel_regularizer=regularization, use_bias=False)(x) x = BatchNormalization()(x) x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) x = add([x, residual]) x = Conv2D(num_classes, (3, 3), padding='same')(x) x = GlobalAveragePooling2D()(x) output = Activation('softmax', name='predictions')(x) model = Model(img_input, output) return model # 创建模型实例(要和你权重对应的输入形状、类别数匹配) input_shape = (224, 224, 3) num_classes = 你的数据集类别数 # 替换成你实际的类别数量 model = mini_XCEPTION(input_shape, num_classes) # 加载你的自定义权重(替换成你的权重文件路径) model.load_weights('你的权重文件路径.h5')
2. 冻结最后一层以外的所有层,仅训练最后一层
接下来我们要把模型大部分层冻结,只让最后一层(或分类头)可训练,这里分两种场景:
场景一:仅训练最后的softmax输出层
如果你的“最后一层”特指名称为predictions的激活层,这么操作:
# 先冻结所有层 for layer in model.layers: layer.trainable = False # 解冻最后的predictions层 model.get_layer('predictions').trainable = True # 关键:必须重新编译模型,Keras才会更新训练参数配置 model.compile(optimizer='adam', # 微调建议用小学习率,比如tf.keras.optimizers.Adam(1e-4) loss='categorical_crossentropy', # 二分类任务换成binary_crossentropy metrics=['accuracy'])
场景二:训练整个分类头(含前面的卷积和池化层)
看你的模型结构,最后三个层组成了分类头:Conv2D(num_classes) → GlobalAveragePooling2D → Activation('predictions'),如果要训练整个分类头,这么做:
# 冻结所有层 for layer in model.layers: layer.trainable = False # 解冻最后三个层(分类头部分) for layer in model.layers[-3:]: layer.trainable = True # 重新编译模型 model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), loss='categorical_crossentropy', metrics=['accuracy'])
额外提醒
- 确保你的自定义权重和当前模型结构完全匹配(输入形状、层数、参数数量一致),否则加载权重会报错。
- 微调时用小学习率,避免破坏预训练好的权重。
- 如果是二分类任务,记得把
num_classes设为1,loss换成binary_crossentropy,输出层激活函数改成sigmoid。
内容的提问来源于stack exchange,提问作者Zunaira Akmal
相关产品推荐
相关产品推荐

