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

如何禁用神经网络中部分层的训练?附尝试代码片段

如何禁用神经网络中部分层的训练?

嘿,看来你在搭建Keras模型的时候想冻结部分层、不让它们参与训练对吧?这事儿在迁移学习或者模型微调里太常见了,我给你分享几个实用的方法,结合你的代码来举例说明:

方法1:直接设置层的trainable属性为False

这是最直接的标准操作,你可以在定义层的时候就指定,或者模型定义完成后通过层名修改。

比如在你定义Block 1的时候直接冻结:

def get_model():
    weight_decay=0.0
    inputs = Input(shape=(INPUT_IMAGE_H, INPUT_IMAGE_W, 3))
    # Block 1 - 把这两个卷积层设为不可训练
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1', 
               kernel_regularizer=l2(weight_decay), trainable=False)(inputs)
    x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2', 
               kernel_regularizer=l2(weight_decay), trainable=False)(x)
    x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
    # Block 2 - 保持默认的可训练状态
    x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1', 
               kernel_regularizer=l2(weight_decay))(x)
    # ... 后续层继续按你的需求定义
    model = Model(inputs, x)
    return model

如果是已经定义好的模型,也可以事后修改:

model = get_model()
# 通过层名找到要冻结的层,设置trainable为False
model.get_layer('block1_conv1').trainable = False
model.get_layer('block1_conv2').trainable = False
# 重点!修改完trainable属性后,必须重新编译模型,否则设置不会生效
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

划重点:修改trainable之后一定要重新编译模型,不然框架还是会更新这些层的参数!

方法2:批量冻结预训练模型的层

如果你用的是像VGG、ResNet这类预训练模型,批量冻结会更高效:

from tensorflow.keras.applications import VGG16

# 加载预训练模型,不包含顶层分类器
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(INPUT_IMAGE_H, INPUT_IMAGE_W, 3))
# 一键冻结所有预训练层
base_model.trainable = False
# 然后添加你自己的顶层网络
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(10, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=x)
model.compile(optimizer='adam', loss='categorical_crossentropy')

要是之后想微调部分预训练层,只需要把对应层的trainable改回True,再重新编译就行。

方法3:自定义训练循环,精细控制梯度更新

如果需要更灵活的控制(比如只冻结层里的部分参数,或者自定义梯度更新逻辑),可以写自定义训练循环:

import tensorflow as tf

optimizer = tf.keras.optimizers.Adam()
loss_fn = tf.keras.losses.CategoricalCrossentropy()

# 筛选出需要训练的参数:排除block1两个卷积层的所有参数
trainable_vars = [var for var in model.trainable_variables 
                  if not ('block1_conv1' in var.name or 'block1_conv2' in var.name)]

@tf.function
def train_step(x, y):
    with tf.GradientTape() as tape:
        predictions = model(x, training=True)
        loss = loss_fn(y, predictions)
    # 只计算可训练参数的梯度
    gradients = tape.gradient(loss, trainable_vars)
    optimizer.apply_gradients(zip(gradients, trainable_vars))
    return loss

# 训练循环示例
for epoch in range(10):
    print(f"Epoch {epoch+1}/10")
    for x_batch, y_batch in train_dataset:
        loss = train_step(x_batch, y_batch)
        print(f"Batch loss: {loss:.4f}", end='\r')

最后给你几个小提醒:

  • 像MaxPooling2D这类池化层本身没有可训练参数,所以不需要冻结,冻结了也没影响。
  • 可以用model.summary()查看模型的可训练/不可训练参数数量,确认冻结是否生效。
  • 迁移学习时通常先冻结预训练层训练顶层,再解冻部分层微调,效果会更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:01:35