TensorFlow默认预分配全部GPU显存,因此set_memory_growth(True)必须在任何TF操作前调用,否则无效;正确顺序是import后立即配置GPU设备并启用内存增长,且多卡需逐个设置。

TensorFlow 默认会一次性申请并锁定全部可见 GPU 显存,不是因为模型大或代码写错,而是它的内存分配策略本身如此——哪怕你只跑一个 tf.constant(1),nvidia-smi 也可能显示显存被占满。
为什么 tf.config.experimental.set_memory_growth(True) 必须在第一行调用
这个配置必须在任何 TensorFlow 操作(包括 tf.data.Dataset 构建、tf.keras.Model 实例化)之前生效,否则 GPU 设备已被初始化、显存已预分配,后续设置无效。常见错误是把它放在模型加载之后、model.fit() 之前,此时早已晚了。
- 正确顺序:
import tensorflow as tf→gpus = tf.config.experimental.list_physical_devices('GPU')→if gpus: tf.config.experimental.set_memory_growth(gpus[0], True) - 如果用了
os.environ['CUDA_VISIBLE_DEVICES'],它也必须在这之前设置,否则list_physical_devices('GPU')可能返回空列表 - 多卡环境下,需对每个可见 GPU 单独调用
set_memory_growth,不能只设gpus[0]
tf.data.cache() 在哪加,决定了显存是平缓还是爆炸
缓存位置不对,.cache() 就是显存爬升的开关。它不关心你 batch 多小、模型多轻,只管把上游输出全塞进显存(或内存),且 epoch 结束也不释放。
- 危险顺序:
.map(...).batch(32).cache()→ 缓存的是 32 张图组成的 batch,显存占用是单图的 32 倍 - 更危险:
.shuffle(10000).map(...).cache()→shuffle的缓冲区先预载 10000 样本,再被整个缓存 - 安全顺序:
.cache().shuffle(...).batch(...).prefetch(...),且.cache()前必须完成降分辨率、裁剪、归一化等轻量预处理 - 实在要缓存大图,改用磁盘缓存:
.cache(filename='/tmp/dataset_cache'),首次慢但彻底避开显存
TensorFlow 2.x 中仍残留 TF 1.x 风格 Session 配置的坑
虽然 TF 2.x 默认启用 eager mode,但部分旧文档或迁移代码仍混用 tf.compat.v1.ConfigProto 和 Session。这类配置在 TF 2.12+ 中已失效,不会报错,但也不起作用——你以为开了 allow_growth,其实什么都没控制住。
立即学习“Python免费学习笔记(深入)”;
- TF 2.0+ 正确方式只有两种:
set_memory_growth或set_virtual_device_configuration(memory_limit=...) -
set_virtual_device_configuration更精确,比如限制为 4096MB,但注意单位是 MB(不是 GB),且该限制是硬上限,超出直接 OOM - 不要混用:
set_memory_growth=True和memory_limit=4096冲突,后者会覆盖前者
真正容易被忽略的是:显存“占满”未必等于“用满”。nvidia-smi 显示的 Memory-Usage 是已分配量,而实际活跃张量可能只占其中 30%。这种“虚高”常让开发者误判瓶颈所在——先确认是分配策略问题,再动模型或数据逻辑。


















