文档首页/ AI开发平台ModelArts/ ModelArts用户指南(Lite Cluster)/ Lite Cluster资源使用/ 在Lite Cluster资源池上使用ranktable路由规划完成Pytorch NPU分布式训练
更新时间:2024-08-15 GMT+08:00
分享

在Lite Cluster资源池上使用ranktable路由规划完成Pytorch NPU分布式训练

场景描述

ranktable路由规划是一种用于分布式并行训练中的通信优化能力,在使用NPU的场景下,支持对节点之间的通信路径根据交换机实际topo做网络路由亲和规划,进而提升节点之间的通信速度。

本案例介绍如何在ModelArts Lite场景下使用ranktable路由规划完成Pytorch NPU分布式训练任务,训练任务默认使用Volcano job形式下发到Lite资源池集群。

图1 任务示意图

约束与限制

  • 该功能只支持贵阳一区域,如果要在其他区域使用请联系技术支持。
  • ModelArts Lite资源池对应的CCE集群需要安装1.10.12及以上版本的华为云版Volcano插件。Volcano调度器的安装升级请参见Volcano调度器。仅华为云版Volcano插件支持开启路由加速特性。
  • 训练使用的Python版本是3.7或3.9,否则无法实现ranktable路由加速。
  • 训练作业的任务节点数要大于或等于3,否则会跳过ranktable路由加速。建议在大模型场景(512卡及以上)使用ranktable路由加速。
  • 脚本执行目录不能是共享目录,否则ranktable路由加速会失败。
  • 路由加速的原理是改变rank编号,所以代码中对rank的使用要统一,如果rank的使用不一致会导致训练异常。

