MirroredStrategy 是单机多卡默认起点,因它自动复制模型与优化器、支持 eager mode 且通过 NCCL 同步梯度;需确保 CUDA_VISIBLE_DEVICES 设置正确、所有变量在 strategy.scope() 内创建,并使用全局 batch size 配合 tf.data 优化流水线。

tf.distribute.MirroredStrategy 为什么是多卡训练的默认起点
单机多卡场景下,MirroredStrategy 是最直接可用的策略,它在每张 GPU 上复制模型和优化器状态,并通过 NCCL(Linux)或 NVIDIA Collective Communications Library)同步梯度。不是所有策略都支持 eager mode,但 MirroredStrategy 支持,这对调试友好。
常见错误现象:ValueError: Device /job:localhost/replica:0/task:0/device:GPU:0 is not visible —— 本质是 CUDA_VISIBLE_DEVICES 没设对,或 nvidia-smi 看不到对应卡;FailedPreconditionError: Error while reading resource variable ... —— 多数因变量在 strategy.scope 外创建。
- 必须把模型构建、编译、数据集创建全放在
strategy.scope()内 - 使用
tf.data.Dataset时,batch()要传入全局 batch size(例如 256),策略会自动按卡均分(4 卡即每卡 64) - 避免在
strategy.scope()外调用model.predict()或model.evaluate(),它们不支持跨设备张量 - Windows 下 NCCL 不可用,此时需改用
MultiWorkerMirroredStrategy+ gRPC 后端,或干脆换TPUStrategy(不现实)—— 实际建议 Linux 部署
如何正确封装 model.fit() 以适配分布式输入
model.fit() 在 MirroredStrategy 下能自动处理数据分发,但前提是数据管道符合要求。它不会帮你做数据预取优化,也不会自动处理样本不均等导致的 step 数偏差。
使用场景:你已有 tf.data.Dataset.from_tensor_slices() 构建的数据集,但训练卡在第一个 epoch 不动,或 loss 不下降。
立即学习“Python免费学习笔记(深入)”;
- 务必调用
.cache().shuffle().batch(GLOBAL_BATCH_SIZE).prefetch(tf.data.AUTOTUNE),否则 I/O 成瓶颈 - 如果用
numpy数组喂数据,fit(x, y)仍可工作,但会隐式转成tf.data.Dataset,失去控制权;推荐显式构造 dataset -
steps_per_epoch应基于全局 batch size 计算(如 10000 样本 / 256 = 39),不要按单卡算 - 回调函数(如
ModelCheckpoint)中save_weights_only=True更安全;若保存完整模型,确保路径在所有 worker 可见(单机无问题)
自定义训练循环中 get_replica_context 和 all_reduce 的实际用途
当 model.fit() 不够用(比如要插自定义梯度裁剪、混合精度更新逻辑),就得写 @tf.function + strategy.run()。这时 tf.distribute.get_replica_context() 不是摆设,它让你在副本内做局部计算,再聚合。
性能影响:手动 all-reduce 比 MirroredStrategy 默认梯度同步更灵活,但也更容易出错。例如误用 tf.distribute.ReduceOp.SUM 而非 MEAN,会导致学习率等效放大 N 倍(N=卡数)。
- 在
strategy.run()内部,用ctx.all_reduce('mean', grad)才等价于默认行为;用'sum'就得把学习率除以卡数 - 不要在
strategy.run()外访问grad张量——它是 PerReplica 类型,直接 print 会报Cannot iterate over a PerReplica - 混合精度训练(
tf.keras.mixed_precision.Policy('mixed_float16'))必须配合tf.keras.mixed_precision.LossScaleOptimizer,且 loss scale 更新逻辑需在strategy.run()内完成
验证多卡是否真正在协同工作而不是“假装分布式”
最常被忽略的一点:没报错 ≠ 多卡生效。TensorFlow 可能静默退化为单卡运行(比如 strategy scope 漏了、dataset 没 batch、甚至 CUDA 驱动版本太旧)。
容易踩的坑:nvidia-smi 显示显存占用高但 GPU-Util 始终 INFO:tensorflow:Using MirroredStrategy with devices 但训练速度和单卡一致。
- 启动时加环境变量
export TF_CPP_MIN_LOG_LEVEL=1,确认日志出现INFO:tensorflow:Initializing collective group - 在训练前插入
print("Devices:", strategy.extended.worker_devices),应输出类似['/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'] - 用
tf.profiler抓 trace,看ncclAllReduce是否频繁出现;没有就说明梯度根本没同步 - 临时把 learning_rate 设为 100,单卡会爆炸性 loss 上升,多卡若上升幅度只有单卡的 1/N,说明同步生效了


















