TensorFlow 和 Horovod - 深度学习 AMI
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

TensorFlow 和 Horovod

本教程介绍如何在带有 Conda 的深度学习 AMI 上 TensorFlow 与 Horovod 配合使用。Horovod 已预装在 Conda 环境中。 TensorFlow推荐使用 Python 3 环境。此处的说明假定您具有一个正在运行的 DLAMI 实例,此实例包含一个或多个 GPU。有关更多信息,请参阅 如何开始使用 DLAMI

注意

仅支持 P3.*、P2.* 和 G3.* 实例类型。

注意

在两个位置有 mpirun(通过 OpenMPI)可用。它在 /usr/bin/home/ubuntu/anaconda3/envs/<env>/bin 中可用。env 是与框架相对应的环境,例如 Tensorflow 和 Apache MXNet。在 Conda 环境中可以使用较新的 OpenMPI 版本。我们建议使用 mpirun 二进制文件的绝对路径或 -- 前缀标志来运行 mpi 工作负载。例如,对于 Tensorflow python36 环境,请使用以下任一方式:

/home/ubuntu/anaconda3/envs/tensorflow_p36/bin/mpirun <args> or mpirun --prefix /home/ubuntu/anaconda3/envs/tensorflow_p36/bin <args>

使用 Horovod 激活并 TensorFlow 进行测试

  1. 验证您的实例是否具有活动的 GPU。NVIDIA 为此提供了一个工具:

    $ nvidia-smi
  2. 激活 Python 3 TensorFlow 环境:

    $ source activate tensorflow_p36
  3. 启动 iPython 终端:

    (tensorflow_p36)$ ipython
  4. TensorFlow 使用 Horovod 测试导入以验证其是否正常运行:

    import horovod.tensorflow as hvd hvd.init()

    以下内容可能显示在您的屏幕上(可能出现在一些警告消息之后)。

    -------------------------------------------------------------------------- [[55425,1],0]: A high-performance Open MPI point-to-point messaging module was unable to find any relevant network interfaces: Module: OpenFabrics (openib) Host: ip-172-31-72-4 Another transport will be used instead, although this may result in lower performance. --------------------------------------------------------------------------

配置您的 Horovod 主机文件

您可以将 Horovod 用于单节点多 GPU 训练或多节点多 GPU 训练。如果您打算使用多个节点进行分布式训练,则必须向主机文件添加每个 DLAMI 的私有 IP 地址。您当前登录的 DLAMI 称为领导。作为集群的一部分的其他 DLAMI 实例称为成员。

在开始本部分之前,请启动一个或多个 DLAMI,然后等待它们进入准备就绪状态。示例脚本需要一个主机文件,即使您计划只使用一个 DLAMI,也请创建仅具有一个条目的主机文件。如果您在训练开始后编辑主机文件,则必须重新启动训练以使已添加或删除的主机生效。

针对训练配置 Horovod
  1. 将目录更改为训练脚本所在的目录。

    cd ~/examples/horovod/tensorflow
  2. 使用 vim 编辑领导的主目录中的文件。

    vim hosts
  3. 在 Amazon Elastic Compute Cloud 控制台中选择其中一个成员,控制台的说明窗格将出现。查找私有 IP 字段,并将 IP 复制并粘贴到一个文本文件中。在新行上复制每个成员的私有 IP。然后,在每个 IP 的旁边添加一个空格,然后添加文本 slots=8,如下所示。这表示每个实例具有的 GPU 的数目。p3.16xlarge 实例具有 8 个 GPU,因此,如果您选择其他实例类型,请提供每个实例的实际 GPU 数。对于领导,您可使用 localhost。对于包含 4 个节点的集群,它应类似于以下内容:

    172.100.1.200 slots=8 172.200.8.99 slots=8 172.48.3.124 slots=8 localhost slots=8

    保存文件并退回到领导的终端。

  4. 将成员实例使用的 SSH 密钥添加到 ssh 代理中。

    eval `ssh-agent -s` ssh-add <key_name>.pem
  5. 现在,您的领导知道如何联系每个成员。这一切都将在专用网络接口上发生。接下来,使用简短的 bash 函数来帮助将命令发送到每个成员。

    function runclust(){ while read -u 10 host; do host=${host%% slots*}; ssh -o "StrictHostKeyChecking no" $host ""$2""; done 10<$1; };
  6. 告诉其他成员不要做 “StrickHostKeyChecking”,因为这可能会导致训练停止响应。

    runclust hosts "echo \"StrictHostKeyChecking no\" >> ~/.ssh/config"

