在Kubernetes上使用PaddlePaddle运行深度学习

编者注:今天的帖子是百度深度学习团队和CoreOS的etcd团队的联合帖子。

** **

什么是PaddlePaddle

划桨 是一个易于使用,高效,灵活和可扩展的深度学习平台,最初在百度开发,自2014年以来将深度学习应用于百度产品。

使用PaddlePaddle进行了50多项创新,支持15种百度产品,包括搜索引擎,在线广告,问答和系统安全。

2016年9月,百度开源 划桨 ,并很快吸引了来自百度之外的许多贡献者。

为什么在Kubernetes上运行PaddlePaddle

划桨 设计为纤薄且独立于计算基础架构。用户可以在Hadoop,Spark,Mesos,Kubernetes等之上运行它。.由于它的灵活性,效率和丰富的功能,我们对Kubernetes有浓厚的兴趣。

当我们在各种百度产品中使用PaddlePaddle时,我们注意到PaddlePaddle的两种主要用法-研究和产品。研究数据不会经常更改,重点是快速实验以达到预期的科学测量。产品数据经常更改。它通常来自Web服务生成的日志消息。

一个成功的深度学习项目包括研究和数据处理管道。有许多参数需要调整。许多工程师同时在项目的不同部分工作。

为了确保该项目易于管理和有效利用硬件资源,我们希望在同一基础架构平台上运行该项目的所有部分。

该平台应提供:

  • 容错。它应该将流水线的每个阶段抽象为一项服务,该服务由许多进程组成,这些进程通过冗余提供高吞吐量和鲁棒性。

  • 自动缩放。在白天,通常有很多活跃用户,该平台应扩展在线服务。在夜间,该平台应释放一些资源用于深度学习实验。

  • 工作打包和隔离。它应该能够将需要GPU的PaddlePaddle训练器进程,需要大内存的Web后端服务以及需要磁盘IO的CephFS进程分配给同一节点,以充分利用其硬件。

我们需要一个运行深度学习系统的平台,Web服务器(例如Nginx),日志收集器(例如fluentd),分布式队列服务(例如Kafka),日志连接器和其他使用以下工具编写的数据处理器同一集群上的Storm,Spark和Hadoop MapReduce。我们希望在同一集群上运行所有作业-在线和离线,生产和实验-因此我们可以充分利用该集群,因为不同种类的作业需要不同的硬件资源。

我们选择基于容器的解决方案,因为VM引入的开销与我们的效率和利用率目标相矛盾。

根据我们对不同容器解决方案的研究,Kubernetes最适合我们的要求。

Kubernetes 分布式培训

划桨 本机支持分布式培训。 划桨 群集中有两个角色: 参数服务器 培训师 。每个参数服务器进程都维护全局模型的碎片。每个培训师都有其模型的本地副本,并使用其本地数据来更新模型。在训练过程中,训练者将模型更新发送到参数服务器,参数服务器负责汇总这些更新,以便训练者可以将其本地副本与全局模型同步。

| | |图1:模型分为两个碎片。分别由两个参数服务器管理。 |

其他一些方法使用一组参数服务器在多个主机上的CPU内存空间中共同保存一个非常大的模型。但是在实践中,我们通常没有这么大的模型,因为由于GPU内存的限制,处理非常大的模型效率非常低。在我们的配置中,多个参数服务器主要用于快速通信。假设只有一个参数服务器进程与所有训练者一起工作,则参数服务器将必须汇总所有训练者的梯度并成为瓶颈。根据我们的经验,实验有效的配置包括相同数量的培训师和参数服务器。我们通常在同一节点上运行一对训练器和参数服务器。在以下Kubernetes作业配置中,我们启动了一个运行N个Pod的作业,并且在每个Pod中都有一个参数服务器和一个训练器进程。

yaml

apiVersion: batch/v1

kind: Job

metadata:

  name:  划桨 -cluster-job

spec:

  parallelism: 3

  completions: 3

  template:

    metadata:

      name:  划桨 -cluster-job

    spec:

      volumes:

      - name: jobpath

        hostPath:

          path: /home/admin/efs

      containers:

      - name:  培训师 

        image: your\_repo/paddle:mypaddle

        command: ["bin/bash",  "-c", "/root/start.sh"]

        env:

        - name: JOB\_NAME

          value: paddle-cluster-job

        - name: JOB\_PATH

          value: /home/jobpath

        - name: JOB\_NAMESPACE

          value: default

        volumeMounts:

        - name: jobpath

          mountPath: /home/jobpath

      restartPolicy: Never

从配置中我们可以看到,并行度都设置为3。因此,此作业将同时启动3个PaddlePaddle吊舱,并且当所有3个吊舱完成时,该作业将完成。

| | |

图2:三个Pod的作业A和一个在两个节点上运行的Pod的作业B。 |

每个吊舱的入口点是 start.sh 。它从存储服务下载数据,以便培训人员可以快速从Pod本地磁盘空间中读取数据。下载完成后,它将运行Python脚本, start_paddle.py,它将启动参数服务器,等待直到所有吊舱的参数服务器准备好服务为止,然后在吊舱中启动培训者流程。

这种等待是必要的,因为每个培训人员都需要与所有参数服务器进行对话,如图所示。 1. Kubernetes API 使培训人员可以检查吊舱的状态,因此Python脚本可以等待所有参数服务器的状态更改为“正在运行”,然后再触发培训过程。

当前,从数据碎片到容器/培训者的映射是静态的。如果要运行N个训练器,则需要将数据划分为N个分片,并将每个分片静态分配给训练器。再次,我们依靠Kubernetes API 将Pod登记在工作中,因此我们可以将Pod /培训员的索引从1索引为N。第i个培训员将读取第i个数据分片。

培训数据通常在分布式文件系统上提供。实际上,我们在内部部署群集上使用CephFS,在AWS上使用Amazon Elastic File System。如果您有兴趣构建Kubernetes集群以运行分布式PaddlePaddle培训工作,请按照 本教程 .

下一步是什么

我们正在努力使Kubernetes更加平稳地运行PaddlePaddle。

您可能会注意到,当前的培训师调度完全基于基于静态分区图的Kubernetes。这种方法易于启动,但可能会导致一些效率问题。

首先,缓慢或死气沉沉的培训师会阻碍整个工作。初始部署后,没有受控的抢占或重新计划。其次,资源分配是静态的。因此,如果Kubernetes的可用资源比我们预期的要多,我们必须手动更改资源需求。这是一项繁琐的工作,与我们的效率和利用率目标不符。

为了解决上述问题,我们将添加一个PaddlePaddle母版,该母版可以理解Kubernetes API ,可以动态添加/删除资源容量,并以更动态的方式将碎片分发给培训师。 划桨 主机将etcd用作从分片到培训师的动态映射的容错存储。因此,即使主机崩溃,映射也不会丢失。 Kubernetes 可以重新启动主服务器,并且作业将继续运行。

另一个潜在的改进是更好的PaddlePaddle作业配置。我们拥有相同数量的培训师和参数服务器的经验主要来自使用专用集群。在仅运行PaddlePaddle作业的客户群集上,该策略表现出色。但是,此策略在运行多种作业的通用集群上可能不是最佳选择。

划桨 训练器可以利用多个GPU来加速计算。 GPU并不是Kubernetes中的一流资源。我们必须半手动管理GPU。我们很乐意与Kubernetes社区合作以改善GPU支持,以确保PaddlePaddle在Kubernetes上运行最佳。

-王怡 百度研究 还有李祥 酷睿