tf.config.experimental.set_memory_growth必须在import后、任何TF计算前调用,否则失效;与set_memory_limit互斥;多进程需各子进程单独配置;CUDA残留需fuser清理。

tf.config.experimental.set_memory_growth 没在正确时机调用,是绝大多数人“设了却没用”的根本原因。它不是开关,而是一次性初始化指令——晚于任何 tf.* 计算操作就彻底失效。
set_memory_growth 必须在 import 后、任何模型/张量创建前执行
TensorFlow 的 GPU 初始化是惰性的,但一旦触发(比如构建 tf.keras.Sequential()、调用 tf.random.normal() 或进入 @tf.function),设备上下文就锁定,后续再调 set_memory_growth 会直接抛 RuntimeError: Physical devices cannot be modified after being initialized。
常见错误写法:
- 先写
model = tf.keras.Sequential([...]),再调配置 - 在 Jupyter notebook 里分多个 cell 导入、建模、再配显存——只要 kernel 已执行过 TF 操作,就晚了
- 用
if __name__ == '__main__':包裹配置,但脚本顶部已有tf.constant(1)类语句
正确顺序只有一条路径:import tensorflow as tf → 立即获取 GPU 列表并启用 growth → 再做其余所有事。
立即学习“Python免费学习笔记(深入)”;
用了 set_memory_growth 却还是占满显存?检查是否误启了 set_memory_limit
set_memory_growth 和 set_memory_limit 是互斥策略:后者强制固定上限,前者按需增长。如果两者混用(比如先设 limit 再设 growth),growth 会被静默忽略。
验证方式很简单:运行后立刻看 nvidia-smi。若初始显存占用是 100–300MB,说明 growth 生效;若一启动就跳到几 GB,大概率是:
- 配置被跳过(条件判断未进分支)
- 有其他模块提前导入了 TF(如某些 logging 工具、auto-reload 库)
- 用了
tf.config.set_visible_devices([], 'GPU')之后又试图配 GPU,报错但被吞掉
多进程场景下,每个子进程都得单独配
Python 的 multiprocessing 启动新进程时,不会继承父进程的 GPU 配置。如果你用 Process 或 Pool 跑多个 TF 任务,每个子进程开头都必须重复执行完整的配置逻辑。
否则会出现:主进程显存正常,子进程一跑就占满整卡——因为子进程里的 TF 是全新初始化的,默认策略照旧。
安全做法是在子进程入口函数最开头加:
import tensorflow as tf
gpus = tf.config.list_physical_devices('GPU')
if gpus:
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
真正难处理的是 CUDA 上下文残留
即使配置全对、脚本也干净,nvidia-smi 仍显示显存不归零,往往是因为上一次运行的子进程或 CUDA 上下文没完全退出。这类残留不暴露在 Python 层,del model 或 gc.collect() 压根无效。
排查命令:fuser -v /dev/nvidia* —— 它会列出所有持有 GPU 设备句柄的 PID。
清理命令:fuser -k /dev/nvidia* 2>/dev/null(注意别在共享服务器上乱用)。
更稳妥的做法是:训练脚本结束前主动调用 tf.keras.backend.clear_session(),并在关键节点(如模型切换)避免复用 tf.distribute.Strategy 实例——它的内部缓存很难被清空。


















