You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

TensorFlow CNN图像分类器所有图像均被判定为同一类别问题求助

问题排查与解决方案

先帮你定位几个最可能导致所有图像都被判定为Cubic的核心问题,按优先级逐一解决:

1. 测试阶段未做与训练一致的图像归一化(最关键)

你的模型在训练时,第一个层就是Rescaling(1./255),把输入图像的像素值从[0,255]缩放到了[0,1]。但在测试代码里,你加载图像后直接转成数组就输入模型,完全没做归一化处理!这会导致模型接收到的输入分布和训练时完全不一致,自然输出毫无意义的固定结果。

修复代码:在测试时给图像数组加入归一化步骤:

# 测试图像加载后添加这行
img_array = keras.preprocessing.image.img_to_array(img)
img_array = img_array / 255.0  # 新增:和训练时保持一致的归一化
img_array = tf.expand_dims(img_array, 0)

2. 训练轮次严重不足

只训练3个epochs对于CNN来说远远不够,模型还没来得及学习到三类正弦曲线图像的特征,处于严重欠拟合状态,权重几乎没有有效更新,自然无法区分不同类别。

修复方案

  • 先把epochs提升到20-30,观察训练/验证的准确率变化:
epochs = 25
history = model.fit(
 train_ds,
 validation_data=val_ds,
 epochs=epochs
 )
  • 可以加入早停机制,防止过拟合并保留最优权重:
from tensorflow.keras.callbacks import EarlyStopping

early_stop = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
history = model.fit(
 train_ds,
 validation_data=val_ds,
 epochs=epochs,
 callbacks=[early_stop]
 )

3. 清理无关代码,避免数据路径干扰

你的代码里先加载了cifar10和flower_photos数据集,虽然后面覆盖了data_dir,但这些冗余代码可能导致混淆,建议直接删除:

# 删除以下无用代码块:
# from keras.datasets import cifar10
# (x_train, y_train), (x_test, y_test) = cifar10.load_data()
# dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
# data_dir = tf.keras.utils.get_file(origin = dataset_url, fname = "flower_photos", untar = True)
# data_dir = pathlib.Path(data_dir)

4. 验证数据集的类别平衡性

如果你的数据集里Cubic类别的图像数量远多于Linear和Quadratic,模型会倾向于输出占比最高的类别(这也是固定输出的常见原因之一)。可以打印训练/验证集的类别分布确认:

import collections

# 统计训练集类别数量
train_counts = collections.defaultdict(int)
for _, labels in train_ds:
    for label in labels:
        train_counts[class_names[label.numpy()]] += 1
print("训练集类别分布:", dict(train_counts))

# 统计验证集类别数量
val_counts = collections.defaultdict(int)
for _, labels in val_ds:
    for label in labels:
        val_counts[class_names[label.numpy()]] += 1
print("验证集类别分布:", dict(val_counts))

如果存在严重不平衡,可以通过过采样少数类欠采样多数类或者数据增强来平衡数据集。

5. 可选:增强模型泛化能力

如果上述步骤后效果仍不理想,可以尝试:

  • 增加卷积层的滤波器数量(比如把Conv2D(32, 3)改成Conv2D(64, 3)
  • 在Dense层前加入Dropout层防止过拟合:
model = tf.keras.Sequential([
 tf.keras.layers.experimental.preprocessing.Rescaling(1./255),
 tf.keras.layers.Conv2D(64, 3, activation='relu'),
 tf.keras.layers.MaxPooling2D(),
 tf.keras.layers.Conv2D(64, 3, activation='relu'),
 tf.keras.layers.MaxPooling2D(),
 tf.keras.layers.Conv2D(64, 3, activation='relu'),
 tf.keras.layers.MaxPooling2D(),
 tf.keras.layers.Flatten(),
 tf.keras.layers.Dropout(0.5),  # 新增Dropout层
 tf.keras.layers.Dense(128, activation='relu'),
 tf.keras.layers.Dense(num_classes)
])
  • 加入数据增强,提升模型对不同图像的适应能力:
data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip("horizontal"),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.1),
  tf.keras.layers.experimental.preprocessing.RandomZoom(0.1),
])

# 把数据增强加入模型开头
model = tf.keras.Sequential([
 data_augmentation,
 tf.keras.layers.experimental.preprocessing.Rescaling(1./255),
 # 后续卷积、池化层保持不变...
])

先从归一化修复增加训练轮次这两个步骤开始,这两个是最可能解决你当前问题的核心措施。

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

火山引擎 最新活动