如何用3个Keras生成器构建mini batch?训练CNN内核崩溃求助
看起来你在构建三输入图像生成器时遇到了内核崩溃的问题,我来帮你拆解问题并给出可行的解决方案:
先排查核心问题点
你的代码里有几个容易触发错误的地方,也是导致内核崩溃的常见原因:
1. flow_from_directory的使用可能不符合要求
flow_from_directory的规则是:传入的目录下必须有子文件夹作为类别(比如Anchor文件夹里要放class1、class2这类子目录,再在子目录里放图片)。如果你的Anchor/Positive/Negative文件夹里直接存图片,没有子类别目录,这个函数会无法正确读取数据,甚至悄悄抛出内存相关的异常,最终导致内核崩溃。
2. 三个生成器的同步逻辑缺失
每个flow_from_directory生成器的内部索引是独立维护的,当某个文件夹的图片数量比其他两个少,调用next()时会触发遍历结束的异常,而你的while True循环没有处理这种情况,会导致生成器逻辑混乱,进而拖垮内核。
3. 输入维度与模型的匹配问题
你生成的input_imgs是(3,224,224,3),如果你的模型输入层定义的是固定批量(比如Input(shape=(3,224,224,3)))而不是(224,224,3),会导致张量运算维度不匹配,触发内存溢出或计算错误。
具体解决方案
方案一:改用手动加载图片(更灵活可控)
如果你的文件夹里直接存图片,没有子类别目录,建议放弃flow_from_directory,手动构建路径列表并加载图片:
import os import numpy as np from tensorflow.keras.preprocessing.image import load_img, img_to_array # 先获取所有图片路径 def get_img_paths(folder): return [os.path.join(folder, fname) for fname in os.listdir(folder) if fname.lower().endswith(('.png', '.jpg', '.jpeg'))] # 替换成你的实际路径 anchor_paths = get_img_paths(r'C:\Users\sinthes\Desktop\AI_anaconda\face_recognition\dataset\train\E\Anchor') positive_paths = get_img_paths(r'C:\Users\sinthes\Desktop\AI_anaconda\face_recognition\dataset\train\E\Positive') negative_paths = get_img_paths(r'C:\Users\sinthes\Desktop\AI_anaconda\face_recognition\dataset\train\E\Negative') def generator_three_imgs(batch_size=1): max_samples = min(len(anchor_paths), len(positive_paths), len(negative_paths)) while True: # 随机选batch_size个样本索引 indices = np.random.choice(max_samples, batch_size, replace=False) anchor_batch = [] positive_batch = [] negative_batch = [] labels = [] for idx in indices: # 加载并预处理图片(归一化到0-1) anchor = img_to_array(load_img(anchor_paths[idx], target_size=(224,224))) / 255.0 positive = img_to_array(load_img(positive_paths[idx], target_size=(224,224))) / 255.0 negative = img_to_array(load_img(negative_paths[idx], target_size=(224,224))) / 255.0 anchor_batch.append(anchor) positive_batch.append(positive) negative_batch.append(negative) # 根据你的需求自定义标签,这里示例为anchor:0, positive:1, negative:2 labels.extend([0, 1, 2]) # 拼接成最终的批量输入 input_imgs = np.concatenate([anchor_batch, positive_batch, negative_batch], axis=0) yield input_imgs, np.array(labels)
方案二:修复flow_from_directory的同步逻辑
如果你坚持用flow_from_directory,需要添加生成器重置逻辑,确保三个生成器同步:
from tensorflow.keras.preprocessing.image import ImageDataGenerator import numpy as np def generator_three_imgs(index, batch_size=1): anchor_dir = anchor_paths[index] positive_dir = positive_paths[index] negative_dir = negative_paths[index] # 共用一个数据增强生成器即可 data_gen = ImageDataGenerator() # 注意class_mode设为None,因为我们不需要自动生成的类别标签 anchor_gen = data_gen.flow_from_directory( anchor_dir, target_size=(224,224), batch_size=batch_size, class_mode=None, shuffle=True ) positive_gen = data_gen.flow_from_directory( positive_dir, target_size=(224,224), batch_size=batch_size, class_mode=None, shuffle=True ) negative_gen = data_gen.flow_from_directory( negative_dir, target_size=(224,224), batch_size=batch_size, class_mode=None, shuffle=True ) # 获取三个生成器的最小步数,避免某个生成器提前耗尽 min_steps = min(len(anchor_gen), len(positive_gen), len(negative_gen)) step_count = 0 while True: if step_count >= min_steps: # 重置所有生成器,重新开始遍历 anchor_gen.reset() positive_gen.reset() negative_gen.reset() step_count = 0 # 获取批量数据 anchor_imgs = anchor_gen.next() positive_imgs = positive_gen.next() negative_imgs = negative_gen.next() input_imgs = np.concatenate([anchor_imgs, positive_imgs, negative_imgs], axis=0) # 自定义标签 labels = np.array([0]*batch_size + [1]*batch_size + [2]*batch_size) yield input_imgs, labels step_count += 1
额外排查步骤
测试生成器是否正常工作
先单独运行生成器,看能不能正常输出数据:gen = generator_three_imgs(0) imgs, labels = next(gen) print(imgs.shape, labels.shape) # 应该输出(3,224,224,3)和(3,)如果这一步就崩溃,说明生成器的图片读取逻辑有问题。
检查模型输入层
确保模型输入层接受单张图片的形状,而不是固定批量:from tensorflow.keras.layers import Input input_layer = Input(shape=(224,224,3)) # 正确,批量维度自动适配缓解内存压力
如果是内存不足导致的崩溃,可以尝试:- 开启TensorFlow的GPU内存增长模式:
import tensorflow as tf gpus = tf.config.experimental.list_physical_devices('GPU') if gpus: try: for gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True) except RuntimeError as e: print(e) - 训练前手动清理内存:
import gc gc.collect()
- 开启TensorFlow的GPU内存增长模式:
内容的提问来源于stack exchange,提问作者edn

