news 2026/9/24 14:36:05

30天吃掉TensorFlow2:用MirroredStrategy两行代码实现多GPU训练Keras模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
30天吃掉TensorFlow2:用MirroredStrategy两行代码实现多GPU训练Keras模型
  • 教程
  • 深度学习
  • 机器学习

【免费下载链接】eat_tensorflow2_in_30_days

Tensorflow2.0 🍎🍊 is delicious, just eat it! 😋😋

项目地址:https://gitcode.com/gh_mirrors/ea/eat_tensorflow2_in_30_days
点击查看免费下载

本文是《30天吃掉那只TensorFlow2》高阶API章节(六、TensorFlow的高阶API)的第 6-4 节配套实战指南,聚焦"使用多GPU训练模型"这一高频需求。当单卡显存不足、或希望成倍缩短参数迭代时间时,TensorFlow 2 提供的tf.distribute.MirroredStrategy是上手门槛最低的方案——在原有内置fit训练流程上,仅需增加两行代码即可将训练扩展到多张 GPU 上。读完本文你将掌握:MirroredStrategy 同步数据并行的完整工作原理、在 Colab 上用单张物理 GPU 模拟多逻辑 GPU 的方法、以及一套可直接复制运行的 Reuters 文本分类多卡训练完整代码。

本文全部代码基于本书 README.md 中说明的TensorFlow 2.1环境编写并在 Colab 上验证通过,配套英文版见 english/Chapter6-4.md。

一,为什么要用多GPU训练:训练耗时从哪来

深度学习的训练过程常常非常耗时,耗时主要来自两部分:数据准备参数迭代(详见 6-3,使用单GPU训练模型):

  • 当数据准备过程是主要瓶颈时,通常用更多进程来准备数据(如tf.data的并行读取与预取);
  • 当参数迭代过程成为主要瓶颈时,常规手段是使用GPU或 Google 的TPU进行加速。

多 GPU 训练正是"参数迭代"维度的进一步加速:把一个大批次的数据切分到 N 张卡上并行计算梯度,再汇总更新参数,从而以接近线性的速度提升训练吞吐。

在 TensorFlow 2 中,如果只是单 GPU 训练,通常无需修改任何代码——存在可用 GPU 时 TensorFlow 会自动优先使用 GPU 创建张量和执行计算(多使用者共享服务器时可通过tf.config.experimental.set_memory_growthset_visible_devices控制显存与设备编号,详见 6-3,使用单GPU训练模型)。而多 GPU 训练则需要显式引入分布式策略。

二,MirroredStrategy 过程简介:同步数据并行的六个步骤

tf.distribute.MirroredStrategy(镜像策略)是 TensorFlow 2 内置的、最易用的单机多卡分布式训练策略。所谓"镜像",是指在每个计算设备上都保存一份完整的模型副本(镜像变量),训练时按"数据并行"方式协同工作。其完整过程如下:

  1. 复制模型:训练开始前,该策略在所有 N 个计算设备上均各复制一份完整的模型;
  2. 切分批次:每次训练传入一个批次的数据时,将数据分成 N 份,分别传入 N 个计算设备(即数据并行);
  3. 本地计算梯度:N 个计算设备使用本地变量(镜像变量)分别计算自己所获得的那部分数据的梯度;
  4. All-reduce 梯度汇总:使用分布式计算的 All-reduce 操作,在计算设备间高效交换梯度数据并进行求和,使得最终每个设备都拥有了所有设备的梯度之和;
  5. 更新镜像变量:使用梯度求和的结果更新本地变量(镜像变量);
  6. 同步进入下一轮:当所有设备均更新完本地变量后,才进行下一轮训练——即该并行策略是同步的。

可以这样理解:N 张卡"各算各的梯度、再互相通报求和",每张卡最终拿到的都是全局一致的梯度,因此各设备上的模型参数始终保持一致,训练结果与单卡在数学上等价(仅批大小被放大 N 倍),这也是它被称为"镜像"的原因。

从源码实现角度看,策略的复制、切分、梯度聚合分别由tf.distribute.Strategy的模型副本机制、数据集experimental_distribute_dataset切分与跨设备梯度规约(All-reduce)机制共同支撑,MirroredStrategy默认使用 NVIDIA NCCL 作为 All-reduce 通信后端,吞吐性能出色;当 NCCL 不可用时会自动回退到"归约到单一设备再广播"的方式(下面实战日志中可见到这一回退提示)。

三,环境准备:Colab 开启 GPU 与逻辑GPU模拟

