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

Keras CNN二分类模型准确率恒为0.5,小样本下如何优化?

问题描述

我的Keras CNN二分类模型训练及验证准确率始终为0.5。目前该CNN面临的首要问题是图片数量过少(总计980张,其中180张划分为测试集),且我无法获取更多图片来训练模型。
我想了解可以对模型进行哪些调整来提升验证准确率;若样本量是核心问题,哪些模型适用于该数据集训练?

classifier=Sequential()

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

train_set = '/content/gdrive/MyDrive/Extra/ICs/ML/Martinez/train_set'
test_set = '/content/gdrive/MyDrive/Extra/ICs/ML/Martinez/test_set'

train_datagen = ImageDataGenerator(
    rescale=1./255,
    rotation_range = 50,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0,
    horizontal_flip=True,
    fill_mode='nearest')

test_datagen = ImageDataGenerator(rescale=1./255)


train_gen = train_datagen.flow_from_directory(
    train_set,
    target_size = (224,224),
    batch_size=100,
    class_mode='categorical')

test_gen = test_datagen.flow_from_directory(
    test_set,
    target_size=(224,224),
    batch_size=10,
    shuffle=False,
    class_mode='categorical')

model = tf.keras.Sequential([
    Conv2D(32, (3,3), activation='relu', input_shape=(224, 224, 3)),
    MaxPool2D(2,2),
    Conv2D(32, (3,3), activation='relu'),
    MaxPool2D(2,2),
    Conv2D(64, (3,3), activation='relu'),
    MaxPool2D(2,2),
    
    Flatten(),
    Dense(780, activation='relu'),
    Dense(1, activation='sigmoid')
])

print(len(train_gen))

model.summary()

model.compile(
    loss=tf.keras.losses.BinaryCrossentropy(),
    optimizer=tf.keras.optimizers.Adam(),
    metrics='accuracy'
)

model.fit(train_gen, steps_per_epoch=6, epochs=6, validation_data=test_gen, validation_steps=10)

解决方案

一、先修正代码中的核心矛盾

你的代码存在标签格式与输出层不匹配的问题:

  • flow_from_directory设置了class_mode='categorical',会输出one-hot编码的2维标签;
  • 但模型输出层是Dense(1, activation='sigmoid'),损失用的BinaryCrossentropy,期望的是1维的二分类标签。
    这会导致模型无法正确学习,直接造成准确率固定0.5。必须二选一修正:
  1. 保持输出层和损失不变,将train_gen、test_gen的class_mode改为'binary';
  2. 保持class_mode='categorical',将输出层改为Dense(2, activation='softmax'),损失替换为CategoricalCrossentropy。

二、针对小样本的模型调整策略

1. 强化数据增强

  • 将zoom_range=0改为0.2,增加随机缩放的多样性;
  • 若图片上下翻转不影响类别判断,添加vertical_flip=True;
  • 增加brightness_range=[0.8,1.2],引入随机亮度调整;
  • 注意:数据增强仅作用于训练集,测试集保持仅归一化即可(你当前的做法正确)。

2. 简化模型避免过拟合

  • 全连接层Dense(780)参数过多,对800张训练图来说极易过拟合,建议改为Dense(128)或Dense(64);
  • 在卷积层后添加Dropout层,比如每个MaxPool2D后加Dropout(0.2),全连接层后加Dropout(0.5);
  • 可减少卷积层数量或滤波器数量,比如将第三个Conv2D的64改为32,或直接去掉一层卷积。

3. 优化训练参数

  • epochs=6太少,建议增加到20-30轮,同时配合早停:
    early_stopping = tf.keras.callbacks.EarlyStopping(patience=3, restore_best_weights=True)
    model.fit(..., callbacks=[early_stopping])
    
  • 减小batch_size至16或32,小batch能让模型接触更多样本组合,提升泛化性;
  • 调整学习率至0.0001,Adam默认的0.001对小样本来说可能过大;
  • 修正steps_per_epoch:训练集共800张,batch_size=100时应设为len(train_gen)(即8),当前设置6会浪费200张训练数据。

4. 添加正则化

在卷积层和全连接层加入L2正则化,限制权重大小:

Conv2D(32, (3,3), activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.001))

三、适合小样本的模型选择

1. 迁移学习模型(首选)

利用预训练CNN的通用特征,仅微调顶层即可快速适配小样本任务:

base_model = tf.keras.applications.MobileNetV2(input_shape=(224,224,3), include_top=False, weights='imagenet')
base_model.trainable = False  # 冻结预训练层

model = tf.keras.Sequential([
    base_model,
    tf.keras.layers.GlobalAveragePooling2D(),  # 替代Flatten,减少参数
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

常用预训练模型:MobileNetV2、ResNet50、VGG16,其中MobileNetV2参数少,适合小样本。

2. 轻量级CNN模型

选择参数更少的模型如MobileNet、SqueezeNet,这类模型本身设计就考虑了低数据量场景,不易过拟合。

3. 传统机器学习结合特征提取

先用简单CNN提取图片特征,再用SVM或随机森林做分类:

  • 训练一个简单CNN,输出中间层特征;
  • 将训练集和测试集的特征保存为数组;
  • 用SVM训练分类器,传统模型对小样本的鲁棒性有时优于CNN。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:05:33