使用合成数据训练

DLAMI 附带一个可用于使用合成数据训练模型的示例脚本。这将测试您的领导是否能与集群的成员通信。需要主机文件。有关说明,请参阅 配置您的 Horovod 主机文件

使用示例数据测试 Horovod 训练
  1. ~/examples/horovod/tensorflow/train_synthetic.sh 默认为 8 个 GPU,但您可以为它提供要运行的 GPU 的数量。以下示例运行此脚本,并将 4 作为 4 个 GPU 的参数传递。

    $ ./train_synthetic.sh 4

    在显示一些警告消息后,您将看到以下输出,其验证 Horovod 正在使用 4 个 GPU。

    PY3.6.5 |Anaconda custom (64-bit)| (default, Apr 29 2018, 16:14:56) [GCC 7.2.0]TF1.11.0Horovod size: 4

    然后,在显示一些其他警告后,您将看到表的开头和一些数据点。如果您不想查看 1000 次批处理,请退出训练。

    Step Epoch Speed Loss FinLoss LR 0 0.0 105.6 6.794 7.708 6.40000 1 0.0 311.7 0.000 4.315 6.38721 100 0.1 3010.2 0.000 34.446 5.18400 200 0.2 3013.6 0.000 13.077 4.09600 300 0.2 3012.8 0.000 6.196 3.13600 400 0.3 3012.5 0.000 3.551 2.30401
  2. Horovod 先使用所有本地 GPU,然后再尝试使用集群成员的 GPU。因此,要确保跨集群的分布式训练正常运行,请试用您计划使用的全部 GPU。例如,如果您有 4 个属于 p3.16xlarge 实例类型的成员,则集群中可包含 32 个 GPU。这是您希望试用全部 32 个 GPU 的位置。

    ./train_synthetic.sh 32

    您的输出与之前的测试类似。Horovod 大小为 32,速度约为四倍。随着此实验完成,您已测试您的领导及其与成员通信的能力。如果您遇到任何问题,请查看 故障排除 部分。

准备数据 ImageNet 集

在本节中,您将下载 ImageNet 数据集,然后从原始数据集生成 TFRecord 格式的数据集。DLAMI 上为该数据集提供了一组预处理脚本,您可以将其用于 ImageNet 其中一个数据集, ImageNet 也可以用作另一个数据集的模板。还提供了为 ImageNet 配置的主要训练脚本。以下部分假定您已通过带 8 个 GPU 的 EC2 实例启动了 DLAMI。建议使用 p3.16xlarge 实例类型。

在 DLAMI 上的 ~/examples/horovod/tensorflow/utils 目录中,您可以找到以下脚本:

  • utils/preprocess_imagenet.py-使用它可以将原始 ImageNet数据集转换为TFRecord格式。

  • utils/tensorflow_image_resizer.py-使用它可以按照建议调整TFRecord数据集的大小,以便进行 ImageNet 训练。

准备数据 ImageNet 集
  1. 访问 image-net.org,创建账户,获取访问密钥,然后下载数据集。image-net.org 托管原始数据集。要下载它,你需要有一个 ImageNet 账户和一个访问密钥。该帐户是免费的,要获得免费访问密钥,您必须同意 ImageNet许可证。

  2. 使用图像预处理脚本从原始 ImageNet 数据集生成 TFRecord 格式的数据集。从 ~/examples/horovod/tensorflow/utils 目录中:

    python preprocess_imagenet.py \ --local_scratch_dir=[YOUR DIRECTORY] \ --imagenet_username=[imagenet account] \ --imagenet_access_key=[imagenet access key]
  3. 使用图像调整大小脚本。如果您调整图像的大小,则训练的运行速度会更快,并且可以更好地与ResNet 参考论文保持一致。从 ~/examples/horovod/utils/preprocess 目录中:

    python tensorflow_image_resizer.py \ -d imagenet \ -i [PATH TO TFRECORD TRAINING DATASET] \ -o [PATH TO RESIZED TFRECORD TRAINING DATASET] \ --subset_name train \ --num_preprocess_threads 60 \ --num_intra_threads 2 \ --num_inter_threads 2

