基于Keras VGG16的食品分类模型验证准确率停滞在50%求助
解决VGG16在Food-101 40类分类中验证准确率停滞的问题
先拆解下你当前遇到的核心问题,再一步步给你针对性的解决方案——你的代码里有几个关键逻辑错误,这才是导致验证准确率卡壳的主要原因:
1. 必须用VGG16专属的preprocess_input()预处理
你现在只用了rescale=1./255做归一化,但VGG16是在ImageNet上预训练的,它的输入要求是减去ImageNet数据集的RGB均值,而不是简单把像素缩到0-1区间。preprocess_input()会帮你完成这个适配,这对预训练模型的特征提取效果影响极大,也是你当前准确率上不去的核心原因之一。
2. 数据增强的逻辑完全搞反了
看你的train_top_model()函数:
- 你用不带增强的生成器加载训练数据,却用带增强的生成器加载验证数据——这完全错误!验证集绝对不能做数据增强,否则验证结果会失真;而训练集才需要靠增强提升泛化能力。
- 更致命的是:你当前的流程是先提取固定的bottleneck特征再训练顶层,但训练集的增强根本没生效(因为bottleneck特征是提前提取好的静态文件,训练顶层时用的是固定数据,增强等于白加)。
3. 训练策略太保守:固定特征提取不如Fine-Tuning
你现在只训练了顶层全连接层,VGG16的卷积层完全冻结,这对于Food-101这种和ImageNet有差异的数据集来说,预训练特征可能不够适配。应该尝试解冻VGG16的最后几层卷积层,联合训练顶层和这些卷积层(也就是Fine-Tuning),让模型学习到更贴合食品分类的特征。
4. 正则化可以再加强
你试过调Dropout到0.75,但还可以给全连接层加上L2正则化,进一步抑制过拟合。
修改后的完整代码
我把所有问题都修正了,还加入了学习率自动调度(当验证准确率停滞时自动降学习率),你可以直接运行:
import numpy as np from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Dropout, Flatten, Dense from keras import applications from keras.utils import to_categorical from keras import optimizers from keras.callbacks import ReduceLROnPlateau # 图像尺寸 img_width, img_height = 150, 150 weights_save_path = 'food_40_classes.h5' train_data_dir = 'D:\intallation\dataset\dataset-101/food/train' validation_data_dir = 'D:\intallation\dataset\dataset-101/food/validation' nb_train_samples = 28000 nb_validation_samples = 12000 epochs = 80 batch_size = 32 # 学习率调度器:验证准确率3轮没提升,学习率乘以0.1 lr_scheduler = ReduceLROnPlateau(monitor='val_accuracy', patience=3, factor=0.1, verbose=1) def train_with_fine_tuning(): # 1. 加载预训练VGG16,冻结前15层,保留最后3层卷积层可训练 base_model = applications.VGG16(weights='imagenet', include_top=False, input_shape=(img_width, img_height, 3)) for layer in base_model.layers[:15]: layer.trainable = False for layer in base_model.layers[15:]: layer.trainable = True # 2. 构建完整模型 model = Sequential() model.add(base_model) model.add(Flatten()) model.add(Dense(4096, activation='relu', kernel_regularizer='l2')) # 加L2正则化 model.add(Dropout(0.75)) model.add(Dense(4096, activation='relu', kernel_regularizer='l2')) # 新增全连接层提升容量 model.add(Dropout(0.75)) model.add(Dense(40, activation='softmax')) # 40类分类输出 # 3. 编译模型:用小学习率避免破坏预训练特征 sgd = optimizers.SGD(lr=1e-5, momentum=0.9, nesterov=True) model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) # 4. 数据生成器:正确应用预处理和增强 train_datagen = ImageDataGenerator( preprocessing_function=applications.vgg16.preprocess_input, # VGG专属预处理 width_shift_range=0.1, height_shift_range=0.1, shear_range=0.1, zoom_range=0.1, horizontal_flip=True, # 新增水平翻转增强 fill_mode='nearest' ) val_datagen = ImageDataGenerator( preprocessing_function=applications.vgg16.preprocess_input # 验证集只用预处理,不用增强 ) train_generator = train_datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='categorical' ) validation_generator = val_datagen.flow_from_directory( validation_data_dir, target_size=(img_width, img_height), batch_size=batch_size, class_mode='categorical' ) # 5. 开始训练 model.fit( train_generator, steps_per_epoch=nb_train_samples // batch_size, epochs=epochs, validation_data=validation_generator, validation_steps=nb_validation_samples // batch_size, callbacks=[lr_scheduler] ) model.save_weights(weights_save_path) # 启动Fine-Tuning训练 train_with_fine_tuning()
关键调整说明
- 预处理修正:用
applications.vgg16.preprocess_input替代简单rescale,完全匹配VGG16的预训练要求。 - 数据增强修正:训练集用增强,验证集只用预处理,且增强参数更合理(新增水平翻转)。
- Fine-Tuning策略:冻结VGG16前15层,训练最后3层卷积层+顶层全连接层,让模型适配食品分类的特征。
- 正则化加强:给全连接层加L2正则化,Dropout调到0.75,新增一层全连接层提升模型容量。
- 学习率调度:自动在验证准确率停滞时降低学习率,避免模型卡在局部最优。
额外建议
- 可以先单独训练顶层全连接层10-20轮,再解冻卷积层进行Fine-Tuning,这样效果会更稳定。
- 监控训练过程中的训练/验证准确率,如果训练准确率很高但验证准确率低,说明过拟合还存在,可以继续增大Dropout比例(比如0.8),或者增加更多数据增强(比如小角度旋转、亮度调整)。
内容的提问来源于stack exchange,提问作者finites
相关产品推荐
相关产品推荐

