Python中图像数组归一化时内存耗尽,求解决方法
解决猫狗分类图像归一化内存耗尽问题
核心问题原因
你当前的代码会一次性将所有训练/测试图像加载到内存中的Numpy数组,加上归一化操作会创建新的数组副本,直接耗尽内存。哪怕减少图像数量,当单张图像分辨率较高时,内存占用依然会超过上限。
最优解决方案:使用TensorFlow tf.data 流式加载+实时归一化
这种方式不需要一次性加载所有图像到内存,而是按需加载单批图像、实时完成归一化,内存占用仅为单批图像的大小,彻底解决内存溢出问题。
步骤1:获取所有图像文件路径
import glob import tensorflow as tf train_paths = glob.glob('/content/drive/MyDrive/Colab Notebooks/Cats_Dogs/training_set/*.jpg') test_paths = glob.glob('/content/drive/MyDrive/Colab Notebooks/Cats_Dogs/test_set/*.jpg')
步骤2:定义加载+预处理函数(内置归一化)
函数会读取单张图像、直接归一化到0-1区间,同时生成对应标签(和你原代码的独热编码格式一致):
def load_and_preprocess(img_path): # 读取图像文件 img_raw = tf.io.read_file(img_path) # 解码JPEG图像,保留3通道 img = tf.image.decode_jpeg(img_raw, channels=3) # 归一化到0-1范围(直接替代原代码的除以255操作) img = tf.cast(img, tf.float32) / 255.0 # 生成标签:从文件名提取首字符,转成独热编码 filename = tf.path.basename(img_path) label_char = tf.strings.substr(filename, 0, 1) # 狗(d)标记为1,猫(c)标记为0,再转独热编码 label = tf.cast(tf.equal(label_char, 'd'), tf.int32) label = tf.one_hot(label, depth=2) return img, label
步骤3:构建流式数据集
设置批次大小,让数据集自动完成洗牌、分批、预加载,训练时直接传入模型即可:
batch_size = 32 # 可根据内存调整,比如16/64 # 构建训练数据集 train_ds = tf.data.Dataset.from_tensor_slices(train_paths) train_ds = train_ds.map(load_and_preprocess, num_parallel_calls=tf.data.AUTOTUNE) train_ds = train_ds.shuffle(len(train_paths)).batch(batch_size).prefetch(tf.data.AUTOTUNE) # 构建测试数据集 test_ds = tf.data.Dataset.from_tensor_slices(test_paths) test_ds = test_ds.map(load_and_preprocess, num_parallel_calls=tf.data.AUTOTUNE) test_ds = test_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE)
步骤4:训练模型
直接将流式数据集传入model.fit即可:
# 你的模型定义(和原代码一致,需替换input_shape为你的图像尺寸) model = Sequential([ Conv2D(32, (3,3), activation='relu', input_shape=(224, 224, 3)), MaxPooling2D((2,2)), Conv2D(64, (3,3), activation='relu'), MaxPooling2D((2,2)), Conv2D(128, (3,3), activation='relu'), MaxPooling2D((2,2)), Flatten(), Dense(512, activation='relu'), Dropout(0.5), Dense(2, activation='softmax') ]) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 训练 model.fit(train_ds, validation_data=test_ds, epochs=10)
备选方案:分批加载并归一化(适合坚持用Numpy的场景)
如果不想用TensorFlow的数据集API,可以分批加载图像,处理一批就存一批,避免一次性占满内存:
import cv2 import numpy as np import glob batch_size = 100 train_paths = glob.glob('/content/drive/MyDrive/Colab Notebooks/Cats_Dogs/training_set/*.jpg') total_batches = len(train_paths) // batch_size + 1 # 分批处理并保存到磁盘(或直接分批训练) for batch_idx in range(total_batches): start = batch_idx * batch_size end = min((batch_idx+1)*batch_size, len(train_paths)) batch_paths = train_paths[start:end] # 加载当前批次图像并归一化 batch_imgs = [] for path in batch_paths: img = cv2.imread(path) img = img / 255.0 batch_imgs.append(img) batch_imgs = np.array(batch_imgs) # 这里可以直接用batch_imgs训练,或者保存到.npy文件后续加载 # np.save(f'train_batch_{batch_idx}.npy', batch_imgs)
你之前尝试的逐个归一化代码问题
你写的img_train = np.array([])是空数组,循环中用img_train[x]赋值是错误的——x是图像数组而非索引,正确的方式应该是用列表逐个append归一化后的图像,但这种方式最终还是会把所有图像加载到内存,无法解决根本问题。
内容的提问来源于stack exchange,提问作者AetherBorn
相关产品推荐
相关产品推荐

