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

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添加自定义层搭建了模型,但训练后准确率极高(训练集存在严重不平衡),不确定实现是否正确,现提出两个问题:

  1. 模型实现是否正确?
  2. 有哪些优化建议?

我的模型代码如下:

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-16include_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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 18:36:26