深度学习 AMI
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

TensorFlow with Horovod

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

注意

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

使用 Horovod 激活和测试 TensorFlow

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

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

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

    (tensorflow_p36)$ ipython
  4. 测试导入 TensorFlow with 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 控制台中选择其中一个成员,控制台的说明窗格将出现。查找 Private IPs (私有 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. 现在,您的领导知道如何联系每个成员。这一切都将在专用网络接口上发生。接下来,使用简短的 bash 函数来帮助将命令发送到每个成员。

    function runclust(){ while read -u 10 host; do host=${host%% slots*}; ssh -o "StrictHostKeyChecking no" $host ""$2""; done 10<$1; };
  5. 当天的第一个命令旨在告知其他成员不要进行“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 配置的主训练脚本。以下部分假定您已启动一个 DLAMI 和一个包含 8 个 GPU 的 EC2 实例。建议使用 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/preprocess 目录中:

    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 模型

注意

在 ImageNet 数据集上使用 Horovod 训练 ResNet50 CNN

  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 with 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 项目