
Horovod 是一个为 TensorFlow、Keras、PyTorch 和 Apache MXNet 设计的分布式深度学习训练框架。其目标是使分布式深度学习变得快速且易于使用。

Horovod 由 LF AI & Data 基金会 托管。如果您是一家致力于在人工智能、机器学习和深度学习领域使用开源技术的公司,并希望支持这些领域的开源项目社区,请考虑加入 LF AI & Data 基金会。有关参与方详情以及 Horovod 所扮演的角色,请阅读 Linux 基金会的 公告。
本项目的主要动机是让用户能够轻松地将单 GPU 训练脚本扩展到多 GPU 并行训练。这涉及两个方面:
在 Uber 内部,我们发现 MPI 模型比之前的解决方案(如使用参数服务器的分布式 TensorFlow)要直观得多,所需的代码改动也少得多。一旦训练脚本为 Horovod 的扩展性而编写,它就可以在单 GPU、多 GPU 甚至多台主机上运行,无需任何进一步的代码更改。更多详情请参阅 使用方法 部分。
除了易于使用,Horovod 的速度也很快。下图展示了在 128 台服务器(每台配备 4 个 Pascal GPU,通过支持 RoCE 的 25 Gbit/s 网络连接)上进行的基准测试结果:

Horovod 在 Inception V3 和 ResNet-101 上实现了 90% 的扩展效率,在 VGG-16 上实现了 68% 的扩展效率。请参阅 基准测试 了解如何复现这些数据。
虽然安装 MPI 和 NCCL 本身可能看起来有些麻烦,但这只需要负责基础设施的团队完成一次,而公司内所有构建模型的其他人则可以享受大规模训练的简便性。
在 Linux 或 macOS 上安装 Horovod:
安装 CMake
如果您从 PyPI 安装了 TensorFlow,请确保已安装 g++-5 或更高版本。从 TensorFlow 2.10 开始,将需要支持 C++17 的编译器,如 g++8 或更高版本。
如果您从 PyPI 安装了 PyTorch,请确保已安装 g++-5 或更高版本。
如果您从 Conda 安装了任一软件包,请确保已安装 gxx_linux-64 Conda 包。
安装 horovod pip 包。
在 CPU 上运行:
bash
$ pip install horovod
使用 NCCL 在 GPU 上运行:
bash
$ HOROVOD_GPU_OPERATIONS=NCCL pip install horovod
有关安装支持 GPU 的 Horovod 的更多详情,请阅读 GPU 上的 Horovod。
有关 Horovod 安装选项的完整列表,请阅读 安装指南。
如果您想使用 MPI,请阅读 使用 MPI 的 Horovod。
如果您想使用 Conda,请阅读 为 Horovod 构建支持 GPU 的 Conda 环境。
如果您想使用 Docker,请阅读 Docker 中的 Horovod。
要从源代码编译 Horovod,请遵循 贡献者指南 中的说明。
Horovod 的核心原则基于 MPI 概念,如 size(大小)、rank(排名)、local rank(本地排名)、allreduce、allgather、broadcast 和 alltoall。更多详情请参阅 此页面。
请参阅以下页面了解 Horovod 的示例和最佳实践:
要在您的程序中使用 Horovod,请进行以下添加:
运行 hvd.init() 来初始化 Horovod。
将每个 GPU 固定到一个进程,以避免资源争用。
在典型的每个进程一个 GPU 的设置中,将此设置为 local rank。服务器上的第一个进程将分配第一个 GPU,第二个进程将分配第二个 GPU,依此类推。
根据工作进程数量缩放学习率。
同步分布式训练中的有效批次大小会随工作进程数量而缩放。增加学习率可以补偿增大的批次大小。
使用 hvd.DistributedOptimizer 包装优化器。
分布式优化器将梯度计算委托给原始优化器,使用 allreduce 或 allgather 对梯度进行平均,然后应用这些平均后的梯度。
将初始变量状态从 rank 0 广播到所有其他进程。
当训练从随机权重开始或从检查点恢复时,这对于确保所有工作进程初始化一致是必要的。
修改您的代码,使其仅在 worker 0 上保存检查点,以防止其他 worker 破坏它们。
使用 TensorFlow v1 的示例(完整训练示例请参见 examples 目录):
import tensorflow as tf
import horovod.tensorflow as hvd
# 初始化 Horovod
hvd.init()
# 将 GPU 固定给处理本地排名的进程使用(每个进程一个 GPU)
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
# 构建模型...
loss = ...
opt = tf.train.AdagradOptimizer(0.01 * hvd.size())
# 添加 Horovod 分布式优化器
opt = hvd.DistributedOptimizer(opt)
# 添加钩子,在初始化期间将变量从 rank 0 广播到所有其他进程。
hooks = [hvd.BroadcastGlobalVariablesHook(0)]
# 创建训练操作
train_op = opt.minimize(loss)
# 仅在 worker 0 上保存检查点,以防止其他 worker 破坏它们。
checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None
# MonitoredTrainingSession 负责会话初始化、从检查点恢复、保存检查点以及在完成或出错时关闭。
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,
config=config,
hooks=hooks) as mon_sess:
while not mon_sess.should_stop():
# 执行同步训练。
mon_sess.run(train_op)
以下示例命令展示了如何运行分布式训练。更多详情,包括 RoCE/InfiniBand 调整和处理挂起的技巧,请参阅 运行 Horovod。
在一台有 4 个 GPU 的机器上运行:
bash
$ horovodrun -np 4 -H localhost:4 python train.py
在 4 台机器上运行,每台有 4 个 GPU:
bash
$ horovodrun -np 16 -H server1:4,server2:4,server3:4,server4:4 python train.py
使用 Open MPI 而不使用 horovodrun 包装器运行,请参阅 使用 Open MPI 运行 Horovod。
在 Docker 中运行,请参阅 Docker 中的 Horovod。
在 Kubernetes 上运行,请参阅 Helm Chart、Kubeflow MPI Operator、FfDL 和 Polyaxon。
在 Spark 上运行,请参阅 Spark 上的 Horovod。
在 Ray 上运行,请参阅 Ray 上的 Horovod。
在 Singularity 中运行,请参阅 Singularity。
在 LSF HPC 集群(例如 Summit)中运行,请参阅 LSF。
在 Hadoop Yarn 上运行,请参阅 TonY。
Gloo 是 Facebook 开发的一个开源集体通信库。
Gloo 已包含在 Horovod 中,允许用户在不安装 MPI 的情况下运行 Horovod。
对于同时支持 MPI 和 Gloo 的环境,您可以在运行时通过向 horovodrun 传递 --gloo 参数来选择使用 Gloo:
$ horovodrun --gloo -np 2 python train.py
Horovod 支持将 Horovod 集合操作与其他 MPI 库(如 mpi4py)混合使用,前提是 MPI 是使用多线程支持构建的。
您可以通过查询 hvd.mpi_threads_supported() 函数来检查 MPI 多线程支持。
import horovod.tensorflow as hvd
# 初始化 Horovod
hvd.init()
# 验证 MPI 多线程是否受支持。
assert hvd.mpi_threads_supported()
from mpi4py import MPI
assert hvd.size() == MPI.COMM_WORLD.Get_size()
您还可以使用 mpi4py 子通信器初始化 Horovod,在这种情况下,每个子通信器将运行一个独立的 Horovod 训练。
from mpi4py import MPI
import horovod.tensorflow as hvd
# 将 COMM_WORLD 拆分为子通信器
subcomm = MPI.COMM_WORLD.Split(color=MPI.COMM_WORLD.rank % 2,
key=MPI.COMM_WORLD.rank)
# 初始化 Horovod
hvd.init(comm=subcomm)
print('COMM_WORLD rank: %d, Horovod rank: %d' % (MPI.COMM_WORLD.rank, hvd.rank()))
了解如何优化模型以进行推理并从图中移除 Horovod 操作,请参阅 此处。
Horovod 的独特之处之一是其能够交错通信和计算,并结合对小规模 allreduce 操作进行批处理的能力,从而提升性能。我们将此批处理功能称为张量融合。
完整详情和调整说明请参阅 此处。
Horovod 能够记录其活动的时间线,称为 Horovod 时间线。

使用 Horovod 时间线来分析 Horovod 性能。完整详情和使用说明请参阅 此处。
选择正确的值以有效利用张量融合和其他高级 Horovod 功能可能涉及大量的试错。我们提供了一个自动化此性能优化过程的系统,称为 autotuning,您只需向 horovodrun 传递一个命令行参数即可启用。
完整详情和使用说明请参阅 此处。
Horovod 允许您在一个分布式训练中,让不同组的进程并发执行不同的集合操作。设置 hvd.process_set 对象以利用此功能。
详细说明请参阅 进程组。
如果您希望在此站点发布任何用户指南,请将链接发送给我们。
如果 Horovod 对您的研究有帮助,请在出版物中引用:
@article{sergeev2018horovod,
Author = {Alexander Sergeev and Mike Del Balso},
Journal = {arXiv preprint arXiv:1802.05799},
Title = {Horovod: fast and easy distributed deep learning in {TensorFlow}},
Year = {2018}
}
Horovod 源代码基于百度 tensorflow-allreduce 仓库,由 Andrew Gibiansky 和 Joel Hestness 编写。他们的原始工作描述在文章 Bringing HPC Techniques to Deep Learning 中。