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

Keras训练二分类模型时数组形状不均ValueError问题求助

Keras/TensorFlow训练二分类模型时的数组形状不匹配错误

问题描述

尝试使用Keras和TensorFlow在包含约21000张图像的数据集上训练二分类模型,运行训练代码时抛出如下错误:

Traceback (most recent call last):
  File "train.py", line 83, in <module>
    training_images = np.array([i[0] for i in training_data])
ValueError: setting an array element with a sequence. The requested array has an inhomogeneous shape after 3 dimensions. The detected shape was (21527, 300, 300) + inhomogeneous part.

之前使用过相同数据集和代码,不清楚当前问题成因。以下是加载数据集并训练模型的代码:

from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import BatchNormalization
from PIL import Image
from random import shuffle, choice
import numpy as np
import os
from keras.callbacks import ModelCheckpoint
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential, Model
from sklearn.model_selection import train_test_split
from keras import optimizers


IMAGE_SIZE = 300
epochs_num = 50
batch_size = 64
IMAGE_DIRECTORY = './data'
retrain_from_prior_model=True

def label_img(name):
    if name == 'object': return np.array([1, 0])
    elif name == 'none' : return np.array([0, 1])


def load_data():
    print("Loading images...")
    train_data = []
    directories = next(os.walk(IMAGE_DIRECTORY))[1]

    for dirname in directories:
        print("Loading {0}".format(dirname))
        file_names = next(os.walk(os.path.join(IMAGE_DIRECTORY, dirname)))[2]
        for i in range(len(file_names)):
            image_name = choice(file_names)
            image_path = os.path.join(IMAGE_DIRECTORY, dirname, image_name)
            label = label_img(dirname)
            if "DS_Store" not in image_path:
                try:
                    img = Image.open(image_path)
                    img = img.resize((IMAGE_SIZE, IMAGE_SIZE), Image.LANCZOS)
                    train_data.append([np.array(img), label])
                except Exception as e:
                    print(f"Error processing image: {image_path}")
                    print(f"Error message: {str(e)}")
                    continue  # Skip this image and continue with the next one

    shuffle(train_data)
    return train_data

def create_model():
    channels = 3
    model = Sequential()
    #change first one to 64
    model.add(Conv2D(32, kernel_size = (5, 5), activation='relu', input_shape=(IMAGE_SIZE, IMAGE_SIZE, channels)))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(BatchNormalization())
    model.add(Conv2D(64, kernel_size=(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(BatchNormalization())
    model.add(Conv2D(128, kernel_size=(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(BatchNormalization())
    model.add(Conv2D(256, kernel_size=(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(BatchNormalization())
    
    model.add(Conv2D(64, kernel_size=(3,3), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(BatchNormalization())
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(256, activation='relu'))
    model.add(Dropout(0.2))
    model.add(Dense(128, activation='relu'))
    model.add(Dense(2, activation = 'softmax'))
    
    return model
  
training_data = load_data()

training_images = np.array([i[0] for i in training_data])

training_labels = np.array([i[1] for i in training_data])

print(str(len(training_images)))
# Split the data
training_images, validation_images, training_labels, validation_labels = train_test_split(training_images, training_labels, test_size=0.2, shuffle= True)
print(str(len(training_images)))

print('creating model')
#========================
if retrain_from_prior_model == False:
    model = create_model()
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    print('training model...model.count_params: '+str(model.count_params()) + '...model.count_layers: '+ str(len(model.layers)))
else:
    model = load_model("model_0.989.h5")
    model.compile(loss='binary_crossentropy', optimizer= optimizers.Adam(learning_rate=0.0001), metrics=['accuracy'])

filepath="./checkpoints/model_{epoch:03d}_{accuracy:.4f}_{val_accuracy:.4f}_{val_loss:.7f}.h5"
checkpoint = ModelCheckpoint(filepath, monitor=["accuracy"], verbose=1, mode='max', save_weights_only=False)
callbacks_list = [checkpoint]

# if you want data augmentation: rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, brightness_range=[0.9,1.1]
datagen = ImageDataGenerator(zoom_range=0.2, horizontal_flip=True)
datagen.fit(training_images)
train_gen=datagen.flow(training_images, training_labels, batch_size=batch_size)
#validation
val_datagen = ImageDataGenerator(horizontal_flip=True)
val_datagen.fit(training_images)
val_gen=datagen.flow(validation_images, validation_labels, batch_size=batch_size)

model.fit(train_gen, validation_data=val_gen, epochs=epochs_num, verbose=1, callbacks=callbacks_list)

print('Training finished. Model saved.')

问题原因

错误核心是图像数据形状不一致:模型输入要求是(300,300,3)的RGB图像,但数据集中存在单通道灰度图(形状为(300,300)),导致无法将所有图像统一构造成4维numpy数组(样本数, 300, 300, 3)。

另外,load_data函数存在逻辑漏洞:用choice(file_names)循环选取图片,会重复加载同一张图片,同时可能遗漏部分图像,但这不是当前报错的直接原因。

修复方法

1. 统一图像通道数

在加载图像后,强制转换为RGB格式,确保所有图像都是3通道。修改load_data函数中的图像处理部分:

img = Image.open(image_path)
img = img.resize((IMAGE_SIZE, IMAGE_SIZE), Image.LANCZOS)
# 强制转为RGB,解决灰度图通道数不足的问题
img = img.convert('RGB')
train_data.append([np.array(img), label])

2. 修复重复加载图片的逻辑

原循环中用choice随机选图会导致重复,改为直接遍历所有文件名:

# 替换原循环代码
for image_name in file_names:
    image_path = os.path.join(IMAGE_DIRECTORY, dirname, image_name)
    label = label_img(dirname)
    if "DS_Store" not in image_path:
        try:
            img = Image.open(image_path)
            img = img.resize((IMAGE_SIZE, IMAGE_SIZE), Image.LANCZOS)
            img = img.convert('RGB')
            train_data.append([np.array(img), label])
        except Exception as e:
            print(f"Error processing image: {image_path}")
            print(f"Error message: {str(e)}")
            continue

3. 可选:添加形状验证(调试用)

如果问题仍然存在,可以在添加数据前验证图像形状,输出异常路径:

img_array = np.array(img)
if img_array.shape != (IMAGE_SIZE, IMAGE_SIZE, 3):
    print(f"Invalid shape {img_array.shape} for image: {image_path}")
    continue
train_data.append([img_array, label])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 01:42:04