MirroredStrategy需在构建模型前初始化并用scope包裹模型、编译及变量定义,数据集须用experimental_distribute_dataset分发,batch_size按GPU总数设置,手动训练循环需用strategy.run和reduce协调多卡计算。

直接用 tf.distribute.MirroredStrategy 就能跑通多 GPU 训练,但必须在构建模型前就初始化策略,否则会报 ValueError: Cannot replicate a tensor that is not on the CPU 这类错误。
为什么 MirroredStrategy 是最常用的选择
它适用于单机多卡(比如一台机器插了 2–8 块 NVIDIA GPU),所有设备同步更新权重,训练逻辑和单卡几乎一致,适配成本最低。
- 策略对象必须在
tf.keras.Model实例化之前创建,且不能晚于任何张量或变量的定义 - 默认使用 NCCL 通信后端(Linux + CUDA 环境下),比
RPC或gRPC更快;Windows 下自动 fallback 到CollectiveOps,性能略低 - 不支持混合精度训练自动启用,需显式加
tf.keras.mixed_precision.Policy并传给model.compile()
模型构建和编译必须放在 strategy.scope() 内
这是最容易漏掉的关键步骤——所有可训练变量(包括 tf.keras.layers、optimizer、loss)都得在策略作用域里声明,否则变量不会被复制到各 GPU 上。
# ✅ 正确写法
strategy = tf.distribute.MirroredStrategy()
print('Number of devices: {}'.format(strategy.num_replicas_in_sync))
<p>with strategy.scope():
model = tf.keras.Sequential([...])
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)</p><h1>❌ 错误:model 在 scope 外定义 → 变量只在 CPU 创建,GPU 上无副本</h1><p>model = tf.keras.Sequential([...])
with strategy.scope():
model.compile(...) # 这里 compile 不会把已有变量分发出去
</p>
数据输入必须用 tf.data.Dataset 且调用 strategy.experimental_distribute_dataset()
虽然 model.fit() 能自动处理大部分情况,但如果你手动写训练循环(tf.function + strategy.run()),就必须显式分发数据集,否则每个 GPU 拿到的是全量数据而非切片。
-
batch_size应设为每卡 batch 大小 × GPU 数量(例如 4 卡、每卡 32,则总 batch_size=128) -
dataset.batch()必须在distribute_dataset()之前完成,否则会触发InvalidArgumentError: Input to reshape is a tensor with 0 elements - 避免在
map()中使用非 tf ops(如cv2.imread),会导致数据加载瓶颈集中在 CPU
验证时别忘了用 strategy.run() 包裹评估逻辑
如果写自定义训练循环,验证阶段同样需要分散执行,否则 strategy.reduce() 拿不到各 GPU 的局部结果,会返回 None 或形状错乱的张量。
# 示例:手动验证 step
@tf.function
def val_step(inputs, labels):
predictions = model(inputs, training=False)
per_example_loss = loss_fn(labels, predictions)
return per_example_loss, predictions
<p>def distributed_val_step(dataset_inputs):
per_replica_losses, per_replica_preds = strategy.run(
val_step, args=(dataset_inputs[0], dataset_inputs[1])
)</p><h1>合并各卡 loss(取平均)</h1><pre class="brush:php;toolbar:false;">mean_loss = strategy.reduce(tf.distribute.ReduceOp.MEAN, per_replica_losses, axis=None)
return mean_loss
真正麻烦的不是策略本身,而是变量生命周期和数据分发时机——一旦模型或数据流提前脱离 strategy.scope() 或没走 experimental_distribute_dataset,错误信息往往不指向根本原因,而是报一些看似无关的设备位置异常或 shape mismatch。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











