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

Keras+TensorFlow GPU处理大规模图像数据时内存溢出问题求助

解决全量数据集下VGG16 predict_generator内存溢出问题

看起来你遇到的核心问题是生成bottleneck特征时,内存(包括主机内存和TensorFlow的固定内存)被耗尽——尤其是你尝试一次性处理120万张图像的特征,直接把所有结果存在内存里,这显然超出了系统的承载能力。结合你的硬件配置和错误信息,我给你以下几个针对性的解决方案:

1. 分批生成并增量保存Bottleneck特征(最关键)

你当前的代码是一次性生成所有训练集的bottleneck特征,然后整体保存到内存中的bottleneck_features_train变量——120万张图的VGG16特征(每张是7×7×512的float32张量),总大小约为120GB,这已经接近你的128GB内存上限,再加上系统和其他进程的占用,必然会触发内存错误。

改用HDF5格式增量写入,避免一次性加载所有数据到内存:

import numpy as np
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras.applications import VGG16
from keras.utils import HDF5Matrix, to_categorical
import h5py
import tensorflow as tf
from keras.backend.tensorflow_backend import set_session

# 先配置TensorFlow会话,优化内存使用
config = tf.ConfigProto()
config.gpu_options.allow_growth = True  # GPU按需分配内存,避免一次性占满显存
config.gpu_options.pinned_memory = False  # 关闭固定主机内存分配,解决报错中的pinned memory问题
set_session(tf.Session(config=config))

# 图像参数
img_width, img_height = 224, 224
top_model_weights_path = 'bottleneck_fc_model.h5'
train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
nb_train_samples = 1200000
nb_validation_samples = 60000
epochs = 50
batch_size = 10
num_classes = 15000  # 匹配你的数据集类别数

# 构建VGG16模型,不包含顶部全连接层
model_vgg = VGG16(include_top=False, weights='imagenet')

# 生成训练集bottleneck特征——分批写入HDF5
datagen = ImageDataGenerator(rescale=1. / 255)

train_generator_bottleneck = datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode=None,
    shuffle=False,
    workers=8,  # 利用多进程加载图像,适配你的16核CPU
    use_multiprocessing=True,
    max_queue_size=10  # 限制预加载队列大小,减少内存占用
)

# 创建HDF5文件存储特征和标签
with h5py.File('bottleneck_features_train.h5', 'w') as f:
    # 创建特征数据集,预设形状和类型
    feat_dset = f.create_dataset('features', shape=(nb_train_samples, 7, 7, 512), dtype='float32')
    # 同时保存one-hot编码的标签
    label_dset = f.create_dataset('labels', shape=(nb_train_samples, num_classes), dtype='float32')
    
    total_batches = nb_train_samples // batch_size
    for batch_idx in range(total_batches):
        # 获取当前批次图像
        x_batch = next(train_generator_bottleneck)
        # 预测特征
        feat_batch = model_vgg.predict_on_batch(x_batch)
        # 获取当前批次的标签并转one-hot
        label_batch = to_categorical(
            train_generator_bottleneck.classes[batch_idx*batch_size : (batch_idx+1)*batch_size],
            num_classes=num_classes
        )
        # 写入HDF5文件
        start = batch_idx * batch_size
        end = start + batch_size
        feat_dset[start:end] = feat_batch
        label_dset[start:end] = label_batch
        
        # 打印进度,方便监控
        if batch_idx % 100 == 0:
            print(f"Processed {start}/{nb_train_samples} images")

# 验证集用同样的方式处理
validation_generator_bottleneck = datagen.flow_from_directory(
    validation_data_dir,
    target_size=(img_width, img_height),
    batch_size=batch_size,
    class_mode=None,
    shuffle=False,
    workers=8,
    use_multiprocessing=True,
    max_queue_size=10
)

with h5py.File('bottleneck_features_validation.h5', 'w') as f:
    feat_dset = f.create_dataset('features', shape=(nb_validation_samples, 7, 7, 512), dtype='float32')
    label_dset = f.create_dataset('labels', shape=(nb_validation_samples, num_classes), dtype='float32')
    
    total_batches = nb_validation_samples // batch_size
    for batch_idx in range(total_batches):
        x_batch = next(validation_generator_bottleneck)
        feat_batch = model_vgg.predict_on_batch(x_batch)
        label_batch = to_categorical(
            validation_generator_bottleneck.classes[batch_idx*batch_size : (batch_idx+1)*batch_size],
            num_classes=num_classes
        )
        start = batch_idx * batch_size
        end = start + batch_size
        feat_dset[start:end] = feat_batch
        label_dset[start:end] = label_batch

# 训练顶部全连接模型——用HDF5Matrix加载,无需一次性读入内存
train_data = HDF5Matrix('bottleneck_features_train.h5', 'features')
train_labels = HDF5Matrix('bottleneck_features_train.h5', 'labels')

validation_data = HDF5Matrix('bottleneck_features_validation.h5', 'features')
validation_labels = HDF5Matrix('bottleneck_features_validation.h5', 'labels')

model_top = Sequential()
model_top.add(Flatten(input_shape=(7,7,512)))
model_top.add(Dense(256, activation='relu'))
model_top.add(Dropout(0.5))
model_top.add(Dense(num_classes, activation='softmax'))  # 多分类场景用softmax

model_top.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',  # 匹配多分类的损失函数
                  metrics=['accuracy'])

model_top.fit(train_data, train_labels,
              epochs=epochs,
              batch_size=batch_size,
              validation_data=(validation_data, validation_labels))

model_top.save_weights(top_model_weights_path)

2. 关闭TensorFlow固定主机内存分配

你的错误日志里明确提到could not allocate pinned host memory,TensorFlow默认会使用固定主机内存来加速GPU-CPU数据传输,但当内存不足时可以关闭这个选项——上面的代码已经包含了这个配置,核心逻辑是:

config = tf.ConfigProto()
config.gpu_options.pinned_memory = False
set_session(tf.Session(config=config))

3. 修正标签生成逻辑

你原来的代码是按二分类生成标签([0]*(nb//2)+[1]*(nb//2)),但你的数据集有15000个类别,这明显不匹配。改用flow_from_directory的classes属性获取真实的类别索引,再转成one-hot编码,上面的代码已经做了修正。

4. 优化系统交换空间利用率

虽然你有300GB交换分区,但系统默认可能不会优先使用它。可以临时调整swappiness参数:

sudo sysctl vm.swappiness=100

如果要永久生效,编辑/etc/sysctl.conf,添加一行vm.swappiness=100,然后重启系统。不过交换空间速度远慢于内存,这是最后的兜底方案。

5. 确认CUDA与TensorFlow版本兼容性

CUDA 9.1对应的TensorFlow GPU版本应该是1.8.x或1.9.x,如果你的TensorFlow版本过高或过低,可能会出现内存分配异常。可以用以下命令检查版本:

pip show tensorflow-gpu

如果版本不匹配,升级或降级到兼容版本即可。


内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:19:35