本书多 GPU 范例设计为在Colab 笔记本上运行(原文档明确说明"以下代码只能在 Colab 上才能正确执行")。开启方式:在 Colab 笔记本中,通过修改 -> 笔记本设置 -> 硬件加速器中选择 GPU。

Colab 免费版通常只提供一张 GPU。为了演示多 GPU 训练流程,范例利用 TensorFlow 的虚拟设备(Virtual Device)机制,把 1 张物理 GPU 切分成两个各 1024MB 显存的逻辑 GPU,从而在一台机器上模拟出双卡环境:

%tensorflow_version 2.x import tensorflow as tf print(tf.__version__) from tensorflow.keras import *
# 此处在colab上使用1个GPU模拟出两个逻辑GPU进行多GPU训练 gpus = tf.config.experimental.list_physical_devices('GPU') if gpus: # 设置两个逻辑GPU模拟多GPU训练 try: tf.config.experimental.set_virtual_device_configuration(gpus[0], [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024), tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)]) logical_gpus = tf.config.experimental.list_logical_devices('GPU') print(len(gpus), "Physical GPU,", len(logical_gpus), "Logical GPUs") except RuntimeError as e: print(e)

关键 API 说明:

  • tf.config.experimental.list_physical_devices('GPU'):列出所有物理 GPU 设备;
  • tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024):声明一个显存上限为 1024MB 的逻辑设备配置,传入列表即为每个逻辑设备分配独立显存;
  • tf.config.experimental.set_virtual_device_configuration(gpus[0], [...]):将第一张物理 GPU 按配置切分成多个虚拟设备;
  • tf.config.experimental.list_logical_devices('GPU'):列出切分后的逻辑 GPU 数量,正常情况下输出1 Physical GPU, 2 Logical GPUs
  • 若虚拟设备已被创建(如重复运行单元格),会抛出RuntimeError,代码中用try/except捕获并打印提示。

如果你在本地服务器上确实拥有多张物理 GPU,则无需这段模拟代码,MirroredStrategy()会自动探测并使用全部可见 GPU;多使用者共享时,可先参考 6-3,使用单GPU训练模型 中的set_visible_devices指定参与训练的卡。

四,完整实战:Reuters 文本分类多GPU训练

整个实战沿用本书统一的"数据准备 -> 定义模型 -> 训练模型"三段式流程(与 6-2,训练模型的3种方法、6-3,使用单GPU训练模型 使用同一套 Reuters 新闻文本分类任务,便于横向对比单卡/多卡/TPU 的训练效果)。

1,准备数据

MAX_LEN = 300 BATCH_SIZE = 32 (x_train,y_train),(x_test,y_test) = datasets.reuters.load_data() x_train = preprocessing.sequence.pad_sequences(x_train,maxlen=MAX_LEN) x_test = preprocessing.sequence.pad_sequences(x_test,maxlen=MAX_LEN) MAX_WORDS = x_train.max()+1 CAT_NUM = y_train.max()+1 ds_train = tf.data.Dataset.from_tensor_slices((x_train,y_train)) \ .shuffle(buffer_size = 1000).batch(BATCH_SIZE) \ .prefetch(tf.data.experimental.AUTOTUNE).cache() ds_test = tf.data.Dataset.from_tensor_slices((x_test,y_test)) \ .shuffle(buffer_size = 1000).batch(BATCH_SIZE) \ .prefetch(tf.data.experimental.AUTOTUNE).cache()

要点说明:

  • datasets.reuters.load_data()加载路透社新闻文本数据集,每条样本为已编码的词索引序列;
  • preprocessing.sequence.pad_sequences(..., maxlen=MAX_LEN)将序列统一填充/截断到 300 长度;
  • MAX_WORDS = x_train.max()+1为词汇表大小,CAT_NUM = y_train.max()+1为分类类别数(46 类);
  • 数据管道按shuffle -> batch -> prefetch -> cache顺序构建:buffer_size=1000打乱、BATCH_SIZE=32分批、prefetch(tf.data.experimental.AUTOTUNE)让数据加载与计算流水线重叠、cache()将数据集缓存到内存以加速后续 epoch;
  • 注意:多 GPU 训练时每个设备的实际批大小为BATCH_SIZE / N(N 为设备数),这是与单卡唯一在数据流上的差异,策略内部会自动完成切分,无需手写。

2,定义模型

