ResNet50 模型不是通过 keras 中的迁移学习进行学习的



我正在尝试对 PASCAL VOC 2012 数据集的 Imagenet 权重预训练的 ResNet50 模型进行迁移学习。由于它是一个多标签数据集,我在最后一层中使用sigmoid激活函数并binary_crossentropy损失。指标precision,recall and accuracy。下面是我用来构建 20 个类模型的代码(PASCAL VOC 有 20 个类(。

img_height,img_width = 128,128
num_classes = 20
#If imagenet weights are being loaded,
#input must have a static square shape (one of (128, 128), (160, 160), (192, 192), or (224, 224))
base_model = applications.resnet50.ResNet50(weights= 'imagenet', include_top=False, input_shape= (img_height,img_width,3))
x = base_model.output
x = GlobalAveragePooling2D()(x)
#x = Dropout(0.7)(x)
predictions = Dense(num_classes, activation= 'sigmoid')(x)
model = Model(inputs = base_model.input, outputs = predictions)
for layer in model.layers[-2:]:
layer.trainable=True
for layer in model.layers[:-3]:
layer.trainable=False
adam = Adam(lr=0.0001)
model.compile(optimizer= adam, loss='binary_crossentropy', metrics=['accuracy',precision_m,recall_m])
#print(model.summary())
X_train, X_test, Y_train, Y_test = train_test_split(x_train, y, random_state=42, test_size=0.2)
savingcheckpoint = ModelCheckpoint('ResnetTL.h5',monitor='val_loss',verbose=1,save_best_only=True,mode='min')
earlystopcheckpoint = EarlyStopping(monitor='val_loss',patience=10,verbose=1,mode='min',restore_best_weights=True)
model.fit(X_train, Y_train, epochs=epochs, validation_data=(X_test,Y_test), batch_size=batch_size,callbacks=[savingcheckpoint,earlystopcheckpoint],shuffle=True)
model.save_weights('ResnetTLweights.h5')

它运行了 35 个纪元,直到提前停止,指标如下(没有 Dropout 层(:

loss: 0.1195 - accuracy: 0.9551 - precision_m: 0.8200 - recall_m: 0.5420 - val_loss: 0.3535 - val_accuracy: 0.8358 - val_precision_m: 0.0583 - val_recall_m: 0.0757

即使使用Dropout层,我也看不出太大区别。

loss: 0.1584 - accuracy: 0.9428 - precision_m: 0.7212 - recall_m: 0.4333 - val_loss: 0.3508 - val_accuracy: 0.8783 - val_precision_m: 0.0595 - val_recall_m: 0.0403

使用 dropout,在几个时期内,模型的验证精度和准确度达到 0.2,但不高于此值。

我看到与有和没有dropout层的训练集相比,验证集的精度和召回率非常低。我应该如何解释这一点?这是否意味着模型过度拟合。如果是这样,我该怎么办?截至目前,模型预测非常随机(完全不正确(。数据集大小为 11000 张图像。

请您修改代码如下并尝试执行

从:

predictions = Dense(num_classes, activation= 'sigmoid')(x)

自:

predictions = Dense(num_classes, activation= 'softmax')(x)

从:

model.compile(optimizer= adam, loss='binary_crossentropy', metrics=['accuracy',precision_m,recall_m])

自:

model.compile(optimizer= adam, loss='categorical_crossentropy', metrics=['accuracy',precision_m,recall_m])

这个问题很老了,但我会回答它,以防它对其他人有帮助:

在此示例中,您冻结了除最后两个图层(全局平均池化和最后一个密集图层(之外的所有图层。有一种更简洁的方法可以达到相同的状态:

rn50 = applications.resnet50.ResNet50(weights='imagenet', include_top=False, 
input_shape=(img_height, img_width, 3))
x = rn50.output
x = GlobalAveragePooling2D()(x)
predictions = Dense(num_classes, activation= 'sigmoid')(x)
model = Model(inputs = base_model.input, outputs = predictions)
rn50.trainable = False  # <- this
model.compile(...)

在这种情况下,特征是从 ResNet50 网络中提取的,并馈送到线性 softmax 分类器,但 ResNet50 的权重没有经过训练。这称为特征提取,而不是微调。

唯一被训练的权重来自分类器,分类器是用从随机分布中提取的权重实例化的,因此应该完全训练。您应该使用Adam的默认学习率:

model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.001))

所以你可以训练它几个时期,一旦完成,你就会解冻骨干并"微调"它:

backbone.trainable = False
model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.001))
model.fit(epochs=50)
backbone.trainable = True
model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.00001))
model.fit(epochs=60, initial_epoch=50)

Keras网站上有一篇关于此的好文章:https://keras.io/guides/transfer_learning/

最新更新