python - 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
解决方案
我认为问题,即为什么 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
在微调期间禁用参数更新。测试它,看看它是否有效。
推荐阅读
- vim - 检查地图是否存在于 vimScript 中
- python-3.x - Python3 从循环中中断
- r - 函数 pcf.ppp() 与 spatstat 中的 pcfinhom() 有何不同?
- xamarin - 为 Xamarin 创建 Android 绑定时出现问题
- python - 使用 pyTrends 时,出现以下错误:TypeError: __init__() missing 2 required positional arguments: 'google_username' and 'google_password'
- java - 当我使用 LocationManager.getLastKnowLocation() 时,应用程序在真实设备中的第二次启动时崩溃
- javascript - 多个组件同时访问相同的数据
- javascript - 如何在 Gatsbyjs 初始加载时根据 IP 地址重定向用户
- angular - ngFor 的离子 GET 对象索引
- javascript - Django datetimefield 未显示新内联表单行的 datetimepicker 小部件