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

求助:Keras+TensorFlow1.8.0图像分类代码内存泄漏优化

排查与优化Keras+TensorFlow 1.8图像分类任务的内存泄漏问题

看了你的代码和问题描述,内存持续增长的核心原因是循环内重复创建Keras模型实例,导致TensorFlow静态计算图不断累积未释放的节点,加上一些不必要的重复初始化操作,最终内存被逐步占满。下面我会拆解问题点,给出优化后的代码,并解释关键优化逻辑:

核心问题分析

  1. 重复创建顶层模型(model2):每次循环都调用create_top_model()新建模型并加载权重,TensorFlow 1.x的静态计算图会保留所有创建过的模型节点,旧模型的显存和内存资源不会被自动回收,这是内存泄漏的主要元凶。
  2. 重复初始化VGG16模型:你在循环前已经初始化了一次model = applications.VGG16(...),但循环内又重复初始化了一次,这不仅浪费内存,还会额外增加计算图节点。
  3. 无效的资源释放操作:手动将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()

关键优化点说明

  1. 模型只初始化一次:将VGG16基础模型和顶层分类模型的创建、权重加载都移到循环外部,避免每次循环都向TensorFlow计算图中添加新节点,从根源上阻止内存累积。
  2. 使用os.path.join拼接路径:避免手动拼接路径的潜在错误,让代码更健壮。
  3. 主动触发垃圾回收:通过del删除循环内临时变量,并调用gc.collect(),帮助Python及时释放未被引用的NumPy数组和底层资源。
  4. 移除无效空赋值:替换为有效的资源释放方式,避免无效操作占用代码空间。

额外建议(针对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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:44:23