在单个 DLAMI 上训练 ResNet -50 ImageNet 模型

注意
使用 Horovod 在数据集上训练 ResNet 50 CNN ImageNet
  1. 导航到 ~/examples/horovod/tensorflow文件夹。

    cd ~/examples/horovod/tensorflow
  2. 验证您的配置并设置要在训练中使用的 GPU 数量。首先,查看与脚本位于相同文件夹中的 hosts。如果您使用的是具有少于 8 个 GPU 的实例,则必须更新此文件。默认为 localhost slots=8。将数量 8 更新为要使用的 GPU 的数量。

  3. 提供了一个 Shell 脚本,此脚本采用您计划使用的 GPU 数作为其唯一参数。运行此脚本以开始训练。以下示例对 4 个 GPU 使用 4。

    ./train.sh 4
  4. 完成此操作需要几个小时。它使用 mpirun 来跨您的 GPU 分布训练。

在 DLAMI 集群上训练 ResNet -50 ImageNet 模型

注意

此示例将引导您在 DLAMI 集群中的多个节点上使用准备好的数据集训练 ResNet -50 模型。

  • 要获得更快的性能,建议您将数据集本地置于集群的每个成员中。

    使用此 copyclust 函数将数据复制到其他成员。

    function copyclust(){ while read -u 10 host; do host=${host%% slots*}; rsync -azv "$2" $host:"$3"; done 10<$1; };

或者,如果您的文件位于 S3 存储桶中,请使用 runclust 函数直接将文件下载到每个成员。

runclust hosts "tmux new-session -d \"export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY && export AWS_SECRET_ACCESS_KEY=YOUR_SECRET && aws s3 sync s3://your-imagenet-bucket ~/data/tf-imagenet/ && aws s3 sync s3://your-imagenet-validation-bucket ~/data/tf-imagenet/\""

使用允许您一次性管理多个节点的工具将节省大量时间。您可以等待每个步骤并单独管理每个实例,也可以使用 tmux 或 screen 等工具断开连接并恢复会话。

在复制操作完成后,您已准备好开始训练。运行脚本,并将 32 作为我们用于此次运行的 32 个 GPU 的参数传递。如果您担心断开连接并终止会话(这将结束训练运行),请使用 tmux 或类似工具。

./train.sh 32

以下输出是你在 32 个 GPU 上运行训练时看到 ImageNet的结果。32 个 GPU 需要 90 – 110 分钟。

Step Epoch Speed Loss FinLoss LR 0 0.0 440.6 6.935 7.850 0.00100 1 0.0 2215.4 6.923 7.837 0.00305 50 0.3 19347.5 6.515 7.425 0.10353 100 0.6 18631.7 6.275 7.173 0.20606 150 1.0 19742.0 6.043 6.922 0.30860 200 1.3 19790.7 5.730 6.586 0.41113 250 1.6 20309.4 5.631 6.458 0.51366 300 1.9 19943.9 5.233 6.027 0.61619 350 2.2 19329.8 5.101 5.864 0.71872 400 2.6 19605.4 4.787 5.519 0.82126 ... 13750 87.9 19398.8 0.676 1.082 0.00217 13800 88.2 19827.5 0.662 1.067 0.00156 13850 88.6 19986.7 0.591 0.997 0.00104 13900 88.9 19595.1 0.598 1.003 0.00064 13950 89.2 19721.8 0.633 1.039 0.00033 14000 89.5 19567.8 0.567 0.973 0.00012 14050 89.8 20902.4 0.803 1.209 0.00002 Finished in 6004.354426383972

在训练运行完成后,脚本将跟进评估运行。它将在领导上运行,因为它运行得足够快,而不必将作业分配给其他成员。以下是评估运行的输出。

Horovod size: 32 Evaluating Validation dataset size: 50000 [ip-172-31-36-75:54959] 7 more processes have sent help message help-btl-vader.txt / cma-permission-denied [ip-172-31-36-75:54959] Set MCA parameter "orte_base_help_aggregate" to 0 to see all help / error messages step epoch top1 top5 loss checkpoint_time(UTC) 14075 90.0 75.716 92.91 0.97 2018-11-14 08:38:28

