Keras多输出模型:CSV加载标注、fit_generator使用及内存优化求助
我的解答
针对问题1:标注存储的最优选择
肯定优先选numpy数组,而不是实时读CSV。原因很简单:
- numpy是二进制格式,加载速度比文本格式的CSV快得多,尤其是数据量较大时,CSV的解析耗时会非常明显;
- numpy能精准保留数据类型(比如整数分类标签、浮点回归值),CSV容易出现类型自动转换的问题;
- 磁盘占用上,numpy数组也比CSV更紧凑。
如果你的数据集结构特别复杂(比如嵌套数据),也可以考虑HDF5格式(用h5py库),但对于大多数图像+多标注的场景,numpy完全够用。只有当数据量极小的时候,实时读CSV才不会有明显影响,但从长期训练效率来看,还是推荐提前存成numpy。
针对问题2:解决GPU内存溢出的核心思路
你的问题本质是一次性加载了全部数据到内存,图像本身体积大,加上五个输出的标注,直接把内存撑爆了。解决的核心是流式加载数据,不要一次性读全量数据:
改用自定义生成器分批加载
不要把所有x_train、y1_train、y2_train...都读进内存,而是保留CSV文件(里面存图像路径+五个标注),写一个自定义生成器,每次只加载一批数据:from tensorflow.keras.preprocessing import image import pandas as pd import numpy as np def custom_generator(csv_path, batch_size=32, target_size=(224,224)): # 循环生成批次数据,符合Keras生成器要求 while True: # 按批次读取CSV for chunk in pd.read_csv(csv_path, chunksize=batch_size): images = [] y_list = [[], [], [], [], []] # 对应五个输出的标注 for _, row in chunk.iterrows(): # 加载并预处理图像 img = image.load_img(row['image_path'], target_size=target_size) img_arr = image.img_to_array(img) img_arr = img_arr / 255.0 # 归一化,根据你的需求调整 images.append(img_arr) # 读取五个标注 y_list[0].append(row['label1']) y_list[1].append(row['label2']) y_list[2].append(row['label3']) y_list[3].append(row['label4']) y_list[4].append(row['label5']) # 转换为numpy数组,返回格式:(图像批次, [标注1批次, 标注2批次,...]) yield np.array(images), [np.array(y) for y in y_list]避免不必要的内存浪费
- 图像尽量用
uint8类型(0-255)存储,不要提前转成float32,等预处理时再转换,能节省3/4的内存; - 升级Keras到最新版本(或直接用TensorFlow内置的Keras),
fit_generator已经被弃用,改用model.fit配合生成器,旧版本的fit_generator确实存在内存泄漏风险; - 临时缓解可以减小
batch_size,但这只是权宜之计,流式加载才是根本解决方法。
- 图像尽量用
针对问题3:ImageDataGenerator适配多输出
ImageDataGenerator本身的flow方法只支持单输出,但可以通过两种方式适配多输出场景:
方法一:结合数据增强的自定义生成器
在上面的自定义生成器基础上,加入ImageDataGenerator的增强逻辑,注意设置相同的seed保证图像增强和标注的对应性:
from tensorflow.keras.preprocessing.image import ImageDataGenerator # 定义数据增强参数 datagen = ImageDataGenerator( rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True ) def augmented_generator(csv_path, batch_size=32): base_gen = custom_generator(csv_path, batch_size=batch_size) while True: x_batch, y_batch = next(base_gen) # 对图像批次做增强 aug_iter = datagen.flow(x_batch, batch_size=batch_size, seed=42) x_aug = next(aug_iter) yield x_aug, y_batch
方法二:用flow_from_dataframe(TensorFlow Keras专属)
如果你的CSV里有图像路径和五个标注列,直接用flow_from_dataframe更便捷,只需设置class_mode='multi_output':
train_df = pd.read_csv('train.csv') train_generator = datagen.flow_from_dataframe( dataframe=train_df, directory='./images', # 图像根目录(如果CSV里是相对路径) x_col='image_path', # CSV中存储图像路径的列名 y_col=['label1', 'label2', 'label3', 'label4', 'label5'], # 五个标注列 target_size=(224,224), batch_size=32, class_mode='multi_output', # 关键:指定多输出模式 seed=42 )
训练时直接传入这个生成器即可,它会自动返回(x_batch, [y1, y2, y3, y4, y5])的格式,完美匹配你的多输出模型。另外,记得在模型编译时给每个输出指定对应的损失函数,比如:
model.compile( optimizer='adam', loss=['binary_crossentropy', 'categorical_crossentropy', 'mse', 'mse', 'sparse_categorical_crossentropy'], loss_weights=[1.0, 0.8, 1.0, 1.0, 0.9], # 可根据任务重要性设置损失权重 metrics=['accuracy'] )
内容的提问来源于stack exchange,提问作者Grigorios Kalliatakis
相关产品推荐
相关产品推荐

