tf.distribute.MirroredStrategy是TensorFlow 2.x单机多卡训练首选方案,通过自动镜像模型、数据分片、All-Reduce梯度同步,在strategy.scope()内封装模型构建与训练,屏蔽通信细节。

多GPU训练必须用 tf.distribute.MirroredStrategy
单机多卡(比如 2 张或 4 张 GPU)最稳定、最常用的方式就是 MirroredStrategy。它在每个 GPU 上复制模型和优化器,同步更新梯度(all-reduce),不需要手动管理设备放置或梯度聚合。
别用 tf.device('/gpu:0') 手动切分数据——那不是分布式训练,只是强行指定设备,还容易出 InvalidArgumentError: Cannot assign a device for operation 错误。
-
MirroredStrategy必须在构建模型和数据集前创建并进入其作用域:strategy = tf.distribute.MirroredStrategy() with strategy.scope(): model = tf.keras.Sequential([...]) model.compile(...) - 数据集要调用
.batch()后再用strategy.experimental_distribute_dataset()包装,或者直接让model.fit()自动处理(Keras 高层 API 已内置支持) - 如果你看到
WARNING:tensorflow:Not all devices in ... are visible,大概率是 CUDA_VISIBLE_DEVICES 没设对,或驱动/CUDA 版本不匹配
model.fit() 能直接跑多GPU,但 batch_size 是每卡的还是全局的?
是每卡的。比如你有 2 张 GPU,batch_size=32,实际每步喂给模型的是 2 × 32 = 64 个样本(策略自动做 global batch 分片)。
这点非常关键:如果你原来单卡跑 batch_size=64 收敛正常,换双卡后还写 batch_size=64,相当于总 batch size 减半,学习率可能跟不上,训练会抖甚至不收敛。
- 推荐做法:按 GPU 数线性缩放
batch_size,同时按相同比例调高学习率(例如 LARS 或 warmup) - 验证是否真用了多卡:运行时看 nvidia-smi,所有目标 GPU 的显存和计算利用率都应该明显上升
- 如果
model.fit()没提速甚至变慢,先检查数据加载瓶颈——dataset.prefetch(tf.data.AUTOTUNE)和.cache()(适合能放进内存的数据)必须加上
自定义训练循环下怎么同步梯度和更新参数?
用 strategy.run() + strategy.reduce(),不能直接对 loss 取均值或用 Python 做 sum。
典型错误是写 loss = np.mean(loss_per_replica) ——这会把分布式的 tensor 转成 numpy,破坏图执行,还会丢掉梯度。
- 损失聚合必须用
strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_loss, axis=None),然后除以strategy.num_replicas_in_sync - 梯度计算要在
@tf.function内、且在strategy.run()中完成;optimizer.apply_gradients()也得在strategy.run()里 - 示例关键片段:
@tf.function def distributed_train_step(dataset_inputs): per_replica_losses = strategy.run(train_step, args=(dataset_inputs,)) return strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses, axis=None)
为什么用了 MirroredStrategy 却只有一张卡在跑?
最常见的三个原因:环境变量没清、TensorFlow 检测失败、Keras backend 混用。
- 启动前确认:
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))输出必须 ≥2;如果只显示 1 个,检查nvidia-smi是否真识别到多卡,以及是否被其他进程占满显存 - 避免混用:不要在
strategy.scope()外创建模型,也不要调用tf.keras.backend.set_session()(TF 2.x 已废弃) - 某些容器或 notebook 环境会缓存旧的 device list,重启 Python 进程比 reload 更可靠
多卡训练的隐性成本常被低估:all-reduce 通信开销、CPU-GPU 数据搬运、跨卡 batch norm 统计不准(tf.keras.layers.BatchNormalization(synchronized=True) 在 TF 2.9+ 才真正支持同步)。这些细节不处理,加卡反而拖慢训练。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