tf.keras.backend.clear_session() def create_model(): model = models.Sequential() model.add(layers.Embedding(MAX_WORDS,7,input_length=MAX_LEN)) model.add(layers.Conv1D(filters = 64,kernel_size = 5,activation = "relu")) model.add(layers.MaxPool1D(2)) model.add(layers.Conv1D(filters = 32,kernel_size = 3,activation = "relu")) model.add(layers.MaxPool1D(2)) model.add(layers.Flatten()) model.add(layers.Dense(CAT_NUM,activation = "softmax")) return(model) def compile_model(model): model.compile(optimizer=optimizers.Nadam(), loss=losses.SparseCategoricalCrossentropy(from_logits=True), metrics=[metrics.SparseCategoricalAccuracy(),metrics.SparseTopKCategoricalAccuracy(5)]) return(model)

要点说明:

  • 模型为经典的"词嵌入 + 一维卷积 + 全连接"文本分类结构:Embedding(MAX_WORDS, 7, input_length=MAX_LEN)把 300 长度的词序列映射为 7 维向量,随后两层Conv1D+MaxPool1D提取局部 n-gram 特征,Flatten后接 46 类的Dense + softmax输出;
  • compile阶段使用optimizers.Nadam()优化器、losses.SparseCategoricalCrossentropy(from_logits=True)稀疏交叉熵损失,以及SparseCategoricalAccuracySparseTopKCategoricalAccuracy(5)两个评估指标;
  • create_modelcompile_model被封装成独立函数,是为了方便在strategy.scope()作用域内统一创建与编译。

3,训练模型:关键的两行代码

# 增加以下两行代码 strategy = tf.distribute.MirroredStrategy() with strategy.scope(): model = create_model() model.summary() model = compile_model(model) history = model.fit(ds_train,validation_data = ds_test,epochs = 10)

这就是原文档所说的"推荐使用内置 fit 方法,较为方便,仅需添加 2 行代码":

  1. strategy = tf.distribute.MirroredStrategy():创建镜像策略对象,此时策略会探测当前机器上的全部可见 GPU(示例环境中即上一步切分出的两个逻辑 GPU);
  2. with strategy.scope()::将模型的创建与编译放入策略作用域。这是使用任何tf.distribute策略时的硬性要求——只有在 scope 内创建的变量才会被自动转化为"镜像变量"(每个设备一份副本并保持同步),模型定义在 scope 之外将无法被策略托管。

之后直接调用model.fit(ds_train, validation_data=ds_test, epochs=10)即可,内置 fit 方法会在内部自动完成"批次切分到各设备 -> 各设备前向反向 -> 梯度 All-reduce 聚合 -> 同步更新镜像变量"的全流程,训练逻辑本身不需要任何改动。这也是"多 GPU 训练推荐使用内置 fit 方法"的原因:fit对分布式策略做了完整封装,而自定义训练循环若要支持多卡,则需要自行处理数据切分与梯度聚合,复杂度明显更高。

五,训练过程日志解读

启动训练后,终端会输出策略初始化与训练进度信息,其中包含几个值得关注的信号:

WARNING:tensorflow:NCCL is not supported when using virtual GPUs, fallingback to reduction to one device INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')
  • 第一条 WARNING 说明:在虚拟 GPU上 NCCL 通信后端不可用,因此回退为"归约到单一设备再广播"的梯度聚合方式——这是本例为演示多卡而使用虚拟设备导致的正常现象;在真实多张物理 GPU 上会默认使用 NCCL,性能更高;
  • 第二条 INFO 显示策略成功接管了两台设备:GPU:0GPU:1,即上一步创建的两个逻辑 GPU;
  • 训练过程中大量Reduce to ... then broadcast to ...的 INFO 日志,正是第二节所述"梯度 All-reduce 汇总后广播"的底层执行记录(观察可见,梯度先在 GPU:0 上完成归约,再广播回两个 GPU,另有一部分变量归约发生在 CPU 上);
  • 模型结构日志(Model: "sequential")显示该模型共332,856 个可训练参数,其中 Embedding 层占 216,874 个参数;
  • Train for 281 steps, validate for 71 steps:训练集按 32 的批大小共 281 步、验证集 71 步。

完整训练输出(10 个 epoch)如下:

