【问题标题】:Transfer learning with pretrained model by tf.GradientTape can't converge通过 tf.GradientTape 使用预训练模型进行迁移学习无法收敛
【发布时间】:2019-12-07 16:06:43
【问题描述】:

我想用 keras 的预训练模型进行迁移学习

import tensorflow as tf
from tensorflow import keras

base_model = keras.applications.MobileNetV2(input_shape=(96, 96, 3), include_top=False, pooling='avg')
x = base_model.outputs[0]
outputs = layers.Dense(10, activation=tf.nn.softmax)(x)

model = keras.Model(inputs=base_model.inputs, outputs=outputs)

用 keras 编译/拟合函数训练可以收敛

model.compile(optimizer=keras.optimizers.Adam(), loss=keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy'])

history = model.fit(train_data, epochs=1)

结果是:损失:0.4402 - 准确度:0.8548

我想用 tf.GradientTape 训练,但它不能收敛

optimizer = keras.optimizers.Adam()
train_loss = keras.metrics.Mean()
train_acc = keras.metrics.SparseCategoricalAccuracy()
def train_step(data, labels):    
    with tf.GradientTape() as gt:
        pred = model(data)
        loss = keras.losses.SparseCategoricalCrossentropy()(labels, pred)

    grads = gt.gradient(loss, model.trainable_variables)

    optimizer.apply_gradients(zip(grads, model.trainable_variables))

    train_loss(loss)
    train_acc(labels, pred)

for xs, ys in train_data:
    train_step(xs, ys)

print('train_loss = {:.3f}, train_acc = {:.3f}'.format(train_loss.result(), train_acc.result()))

但结果是:train_loss = 7.576, train_acc = 0.101

如果我只通过设置训练最后一层

base_model.trainable = False

收敛,结果为:train_loss = 0.525, train_acc = 0.823

代码有什么问题?我应该如何修改它?谢谢

【问题讨论】:

  • 你有没有试过降低学习率看看它是否收敛?
  • @StatisticDean,我试过 lr=0.0001(默认为 0.001),它变成了 train_loss = 0.377,train_acc = 0.874,它确实收敛了,但为什么呢?设置应与 Keras 相同。 keras compile/fit 函数里面有什么魔法吗?如果我想编写自己的训练代码,我应该如何获得与 Keras 相同的设置的结果?谢谢

标签: python keras tensorflow2.0 transfer-learning


【解决方案1】:

尝试使用 RELU 作为激活函数。如果您使用 RELU 以外的激活函数,可能会出现梯度消失问题。

【讨论】:

  • 那么我应该如何修改我的代码呢?用 tf.nn.relu 替换 tf.nn.softmax ?但是同样的模型可以通过keras fit训练出来
  • 需要检查一下,我在没有 tensorflow 分类器的情况下以不同的方式使用。add(Dense(output_dim = 6, init = 'uniform', activation = 'relu', input_dim = 11, kernel_regularizer=l2( 0.001)))
【解决方案2】:

根据我的评论,它没有收敛的原因是因为你选择了一个太大的学习率。这导致权重变化太大,损失爆炸。当将base_model.trainable 设置为 False 时,网络中的大部分权重都是固定的,并且学习率非常适合您的最后一层。这是一张图片:

作为一般规则,应始终为每个实验选择您的学习率。

编辑:根据威尔逊的评论,我不确定这是否是您得到不同结果的原因,但可能是这样:

当你指定你的损失时,你的损失是在批次的每个元素上计算的,然后为了得到批次的损失,你可以取损失的总和或平均值,这取决于你选择哪一个,你得到不同的幅度。例如,如果您的批量大小为 64,则将损失求和将产生 64 倍的损失,这将产生 64 倍的梯度,因此在批量大小为 64 时选择总和而不是平均值就像选择大 64 倍的学习率。 所以也许你有不同结果的原因是默认情况下,包裹在model.compile 中的keras.losses 具有不同的缩减方法。同样,如果通过 sum 方法减少损失,则损失的大小取决于批量大小,如果批量大小是两倍,则(平均)会得到两倍的损失,以及两倍的梯度等等这就像将学习率加倍。

我的建议是检查损失使用的减少方法,以确保它在两种情况下都相同,如果是总和,则检查批量大小是否相同。我建议一般使用均值缩减,因为它不受批量大小的影响。

【讨论】:

  • 感谢您的评论。但是为什么它会通过具有相同设置的 keras compile/fit 函数收敛呢?
  • 我在 Keras 中设置了 0.01 的学习率,比在 TF 中使用的要大得多。但它仍然工作得不那么糟糕。 epoch1:损失:2.1312 - 准确度:0.2726,epoch2:损失:1.5062 - 准确度:0.4551,epoch3:损失:1.1453 - 准确度:0.5884。但是这个 lr 在 TF 中会失败,accuracy=0.1。因为我通常会为特定目的编写自己的训练循环,所以我只想知道为什么以及如何像 Keras 那样达到预期的结果。谢谢
  • @Wilson 我编辑了答案来回答你的问题。
  • 感谢您的回答,但这可能是 TF2.0-beta1 中的错误。我已经询问了有关 TF git 问题的问题,他们也重现了该问题并将其标记为错误。链接是github.com/tensorflow/tensorflow/issues/31184,希望对你有帮助
  • 感谢您分享这些信息。我很高兴您找到了结果不同的原因。尽管如此,在良好的训练中使用正确的学习率仍然是必不可少的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 2021-04-17
  • 2018-04-12
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 2022-01-14
相关资源
最近更新 更多