You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VGG16肺部影像三分类:验证准确率异常波动/固定问题求助

COVID、肺炎、正常肺部三分类VGG16实现及优化问题

数据加载与预处理代码

# importing necessary packages
import cv2,os 
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from tensorflow.keras.applications import VGG19
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.optimizers import RMSprop
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.applications.vgg19 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report 
from sklearn.metrics import confusion_matrix
from sklearn.metrics import plot_confusion_matrix
from tensorflow.keras import models, layers

from google.colab import drive
drive.mount('/content/drive')

import zipfile

with zipfile.ZipFile("New_1300_dataset.zip","r") as zip_ref:
    zip_ref.extractall("DataSet")

datapath = "/content/DataSet/New_1300_dataset"
categories = os.listdir(datapath)
label_cat = []
for i in range(len(categories)):
    label_cat.append(i)

print(categories)
print(label_cat)

# initializing the parameters like initial learning rate, number of epochs, batch size
initial_LR = 1e-3
num_epochs = 50
b_size = 32

# iterating through all images and appending them to list
print("[Information] Loading All the Images..")
data = []
labels = []

for category in categories:
    path = os.path.join(datapath, category)
    img_names = os.listdir(path)
    for img in img_names:
        img_path = os.path.join(path, img)
        image = load_img(img_path, target_size=(64, 64))
        image = img_to_array(image)
        image = preprocess_input(image)
        
        data.append(image)
        labels.append([category])

# one hot encoding the output .. 
encoder = OneHotEncoder(sparse=False)
labels = encoder.fit_transform(labels)

data = np.array(data, dtype="float32")
labels = np.array(labels)

(x_train, x_test, y_train, y_test) = train_test_split(data, labels, test_size=0.1, stratify=labels, random_state=42)

# Normalizing the data (i.e.. zero mean and unit variance)
mean = np.mean(x_train, axis = (0,1,2,3))
std = np.std(x_train, axis = (0,1,2,3))

x_train = (x_train-mean)/(std + 1e-7)
x_test = (x_test-mean)/(std + 1e-7)

定义模型代码

model = models.Sequential([
layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same', input_shape=(64,64,3)),
layers.BatchNormalization(),
layers.Activation('relu') ,
layers.Conv2D(filters=64, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.5),

layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=128, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.5),

layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=256, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.5),

layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.5),

layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.Conv2D(filters=512, kernel_size=(3, 3), padding='same'),
layers.BatchNormalization(),
layers.Activation('relu'),
layers.MaxPooling2D((2, 2)),
layers.Dropout(0.5),

layers.Flatten(),
layers.Dense(512, activation='relu'),
layers.Dense(512, activation='relu'),
layers.Dense(3, activation='softmax')
])

opt = RMSprop(learning_rate=1e-4) 
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy']) 

问题描述

针对COVID、肺炎、正常肺部三分类任务,每个类别各1300张图像。实现了VGG16结构的模型,在每个Conv2D层后添加BatchNormalization,每个MaxPooling层后添加0.5比例的Dropout以抑制过拟合。训练后得到的准确率曲线显示:训练准确率逐步上升至接近100%,但验证准确率波动极大,在30%-90%区间反复震荡。尝试更换Adam、SGD等优化器后,验证准确率固定在33.24%无变化,调整学习率也未改善效果。

改进建议

  • 修正数据预处理流程:
    代码中先使用了preprocess_input(适配VGG模型的预处理,将像素值转换为[-127.5,127.5]范围),后续又做了自定义的均值/std归一化,这会破坏预训练模型期望的数据分布,导致模型无法有效学习。直接删除自定义归一化的代码块。

  • 调整模型结构:

    1. 输入尺寸修改:VGG系列模型的标准输入尺寸为224x224,当前使用64x64输入,经过5次MaxPooling后特征图尺寸仅为2x2,无法捕捉肺部X射线的全局特征。将load_img的target_size改为(224,224),同时修改模型的input_shape为(224,224,3)。
    2. 降低Dropout比例:0.5的Dropout在每个MaxPool后添加,过度抑制了特征学习,建议将Dropout比例调整为0.2-0.3,或仅在全连接层后添加Dropout。
    3. 简化全连接层:输入尺寸改为224x224后,Flatten后的特征维度足够,可去掉一个512的全连接层,减少参数冗余。
  • 优化训练策略:

    1. 检查标签正确性:验证准确率固定在33%(随机猜测的准确率),首先确认标签与图像类别是否正确对应,排除数据标注错误的可能。
    2. 调整优化器与学习率:使用SGD优化器时,初始学习率设为1e-2,配合ReduceLROnPlateau回调函数,当验证损失停滞时自动降低学习率,比Adam/RMSprop更稳定;使用Adam时,初始学习率设为1e-5尝试。
    3. 添加早停机制:使用EarlyStopping回调函数,监控val_loss,当连续3-5个epoch验证损失未下降时停止训练,避免无效迭代。
    4. 加入数据增强:针对肺部X射线数据,使用ImageDataGenerator实现随机水平翻转、小角度旋转、缩放等增强操作,提升模型泛化能力。示例代码:
      from tensorflow.keras.preprocessing.image import ImageDataGenerator
      datagen = ImageDataGenerator(
          horizontal_flip=True,
          rotation_range=10,
          zoom_range=0.1
      )
      datagen.fit(x_train)
      # 训练时使用datagen.flow
      history = model.fit(datagen.flow(x_train, y_train, batch_size=b_size),
                         epochs=num_epochs,
                         validation_data=(x_test, y_test))
      
  • 采用迁移学习:
    代码中导入了VGG19但未使用,直接从头训练VGG-like模型效率低。建议加载预训练的VGG16权重,冻结前几层卷积层,仅训练顶部的分类层,示例:

    base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224,224,3))
    # 冻结基础模型
    for layer in base_model.layers:
        layer.trainable = False
    # 添加自定义分类头
    x = base_model.output
    x = Flatten()(x)
    x = Dense(512, activation='relu')(x)
    x = Dropout(0.3)(x)
    predictions = Dense(3, activation='softmax')(x)
    model = Model(inputs=base_model.input, outputs=predictions)
    model.compile(optimizer=Adam(learning_rate=1e-4), loss='categorical_crossentropy', metrics=['accuracy'])
    

内容的提问来源于stack exchange,提问作者vamsi bharadwaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:10:20