WARNING:tensorflow:NCCL is not supported when using virtual GPUs, fallingback to reduction to one device INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1') Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 300, 7) 216874 _________________________________________________________________ conv1d (Conv1D) (None, 296, 64) 2304 _________________________________________________________________ max_pooling1d (MaxPooling1D) (None, 148, 64) 0 _________________________________________________________________ conv1d_1 (Conv1D) (None, 146, 32) 6176 _________________________________________________________________ max_pooling1d_1 (MaxPooling1 (None, 73, 32) 0 _________________________________________________________________ flatten (Flatten) (None, 2336) 0 _________________________________________________________________ dense (Dense) (None, 46) 107502 ================================================================= Total params: 332,856 Trainable params: 332,856 Non-trainable params: 0 _________________________________________________________________ INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). Train for 281 steps, validate for 71 steps Epoch 1/10 INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:GPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1'). 281/281 [==============================] - 15s 53ms/step - loss: 2.0270 - sparse_categorical_accuracy: 0.4653 - sparse_top_k_categorical_accuracy: 0.7481 - val_loss: 1.7517 - val_sparse_categorical_accuracy: 0.5481 - val_sparse_top_k_categorical_accuracy: 0.7578 Epoch 2/10 281/281 [==============================] - 4s 14ms/step - loss: 1.5206 - sparse_categorical_accuracy: 0.6045 - sparse_top_k_categorical_accuracy: 0.7938 - val_loss: 1.5715 - val_sparse_categorical_accuracy: 0.5993 - val_sparse_top_k_categorical_accuracy: 0.7983 Epoch 3/10 281/281 [==============================] - 4s 14ms/step - loss: 1.2178 - sparse_categorical_accuracy: 0.6843 - sparse_top_k_categorical_accuracy: 0.8547 - val_loss: 1.5232 - val_sparse_categorical_accuracy: 0.6327 - val_sparse_top_k_categorical_accuracy: 0.8112 Epoch 4/10 281/281 [==============================] - 4s 13ms/step - loss: 0.9127 - sparse_categorical_accuracy: 0.7648 - sparse_top_k_categorical_accuracy: 0.9113 - val_loss: 1.6527 - val_sparse_categorical_accuracy: 0.6296 - val_sparse_top_k_categorical_accuracy: 0.8201 Epoch 5/10 281/281 [==============================] - 4s 14ms/step - loss: 0.6606 - sparse_categorical_accuracy: 0.8321 - sparse_top_k_categorical_accuracy: 0.9525 - val_loss: 1.8791 - val_sparse_categorical_accuracy: 0.6158 - val_sparse_top_k_categorical_accuracy: 0.8219 Epoch 6/10 281/281 [==============================] - 4s 14ms/step - loss: 0.4919 - sparse_categorical_accuracy: 0.8799 - sparse_top_k_categorical_accuracy: 0.9725 - val_loss: 2.1282 - val_sparse_categorical_accuracy: 0.6037 - val_sparse_top_k_categorical_accuracy: 0.8112 Epoch 7/10 281/281 [==============================] - 4s 14ms/step - loss: 0.3947 - sparse_categorical_accuracy: 0.9051 - sparse_top_k_categorical_accuracy: 0.9814 - val_loss: 2.3033 - val_sparse_categorical_accuracy: 0.6046 - val_sparse_top_k_categorical_accuracy: 0.8094 Epoch 8/10 281/281 [==============================] - 4s 14ms/step - loss: 0.3335 - sparse_categorical_accuracy: 0.9207 - sparse_top_k_categorical_accuracy: 0.9863 - val_loss: 2.4255 - val_sparse_categorical_accuracy: 0.5993 - val_sparse_top_k_categorical_accuracy: 0.8099 Epoch 9/10 281/281 [==============================] - 4s 14ms/step - loss: 0.2919 - sparse_categorical_accuracy: 0.9304 - sparse_top_k_categorical_accuracy: 0.9911 - val_loss: 2.5571 - val_sparse_categorical_accuracy: 0.6020 - val_sparse_top_k_categorical_accuracy: 0.8126 Epoch 10/10 281/281 [==============================] - 4s 14ms/step - loss: 0.2617 - sparse_categorical_accuracy: 0.9342 - sparse_top_k_categorical_accuracy: 0.9937 - val_loss: 2.6700 - val_sparse_categorical_accuracy: 0.6077 - val_sparse_top_k_categorical_accuracy: 0.8148 CPU times: user 1min 2s, sys: 8.59 s, total: 1min 10s Wall time: 58.5 s

从日志中可以观察到几个规律:

  • 第 1 个 epoch 明显更慢(15s/步级 53ms),这是因为其中包含模型图构建、设备复制与首次 All-reduce 初始化等一次性开销;从第 2 个 epoch 起稳定在4s 左右(13~14ms/step)
  • 训练指标随 epoch 稳步上升:sparse_categorical_accuracy从 0.4653 提升到 0.9342,sparse_top_k_categorical_accuracy最终达到 0.9937;
  • 验证集指标(val_*)在第 1~3 epoch 上升后开始小幅波动,呈现出典型的过拟合趋势(训练 loss 持续下降至 0.2617,验证 loss 则从 1.75 逐步升高到 2.67),10 个 epoch 对这个小模型而言略多,实际使用时可通过回调早停(见 5-8,回调函数callbacks.md)控制。