以下是使用 256 个 GPU 运行此脚本时的示例输出,其中运行时间为 14 到 15 分钟。

Step Epoch Speed Loss FinLoss LR 1400 71.6 143451.0 1.189 1.720 0.14850 1450 74.2 142679.2 0.897 1.402 0.10283 1500 76.7 143268.6 1.326 1.809 0.06719 1550 79.3 142660.9 1.002 1.470 0.04059 1600 81.8 143302.2 0.981 1.439 0.02190 1650 84.4 144808.2 0.740 1.192 0.00987 1700 87.0 144790.6 0.909 1.359 0.00313 1750 89.5 143499.8 0.844 1.293 0.00026 Finished in 860.5105031204224 Finished evaluation 1759 90.0 75.086 92.47 0.99 2018-11-20 07:18:18

故障排除

以下命令可能有助于解决您在使用 Horovod 进行实验时出现的错误。

  • 如果训练因某种原因发生崩溃,则 mpirun 可能无法清理每台计算机上的所有 python 进程。在此情况下,在您开始下一个作业之前,请停止所有计算机上的 Python 进程,如下所示:

    runclust hosts "pkill -9 python"
  • 如果进程突然完成且没有错误,请尝试删除您的日志文件夹。

    runclust hosts "rm -rf ~/imagenet_resnet/"
  • 如果弹出其他无法解释的问题,请检查您的磁盘空间。如果您已退出,请尝试删除日志文件夹,因为其中包含所有检查点和数据。您也可以为每个成员增加卷的大小。

    runclust hosts "df /"
  • 作为最后的手段,您也可以尝试重新启动。

    runclust hosts "sudo reboot"

如果您尝试在不支持的实例类型上使用 TensorFlow Horovod,则可能会收到以下错误代码:

--------------------------------------------------------------------------- NotFoundError Traceback (most recent call last) <ipython-input-3-e90ed6cabab4> in <module>() ----> 1 import horovod.tensorflow as hvd ~/anaconda3/envs/tensorflow_p36/lib/python3.6/site-packages/horovod/tensorflow/__init__.py in <module>() ** *34* check_extension('horovod.tensorflow', 'HOROVOD_WITH_TENSORFLOW', __file__, 'mpi_lib') ** *35* ---> 36 from horovod.tensorflow.mpi_ops import allgather, broadcast, _allreduce ** *37* from horovod.tensorflow.mpi_ops import init, shutdown ** *38* from horovod.tensorflow.mpi_ops import size, local_size, rank, local_rank ~/anaconda3/envs/tensorflow_p36/lib/python3.6/site-packages/horovod/tensorflow/mpi_ops.py in <module>() ** *56* ** *57* MPI_LIB = _load_library('mpi_lib' + get_ext_suffix(), ---> 58 ['HorovodAllgather', 'HorovodAllreduce']) ** *59* ** *60* _basics = _HorovodBasics(__file__, 'mpi_lib') ~/anaconda3/envs/tensorflow_p36/lib/python3.6/site-packages/horovod/tensorflow/mpi_ops.py in _load_library(name, op_list) ** *43* """ ** *44* filename = resource_loader.get_path_to_datafile(name) ---> 45 library = load_library.load_op_library(filename) ** *46* for expected_op in (op_list or []): ** *47* for lib_op in library.OP_LIST.op: ~/anaconda3/envs/tensorflow_p36/lib/python3.6/site-packages/tensorflow/python/framework/load_library.py in load_op_library(library_filename) ** *59* RuntimeError: when unable to load the library or get the python wrappers. ** *60* """ ---> 61 lib_handle = py_tf.TF_LoadLibrary(library_filename) ** *62* ** *63* op_list_str = py_tf.TF_GetOpList(lib_handle) NotFoundError: /home/ubuntu/anaconda3/envs/tensorflow_p36/lib/python3.6/site-packages/horovod/tensorflow/mpi_lib.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZN10tensorflow14kernel_factory17OpKernelRegistrar12InitInternalEPKNS_9KernelDefEN4absl11string_viewEPFPNS_8OpKernelEPNS_20OpKernelConstructionEE

更多信息

有关实用工具和示例,请参阅 DLAMI 的主目录中的 ~/examples/horovod 文件夹。

有关更多教程和示例,请参阅 Horovod 项目 GitHub