首页 > 解决方案 > ResNet152 - 训练准确度高,但无法对二进制标签进行分类

问题描述

我正在为我的迷你项目制作Kaggle中可用的皮肤癌图像。我正在尝试使用不同的 CNN 模型进行比较。VGG16 和 VGG19 都在数据上工作并产生可接受的结果,训练、验证数据的准确率 > 90%,测试数据的准确率约为 85%。

然而,ResNet50/152 似乎过拟合了数据,因为它也可以在训练数据上产生 >90% 的准确度,但在验证/测试数据上失败(所有验证/测试图像都归类为 1/0)。我已经尝试过图像增强和辍学,但它们都不适合我。如果我能对以下代码块发表任何评论,非常感谢!

IMAGE_WIDTH = 224
IMAGE_HEIGHT = 224
IMAGE_CHANNELS = 3

train_data, valid_data, train_label, valid_label = train_test_split(trainval_data, trainval_label, test_size=0.05, random_state=999)

train_label = to_categorical(train_label)
valid_label = to_categorical(valid_label)
test_label = to_categorical(test_label)

train_array = np.zeros((len(train_data), IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS))
test_array = np.zeros((len(test_data), IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS))
valid_array = np.zeros((len(valid_data), IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS))

for i in range(len(train_data)):
    image = load_img(train_data[i], target_size=(224, 224))
    train_array[i] = img_to_array(image)

for i in range(len(test_data)):
    image = load_img(test_data[i], target_size=(224, 224))
    test_array[i] = img_to_array(image)

for i in range(len(valid_data)):
    image = load_img(valid_data[i], target_size=(224, 224))
    valid_array[i] = img_to_array(image)

train_array = train_array/255.0
test_array = test_array/255.0
valid_array = valid_array/255.0

def img_transfer(image):
    image = image - image.mean()
    return image

# data pre-processing for training
train_datagen =  ImageDataGenerator(
    rotation_range = 20,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    shear_range = 0.2,
    zoom_range = 0.2,
    fill_mode = 'nearest',
    horizontal_flip = True,
    preprocessing_function=img_transfer)

# data pre-processing for validation
validate_datagen =  ImageDataGenerator(
    rotation_range = 20,
    width_shift_range = 0.2,
    height_shift_range = 0.2,
    shear_range = 0.2,
    zoom_range = 0.2,
    fill_mode = 'nearest',
    horizontal_flip = True,
    preprocessing_function=img_transfer)

test_datagen = ImageDataGenerator(
    preprocessing_function=img_transfer)

train_datagen.fit(train_array, augment=True, seed=8021)
train_generator = train_datagen.flow(train_array, train_label, shuffle=True, seed = 8021)

validate_datagen.fit(valid_array, augment=True, seed=8021)
val_generator = validate_datagen.flow(valid_array, valid_label, shuffle=True, seed = 8021)

resnet152model = ResNet152(include_top=False, classes=2, input_shape = (224,224,3))
#print(vgg16model.summary())

for layer in resnet152model.layers:
    layer.trainable = False

x = resnet152model.output
x = Flatten()(x)
x = Dense(512, activation="relu")(x)
x = Dense(256, activation="relu")(x)
predictions = Dense(2, activation="softmax")(x)

resnet152model = Model(inputs=resnet152model.input,outputs=predictions)

earlystop = EarlyStopping(patience=10)

learning_rate_reduction = ReduceLROnPlateau(monitor='val_accuracy', 
                                            patience=5, 
                                            verbose=1, 
                                            factor=0.5, 
                                            min_lr=0.00001)

filepath="weights-improvement-{epoch:02d}-{val_accuracy:.2f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')

callbacks_list = [earlystop, checkpoint, learning_rate_reduction]

resnet152model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

history1 = resnet152model.fit_generator(train_generator, validation_data=val_generator,
                    epochs=30, verbose=1, callbacks=callbacks_list)

Epoch 1/30
79/79 [==============================] - 65s 819ms/step - loss: 3.4226 - accuracy: 0.7673 - val_loss: 0.5739 - val_accuracy: 0.6818

Epoch 00001: val_accuracy improved from -inf to 0.68182, saving model to weights-improvement-01-0.68.hdf5
Epoch 2/30
79/79 [==============================] - 44s 559ms/step - loss: 0.7746 - accuracy: 0.8092 - val_loss: 0.3414 - val_accuracy: 0.6818

Epoch 00002: val_accuracy did not improve from 0.68182
Epoch 3/30
79/79 [==============================] - 44s 559ms/step - loss: 0.4426 - accuracy: 0.8407 - val_loss: 0.7188 - val_accuracy: 0.6818

Epoch 00003: val_accuracy did not improve from 0.68182
Epoch 4/30
79/79 [==============================] - 44s 560ms/step - loss: 0.4133 - accuracy: 0.8415 - val_loss: 0.5881 - val_accuracy: 0.6818

Epoch 00004: val_accuracy did not improve from 0.68182
Epoch 5/30
79/79 [==============================] - 44s 558ms/step - loss: 0.3836 - accuracy: 0.8595 - val_loss: 1.2216 - val_accuracy: 0.3182

Epoch 00005: val_accuracy did not improve from 0.68182
Epoch 6/30
79/79 [==============================] - 44s 558ms/step - loss: 0.3961 - accuracy: 0.8551 - val_loss: 1.0454 - val_accuracy: 0.3182

Epoch 00006: val_accuracy did not improve from 0.68182

Epoch 00006: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257.
Epoch 7/30
79/79 [==============================] - 44s 558ms/step - loss: 0.3074 - accuracy: 0.8719 - val_loss: 0.9247 - val_accuracy: 0.3182

标签: pythontensorflowkerasresnetvgg-net

解决方案


我认为问题,即为什么 VGG 工作而 ResNet 不工作,是由 kerasBatchNormalization层引起的。长话短说,由于 ImageNet 数据集和您自己的数据集之间的域差距,预训练的 BatchNormalization 参数不能反映新数据集的实际批量统计信息。

因此,这里有一些选项:

  • 选项 1:快速训练,但性能可能稍差

    • 冻结 ResNet 模型的所有特征提取层
    • 只训练你的分类层
  • 选项 2:训练速度稍慢,但性能可能更好

    • BatchNormalization构建一个定制的 ResNet——除了那些层之外,一切都与原始 ResNet 相同。
    • 在这个定制的中加载一个预训练的 ResNet
    • 而是训练定制的网络。
    • 更准确地说,您应该BatchNormalization如下调用 layer,其中training=False(仔细阅读 keras 文档,https: //keras.io/api/layers/normalization_layers/batch_normalization/ )
f = BatchNormalization(...)(x, training=False)

注意:这两个选项都做一件共同的事情——BatchNormalization在微调期间禁用参数更新。测试它,看看它是否有效。


推荐阅读