六,与单GPU、TPU训练方案的横向衔接

多 GPU 训练只是"加速训练"选项之一,本书在第 6 章提供了完整的三级加速方案,三者的改造量都极小,且共用同一套数据与模型代码:

方案关键改造新增代码量适用场景对应章节
单 GPU通常无需改代码,自动使用 GPU;服务器共享场景可设置显存按需增长与可见设备0~4 行单卡即可满足显存与算力需求6-3,使用单GPU训练模型.md
多 GPUMirroredStrategy()+with strategy.scope()包裹模型创建与编译2 行单机多卡,需要更大吞吐或更大有效批大小本文
TPUTPUClusterResolver连接集群、TPUStrategy包裹模型,共 6 行6 行Colab TPU(8 核)等云端加速6-5,使用TPU训练模型.md

其中 TPU 方案(6-5,使用TPU训练模型.md)的 6 行代码为:通过tf.distribute.cluster_resolver.TPUClusterResolver(tpu='grpc://' + os.environ['COLAB_TPU_ADDR'])解析 TPU 集群地址、tf.config.experimental_connect_to_cluster(resolver)连接集群、tf.tpu.experimental.initialize_tpu_system(resolver)初始化 TPU 系统,再以tf.distribute.experimental.TPUStrategy(resolver)包裹模型创建与编译——与本文的 MirroredStrategy 用法完全同构,理解了本文的 scope 机制即可无缝迁移。

七,注意事项与适用边界

  • 代码运行环境:本文范例依赖 Colab 的 GPU 环境,原文档明确标注"以下代码只能在 Colab 上才能正确执行";本地环境需要自行安装 GPU 版 TensorFlow 与 CUDA,并确保存在 ≥2 张可见 GPU(或按第三节方式切分虚拟设备);
  • 虚拟 GPU 的通信限制:在虚拟 GPU 上 NCCL 不可用,会自动回退为"归约到单一设备再广播",日志中的 WARNING 属正常现象,不代表出错;真实多卡环境下默认走 NCCL,通信效率更高;
  • scope 是硬性要求:模型(以及优化器等带变量对象)必须在strategy.scope()内创建与编译,否则变量不会被镜像化,策略无法生效——这是多 GPU 训练最容易踩的坑;
  • 同步策略的语义:MirroredStrategy 是同步数据并行,每轮迭代需要等待所有设备完成梯度聚合后才更新参数,因此各设备算力应尽量均衡(建议使用同型号 GPU),否则整体速度会被最慢的设备拖累;
  • 有效批大小变化:N 卡训练时全局有效批大小相当于原来的 N 倍(每设备 BATCH_SIZE/N),在大数据集上通常需要相应调大学习率,这一点与单卡训练的超参数调优经验不同;
  • 版本适用前提:本书全部代码在 TensorFlow 2.1 上测试通过(见 README.md),tf.distribute的相关 API(如experimental前缀接口)在新版本中可能被调整或迁移到稳定命名空间,升级大版本后建议先核对 API 兼容性。

至此,你已经掌握了"两行代码开启多 GPU 训练"的完整方法论:理解 MirroredStrategy 的同步镜像机制、会用虚拟设备在单卡上模拟多卡、并能在不修改模型与 fit 训练逻辑的前提下完成多卡训练。将这套模式与本书第 6 章其余方案(6-2,训练模型的3种方法.md、6-3,使用单GPU训练模型.md、6-5,使用TPU训练模型.md)组合使用,即可根据手头硬件灵活选择加速方案。

  • 教程
  • 深度学习
  • 机器学习

【免费下载链接】eat_tensorflow2_in_30_days

Tensorflow2.0 🍎🍊 is delicious, just eat it! 😋😋

项目地址:https://gitcode.com/gh_mirrors/ea/eat_tensorflow2_in_30_days
点击查看免费下载

相关推荐

上一篇:基于 VuePress 1.x 模板的文档站搭建:默认主题首页布局(Home Layout)配置实战
下一篇:Apache Doris Remote UDF Java 实现指南:基于 gRPC 的 RPC 函数服务开发实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 14:35:55

单片机毕设选题推荐:基于 STM32 或 51 单片机多模式智能窗帘监测与控制系统设计 基于 STM32 或 51 单片机 OLED 显示环境监测智能窗帘装置设计(025608)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/9/24 14:31:33

大麦抢票脚本从环境到出票的完整上手路径

大麦抢票脚本从环境到出票的完整上手路径 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase ticket-purchase 是一个开源的大麦抢票自动化项目&#xf…

作者头像 李华