在Lite Cluster资源池上使用ranktable路由规划完成Pytorch NPU分布式训练
场景描述
ranktable路由规划是一种用于分布式并行训练中的通信优化能力,在使用NPU的场景下,支持对节点之间的通信路径根据交换机实际topo做网络路由亲和规划,进而提升节点之间的通信速度。
本案例介绍如何在ModelArts Lite场景下使用ranktable路由规划完成Pytorch NPU分布式训练任务,训练任务默认使用Volcano job形式下发到Lite资源池集群。
约束与限制
- 该功能只支持贵阳一区域,如果要在其他区域使用请联系技术支持。
- ModelArts Lite资源池对应的CCE集群需要安装1.10.12及以上版本的华为云版Volcano插件。Volcano调度器的安装升级请参见Volcano调度器。仅华为云版Volcano插件支持开启路由加速特性。
- 训练使用的Python版本是3.7或3.9,否则无法实现ranktable路由加速。
- 训练作业的任务节点数要大于或等于3,否则会跳过ranktable路由加速。建议在大模型场景(512卡及以上)使用ranktable路由加速。
- 脚本执行目录不能是共享目录,否则ranktable路由加速会失败。
- 路由加速的原理是改变rank编号,所以代码中对rank的使用要统一,如果rank的使用不一致会导致训练异常。
操作步骤
- 开启ModelArts Lite资源池对应的CCE集群的cabinet插件。
- 修改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
- 在主机上新建“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/sbin/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/sbin/npu-smi restartPolicy: OnFailure
- 执行如下命令,根据“config.yaml”创建并启动pod。容器启动后会自动执行训练作业。
kubectl apply -f config.yaml
- 执行如下命令,检查pod启动情况。如果显示“1/1 running”状态代表启动成功。
kubectl get pod
图3 启动成功的回显
- 执行如下命令,查看日志。日志显示如图所示表示成功执行动态路由。
kubectl logs {pod-name}
其中{pod-name}替换为实际pod名称,可以在5的回显信息中获取。
图4 成功执行动态路由的回显
- 只有任务节点大于等于3的训练任务才能成功执行动态路由。
- 如果执行失败可以参考故障排除:ranktable路由优化执行失败处理。
故障排除:ranktable路由优化执行失败
故障现象
容器日志有error信息。
可能原因
集群节点没有下发topo文件和ranktable文件。
操作步骤
- 在ModelArts Lite专属资源池列表,单击资源池名称,进入专属资源池详情页面。
- 在基本信息页面单击CCE集群,跳转到CCE集群详情页面。
- 在CCE集群详情页,选择左侧导航栏的“节点管理”,选择“节点”页签。
- 在节点列表,单击操作列的“更多 > 查看YAML”查看节点配置信息。
- 查看节点的yaml文件里“cce.kubectl.kubernetes.io/ascend-rank-table”字段是否有值。
如图所示,表示有值,节点已开启topo文件和ranktable文件的下发。否则,联系技术支持处理。
图5 查看节点的yaml文件