我有两个训练好的模型(model_A
和 model_B
),它们都包含dropout层。我已经冻结了model_A
和 model_B
,并将它们与一个新的全连接层合并,得到model_AB
(但我没有移除model_A
和 model_B
的dropout层)。model_AB
的权重将是不可训练的,除了新添加的全连接层之外。
现在我的问题是:当我在训练model_AB
时,model_A
和 model_B
中的dropout层是否仍然有效(即是否会丢弃神经元)?
回答:
简答:即使你将dropout层的trainable
属性设置为False
,在训练过程中,dropout层仍然会继续丢弃神经元。
详答:在Keras中,有两个不同的概念:
-
更新层的权重和状态:这是通过该层的
trainable
属性来控制的,即如果你设置layer.trainable = False
,那么该层的权重和内部状态将不会被更新。 -
层在训练和测试阶段的行为:如你所知,一些层(如dropout)在训练和测试阶段可能有不同的行为。Keras中的学习阶段是通过
keras.backend.set_learning_phase()
来设置的。例如,当你调用model.fit(...)
时,学习阶段会自动设置为1(即训练),而当你使用model.predict(...)
时,它会自动设置为0(即测试)。此外,请注意,学习阶段为1(即训练)并不一定意味着更新层的权重/状态。你可以以学习阶段为1(即训练阶段)运行模型,但不会更新任何权重;只是层会切换到它们的训练行为(有关更多信息,请参见这个答案)。此外,还可以通过在调用层时传递training=True
参数来为每个单独的层设置学习阶段(有关更多信息,请参见这个答案)。
因此,根据上述几点,当你将dropout层的trainable
设置为False
并在训练模式下使用它时(例如通过调用model.fit(...)
,或手动将学习阶段设置为训练模式,如下面的示例所示),dropout层仍然会丢弃神经元。
这里是一个可复现的示例来说明这一点:
from keras import layersfrom keras import modelsfrom keras import backend as Kimport numpy as npinp = layers.Input(shape=(10,))out = layers.Dropout(0.5)(inp)model = models.Model(inp, out)model.layers[-1].trainable = False # 将dropout层设置为不可训练model.compile(optimizer='adam', loss='mse') # 重要:在更改`trainable`属性后,我们必须始终重新编译模型# 创建一个自定义的后端函数,以便我们可以控制学习阶段func = K.function(model.inputs + [K.learning_phase()], model.outputs)x = np.ones((1,10))# 学习阶段 = 1,即训练模式print(func([x, 1]))# 输出将是:[array([[2., 2., 2., 0., 0., 2., 2., 2., 0., 0.]], dtype=float32)]# 如你所见,一些神经元已经被丢弃# 现在设置学习阶段 = 0,即测试模式print(func([x, 0]))# 输出将是:[array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]], dtype=float32)]# 不出所料,在测试阶段没有神经元被丢弃