VGG-16添加自定义层的模型实现正确性及优化建议咨询
图像分类器构建问题
我用Keras、TensorFlow构建图像分类器,数据集包含4种蔬菜(甜椒、辣椒、新墨西哥青辣椒、番茄),每种蔬菜对应5个子类别(受损、干制、老化、成熟、未成熟),仅番茄的干制类没有图像。数据集统计如下:
Found 6180 files belonging to 19 classes. Using 4944 files for training. Found 6180 files belonging to 19 classes. Using 1236 files for validation.
我基于VGG-16添加自定义层搭建了模型,但训练后准确率极高(训练集存在严重不平衡),不确定实现是否正确,现提出两个问题:
- 模型实现是否正确?
- 有哪些优化建议?
我的模型代码如下:
vgg = keras.applications.VGG16( weights="imagenet", input_shape=(256, 256, 3), include_top=False, ) for layer in vgg.layers: layer.trainable = False def build_model(): # add a Flatten or a GlobalAveragePooling layer x = layers.Flatten()(vgg.output) # add a Dense layer x = layers.Dense(4096, activation='relu')(x) # add a Dropout layer x = layers.Dropout(0.5)(x) # add a Dense layer x = layers.Dense(4096, activation='relu')(x) # add a Dropout layer x = layers.Dropout(0.5)(x) # add the final layer outputs = layers.Dense(class_amount)(x) # build the model model = keras.Model(inputs=vgg.input, outputs=outputs) # compile the model model.compile(loss=keras.losses.BinaryCrossentropy(from_logits=True), optimizer='adam', metrics='accuracy') # print the summary model.summary() return model model = build_model() # train the model history = model.fit(train_ds, epochs = EPOCHS, validation_data=val_ds, verbose = 1)
训练100轮后的结果如下:
Epoch 95/100 155/155 [==============================] - 6s 36ms/step - loss: 0.2588 - accuracy: 0.9958 - val_loss: 2.0675 - val_accuracy: 0.9765 Epoch 96/100 155/155 [==============================] - 6s 36ms/step - loss: 0.3016 - accuracy: 0.9941 - val_loss: 2.1440 - val_accuracy: 0.9733 Epoch 97/100 155/155 [==============================] - 6s 36ms/step - loss: 0.2977 - accuracy: 0.9941 - val_loss: 2.1595 - val_accuracy: 0.9749 Epoch 98/100 155/155 [==============================] - 6s 36ms/step - loss: 0.2545 - accuracy: 0.9941 - val_loss: 2.3368 - val_accuracy: 0.9790 Epoch 99/100 155/155 [==============================] - 6s 36ms/step - loss: 0.1605 - accuracy: 0.9970 - val_loss: 1.8344 - val_accuracy: 0.9822 Epoch 100/100 155/155 [==============================] - 6s 36ms/step - loss: 0.2663 - accuracy: 0.9962 - val_loss: 2.8118 - val_accuracy: 0.9806
1. 模型实现是否正确?
模型整体结构逻辑通顺,但存在两个关键错误:
- 损失函数选型错误:这是19类的多分类任务,你误用了二分类场景的
BinaryCrossentropy,应该替换为多分类对应的SparseCategoricalCrossentropy(from_logits=True)(标签为整数形式时)或CategoricalCrossentropy(from_logits=True)(标签为one-hot编码时)。损失函数不匹配是训练准确率异常偏高的核心原因之一。 - 全连接层参数冗余:VGG-16
include_top=False的输出为(8,8,512),Flatten后是32768维,连续堆叠两个4096维的全连接层会导致参数过量,极易引发过拟合,尤其在数据集不平衡的场景下。
2. 优化建议
数据集层面
- 处理类别不平衡:
- 对样本量少的类别做数据增强(随机翻转、旋转、缩放、亮度调整等),扩充样本数量;
- 对样本量多的类别做随机下采样,降低优势类别的样本占比;
- 训练时设置
class_weight参数,给样本稀缺的类别分配更高权重,引导模型关注这些类别。
- 验证集分布校验:确保验证集的类别分布与训练集一致,避免因划分不当导致验证准确率失真。
模型层面
- 修正损失函数:替换为多分类适配的损失函数,示例代码:
model.compile(loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True), optimizer='adam', metrics=['accuracy']) - 简化全连接层:用
GlobalAveragePooling2D替代Flatten减少参数,同时缩小全连接层维度,示例:x = layers.GlobalAveragePooling2D()(vgg.output) x = layers.Dense(1024, activation='relu')(x) x = layers.Dropout(0.5)(x) outputs = layers.Dense(class_amount)(x) - 微调VGG-16:解冻VGG-16的最后3-5层,训练后期进行微调(需降低学习率,避免破坏预训练特征),让模型更好适配你的数据集。
- 添加正则化:在全连接层加入L2正则化抑制过拟合,示例:
x = layers.Dense(1024, activation='relu', kernel_regularizer=keras.regularizers.L2(0.001))(x)
训练过程层面
- 加入早停机制:当验证损失连续多轮不下降时停止训练,保留最优权重,示例:
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit(train_ds, epochs=EPOCHS, validation_data=val_ds, verbose=1, callbacks=[early_stop]) - 使用多维度评估指标:因数据集不平衡,准确率无法真实反映模型性能,需加入精确率、召回率、F1值等指标,或通过混淆矩阵分析每个类别的分类情况,示例:
from sklearn.metrics import classification_report, confusion_matrix import numpy as np val_preds = np.argmax(model.predict(val_ds), axis=1) val_labels = np.concatenate([y for x, y in val_ds], axis=0) print(classification_report(val_labels, val_preds)) print(confusion_matrix(val_labels, val_preds))
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