操作步骤

  1. 开启ModelArts Lite资源池对应的CCE集群的cabinet插件。

    1. 在ModelArts Lite专属资源池列表,单击资源池名称,进入专属资源池详情页面。
    2. 在基本信息页面单击CCE集群,跳转到CCE集群详情页面。
    3. 在左侧导航栏选择“插件中心”,搜索“Volcano调度器”。
    4. 单击“编辑”,查看高级配置的“plugins”参数下是否有“{"name":"cabinet"}”,如图2所示。
      图2 Volcano调度器的高级配置
      • 是,则执行2
      • 否,则在高级配置的“plugins”参数下添加“{"name":"cabinet"}”,单击下方的“安装”使Volcano调度器更新配置,完成滚动重启。

  2. 修改torch_npu训练启动脚本。

    脚本要使用torch.distributed.launch/run命令启动,不能使用mp.spawn命令启动,否则无法实现ranktable路由加速。

    在使用Pytorch训练时,需要将“RANK_AFTER_ACC”环境变量赋值给“NODE_RANK”,使得ranktable路由规划生效。训练启动脚本(xxxx_train.sh)示例如下。其中“MASTER_ADDR”“NODE_RANK”必须保持该赋值。

    #!/bin/bash
    
    # MASTER_ADDR
    MASTER_ADDR="${MA_VJ_NAME}-${MA_TASK_NAME}-${MA_MASTER_INDEX}.${MA_VJ_NAME}"
    NODE_RANK="$RANK_AFTER_ACC"
    NNODES="$MA_NUM_HOSTS"
    NGPUS_PER_NODE="$MA_NUM_GPUS"
    # self-define, it can be changed to >=10000 port
    MASTER_PORT="39888"
    
    # replace ${MA_JOB_DIR}/code/torch_ddp.py to the actutal training script
    PYTHON_SCRIPT=${MA_JOB_DIR}/code/torch_ddp.py
    PYTHON_ARGS=""
    
    # set hccl timeout time in seconds
    export HCCL_CONNECT_TIMEOUT=1800
    
    # replace ${ANACONDA_DIR}/envs/${ENV_NAME}/bin/python to the actual python
    CMD="${ANACONDA_DIR}/envs/${ENV_NAME}/bin/python -m torch.distributed.launch \
        --nnodes=$NNODES \
        --node_rank=$NODE_RANK \
        --nproc_per_node=$NGPUS_PER_NODE \
        --master_addr $MASTER_ADDR \
        --master_port=$MASTER_PORT \
        $PYTHON_SCRIPT \
        $PYTHON_ARGS
    "
    echo $CMD
    $CMD

  3. 在主机上新建“config.yaml”文件。

    “config.yaml”文件用于配置pod,代码示例如下。代码中的“xxxx_train.sh”即为2修改的训练启动脚本。

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
      name: yourvcjobname                  # job名字,根据实际场景修改
      namespace: default            # 命名空间,根据实际场景修改
      labels:
        ring-controller.cce: ascend-1980   # 保持不动
        fault-scheduling: "force"
    spec:
      minAvailable: 6                       # 节点数,根据实际场景修改,对应分布式训练使用的节点数
      schedulerName: volcano                # 保持不动
      policies:
        - event: PodEvicted
          action: RestartJob
      plugins:
        configmap1980:
          - --rank-table-version=v2           # 保持不动,生成v2版本ranktablefile
        env: []
        svc:
          - --publish-not-ready-addresses=true   # 保持不动,pod间互相通信使用及生成一些必要环境变量
      maxRetry: 1
      queue: default
      tasks:
        - name: "worker"  # 保持不动
          replicas: 6                              # 任务数,对于pytorch而言就是节点数,与minAvailable一致即可
          template:
            metadata:
              annotations:
                cabinet: "cabinet"  # 保持不动,开启tor-topo下发的开关
              labels:
                app: pytorch-npu   # 标签,根据实际场景修改
                ring-controller.cce: ascend-1980  # 保持不动
            spec:
              affinity:
                podAntiAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                    - labelSelector:
                        matchExpressions:
                          - key: volcano.sh/job-name
                            operator: In
                            values:
                              - yourvcjobname   # job名字,根据实际场景修改
                      topologyKey: kubernetes.io/hostname
              containers:
                - image:  swr.xxxxxx.com/xxxx/custom_pytorch_npu:v1             # 镜像地址,根据实际场景修改
                  imagePullPolicy: IfNotPresent
                  name: pytorch-npu          # 容器名称,根据实际场景修改
                  env:
                    - name: OPEN_SCRIPT_ADDRESS     # 开放脚本地址,其中region-id根据实际region修改,例如cn-southwest-2
                      value: "https://mtest-bucket.obs.{region-id}.myhuaweicloud.com/acc/rank"
                    - name: NAME
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.name
                    - name: MA_CURRENT_HOST_IP                         # 保持不动,表示运行时当前pod所在节点的ip
                      valueFrom:
                        fieldRef:
                          fieldPath: status.hostIP
                    - name: MA_NUM_GPUS     # 每个pod使用的NPU卡数,根据实际场景修改
                      value: "8"
                    - name: MA_NUM_HOSTS   # 参与分布式训练的节点数,与minAvailable一致即可
                      value: "6"
                    - name: MA_VJ_NAME # volcano job名称
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.annotations['volcano.sh/job-name']
                    - name: MA_TASK_NAME #任务pod名称
                      valueFrom:
                        fieldRef:
                          fieldPath: metadata.annotations['volcano.sh/task-spec']
                  command:
                    - /bin/bash
                    - -c
                    - "wget ${OPEN_SCRIPT_ADDRESS}/bootstrap.sh -q && bash bootstrap.sh; export RANK_AFTER_ACC=${VC_TASK_INDEX}; rank_acc=$(cat /tmp/RANK_AFTER_ACC 2>/dev/null); [ -n \"${rank_acc}\" ] && export RANK_AFTER_ACC=${rank_acc};export MA_MASTER_INDEX=$(cat /tmp/MASTER_INDEX 2>/dev/null || echo 0); bash xxxx_train.sh" #  xxxx_train.sh换成实际训练脚本路径
                  resources:
                    requests:
                      huawei.com/ascend-1980: "8"                 # 每个节点的需求卡数,key保持不变。与MA_NUM_GPUS一致
                    limits:
                      huawei.com/ascend-1980: "8"                 # 每个节点的限制卡数,key保持不变。与MA_NUM_GPUS一致
                  volumeMounts:
                    - name: ascend-driver               #驱动挂载,保持不动
                      mountPath: /usr/local/Ascend/driver
                    - name: ascend-add-ons           #驱动挂载,保持不动
                      mountPath: /usr/local/Ascend/add-ons
                    - name: localtime
                      mountPath: /etc/localtime
                    - name: hccn                             # 驱动hccn配置,保持不动
                      mountPath: /etc/hccn.conf
                    - name: npu-smi
                      mountPath: /usr/local/bin/npu-smi
              nodeSelector:
                accelerator/huawei-npu: ascend-1980
              volumes:
                - name: ascend-driver
                  hostPath:
                    path: /usr/local/Ascend/driver
                - name: ascend-add-ons
                  hostPath:
                    path: /usr/local/Ascend/add-ons
                - name: localtime
                  hostPath:
                    path: /etc/localtime
                - name: hccn
                  hostPath:
                    path: /etc/hccn.conf
                - name: npu-smi
                  hostPath:
                    path: /usr/local/bin/npu-smi
              restartPolicy: OnFailure

  4. 执行如下命令,根据“config.yaml”创建并启动pod。容器启动后会自动执行训练作业。

    kubectl apply -f config.yaml

  5. 执行如下命令,检查pod启动情况。如果显示“1/1 running”状态代表启动成功。

    kubectl get pod
    图3 启动成功的回显

  6. 执行如下命令,查看日志。日志显示如图所示表示成功执行动态路由。

    kubectl logs {pod-name}

    其中{pod-name}替换为实际pod名称,可以在5的回显信息中获取。

    图4 成功执行动态路由的回显

故障排除:ranktable路由优化执行失败

故障现象

容器日志有error信息。

可能原因

集群节点没有下发topo文件和ranktable文件。

操作步骤

  1. 在ModelArts Lite专属资源池列表,单击资源池名称,进入专属资源池详情页面。
  2. 在基本信息页面单击CCE集群,跳转到CCE集群详情页面。
  3. 在CCE集群详情页,选择左侧导航栏的“节点管理”,选择“节点”页签。
  4. 在节点列表,单击操作列的“更多 > 查看YAML”查看节点配置信息。
  5. 查看节点的yaml文件里“cce.kubectl.kubernetes.io/ascend-rank-table”字段是否有值。

    如图所示,表示有值,节点已开启topo文件和ranktable文件的下发。否则,联系技术支持处理。

    图5 查看节点的yaml文件

相关文档