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

Keras多输出模型:CSV加载标注、fit_generator使用及内存优化求助

我的解答

针对问题1:标注存储的最优选择

肯定优先选numpy数组,而不是实时读CSV。原因很简单:

  • numpy是二进制格式,加载速度比文本格式的CSV快得多,尤其是数据量较大时,CSV的解析耗时会非常明显;
  • numpy能精准保留数据类型(比如整数分类标签、浮点回归值),CSV容易出现类型自动转换的问题;
  • 磁盘占用上,numpy数组也比CSV更紧凑。

如果你的数据集结构特别复杂(比如嵌套数据),也可以考虑HDF5格式(用h5py库),但对于大多数图像+多标注的场景,numpy完全够用。只有当数据量极小的时候,实时读CSV才不会有明显影响,但从长期训练效率来看,还是推荐提前存成numpy。

针对问题2:解决GPU内存溢出的核心思路

你的问题本质是一次性加载了全部数据到内存,图像本身体积大,加上五个输出的标注,直接把内存撑爆了。解决的核心是流式加载数据,不要一次性读全量数据:

  1. 改用自定义生成器分批加载
    不要把所有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]
    
  2. 避免不必要的内存浪费

    • 图像尽量用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:47:58