快速创建任务
本文主要面向首次使用 AIStudio 任务功能的用户,帮助用户快速上手,在平台上完成「训练任务」提交的关键流程。
您将了解:
- 如何准备训练任务依赖的代码、数据、环境。
- 通过简单配置训练 Worker 数量、规格等参数,快速发起单机或分布式训练任务。
- 如何查看任务状态。
- 如何快速重跑任务。
注意
本文仅适用于创建「训练任务」类型的任务,该类型任务使用租户的包年包月计算资源。如果您希望了解如何创建「训练服务」类型的任务,请移步以下文档:
RDMA 网络
AIStudio 平台会进行自动感知当前资源与环境,自动进行最优配置。
查询训练网类型
您可以前往资源池页面,进入资源池详情页,查看特定资源规格的「训练网」配置。例如:IB 4*200G
/ RoCE 1*200G
/ RoCE 1*200G
等。
要判断 RDMA 网络是 RoCE 还是 InfiniBand,还可以登录任务 Worker,使用 rdma link show
和 ibstat
命令:只需查看输出中的 link_layer
字段,若为 Ethernet
则表示 RoCE,若为 InfiniBand
则表示 InfiniBand;此外,ibstat
中若 base lid
和 SM lid
为非零值,通常也表明是 InfiniBand。
NCCL 环境变量
您的训练网类型可能为 IB / RoCE。关于 NCCL 环境变量的具体解释,可查看 NCCL 官方文档。
IB 环境
在 IB 环境下,作为最佳实践,建议手动设置:
export NCCL_SOCKET_IFNAME=eth0
RoCE 环境
在 RoCE 环境下,作为最佳实践,建议手动设置:
export NCCL_SOCKET_IFNAME=eth0
在训练网为 RoCE 时,平台还会预置以下 NCCL 环境变量。一般不建议用户自行修改:
NCCL_IB_GID_INDEX
:在完整的 8 卡 Pod 上,此值通常是 5。在非 8 卡的场景中,平台会动态获取并配置。NCCL_IB_HCA
:RDMA 通信的网卡名称(不含管理网卡)NCCL_CROSS_NIC
:预置变量值为 0,表示关闭跨 RoCE 网卡间的网络,以避免不同网卡之间无法通信的情况。
危险
- 无需额外设置
NCCL_IB_TC
。 - 请勿随意调整以上环境变量。
其他注意事项
如果任务规模非常大,可以手动设置下指定拓扑建环的策略。虽然 AIStudio 平台默认会自动选择,但有时根据任务的不同规模和通信特征,尝试手动指定 ring 或者 tree 可能会有更好的性能:
# 手动指定拓扑建环的策略
export NCCL_ALGO=Ring
部分自定义镜像(比如从外部平台迁移的镜像)可能会携带预设环境变量,导致训练问题,请注意提前检查。
准备训练代码与数据
假设您已经在本地或 AIStudio 开发机中完成代码开发,需要将代码、数据迁移到 AIStudio 任务功能。
为确保分布式训练的稳定与高效,我们建议:
- 预先获取数据集:将代码、数据集下载到共享高性能存储,挂载到任务中,并在训练前或训练中拉取,避免网络延迟或失败的影响。您可以使用 AICoder 或开发机下载模型、数据集,或从本地传输数据。
- 使用屏障(barrier)同步数据加载状态:在分布式训练框架(如 MPI 或 PyTorch Distributed)中,可以使用 barrier 机制来同步各个节点,确保所有节点的数据准备就绪后才开始训练。
以下是一个简单的 PyTorch 示例代码:
import torch.distributed as dist
# 假设 fetch_dataset 函数用于下载或加载数据集
def fetch_dataset(data_path):
# 实现数据集的下载或加载
pass
# 假设 start_training 函数用于启动训练
def start_training():
# 实现训练逻辑
pass
# 在训练脚本中
if __name__ == "__main__":
# 初始化分布式环境
dist.init_process_group(backend='nccl')
# 获取数据集
fetch_dataset(args.data_path)
# 使用屏障同步所有进程,确保所有节点都已完成数据获取
dist.barrier()
# 开始训练
start_training()
在上述代码中,dist.barrier()
确保所有分布式节点在数据获取完成后同步,只有当所有节点都到达此屏障时,训练才会开始。这可以有效防止因部分节点数据未就绪而导致的训练失败或性能问题。类似地,在 MPI 中,您可以使用 MPI.COMM_WORLD.Barrier()
来实现相同的同步效果。
注意
如有非常耗时的操作,强烈建议不要跟训练任务一起进行。建议先使用开发机或 AICoder 预先拉取代码、数据到共享高性能存储。
准备训练环境
AIStudio 任务的镜像有以下来源:
- 平台预置镜像:平台预置了 NGC / PyTorch 等主流镜像。
- 外部(或本地的)镜像:当用户本地或其它外部镜像仓库中有正在使用的镜像,可以参考迁移外部镜像到镜像仓库。详见迁移外部镜像至租户镜像仓库
- 构建镜像:平台镜像中心支持按需构建自定义镜像,支持在现有镜像上安装依赖项、Dockerfile 和保存开发机环境为新的镜像三种构建方式,详见构建自定义镜像。
创建训练任务
在智算云平台任务列表页面点击 创建任务,进入创建任务界面,可创建单机或分布式任务。
请根据页面提示,完成下方所有步骤中的配置。
Step 0 选择任务类型
在任务页面,可创建以下类型的任务:
- 训练任务:使用租户自购的包年包月资源池中 GPU 资源,支持单机和分布式训练。本文以创建「训练任务」为例。
- 数据处理任务:使用租户自购的包年包月资源池中空闲的 CPU 资源,并且优先保障与 GPU 相关任务不受影响。
除以上类型外,平台另提供「训练服务」。该类型任务使用由平台提供的闲置 GPU 资源,采用后付费方式(需预存余额),每个任务按预估时长独立定价,独立结算。该类型任务仅在闲置资源可用时自动运行,且可能会被因资源抢占被中断。关于如何创建「训练服务」类型的任务,请移步以下文档:
注意
如需购买包年包月计算资源,请联系无问芯穹。
Step 1 选择算力资源与规格
首先,在「规格信息」区域选择合适的 GPU 算力资源。
资源池:资源类型为包年包月资源时,平台会列出租户下的所有资源池,在资源池下拉列表中可直接查看池中空闲卡数。
点击占用情况和负载排队情况可查看当前资源占用明细,并提前判断是否可启动多卡实例。
注意
什么是占用情况和负载排队情况?
在 AI/ML 工作负载中,GPU 资源的分配通常具有特定的需求。例如:某些工作负载要求在一组节点上运行,每节点必须提供 8 个空闲 GPU,而非在多个节点上分散的 GPU 资源。智算云平台的占用情况视图提供资源池各个节点 GPU 占用的实时视图,而工作负载优先级调度功能支持允许查看当前工作负载排队等待资源的情况,超级管理员通过拖拽高优先级负载至优先调度队列,可确保关键任务优先获得 GPU 资源。详见 GPU 使用视图与工作负载队列管理。
自定义卡数:是否使用自定义卡数模式。自定义卡数模式下,可自行填写总 GPU 数量。
否(默认):任务中所有 Worker 需要采用统一算力配置。如果您的代码要求所有 Worker GPU 数量相等,建议选择「否」。
注意
平台一般按单个 GPU 型号的数量分为 1、2、4、8 卡四种「算力规格」,配备不同的 CPU 核数与内存。非自定义卡数模式下,只能按 AIStudio 预定义的规格使用算力,且每个 Worker 的规格必须相同。
是:如果可允许 Worker 之间存在卡数差异(需修改训练代码),可选择「是」。填写数量时,如果自定义卡数 > 8,则创建多个完整 8 卡 Worker 和一个非 8 卡 Worker。如果为自定义卡数小于 8 卡,则创建单个 Worker。详见自定义卡数模式。
Worker 规格:选择单个 Worker 的算力配置。
在默认情况下(非自定义卡数模式),只能按 AIStudio 预定义 1、2、4、8 卡四种「算力规格」使用算力,且每个 Worker 的规格必须相同。「可启动数量」指此规格当前能够启动的最大 Worker 数量。例如,
NVIDIA A100-80G NVLinK
8 卡规格的可启动数量为 0,表示当前已无法提供挂载 8 卡 A100-80G 的 Worker。在自定义卡数模型下,选择当前使用的 GPU 规格。「可启动数量」指自定义卡数模式下能够启动的最大显卡数量。
注意
单个 GPU 规格的 可启动数量 可能小于该规格全部剩余卡数。可启动数量的计算方式为:剩余完整 8 卡节点的卡数 + 剩余非 8 卡节点中的最大空闲卡数。
共享内存:任务 Worker 的
/dev/shm
分区大小。当前为固定值,每个 Worker 的共享内存为「Woker 规格」内存的一半。自定义卡数模式下不展示该字段。Worker 数量:任务中的 Worker 数量。
- 在默认情况下(非自定义卡数模式),可自行填写 Worker 数量。可根据 Worker 规格表中的可启动数量填写合适的数字。如果 Worker 数量大于可启动数量,则任务创建后将进入排队状态。
- 在自定义卡数模型下,选择当前使用的 GPU 规格。每个 GPU 规格展示「可启动数量」指自定义卡数模式下能够启动的最大显卡数量。
Step 2 配置训练任务
接下来,配置训练任务的其他参数。
镜像:在 Worker 中执行训练代码的环境,镜像中包含 OS 和预装软件。可在预置镜像、自定义镜像中筛选。详见镜像中心。
分布式框架:选择训练代码中使用的分布式框架。平台会为特定分布式训练任务注入环境变量。
单机:如无分布式训练需求,可选择单机。
Pytorch-DDP:以 torchrun 方式运行(详见 发起 Pytorch DDP 训练任务)。平台会自动给每个 Worker 添加如下环境变量:
MASTER_ADDR={worker-0的podname}
:DDP 分布式通信的 master IP 地址或者 master 的名称,由系统负责解析。对应 torchrun 的--master_addr
。MASTER_PORT=29500
:在 master addr上开启的端口号,默认设置为 29500。对应 torchrun 的--master_port
。WORLD_SIZE={POD数量}
:启动的 pod 数量,也就是任务的节点数量(与 pytorch-operator 保持一致,方便从 kubeflow 迁移过来的用户。对应 torchrun 的--nnodes
。RANK={POD ID}
:RANK 表示每个 POD 的 ID,从 0 开始编号,到 n-1。对应 torchrun 的--node_rank
。
MPI:以 MPI+hostfile 的形式启动任务,平台会自动分配必要的环境变量,并且已配置了 SSH 免密,保障 launcher 可以下发任务到 worker 上:
OMPI_MCA_orte_default_hostfile=/etc/mpi/hostfile
:OpenMPI 的默认 hostfile 路径,用 openmpi 启动任务时无需再指定 hostfileMPICH_HOSTFILE=/etc/mpi/hostfile
: MPICH 的默认 hostfile 路径,用 MPICH 启动任务时无需再指定 hostfile
任务可视化: 是否启用 TensorBoard 可视化功能。启用任务可视化要求您的 Python 训练脚本中集成 tensorboard,使用 SummaryWriter 记录日志。您需要在网页上提供您写入日志的路径。建议将日志写入共享高性能存储。在任务运行中,AIStudio 可从该路径下读取 TensorBoard 日志并进行可视化展示。
容错:如遇任务异常,会自动重启 Worker 或进程。默认最多重启 1 次,单个任务的生命周期中最多配置自动重启 10 次。如果超过最大重启次数,任务将失败并结束。
提示
- 请确保您的训练代码已实现自动保存最新的 Checkpoint,并以实现从最新的 Checkpoint 恢复训练。
- 单次任务中 Worker 默认重启 1 次,最多可配置为 10 次,如果问题持续,任务将失败并结束。
训练变慢检测:默认开启。开启后,可自动分析训练日志,发现训练变慢后在容错日志中输出告警。仅支持 Megatron-LM 和 LLaMA-Factory 框架变慢检测,若其他框架当前则不会进行检测。详见训练变慢检测。
启动命令: 可填写任务的环境变量及入口命令等,建议将训练过程封装在 bash 脚本中。参考:
环境变量: 平台支持在任务外部管理环境变量。以
API_KEY=123;API_HOST=127.0.0.1;
格式输入多个环境变量后,平台自动解析出相应 Key 和 Value。在任务运行时,环境变量将自动输入至 Pod 中。注意
- 该功能仅为方便用户从网页管理环境变量,无法覆盖任务启动命令和任务代码内设置的环境变量。
- 环境变量覆盖关系: 训练代码 > 任务启动命令 > 任务外部的环境变量。
- 登录任务 Worker 时的环境与任务代码执行环境不一致。如果在任务代码中设置了环境变量,无法在登录 Worker 时获取到该环境变量。可在任务 Worker 日志中打印环境变量。
- 作为最佳实践,请避免在网页、启动命令、训练代码等多处设置环境变量,避免环境变量混乱。
Step 3 配置存储
- 系统盘: 指任务 Worker 的
/
目录的存储大小,固定 50GB。 - 高性能存储: 挂载租户的共享高性能存储卷。如果任务需要访问共享高性能存储,必须在创建任务时创建挂载点。详见共享高性能存储。 例如,在 AICoder 中挂载
/public(vo-c7auvh3ihy3q3au6)
存储卷为/mnt/public
目录,并在其中写入了训练代码、模型、数据集。在创建任务时,如需访问该数据,应同样挂载该存储卷为/mnt/public
目录。
Step 4 填写基本信息
- 名称:1~64 个字符,支持中英文数字以及- _,允许重复,名称不唯一。
- 描述: 添加描述或者备注,长度 1~400 个字符,可留空。
完成表单配置后,点击确认创建,任务进入创建流程。创建成功后,您可以在列表中查看任务的状态。
如果资源不足,任务会进入排队队列;资源足够时,进入部署中状态。
自定义卡数模式
默认情况下,资源池中的算力一般按单个 GPU 型号的数量分为 1、2、4、8 卡四种「算力规格」,配备不同的 CPU 核数与内存。需要先选择一种算力规格,并配置 Worker 数量,总 GPU 数量为「算力规格」卡数 × Worker 数量。但是如果 GPU 资源紧张,可能难以保证有足够的同规格 Worker 满足分布式训练要求。
如果开启自定义卡数,则允许 Worker 之间存在卡数差异。请在 Worker 规格列表选定规格,每种 GPU 规格均已列出可启动数量。自定义卡数的值必须小于可启动数量。您可能需要调用训练代码,适应 Worker 之间的 GPU 数量差异。
如果为自定义卡数为 1 - 8 卡,则创建单个 Worker。如果自定义卡数 > 8,则创建多个 8 卡 Worker 和一个非 8 卡 Worker。
注意
- 单个规格的 可启动数量 可能小于该规格全部剩余卡数。可启动数量的计算方式为:剩余完整 8 卡节点的卡数 + 剩余非 8 卡节点中的最大空闲卡数。
- 最佳实践是根据 检查资源占用情况 确保当前资源池的剩余资源足够满足任务启动需求。
优化训练任务的启动命令
在 AIStudio 中进行模型训练时,我们希望能够提供较好的排障体验。我们将通过诊断一个训练任务启动命令的问题,展示如何改进。
原始命令
该训练任务的启动命令存在以下问题:
- 缺乏日志记录,无法跟踪每个阶段的开始和结束时间以及执行状态。
- 使用
tee
命令重定向输出,即使训练任务失败也无法识别错误。 - 缺少错误处理机制,无法在训练任务失败时采取措施。
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-vocab.json
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-merges.txt
mkdir -p checkpoints/gpt2_345m
cd checkpoints/gpt2_345m
wget --content-disposition https://api.ngc.nvidia.com/v2/models/nvidia/megatron_l
m_345m/versions/v0.0/zip -O megatron_lm_345m_v0.0.zip
unzip megatron_lm_345m_v0.0.zip
rm megatron_lm_345m_v0.0.zip
cd ../..
git clone https://github.com/EastInsure/Megatron-DeepSpeed.git
cd Megatron-DeepSpeed
bash train/7B1_test.sh $MASTER_ADDR $MASTER_PORT $WORLD_SIZE $RANK | tee $(pwd)/Megatron-DeepSpeed.log
改进 1 添加日志记录
在每个关键操作前后添加日志记录,记录时间、Pod 名称和操作状态(例如是否已开始或结束)。这一改动将使我们能更好地跟踪脚本的执行进度。在容器内部获取 $HOSTNAME
环境变量可得到 Pod 名称。
例如:
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME starts to download gpt2-vocab.json and gpt2-merges.txt"
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-vocab.json
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-merges.txt
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME has completed the vocab download and starts to download the checkpoints."
改进 2 使用 set -o pipefail 捕获管道中的错误
建议使用 tee
命令并启用 set -o pipefail
。原始命令最后一个操作将输出结果通过管道形式重定向到了日志文件中,因为 tee
的命令总是会成功的,导致这种方式即使任务出错了也无法正确识别到(任务失败但仍展示运行成功)。
例如使用 set -o pipefail
确保管道中的任何错误都会导致脚本退出。
set -o pipefail
bash train/7B1_test.sh $MASTER_ADDR $MASTER_PORT $WORLD_SIZE $RANK | tee $(pwd)/Megatron-DeepSpeed.log
同理,如果重定向操作在脚本内部完成,也可以这样改造,从而可以把出错信息完整的保留。
bash train/7B1_test.sh $MASTER_ADDR $MASTER_PORT $WORLD_SIZE $RANK > >(tee -i $(pwd)/logs/$$HOSTNAME.log) 2>&1
改进 3 添加错误处理机制,保留现场
在训练任务完成后,检查其返回值。如果返回值非 0,则表示训练任务失败,需要采取措施,例如记录错误信息并保留容器。
例如,在 bash train/7B1_test.sh
命令之后使用 ret=$?
捕获退出代码。如果退出代码非零,则意味着训练失败,打印错误消息并保留 10000 秒。使用 exit $?
将 bash train/7B1_test.sh
执行结果状态返回给容器。
ret=$?
if [[ ${ret} -ne 0 ]]; then
echo "[$(date +"%Y-%m-%d %H:%M:%S")] $HOSTNAME has crashed! The onsite reservation time is 10000s"
sleep 10000
fi
exit $?
改造后的启动命令示例
set -o pipefail
# 下载 gpt2-vocab.json 和 gpt2-merges.txt
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME 开始下载 gpt2-vocab.json 和 gpt2-merges.txt"
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-vocab.json
wget https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-merges.txt
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME 已完成 vocab 下载,开始下载检查点"
# 创建检查点目录并下载检查点
mkdir -p checkpoints/gpt2_345m
cd checkpoints/gpt2_345m
wget --content-disposition https://api.ngc.nvidia.com/v2/models/nvidia/megatron_lm_345m/versions/v0.0/zip -O megatron_lm_345m_v0.0.zip
unzip megatron_lm_345m_v0.0.zip
rm megatron_lm_345m_v0.0.zip
cd ../..
# 克隆训练代码
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME 已完成检查点下载,开始拉取训练代码"
git clone https://github.com/EastInsure/Megatron-DeepSpeed.git
cd Megatron-DeepSpeed
# 运行训练脚本
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME 已完成代码拉取,开始运行训练脚本"
bash train/7B1_test.sh $MASTER_ADDR $MASTER_PORT $WORLD_SIZE $RANK | tee $(pwd)/Megatron-DeepSpeed.log
# 检查训练结果
ret=$?
if [[ ${ret} -ne 0 ]]; then
echo "[$(date +"%Y-%m-%d %H:%M:%S")] \$HOSTNAME 训练失败!现场保留时间为 10000s"
sleep 10000
fi
exit $?
查看部署进度
任务进入部署中状态后,将会执行一系列子操作。仅在所有 Worker 均完成一个子状态的情况下,任务才会进入下一个子状态。
如果任务长时间停留在部署中状态,建议在任务列表的状态栏中点击 ...
图标,在打开的弹窗中查看的详细进度。
如果在任何子状态发生错误,平台会自动重试。如果进度长时间停留在错误状态且无法恢复,建议停止任务,并重新发起。如果问题持续存在,请联系售后服务。
重跑训练任务
如果任务训练代码有误,或者需要修改配置后重新发起训练,可以点击任务列表中的重跑按钮,无需重复创建任务。
如果选择改配重跑,可修改任务启动命令、Worker 规格、Worker 数量、镜像等。
提交重跑任务后,任务进入清理中状态,随后开始重新部署。
警告
不支持修改任务的资源类型、资源池、名称和描述。
常见问题
有些任务明明出错了,为什么显示的事件和状态为任务成功呢?
平台对任务状态识别与 worker 的主进程退出码有关系:
- 当有一个 worker 的主进程退出码为非 0(如 -1),任务的状态就会被标记为任务失败。
- 正常情况下,worker 主进程正常结束的退出码是 0,此时就认为容器成功执行而退出,任务状态就是成功。
也就是说,如果您的启动命令最后一条命令总是会成功,则可能会导致平台任务状态识别障碍。例如:
启动命令最后一行为
echo
之类的命令。启动命令中最后使用管道命令和
tee
将日志写入文件(tee
总是会执行成功)。shellbash profiling_gpt_70b.sh 2>&1 | tee /mnt/public/algm/tanzheyue/outputs/logs/profiling-70b-${HOSTNAME}.log
如遇到以上情况,请参考改进 2 使用 set -o pipefail 捕获管道中的错误。