如何在运行的Jupyter Notebook中释放TensorFlow 2.17.0占用的NVIDIA GPU内存?
我完全懂你这种反复重启kernel的痛苦——加载数据花半天,调参没几次就爆显存,太折腾了!结合你的场景(GCE Debian机器、Conda kernel、Jupyter里反复跑模型调参),给你几个实用的解决方案,不用重启kernel也能释放GPU内存:
1. 每次训练前彻底清理旧模型与会话资源
你之前可能只跑了tf.keras.backend.clear_session()和gc.collect(),但漏了手动删除模型相关的变量!TensorFlow有时候会因为这些变量被引用,导致显存里的资源“赖着不走”。每次运行训练细胞前,先执行这段代码:
import tensorflow as tf import gc # 清除Keras的全局会话 tf.keras.backend.clear_session() # 手动删除之前的模型、训练历史变量(如果存在) if 'model' in locals(): del model if 'history' in locals(): del history # 强制触发Python垃圾回收 gc.collect()
为什么有用:手动删除model和history后,切断了Python对TensorFlow显存资源的引用,再配合clear_session清除Keras的内部状态,垃圾回收器就能真正把显存里的旧模型资源回收掉。
2. 启用TensorFlow动态显存分配(必试!)
默认情况下TensorFlow会一次性占满GPU的大部分显存,启用内存增长模式后,它会根据训练需要动态分配显存,不用的资源也会及时释放,从根源减少显存累积。
把这段代码放在第一个加载数据的细胞最开头(必须在import TensorFlow或任何模型操作之前执行):
import tensorflow as tf # 检测可用GPU gpus = tf.config.list_physical_devices('GPU') if gpus: try: # 为每个GPU启用动态显存分配 for gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True) logical_gpus = tf.config.list_logical_devices('GPU') print(f"{len(gpus)} 个物理GPU,{len(logical_gpus)} 个逻辑GPU") except RuntimeError as e: # 内存增长模式必须在GPU初始化前设置,所以要放在最开头 print(e)
为什么有用:这样TensorFlow不会一开始就把显存占满,每次训练结束后会主动释放不用的显存空间,多次调参的显存占用就不会越积越多。
3. 把训练逻辑封装成函数(进阶优化)
把模型定义和训练过程都放进函数里,利用Python的局部变量生命周期自动回收资源。这样每次训练结束后,函数内部的模型变量会被自动销毁,TensorFlow很难再持有显存引用:
def train_model(img_size, categories, train_data, val_data, lr=0.0001, epochs=20, batch_size=32): import tensorflow as tf from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense, Dropout, Flatten, Input from tensorflow.keras.optimizers import Adam train_images, train_labels = train_data validate_images, validate_labels = val_data # 在函数内部定义模型(局部变量) model = Sequential([ Input(shape=(img_size, img_size, 3)), Flatten(), Dense(256, activation='relu'), Dropout(0.4), Dense(128, activation='relu'), Dense(64, activation='relu'), Dense(len(categories), activation='softmax') ]) model.compile(optimizer=Adam(learning_rate=lr), loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 执行训练 history = model.fit(train_images, train_labels, epochs=epochs, batch_size=batch_size, validation_data=(validate_images, validate_labels)) return history
每次调参时,先执行清理步骤,再调用函数:
# 先清理旧资源 tf.keras.backend.clear_session() if 'model' in locals(): del model if 'history' in locals(): del history gc.collect() # 传入新的超参数开始训练 history = train_model(img_size, categories, (train_images, train_labels), (validate_images, validate_labels), lr=0.00005, epochs=15)
4. 尝试使用cuda_malloc_async显存分配器
错误提示里提到的TF_GPU_ALLOCATOR=cuda_malloc_async确实能缓解显存碎片问题,但要注意设置时机:必须在任何TensorFlow操作之前设置环境变量。
把这段代码放在第一个细胞的最最开头(甚至在import TensorFlow之前):
import os os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async' # 之后再import TensorFlow和加载数据 import tensorflow as tf # ... 加载数据的代码 ...
注意:如果已经import过TensorFlow再设置这个环境变量,是不会生效的,所以必须第一次运行第一个细胞时就执行这段。
总结最省心的组合方案
- 第一个细胞开头启用动态显存增长模式;
- 每次运行训练细胞前,执行清理旧变量+clear_session+gc.collect;
- 配合把训练逻辑封装成函数,基本能彻底解决显存累积的问题,不用再重启kernel啦!
备注:内容来源于stack exchange,提问作者Ennio

