新建任务中点击 多任务配置 按钮,进入多任务配置任务界面。您可以在该界面对子任务的参数进行设置。

1553165957291

动机

一般情况下新建的任务,其内部实际上蕴含了一个子任务组,这个子任务组之下有一个子任务,每个子任务对应一个docker容器,所能申请的资源不能超过一台服务器所具有资源上限。

因为通常使用是单机任务,上述的过程也就被简化和隐藏了。但如果你的任务需要跨多个服务器的资源,那么就需要多次提交任务,或者使用这里的多任务配置。

需要说明的是,使用者多次提交,实质上在系统中就创建了多个docker容器,只要这些容器可以通信(具体集群通信上的配置参考集群网络配置),那么也就可以开始多机多卡训练。只是需要自行处理一些容器发现(如手动设定master节点的IP)的问题。

之所以需要额外有多任务配置,是出于下列益处:

  • 有些任务要求的资源数量是刚需,资源少了运行不了,那么就会遭遇一种情况,多次提交任务,但后续的任务因资源紧张分配不到,前面的资源空等待,浪费了机时。而在多任务配置中,会自动处理多个子任务的资源申请,只有所有子任务的资源都申请到了才启动(也才开始计费)。当然,资源紧张时,是不能加速获得资源的,甚至说,如果超时未分到所有资源,还会将已经预留的部分资源还回去(毕竟你留着也没用上)。这对整体有利,但对个人可能不是很有利 :( 。它也有被小任务“饿死”的情况,是有考虑在调度上对这类任务予以一定保护。
  • 将所有子任务的IP地址写入到每个子任务的环境变量(见下文)中,不需要自行处理容器发现了。
  • 一定的错误处理机制,机器总是有故障的可能,某一或某些子任务故障了,整体任务该怎么处理,如是否有任一故障就把整体任务终止,是可以通过配置实现的。

概念说明

子任务:对应于实际执行用户设定的启动命令的docker容器,运行在某一个服务器节点之上

子任务组:为了便捷地创建多个子任务而设定的组织概念,同一个子任务组下的子任务具有相同的资源规格(GPU数量)和启动命令。也就是说,你可以通过增大上图中子任务数量而快速地创建多个子任务。你也可以创建多个子任务组。

环境变量:子任务在启动之后,系统会自动在其中注入一些环境变量,用于子任务标识自己(如知道自己是哪个编号的子任务)和发现其他子任务。你需要关心的有:

变量名称 用途
PAI_JOB_TASK_COUNT 任务中所有子任务的数目。假如你设定了子任务组TaskG1,下辖3个任务,子任务组TaskG2,下辖5个子任务,那么该环境变量的值为8。每个子任务中都具有相同值。
PAI_JOB_TASK_ROLE_COUNT 任务中子任务组的数量。在上述例子中,该值为2。每个子任务中都具有相同值。
PAI_CURRENT_TASK_ROLE_INDEX 当前子任务所属的子任务组的编号,从0开始。如在上述例子中,TaskG2下属的子任务该值会是1。
PAI_TASK_INDEX 当前子任务在所属子任务组中的编号,注意不是在所有子任务中的编号。如上述例子中,TaskG1下属的3个子任务,该值会分别为0, 1, 2; TaskG2下属的5个子任务,该值会分别为0, 1, 2, 3, 4
PAI_CURRENT_TASK_ROLE_CURRENT_TASK_INDEX 同PAI_TASK_INDEX
PAI_CONTAINER_IP 当前子任务的IP地址,用该IP与其他子任务通信。该地址是172.*.*.*
PAI_CONTAINER_HOST_IP 当前子任务所在的宿主机的IP,该地址是10.11.*.*。该值一般用不上。
PAICONTAINER_LIST\$子任务组编号_$子任务编号 这是一系列环境变量,总共会有与子任务数量相同的环境变量。在上述例子中,会共有8个环境变量,分别为PAI_CONTAINER_LIST_0_0, PAI_CONTAINER_LIST_0_1, PAI_CONTAINER_LIST_0_2, PAI_CONTAINER_LIST_1_0, PAI_CONTAINER_LIST_1_1, PAI_CONTAINER_LIST_1_2, PAI_CONTAINER_LIST_1_3, PAI_CONTAINER_LIST_1_4。每个环境变量中分别填入对应编号的子任务的IP地址。每个子任务中都有这些变量,有相同的值。
一种常见的使用方式是选择0号子任务组中的0号子任务为master节点,那么就可以在启动命令中使用PAI_CONTAINER_LIST_0_0这个环境变量。

在这些环境变量中,最需要关心的IP地址相关的,因为在任务实际被调度执行前,是无法预知其IP的,而像子任务数量之类的,是由你的配置决定的,是事先可知的。

如果你好奇这些环境变量是怎么产生的,可以在具体启动的任务中,查阅/pai_bootstrap.sh文件(你还可以在里面找到你设定的启动命令)。简单说,是每个子任务会往一个共享目录中输出信息,由脚本负责收集和同步。

参数填写说明:

  1. 子任务组名称

    必选项。
    填写方式:长度要求为1~20个字符(含),以字母开头,仅允许包含 字母、数字、横线和下划线,不同子任务组的名称必须互不相同。如果只有一个,设置成默认值即可。

  2. 子任务个数

    必选项。
    表示该子任务将运行的副本数量。若将子任务类比于进程,该选项定义了将启动的进程数量。当启动多个子任务时,可以通过环境变量PAI_TASK_INDEX来区别不同子任务(功能类似pid之于进程)。

  3. 最少成功次数

    非必填项。
    当所属子任务组中有X个子任务已经运行完成了,那么整个任务终止,不再等待其他子任务。 填写方式:只有在 子任务数>1时才有效。如果你希望等所有子任务都运行完才结束任务,该项可不填。

  4. 最少失败次数

    非必填项。
    当所属子任务组中有X个已经运行失败了,那么整个任务终止,不再等待其他子任务。 填写方式:只有在 子任务数>1时才有效。如果你希望任意一个子任务失败就结束任务,该项可不填。

    如果你利用多任务配置启动多个独立无关的子任务,那么这个选项你需要关心,因为不排除某个子任务会失败,而在默认情况下,会把你其他所有子任务也终止,这也许不是你想要的。这种情况下,你应该让X=子任务数

示例

在这里有一个公开项目,演示如何启动多个子任务进行多机多卡训练:https://bitahub.ustc.edu.cn/openproject/detail?id=24270

该项目有一个子任务组,下辖4个子任务,每个子任务申请4卡GPU。

设定的启动命令如下:

wget https://git.openi.org.cn/xwzheng/GPUCluster/raw/branch/master/test_cases/test_case_for_multi_gpu.py; python test_case_for_multi_gpu.py -b 384 --dist-url "tcp://${PAI_CONTAINER_LIST_0_0}:12356" --dist-backend 'nccl' --multiprocessing-distributed --world-size ${PAI_JOB_TASK_COUNT} --rank ${PAI_TASK_INDEX} -j 16 --epochs 3

尽管每个子任务都使用相同的启动命令,但他们有环境变量可以标识自身的编号(PAI_TASK_INDEX),所以也可以轻松的应对。

在上述例子中,是使用pytorch的DistributedDataParallel,它要求在初始化时指定:

  • master节点的IP和端口,IP我们选择了0号子任务组中的0号任务,这个值由PAI_CONTAINER_LIST_0_0给出(之所以要用环境变量给出该值,是因为在任务具体运行之前,谁也不知道它会运行在哪台服务器上,以什么样的IP),端口则是随意指定的(因为也没被占用)。当然,你愿意的话,也可以选其他子任务的IP来做master。
  • 参与的机器数量,这个由环境变量PAI_JOB_TASK_COUNT给出
  • 每个子进程分别运行命令,并指定本子进程的rank编号,该值由PAI_TASK_INDEX给出。注意,如果你有多个子任务组,那么该值需要自行处理下,如加上其他子任务组的子任务数。

你可以随意变动启动任务时申请的资源数量和子任务数量,上述启动命令可以自行应对。

其他:

  • 对于单子任务的情况,上述启动命令也是可用的,因为这些环境变量单子任务也有
  • bash中的字符串可以用单引号或双引号,但实际这两者是有区别的,双引号会展开环境变量,而单引号不会,所以上述例子中只能使用双引号。

results matching ""

    No results matching ""