如何让Keras数据生成器适配图像numpy数组?报错求助
云识别模型开发中Keras数据处理报错排查与解决
开发云识别模型时,使用Keras从CSV读取图片ID和标签、加载指定目录图像,调用ImageDataGenerator.flow()时触发错误:
ValueError: ('Input data in
NumpyArrayIteratorshould have rank 4. You passed an array with shape', (0,))
尝试修改图像numpy数组生成逻辑但未解决,附上完整代码与报错信息,请求排查解决。
原代码
import numpy as np import matplotlib.pyplot as plt import tensorflow as tf import cv2 import pandas as pd import tensorflow.python.keras import keras import os from PIL import Image from numpy import asarray adam = Adam(learning_rate=0.0001) train_data_map = pd.read_csv('C:/Users/owenc/Desktop/WeatherIdentify/input/cloud-type-classification2/train.csv') img_path = 'C:/Users/owenc/Desktop/WeatherIdentify/input/cloud-type-classification2/images/train' sub_class = os.listdir(img_path) checkpoint_path = "C:\\Users\\owenc\\Desktop\\WeatherIdentify\\codes\\cp.ckpt" checkpoint_dir = os.path.dirname(checkpoint_path) # Create a callback that saves the model's weights cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path, save_weights_only=True, verbose=1) #class_names = ['cirriform clouds', 'high cumuliform clouds', 'stratocumulus clouds', 'cumulus clouds', 'cumulonimbus clouds', 'stratiform clouds', 'clear sky'] cases_count = train_data_map['label'].value_counts() num_class = 7 epochs = 100 batch_size = 100 train_data_arr = [] train_data_label_arr = [] train_datagen = ImageDataGenerator( featurewise_center=True, featurewise_std_normalization=True, rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True, validation_split=0.2) for idx in range(len(train_data_arr)): train_data_label_arr.append(train_data_map.iloc[idx]['label']) train_data_arr.append(train_data_map.iloc[idx]['id']) train_data_label_np = np.array(train_data_label_arr) train_data = np.array([np.array(cv2.resize(cv2.imread(fname),244,244)) for fname in train_data_arr]) ''' for fname in train_data_arr: Img = Image.open(os.path.join(img_path, str(fname))) Img.resize((244,244)) np.append(train_data, np.array(Img)) ''' model = Sequential() model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu', input_shape = (224,224,3))) model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', activation ='relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu')) model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu')) model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(256, activation = "relu")) model.add(Dropout(0.5)) model.add(Dense(num_class, activation = "softmax")) model.build() model.summary() model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=adam) #TODO test train_gen = train_datagen.flow(train_data, train_data_label_np, batch_size=batch_size) print(train_gen) history = model.fit(train_gen, epochs = epochs, steps_per_epoch=100 // batch_size,callbacks=[cp_callback]) model.save('supermod100.h5','C:\\Users\\owenc\\Desktop\\WeatherIdentify\\models')
报错信息
Traceback (most recent call last): File "c:\Users\owenc\Desktop\WeatherIdentify\codes\main.py", line 88, in <module> train_gen = train_datagen.flow(train_data, train_data_label_np, batch_size=batch_size) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\owenc\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\keras\src\preprocessing\image.py", line 1545, in flow return NumpyArrayIterator( ^^^^^^^^^^^^^^^^^^^ File "C:\Users\owenc\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\keras\src\preprocessing\image.py", line 758, in __init__ raise ValueError( ValueError: ('Input data in `NumpyArrayIterator` should have rank 4. You passed an array with shape', (0,)) PS C:\Users\owenc\Desktop\WeatherIdentify>
问题排查与修复方案
核心错误点解析
训练数据为空
初始化train_data_arr = []后,循环条件用了range(len(train_data_arr)),此时数组长度为0,循环完全没执行,导致train_data_arr和标签数组都是空的,最终train_data形状为(0,),触发rank不匹配的错误。图像路径错误
读取图像时直接使用fname(图片ID)作为路径,没有拼接图像目录img_path,会导致找不到图片,即使循环正常也加载失败。图像尺寸不匹配
模型输入形状是(224,224,3),但代码中resize设置为244,尺寸不一致会导致后续输入不兼容。标签格式错误
模型使用categorical_crossentropy损失,要求标签是独热编码格式,但当前直接将原始标签转为numpy数组,不符合要求。其他细节问题
- 缺少
Adam、Sequential等类的导入语句,代码无法运行; steps_per_epoch计算错误,100//100=1,训练步数严重不足;model.save()参数格式错误,第二个参数不是路径,应直接传入完整保存路径。
- 缺少
修正后的完整代码
import numpy as np import matplotlib.pyplot as plt import tensorflow as tf import cv2 import pandas as pd import os from PIL import Image # 补充必要的导入 from tensorflow.keras.optimizers import Adam from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense from tensorflow.keras.utils import to_categorical from tensorflow.keras.preprocessing.image import ImageDataGenerator adam = Adam(learning_rate=0.0001) train_data_map = pd.read_csv('C:/Users/owenc/Desktop/WeatherIdentify/input/cloud-type-classification2/train.csv') img_path = 'C:/Users/owenc/Desktop/WeatherIdentify/input/cloud-type-classification2/images/train' checkpoint_path = "C:\\Users\\owenc\\Desktop\\WeatherIdentify\\codes\\cp.ckpt" checkpoint_dir = os.path.dirname(checkpoint_path) # 保存权重的回调 cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path, save_weights_only=True, verbose=1) num_class = 7 epochs = 100 batch_size = 100 train_data_arr = [] train_data_label_arr = [] train_datagen = ImageDataGenerator( featurewise_center=True, featurewise_std_normalization=True, rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True, validation_split=0.2) # 修正循环逻辑:遍历train_data_map的索引 for idx in range(len(train_data_map)): train_data_label_arr.append(train_data_map.iloc[idx]['label']) # 拼接完整图像路径 img_full_path = os.path.join(img_path, str(train_data_map.iloc[idx]['id'])) train_data_arr.append(img_full_path) # 加载并预处理图像:修正尺寸为224,匹配模型输入 train_data = [] for fname in train_data_arr: # 读取图像,确保路径正确 img = cv2.imread(fname) if img is not None: # resize参数应为(宽度,高度),cv2.resize的第二个参数是dsize=(w,h) img_resized = cv2.resize(img, (224, 224)) train_data.append(img_resized) train_data = np.array(train_data) # 标签转为独热编码 train_data_label_np = to_categorical(train_data_label_arr, num_classes=num_class) # 构建模型 model = Sequential() model.add(Conv2D(filters=32, kernel_size=(5,5), padding='Same', activation='relu', input_shape=(224,224,3))) model.add(Conv2D(filters=32, kernel_size=(5,5), padding='Same', activation='relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='Same', activation='relu')) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='Same', activation='relu')) model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(256, activation="relu")) model.add(Dropout(0.5)) model.add(Dense(num_class, activation="softmax")) model.summary() model.compile(loss='categorical_crossentropy', metrics=['acc'], optimizer=adam) # 生成数据生成器 train_gen = train_datagen.flow(train_data, train_data_label_np, batch_size=batch_size) # 修正steps_per_epoch:用训练样本总数除以batch_size steps_per_epoch = len(train_data) // batch_size history = model.fit(train_gen, epochs=epochs, steps_per_epoch=steps_per_epoch, callbacks=[cp_callback]) # 修正模型保存路径 model.save('C:\\Users\\owenc\\Desktop\\WeatherIdentify\\models\\supermod100.h5')
内容的提问来源于stack exchange,提问作者Chen Owen
相关产品推荐
相关产品推荐

