基于胸片的COVID-19检测CNN模型过拟合问题求助
问题描述
我正在构建一个基于CNN的胸片COVID-19检测模型,使用包含约27000张图像的数据集,仅选用其中的COVID和NORMAL两类。参考Keras图像分类教程调整后得到代码如下:
batch_size = 16 img_height = 160 img_width = 160 img_size = (img_height, img_width)
seed_train_validation = 1 shuffle_value = True validation_split = 0.3
train_ds = tf.keras.utils.image_dataset_from_directory( data_dir, image_size = img_size, validation_split = validation_split, subset = "training", seed = seed_train_validation, color_mode = "grayscale", shuffle = shuffle_value )
val_ds = tf.keras.utils.image_dataset_from_directory( data_dir, image_size = img_size, validation_split = validation_split, subset = "validation", seed = seed_train_validation, color_mode = "grayscale", shuffle = shuffle_value )
val_batches = tf.data.experimental.cardinality(val_ds) test_ds = val_ds.take((2*val_batches) // 3) val_ds = val_ds.skip((2*val_batches) // 3)
AUTOTUNE = tf.data.AUTOTUNE train_ds = train_ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE) val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
resize_and_rescale = tf.keras.Sequential([ layers.Resizing(img_height, img_width), layers.Rescaling(1./255) ]) data_augmentation = tf.keras.Sequential([ layers.RandomFlip("horizontal_and_vertical"), layers.RandomRotation(0.2), layers.RandomZoom(0.1) ])
num_classes = len(class_names) model_1 = Sequential([ resize_and_rescale, data_augmentation, layers.Conv2D(16, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(32, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Conv2D(64, 3, padding='same', activation='relu'), layers.MaxPooling2D(), layers.Dropout(0.2), layers.Flatten(), layers.Dense(128, activation='relu'), layers.Dense(num_classes) ]) model_1.compile(optimizer="adam", loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) epochs = 75 history = model_1.fit( train_ds, validation_data = val_ds, epochs = epochs )
训练轮数较少(如10轮)时,准确率和损失曲线表现正常;但训练75轮时曲线出现异常,已加入数据增强和Dropout层但效果不佳,怀疑是过拟合问题,寻求解决建议。
解决建议
提前停止训练(Early Stopping)
直接避免模型过度训练,当验证集性能连续多轮无提升时自动停止,并恢复到最优权重:early_stopping = tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=10, restore_best_weights=True ) # 训练时加入回调 history = model_1.fit( train_ds, validation_data=val_ds, epochs=75, callbacks=[early_stopping] )强化正则化
现有正则化力度不足,可从两方面优化:- 提升Dropout比例至0.3-0.5
- 给卷积层和全连接层添加L2正则化,限制权重规模:
from tensorflow.keras import regularizers model_1 = Sequential([ resize_and_rescale, data_augmentation, layers.Conv2D(16, 3, padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.001)), layers.MaxPooling2D(), layers.Conv2D(32, 3, padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.001)), layers.MaxPooling2D(), layers.Conv2D(64, 3, padding='same', activation='relu', kernel_regularizer=regularizers.l2(0.001)), layers.MaxPooling2D(), layers.Dropout(0.3), layers.Flatten(), layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l2(0.001)), layers.Dense(num_classes) ])
优化数据增强策略
胸片垂直翻转无医学意义,反而引入噪声,同时可增加更多有效扰动:data_augmentation = tf.keras.Sequential([ layers.RandomFlip("horizontal"), layers.RandomRotation(0.15), layers.RandomZoom(0.15), layers.RandomContrast(0.1), layers.RandomTranslation(height_factor=0.1, width_factor=0.1) ])精简模型结构
降低模型容量减少过拟合风险:- 把全连接层的128个神经元缩减至64
- 在卷积层后添加BatchNormalization层,稳定训练同时抑制过拟合:
model_1 = Sequential([ resize_and_rescale, data_augmentation, layers.Conv2D(16, 3, padding='same', activation='relu'), layers.BatchNormalization(), layers.MaxPooling2D(), layers.Conv2D(32, 3, padding='same', activation='relu'), layers.BatchNormalization(), layers.MaxPooling2D(), layers.Conv2D(64, 3, padding='same', activation='relu'), layers.BatchNormalization(), layers.MaxPooling2D(), layers.Dropout(0.3), layers.Flatten(), layers.Dense(64, activation='relu'), layers.Dense(num_classes) ])
调整学习率策略
降低初始学习率或添加学习率衰减,避免训练后期震荡:lr_scheduler = tf.keras.optimizers.schedules.ExponentialDecay( initial_learning_rate=0.001, decay_steps=1000, decay_rate=0.96, staircase=True ) optimizer = tf.keras.optimizers.Adam(learning_rate=lr_scheduler) model_1.compile(optimizer=optimizer, loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])
内容的提问来源于stack exchange,提问作者Vinicius Cavalcante
相关产品推荐
相关产品推荐

