【问题标题】:Resnet50 Transfer Learning with tensorflow.keras version 2.4+Resnet50 迁移学习与 tensorflow.keras 版本 2.4+
【发布时间】:2021-09-05 23:50:00
【问题描述】:

我有一个基于 resnet50 的模型架构,需要定期重新训练。它工作了多年。它在 tensorflow 1.9 版和 keras 2.3.1 上运行。现在我买了一台带有 RTX 3070 的新电脑——这意味着我必须使用 tensorflow 2.4 或更高版本才能使用 GPU。我将 tensorflow 2.5 与相关的 Cuda 11.2 和 cudnn 8.1 一起安装,手动复制了一些文件——模型确实在 GPU 上运行。但是,当我冻结基础模型的图层时,与在旧计算机上运行它时相比,我得到了完全不同的结果。例如:对于 resnet50 的所有层都冻结的两个热身时期,我在旧计算机上获得了超过 50% 的准确率 - 但在新计算机上只有 7.5。 我知道 BatchNormalization 层的问题,并在此处遵循教程(或说明):

https://www.tensorflow.org/tutorials/images/transfer_learning

如何解决问题(如您在下面的代码中所见)。我还尝试将 tensorflow 降级到 2.4,重新安装 Anaconda 并从头开始设置一切,等等 - 但没有任何效果。 为了比较这两种架构并确保没有其他原因可以导致差异,我将整个数据复制到外部硬盘驱动器上 - 并且只调整了从 keras 到 tensorflow.keras 的导入(以及其他一些小的改动必须使用 tensorflow.keras,即使用 fit 而不是 fit_generator 等)。有人可以查看 tensorflow.keras 模型的代码(从顶部开始的第二个代码块) - 并告诉我哪里出错了。

这是 keras 中模型的代码(完美运行):

# =============================================================================
# Build model
# =============================================================================

from keras.applications.resnet50 import ResNet50
from keras.models import  Model
from keras.layers import Dense, Flatten, Dropout, Input, \
    AveragePooling2D
from keras import initializers
from keras import optimizers

in_shape = (224,224,3) # Shape of input images

n_classes = 26 # Number of classes

dor = 0.3 # Dropout rate

learning_rate = 5e-5

optim = optimizers.Adam(lr=learning_rate)

base_model = ResNet50(include_top=False, weights='imagenet', \
                      input_shape=in_shape)

inp = Input(shape=in_shape)
x = base_model(inp)
x = AveragePooling2D((7, 7), name='avg_pool')(x)
x = Flatten()(x)
x = Dropout(dor)(x)
x = Dense(2048, \
              kernel_initializer=initializers.he_normal(), \
              bias_initializer=initializers.ones(), \
              activation='relu')(x)
x = Dense(n_classes, kernel_initializer=initializers.he_normal(), \
          bias_initializer=initializers.ones(), activation='softmax')(x)
model = Model(inp, x)

model.compile(loss = 'categorical_crossentropy', optimizer=optim, \
              metrics=['accuracy'])

model.summary()

# =============================================================================
# Train model
# =============================================================================

# Warm up phase
for layer in model.layers[1].layers:
  layer.trainable =  False

model.compile(loss = 'categorical_crossentropy', optimizer=optim, metrics=['accuracy'])

model.summary()

history = model.fit_generator(train_generator,
                              validation_data=val_generator,
                              epochs=warm_up_epochs,
                              steps_per_epoch=train_spe, 
                              validation_steps=val_spe,
                              verbose=1)

输出是:

这里是 tensorflow.keras 模型的代码(不起作用):

# =============================================================================
# Build model
# =============================================================================

from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.models import  Model
from tensorflow.keras.layers import Dense, Flatten, Dropout, Input, \
    AveragePooling2D
from tensorflow.keras import initializers
from tensorflow.keras import optimizers

in_shape = (224,224,3) # Shape of input images

n_classes = 26 # Number of classes

dor = 0.3 # Dropout rate

learning_rate = 5e-5

optim = optimizers.Adam(learning_rate=learning_rate)

# resnet50, pretrained on Imagenet
base_model = ResNet50(include_top=False, weights='imagenet', \
                      input_shape=in_shape)

inp = Input(shape=in_shape)
x = base_model(inp, training=False)
x = AveragePooling2D((7, 7), name='avg_pool')(x)
x = Flatten()(x)
x = Dropout(dor)(x)
x = Dense(2048, \
              kernel_initializer=initializers.he_normal(), \
              bias_initializer=initializers.ones(), \
              activation='relu')(x)
x = Dense(n_classes, kernel_initializer=initializers.he_normal(), \
          bias_initializer=initializers.ones(), activation='softmax')(x)
model = Model(inp, x)

model.compile(loss = 'categorical_crossentropy', optimizer=optim, \
              metrics=['accuracy'])

model.summary()

# =============================================================================
# Train model
# =============================================================================

# Warm up phase
for layer in model.layers[1].layers:
  layer.trainable =  False

model.compile(loss = 'categorical_crossentropy', optimizer=optim, \
              metrics=('accuracy'))

model.summary()

history = model.fit(train_generator,
                    validation_data=val_generator,
                    epochs=warm_up_epochs,
                    steps_per_epoch=train_spe, 
                    validation_steps=val_spe,
                    verbose=1)

输出是:

引人注目的是:当我不冻结层时,tensorflow.keras 模型的性能与 keras 模型的性能相当。正如我所说,我不知道我在哪里出错了。任何帮助表示赞赏, 非常感谢您的回答!

【问题讨论】:

    标签: machine-learning keras tensorflow2.0 transfer-learning resnet


    【解决方案1】:

    好的,我实际上(经过几天的绝望并由于沮丧而开始使用 PyTorch)刚刚找到了解决这种行为的方法。问题是关于微调模型的官方tensorflow帖子:

    https://www.tensorflow.org/tutorials/images/transfer_learning

    实际上是错误的 - 至少对于 tensorflow 2.5 版(但我认为它可能是从 2.4 开始)。 在上面的链接中,非常详细地解释了为什么在构建模型时必须将参数“training”设置为 False,即在上面的代码行中:

    x = base_model(inp, training=False)
    

    如果您不这样做 - 然后仅在冻结层时将非 batch_normalization 层设置为 False,则一切正常。 IE。我所做的是:

    # Warm up phase
    for layer in model.layers[1].layers:
      if '_bn' not in layer.name:
         layer.trainable =  False
    

    在检查 resnet50 中的层名称后 - 每个 BatchNormalization 层名称都以“_bn”结尾。

    如果您从冻结中排除 BatchNormalization 层(如上)并将训练参数设置为 False,它仍然不起作用。 这当然只是一个快速而肮脏的黑客 - 也许有更好的解决方案。如果你知道一个,请告诉我。但目前至少这是可行的,也可以只冻结一些图层等。

    【讨论】:

      猜你喜欢
      • 2019-12-31
      • 2020-02-11
      • 1970-01-01
      • 2018-10-26
      • 1970-01-01
      • 2023-01-09
      • 1970-01-01
      • 2018-11-13
      • 2017-04-08
      相关资源
      最近更新 更多