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

使用Keras函数式API从零训练VGG16时所有测试图被预测为同一类怎么办

问题排查与修正方案

核心错误点

  • 损失函数与分类配置不匹配:你使用class_mode='categorical'加载数据,模型输出层是2神经元+softmax,对应应该使用categorical_crossentropy作为损失函数,当前用的binary_crossentropy仅适用于二分类单神经元sigmoid输出、class_mode='binary'的场景,损失函数错误直接导致模型梯度更新逻辑错误,无法正常学习分类边界。
  • 预测调用模型名称错误:你定义的模型变量名为model1,但预测时调用的是model.predict(),如果没有额外定义过model变量,该调用要么报错要么返回无关模型的输出,是所有样本输出同一类的直接原因。
  • 类别标签映射错误:flow_from_directory默认按文件夹名称的字典序分配标签,比如如果你的数据集文件夹命名为car、plane,那么标签0对应car、1对应plane,你当前判断pos==0输出plane的逻辑完全颠倒,也会导致分类结果全错。
  • 训练迭代轮数不足:VGG16参数量超过1.3亿,你仅训练5轮,模型完全没有收敛,从损失曲线也能看出训练/验证损失还处于持续下降阶段,没有进入稳定区间。
  • 步长计算逻辑错误:steps_per_epoch的计算逻辑为math.ceil(traindata.samples//batch_size),先做整数除法再取整等于直接丢弃了最后不足一个batch的样本,你1000张训练图batch=32的话,完整步长应该是32,按你的写法只会取31步,每次训练少用8张图,验证集同理也会丢失样本。
  • 小数据集训练策略不合理:你从零开始训练VGG16,仅用1000张训练样本远不足以支撑这么大的模型收敛,很容易出现过拟合或者欠拟合。

修正方案

1. 修正模型编译逻辑

将损失函数替换为匹配的categorical交叉熵,可替换更稳定的Adam优化器降低调参难度:

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

2. 修正训练步长计算

直接使用生成器自动计算步长,或者修正计算逻辑:

history = model1.fit_generator(
      traindata,
      steps_per_epoch=traindata.samples // batch_size,
      epochs=30, # 至少训练30轮保证收敛
      verbose=1,
      validation_data = validdata,
      validation_steps=validdata.samples // batch_size)

3. 修正预测逻辑

首先确认标签映射,再修正模型调用变量名:

# 先打印确认标签对应关系
print(traindata.class_indices)
# 假设输出为{'car':0, 'plane':1},则预测逻辑调整为:
uploaded = files.upload()
for fn in uploaded.keys():
  path = '/content/' + fn
  img = image.load_img(path, target_size=(224, 224))
  img = np.asarray(img)
  plt.imshow(img)
  img = np.expand_dims(img, axis=0)
  classes = model1.predict(img/255) # 修正为model1
  pos=np.argmax(classes[0])
  if pos==0:
    print("car")
  elif pos==1:
    print("plane")

4. 可选优化(大幅提升效果)

使用预训练VGG16权重做迁移学习,冻住卷积层只训练全连接层,适配小数据集场景:

from keras.applications import VGG16
from keras.layers import Dropout
# 加载预训练权重,去掉顶部全连接层
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(224,224,3))
# 冻住卷积层不训练
for layer in base_model.layers:
    layer.trainable = False
# 拼接自定义全连接层
x = Flatten()(base_model.output)
x = Dense(4096, activation='relu')(x)
x = Dropout(0.5)(x) # 加Dropout防止过拟合
x = Dense(4096, activation='relu')(x)
x = Dropout(0.5)(x)
output = Dense(2, activation='softmax')(x)
model1 = Model(inputs=base_model.input, outputs=output)

内容的提问来源于stack exchange,提问作者kumar siddharth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:54:03