求助:Keras+TensorFlow1.8.0图像分类代码内存泄漏优化
排查与优化Keras+TensorFlow 1.8图像分类任务的内存泄漏问题
看了你的代码和问题描述,内存持续增长的核心原因是循环内重复创建Keras模型实例,导致TensorFlow静态计算图不断累积未释放的节点,加上一些不必要的重复初始化操作,最终内存被逐步占满。下面我会拆解问题点,给出优化后的代码,并解释关键优化逻辑:
核心问题分析
- 重复创建顶层模型(model2):每次循环都调用
create_top_model()新建模型并加载权重,TensorFlow 1.x的静态计算图会保留所有创建过的模型节点,旧模型的显存和内存资源不会被自动回收,这是内存泄漏的主要元凶。 - 重复初始化VGG16模型:你在循环前已经初始化了一次
model = applications.VGG16(...),但循环内又重复初始化了一次,这不仅浪费内存,还会额外增加计算图节点。 - 无效的资源释放操作:手动将
model2=""、image_arr=""这类变量赋值为空字符串,根本无法释放Keras模型和NumPy数组占用的底层TensorFlow资源。
优化后的完整代码
import os import random import fnmatch import time import operator import numpy as np import cv2 from keras.preprocessing.image import load_img, img_to_array from keras import applications from keras.models import Model # 假设create_top_model基于Model构建,需确保导入正确 # 全局配置 class_labels = ['cc', '', 'cc', 'xx'] target_size = (224, 224) # VGG16默认输入尺寸,补充你可能遗漏的定义 path = "/home/dataset/test" pattern = "*.jpg" # 仅初始化一次VGG16特征提取模型 base_model = applications.VGG16(include_top=False, weights='imagenet') # 仅创建并加载一次顶层分类模型 # 先通过一张测试图获取瓶颈特征形状,用于初始化顶层模型(仅执行一次) sample_img_path = os.path.join(path, [f for f in os.listdir(path) if fnmatch.fnmatch(f, pattern)][0]) dummy_image = load_img(sample_img_path, target_size=target_size) dummy_arr = img_to_array(dummy_image) / 255.0 dummy_arr = np.expand_dims(dummy_arr, axis=0) dummy_bottleneck = base_model.predict(dummy_arr) top_model = create_top_model("softmax", dummy_bottleneck.shape[1:]) top_model.load_weights("res/_top_model_weights.h5") # 加载并打乱测试文件列表 listOfFiles = os.listdir(path) random.shuffle(listOfFiles) for entry in listOfFiles: if fnmatch.fnmatch(entry, pattern): img_full_path = os.path.join(path, entry) start_time = time.time() # 图像预处理 image = load_img(img_full_path, target_size=target_size) image_arr = img_to_array(image) / 255.0 image_arr = np.expand_dims(image_arr, axis=0) # 复用已初始化的模型执行预测 bottleneck_features = base_model.predict(image_arr) predicted = top_model.predict(bottleneck_features) # 解析并输出预测结果 decoded_predictions = dict(zip(class_labels, predicted[0])) decoded_predictions = sorted(decoded_predictions.items(), key=operator.itemgetter(1), reverse=True) elapsed_time = time.time() - start_time print() count = 1 for key, value in decoded_predictions[:5]: print("{}. {}: {:8f}%".format(count, key, value * 100)) count += 1 print("time: ", time.strftime("%H:%M:%S", time.gmtime(elapsed_time)), " - ", elapsed_time) # 主动释放循环内临时变量,加速资源回收(TF1.x环境下效果明显) del image, image_arr, bottleneck_features, predicted import gc gc.collect()
关键优化点说明
- 模型只初始化一次:将VGG16基础模型和顶层分类模型的创建、权重加载都移到循环外部,避免每次循环都向TensorFlow计算图中添加新节点,从根源上阻止内存累积。
- 使用
os.path.join拼接路径:避免手动拼接路径的潜在错误,让代码更健壮。 - 主动触发垃圾回收:通过
del删除循环内临时变量,并调用gc.collect(),帮助Python及时释放未被引用的NumPy数组和底层资源。 - 移除无效空赋值:替换为有效的资源释放方式,避免无效操作占用代码空间。
额外建议(针对TensorFlow 1.x)
如果因业务需求必须在循环内动态创建模型,那么每次创建新模型前必须调用keras.backend.clear_session()清理之前的计算图节点:
from keras import backend as K # 循环内创建模型前执行 K.clear_session() dynamic_model = create_top_model("softmax", bottleneck_features.shape[1:]) dynamic_model.load_weights("res/_top_model_weights.h5")
但这种方式效率远低于复用模型,因此优先推荐复用模型的方案。
内容的提问来源于stack exchange,提问作者2adnielsenx xx
相关产品推荐
相关产品推荐

