深度学习模型并行与TensorFlow分布式训练策略详解
在深度学习领域,深度神经网络如Darknet等往往需要计算数十亿的参数。即使在小批量的情况下,将整个网络加载到单个CPU或GPU的内存中也是一项挑战。为了解决这个问题,模型并行应运而生。
1. 模型并行(Model Parallelism)
模型并行是一种将模型拆分成不同部分的方法,每个部分在不同的CPU、GPU或物理计算机硬件节点上对同一组数据进行操作。相同的数据批次会被复制到集群中的所有节点,但每个节点会获取模型的不同部分。这些模型部分会在不同节点上同时对输入数据集进行操作。
当模型的各个部分并行运行时,它们的共享参数需要进行同步。这种并行方法在同一台机器上有多个CPU或GPU的情况下效果最佳,因为这些设备通过高速总线连接。
2. TensorFlow分布式策略(TensorFlow Distribution Strategy)
TensorFlow提供了一个高级API,用于在多个GPU或多个节点上进行分布式训练。这个API通过
tf.distribute.Strategy
类暴露。只需添加几行代码并进行少量修改,就可以将之前示例中的神经网络进行分布式训练。
可以将
tf.distribute.Strategy
与Keras结合使用,以分布式方式训练使用Keras API构建的网络,也可以用于分布式自定义训练循环。一般来说,TensorFlow中的任何计算都可以使用这个API进行分布式处理。
TensorFlow支持以下几种类型的分布式策略:
2.1 镜像策略(MirroredStrategy)
镜像策略支持在一台机器上的多个GPU上进行同步分布式训练。模型的所有变量会在所有GPU上进行镜像,这些变量统称为
MirroredVariables
。训练计算会在每个GPU上并行进行,通过应用相同的更新来同步变量。
MirroredVariables
通过全归约算法(all-reduce algorithms)在所有设备上进行更新。全归约算法通过将所有设备上的张量相加来聚合它们,并使它们在每个设备上可用。TensorFlow在
MirroredStrategy
中默认使用NVIDIA NCCL作为全归约算法。
以下是使用
MirroredStrategy
对深度学习网络进行分布式训练的步骤:
1. 创建
MirroredStrategy
的实例。
2. 将模型的创建和编译(如示例代码中的第11行和第19行)移动到
MirroredStrategy
对象的
scope()
方法内部。
3. 调用
model.fit()
方法(如示例代码中的第24行),无需更改。
示例代码如下:
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
model = tf.keras.Sequential([...])
model.compile(...)
model.fit(...)
每个输入批次会在各个副本之间平均分配。例如,如果输入批次大小为16,使用
MirroredStrategy
和两个GPU,每个GPU在每一步将获得8个输入示例。应适当调整批次大小,以有效利用GPU的计算能力。
如果只想使用机器上的部分GPU,可以这样做:
strategy = tf.distribute.MirroredStrategy(devices=["/gpu:0", "/gpu:1"])
2.2 中央存储策略(CentralStorageStrategy)
中央存储策略将模型变量放置在CPU上,并在一台机器上的所有本地GPU上复制计算。除了将变量放置在CPU上而不是在GPU上复制之外,中央存储策略与镜像策略类似。
在编写本文时,中央存储策略是实验性的,未来可能会发生变化。要使用中央存储策略进行分布式训练,只需将上述示例代码中的第1行替换为:
strategy = tf.distribute.experimental.CentralStorageStrategy()
2.3 多工作节点镜像策略(MultiWorkerMirroredStrategy)
多工作节点镜像策略与镜像策略类似,它可以在多个机器上进行分布式训练,每台机器可以有一个或多个GPU。它会将模型中的所有变量复制到所有机器的每个设备上,进行计算的机器被称为工作节点(workers)。
为了在所有工作节点之间同步变量,它使用
CollectiveOps
作为全归约通信方法。
CollectiveOps
是TensorFlow图中的单个操作,它可以根据硬件、网络拓扑和张量大小在TensorFlow运行时自动选择全归约算法。
要使用多工作节点镜像策略进行分布式训练,只需将上述示例代码中的第1行替换为:
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()
可以选择以下两种
CollectiveOps
的实现方式:
-
CollectiveCommunication.RING
:使用gRPC作为通信层实现基于环的集合操作。gRPC是Google开发的远程过程调用的开源实现。使用示例如下:
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy(
tf.distribute.experimental.CollectiveCommunication.RING)
-
CollectiveCommunication.NCCL:使用NVIDIA NCCL实现集合操作。使用示例如下:
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy(
tf.distribute.experimental.CollectiveCommunication.NCCL)
在使用
MultiWorkerMirroredStrategy
进行分布式训练之前,必须在所有参与模型训练的工作节点上设置
TF_CONFIG
环境变量。
2.4 TPU策略(TPUStrategy)
张量处理单元(TPUs)是Google设计的专用应用特定集成电路(ASIC),用于显著加速机器学习工作负载。TPUs可以在Cloud TPU和Google Colab上使用。
在实现上,TPU策略与镜像策略相同,只是模型变量会被镜像到TPU上。以下是实例化TPU策略的代码:
cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(
tpu=tpu_address)
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
tpu_strategy = tf.distribute.experimental.TPUStrategy(cluster_resolver)
2.5 参数服务器策略(ParameterServerStrategy)
在参数服务器策略中,模型变量被放置在一个专用机器上,称为参数服务器。在这种情况下,一些机器被指定为工作节点,一些被指定为参数服务器。计算会在所有工作节点的所有GPU上进行复制,而变量会在参数服务器上进行更新。
参数服务器策略的实现与多工作节点镜像策略相同,必须在每个参与的机器上设置
TF_CONFIG
环境变量。要使用参数服务器策略进行分布式训练,只需将上述示例代码中的第1行替换为:
strategy = tf.distribute.experimental.ParameterServerStrategy()
2.6 单设备策略(OneDeviceStrategy)
有时,在将分布式代码迁移到涉及多个设备的完全分布式系统之前,需要在单个设备(GPU)上进行测试。单设备策略就是为此目的而设计的。使用此策略时,模型变量会被放置在指定的设备上。
使用代码如下:
strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")
需要注意的是,除了镜像策略之外,上述所有用于分布式训练的策略目前都是实验性的。
3. TF_CONFIG:TensorFlow集群配置
用于分布式训练的TensorFlow集群由一个或多个机器(称为工作节点)组成。模型训练的计算在每个工作节点上进行。有一个特殊的工作节点,称为主节点或首席工作节点,除了作为普通工作节点外,还承担额外的职责,包括保存检查点和为TensorBoard写入摘要文件。
TensorFlow集群还可能包括专用的参数服务器机器,在参数服务器策略中,参数服务器是必需的。
TensorFlow集群配置由
TF_CONFIG
环境变量指定,必须在集群中的所有机器上设置该环境变量。
TF_CONFIG
的格式是一个JSON文件,由两个部分组成:
cluster
和
task
。
| 键 | 描述 | 示例 |
|---|---|---|
| cluster |
包含
worker
、
chief
和
ps
键的字典,每个键是参与训练的所有机器的主机名和通信端口列表
|
cluster: { "worker":["host1:12345", "host2:2345"] }
|
| task |
指定特定机器将执行的任务,包含
type
(指定工作节点类型,取值为
worker
、
chief
或
ps
)、
index
(任务的从零开始的索引)和
trial
(用于超参数调优时设置训练试验次数)
|
task: { "type": "chief", "index":0 }
|
| job | 启动作业时使用的作业参数,可选,在大多数情况下可以忽略 |
以下是一个
TF_CONFIG
的示例:
假设有一个由三台机器组成的集群用于分布式训练,机器的主机名分别为
host1.local
、
host2.local
和
host3.local
,它们都通过端口8900进行通信。各机器的角色如下:
- 工作节点:
host1.local
(首席工作节点)
- 工作节点:
host2.local
(普通工作节点)
- 参数服务器:
host3.local
需要在所有三台机器上设置的
TF_CONFIG
环境变量如下:
| 角色 | TF_CONFIG |
|---|---|
| 首席工作节点 |
{ "cluster": { "worker": ["host1.local:8900", "host2.local:8900"], "ps": ["host3.local:8900"] }, "task": { "type": "worker", "index": 0 } }
|
| 普通工作节点 |
{ "cluster": { "worker": ["host1.local:8900", "host2.local:8900"], "ps": ["host3.local:8900"] }, "task": { "type": "worker", "index": 1 } }
|
| 参数服务器 |
{ "cluster": { "worker": ["host1.local:8900", "host2.local:8900"], "ps": ["host3.local:8900"] }, "task": { "type": "ps", "index": 0 } }
|
4. 分布式训练示例代码
以下是一个使用参数服务器策略将训练分布到多个工作节点的示例代码:
File name: distributed_training_ps.py
01: import argparse
02: import tensorflow as tf
03: from tensorflow_core.python.lib.io import file_io
04:
05: #Disable eager execution
06: tf.compat.v1.disable_eager_execution()
07:
08: #Instantiate the distribution strategy -- ParameterServerStrategy.
#This needs to be in the beginning of the code.
09: strategy = tf.distribute.experimental.ParameterServerStrategy()
10:
11: #Parse the command line arguments
12: parser = argparse.ArgumentParser()
13: parser.add_argument(
14: "--input_path",
15: type=str,
16: default="",
17: help="Directory path to the input file. Could you be cloud storage"
18: )
19: parser.add_argument(
20: "--output_path",
21: type=str,
22: default="",
23: help="Directory path to the input file. Could you be cloud storage"
24: )
25: FLAGS, unparsed = parser.parse_known_args()
26:
27: # Load MNIST data using built-in datasets' download function
28: mnist = tf.keras.datasets.mnist
29: (x_train, y_train), (x_test, y_test) = mnist.load_data()
30:
31: #Normalize the pixel values by dividing each pixel by 255
32: x_train, x_test = x_train / 255.0, x_test / 255.0
33:
34: BUFFER_SIZE = len(x_train)
35: BATCH_SIZE_PER_REPLICA = 16
36: GLOBAL_BATCH_SIZE = BATCH_SIZE_PER_REPLICA * 2
37: EPOCHS = 10
38: STEPS_PER_EPOCH = int(BUFFER_SIZE/EPOCHS)
39:
40: train_dataset = tf.data.Dataset.from_tensor_slices((x_train,
y_train)).shuffle(BUFFER_SIZE).batch(GLOBAL_BATCH_SIZE)
41: test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test)).
batch(GLOBAL_BATCH_SIZE)
42:
43:
44: with strategy.scope():
45: # Build the ANN with 4-layers
46: model = tf.keras.models.Sequential([
47: tf.keras.layers.Flatten(input_shape=(28, 28)),
48: tf.keras.layers.Dense(128, activation='relu'),
49: tf.keras.layers.Dense(60, activation='relu'),
50: tf.keras.layers.Dense(10, activation='softmax')])
51:
52: # Compile the model and set optimizer,loss function and metrics
53: model.compile(optimizer='adam',
54: loss='sparse_categorical_crossentropy',
55: metrics=['accuracy'])
56:
57: #Save checkpoints to the output location--most probably on a cloud
storage, such as GCS
58: callback = tf.keras.callbacks.ModelCheckpoint(filepath=FLAGS.output_path)
59: # Finally, train or fit the model
60: history = model.fit(train_dataset, epochs=EPOCHS, steps_per_
epoch=STEPS_PER_EPOCH, callbacks=[callback])
61:
62: # Save the model to the cloud storage
63: model.save("model.h5")
64: with file_io.FileIO('model.h5', mode='r') as input_f:
65: with file_io.FileIO(FLAGS.output_path+ '/model.h5', mode='w+') as
output_f:
66: output_f.write(input_f.read())
这段代码可以分为四个逻辑部分:
1.
读取和解析命令行参数
(第11行到第25行):接受两个参数,即训练数据的输入路径和保存检查点及最终模型的输出路径。
2.
加载输入图像并创建训练和测试集
(第27行到第41行):需要注意的是,参数服务器策略不支持处理最后一个部分批次,当数据集在多个工作节点上不平衡时,需要将
steps_per_epoch
参数传递给
model.fit()
方法。
3.
在参数服务器策略的范围内创建和编译Keras模型
(第9行和第44行到第55行):
- 在程序开始时创建
ParameterServerStrategy
或
MultiWorkerMirroredStrategy
的实例,并将可能创建操作的代码放在策略实例化之后。
- 需要分布式处理的代码部分必须包装在策略的
scope()
方法内部。
- 第44行定义了
scope()
块,在其中包装了模型定义和编译。
- 第45行到第50行在策略范围内创建模型。
- 第53行到第55行在策略范围内编译模型。
4.
训练模型并保存检查点和最终模型
(第57行到第66行):
- 第58行创建模型检查点对象,并将其传递给
model.fit()
方法,以便在模型训练时保存检查点。
- 第60行调用
fit()
方法触发模型训练,传递给
fit()
方法的
train_dataset
会由分布策略(在本例中为参数服务器策略)自动进行分布式处理。
- 第63行将完整模型保存到本地目录,第64行到第66行将本地模型复制到云存储,如Google Cloud Storage(GCS)或Amazon S3。
- 注意,第57行到第66行不在策略的
scope()
方法内部。
通过以上内容,我们详细介绍了TensorFlow中的各种分布式训练策略以及如何进行集群配置和代码实现。这些策略可以帮助我们更高效地利用计算资源,加速深度学习模型的训练过程。
接下来,我们将介绍在云端运行分布式训练的具体步骤。
5. 在云端运行分布式训练的步骤
基于特定架构在云端部署TensorFlow集群并执行训练,可按以下步骤操作:
1.
创建TensorFlow集群
-
参数服务器、首席和工作节点
:AWS、GCP、Azure这三大云服务提供商均提供基于浏览器的shell和图形用户界面(UI)来创建和管理虚拟机。可根据数据规模和神经网络复杂度,选择创建基于GPU或CPU的虚拟机。
2.
在所有虚拟机上安装TensorFlow及必备库
:若运行上述示例代码,仅需安装TensorFlow。可参考相关安装指南进行操作。
3.
创建云存储目录(即存储桶)
:依据不同的云服务提供商,可创建以下存储桶:
- AWS S3存储桶
- Google Cloud Storage(GCS)存储桶
- Azure容器
4.
上传Python代码并在每台机器上执行训练
:借助云shell或其他SSH客户端登录每个节点,执行以下操作:
-
上传代码
:将包含依赖项和模型训练代码(如上述示例代码)的Python包上传至每个节点。可通过scp或其他文件传输协议上传代码。若代码存于GitHub,可在每台机器上克隆仓库来下载代码,示例代码如下:
git clone https://github.com/ansarisam/dist-tf-modeling.git
- **设置环境变量并执行代码**:需在每台机器上设置特定于机器角色的TF_CONFIG环境变量,并执行用于分布式训练的Python代码,示例代码如下:
export TF_CONFIG=$CONFIG;python distributed_training_ps.py --input_path gs://cv_training_data --output_path gs://cv_distributed_model/output
手动在每个节点上执行上述命令效率较低,尤其是在工作节点数量众多的情况下。可编写脚本自动化大型集群上的分布式训练启动过程。上述GitHub仓库中有可用于自动化的Python脚本。为深入理解其工作原理,可先按手动步骤逐台虚拟机启动训练。
综上所述,通过运用TensorFlow提供的分布式策略,结合云端资源和合理的配置,能够显著提升深度学习模型训练的效率和可扩展性。无论是应对大规模数据还是复杂模型,这些技术都为深度学习的发展提供了有力支持。
深度学习模型并行与TensorFlow分布式训练策略详解
6. 数据集分片与容错机制
在分布式训练中,数据集分片和容错机制是两个重要的方面。
6.1 数据集分片
当使用
model.fit(x=train_datasets, epochs=3, steps_per_epoch=5)
时,我们直接将训练集传递给
fit()
函数。在多工作节点训练中,数据集会自动进行分片。例如,若有多个工作节点,每个工作节点会得到数据集的一部分进行训练。
6.2 容错机制
在分布式训练中,如果任何一个工作节点发生故障,整个集群可能会失败,并且TensorFlow本身没有内置的故障恢复机制。不过,使用
tf.distribute.Strategy
结合Keras可以通过保存训练检查点来提供容错机制。具体操作如下:
1. 在代码中设置模型检查点回调,如示例代码中的第58行:
callback = tf.keras.callbacks.ModelCheckpoint(filepath=FLAGS.output_path)
-
将回调传递给
model.fit()方法,如示例代码中的第60行:
history = model.fit(train_dataset, epochs=EPOCHS, steps_per_epoch=STEPS_PER_EPOCH, callbacks=[callback])
当有工作节点发生故障时,其他工作节点会等待故障节点重启。由于训练检查点已保存,当故障节点恢复后,训练将从停止的位置继续进行。
7. 不同策略的特点对比
为了更清晰地了解不同分布式训练策略的特点,我们可以通过以下表格进行对比:
| 策略名称 | 适用场景 | 变量放置 | 通信方式 | 实验性 |
|---|---|---|---|---|
| MirroredStrategy | 单机器多GPU同步训练 | 所有GPU镜像 | 全归约算法(默认NVIDIA NCCL) | 否 |
| CentralStorageStrategy | 单机器多GPU,变量放CPU | CPU | 类似MirroredStrategy | 是 |
| MultiWorkerMirroredStrategy | 多机器分布式训练 | 所有设备复制 | CollectiveOps | 是 |
| TPUStrategy | 使用TPU加速训练 | TPU | 类似MirroredStrategy | 是 |
| ParameterServerStrategy | 多机器,有参数服务器 | 参数服务器 | 类似MultiWorkerMirroredStrategy | 是 |
| OneDeviceStrategy | 单设备测试分布式代码 | 指定设备 | 无 | 是 |
8. 总结与建议
通过对TensorFlow各种分布式训练策略的介绍,我们可以根据不同的场景选择合适的策略:
-
单机器多GPU场景
:优先考虑
MirroredStrategy
,它能充分利用单机器上多个GPU的计算资源,实现高效的同步训练。
-
多机器分布式训练场景
:
MultiWorkerMirroredStrategy
和
ParameterServerStrategy
是不错的选择。
MultiWorkerMirroredStrategy
适用于机器配置较为一致的情况,而
ParameterServerStrategy
在需要专门的参数服务器管理变量时更为合适。
-
使用TPU加速
:若有TPU资源,可使用
TPUStrategy
,能显著提升训练速度。
-
代码测试
:在将分布式代码迁移到多设备环境之前,使用
OneDeviceStrategy
在单设备上进行测试,确保代码的正确性。
同时,为了保证分布式训练的稳定性和容错性,一定要设置训练检查点。在实际应用中,还可以根据具体的硬件资源、数据规模和模型复杂度,对批次大小、训练轮数等参数进行调优,以达到最佳的训练效果。
以下是一个简单的mermaid流程图,展示了在云端运行分布式训练的整体流程:
graph LR
A[创建TensorFlow集群] --> B[安装TensorFlow及必备库]
B --> C[创建云存储目录]
C --> D[上传代码并设置环境变量]
D --> E[执行分布式训练]
E --> F{训练是否完成}
F -- 是 --> G[保存模型]
F -- 否 --> E
通过以上的介绍和分析,希望大家能更好地理解和运用TensorFlow的分布式训练策略,提升深度学习模型的训练效率和性能。
超级会员免费看
1846

被折叠的 条评论
为什么被折叠?



