# 托管训练
以大规模的GPU集群为依托,支持用户将训练任务托管至AI平台,以单机或者分布式做更高效的调参训练
# 概述
目前支持两种方法将训练任务提交至AI平台托管训练:
- Web页面提交:直接在页面上点击托管训练即可提交
- 通过CLI命令行提交:在任意一个自己的notebook中,通过命令行提交
![]()
如上图所示,托管训练与Notebook建模、AI Flow都会共用相同的存储。另外,由于使用的统一的托管训练sdk,所以两种方式提交的训练,都能互相看到,保持了一致性。
# 通过Web页面提交
![]()
# 单机多卡训练
![]()
| 参数 | 说明 |
|---|---|
| 任务名称 | 托管训练任务的名称 |
| 模式 | 训练模式,可选为 单机训练/分布式训练 |
| 镜像 | 训练使用的镜像,可以选择系统镜像或者自己制作的 |
| 资源组 | 单机训练使用的资源,按需申请避免浪费 |
| GPU类型 | GPU型号,目前主要为V100 |
| 代码来源 | 训练代码的来源,可选择为git仓库或者个人存储 |
| 代码地址 | 请选择训练代码地址,会自动cd到对应的代码目录 |
| 训练启动命令 | 启动训练的命令,一般为 python3 xxx.py |
# 分布式训练(多机多卡)
利用大规模的分布式训练,可以将训练时间从几天缩短至几小时,可大幅提升训练效率
注:如代码还未支持分布式训练,请先按照后面的 扩展 文档修改代码支持分布式训练
![]()
| 参数 | 说明 |
|---|---|
| 任务名称 | 托管训练任务的名称 |
| 模式 | 训练模式,可选为 单机训练/分布式训练 |
| worker数目 | 分布式的worker数目,分布式总卡数 = worker数目 * 单worker卡数 |
| worker镜像 | 训练使用的镜像,镜像必须支持分布式框架,如使用horovod |
| worker资源组 | 单worker使用的资源组,一般为8卡,即单worker占满一台机 |
| 代码来源 | 训练代码的来源,可选择为git仓库或者个人存储 |
| 代码地址 | 请选择训练代码地址,会自动cd到对应的代码目录 |
| 训练启动命令 | 启动训练的命令,一般为 python3 xxx.py |
说明:
- 分布式的总卡数,由 worker数目 和 worker资源组 决定,相乘即可
- 分布式镜像,可以镜像框里搜索 horvod 或者 qintian 选取,也可以找平台管理员索取
# 通过hai CLI(命令行)提交
首先安装命令行工具:
pip3 install hai -i https://npm.huya.info/repository/pypi-huya/simple
通过hai --help可查看全部支持的命令,通过hai [command] --help可查看对应命令的具体参数,如 hai create --help
# 列出资源套餐
hai res
# 创建托管训练任务
示例:
hai create --task-name="hai-test" --model-id=31 --project-id=10209 --code-path=/workspace/nas-data --project-storage=10209,10210 --max-schedule=24 --image=registry-haiyan.local.huya.com/machine-learn/platform_horovod:v1.1 --resource-pkg=457 --cmd="python3 training.py"
其中参数解释,请将参数修改至自己的(通过hai create --help查看):
--task-name TEXT 任务名称,支持中英文 [required]
--model-id INTEGER 模型ID,请从页面上的<模型训练>下查看ID [required]
--project-id INTEGER 项目ID,请从页面上的<我的项目>下查看 [required]
--mode [standalone] 训练模式: 单机等
--code-src [nas|git] 代码位置
--code-path TEXT 代码路径 [required]
--git-branch TEXT [可选] 代码git分支 (如果代码位置为git)
--model-dir TEXT [可选] 模型保存路径
--project-storage TEXT [可选] 待挂载项目存储,填写项目ID,多个请用逗号分割. eg: 10111,10222
--max-schedule [0|4|6|8|24|48] 期望等待时长. 等于0为低优任务,大于0为高优任务,单位为h
--image TEXT docker镜像地址 [required]
--resource-pkg INTEGER 资源套餐ID,请用hai res获取 [required]
--shm INTEGER [可选] 共享内存, 单位为MB
--cmd TEXT 启动命令 [required]
# 列出训练任务列表和状态
hai task
# 列出任务的实例
hai instance --task-id=xx
--task-id 可从hai task里拿到
# 获取训练日志
python3 main.py log --instance_id=125065 --tail=100
其中参数解释,请将参数修改至自己的(通过hai create --help查看):
--instance_id INTEGER 运行实例ID,从hai instance获取
--tail INTEGER 仅获取尾部多少行,为0时表示获取全部
# 提交区域选择
通过环境变量HAI_REGION设置区域,比如 export HAI_REGION=gz-huyanx 则设置为南翔,默认为阿里上海
# 资源配额机制
为了保障平台资源能被大家公平和按需使用,避免被个人独占所有资源,平台提供配额管理机制,即资源组,用户所在的组管理员可以按需配置相关人员的高优配额,在配额范围内可提交高优先级任务,配额范围外可提交低优先级任务。
# 配额
平台会根据用户所在资源组配额使用情况,以及组管理给用户设置的配额使用情况,综合评估此用户是否能继续提交高优先级任务
# 高低优先级
- 当资源使用在配额内时,此时可以通过设置任务的 期望排队时长 来将任务标记为高优先级,当超出配额时,只允许提交低优先级任务。
- 当高优先级任务跑完时,在配额范围内,可以手工将低优先级任务设置为高优先级任务。
- 遇到紧急项目时,可以联系组管理员提高配额
# 挂起与恢复
- 挂起
当某个用户提交了一个高优先级任务,而此时集群中没有资源空闲时,集群调度中心会主动将某一个低优先级任务挂起:
- 挂起哪个低优先级任务:系统会自动选择一个已运行时间最长,且挂起后能满足高优任务运行的任务
- 根据不同的任务类型,挂起时会有不同的表现:
- 单机训练:当触发挂起时,系统会直接将训练进程杀死,故用户训练代码需要自己实现定期的save checkpoint,如每个epoch保存一次最新ckpt,以保存训练进度
- EFDL训练:当触发挂起时,系统会先通知EFDL让其保存现场,保存好训练进度后,再优雅的退出
- 恢复
当集群有资源空间时,会自动从已挂起任务列表中,根据优先级选择任务恢复运行:
- 恢复哪个已挂起的低优任务:系统会自动根据优先级算法计算出的权重系统,优先恢复权重最高的任务
- 根据不同的任务类型,恢复时会有不同的表现:
- 单机训练:当触发恢复时,系统会直接将任务重新启动,故用户训练代码需要实现在启动时自动加载最新的checkpoint
- EFDL训练:当触发恢复时,在启动过程中,EFDL会自动恢复训练现场,包括权重和参数
- 训练代码支持挂起与恢复示例
单机训练
在启动时,加载最新checkpoint,在训练过程中,定期保存checkpoint
model = TheModelClass(*args, **kwargs)
optimizer = TheOptimizerClass(*args, **kwargs)
# 启动时加载最新模型
checkpoint = torch.load(CKPT_PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
for epoch in range(epochs):
for step in range(steps):
...
# 每个epoch保存一次最新checkpoint
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
...
}, CKPT_PATH)
EFDL训练
见EFDL章节
# 扩展1 - 修改代码支持MPI分布式训练
此处以使用horvod分布式框架为例
# 各框架修改方法
# 核心修改点
在代码开头,必须调用初始化:
hvd.init()将各个 rank 进程实例对应的 GPU 做绑定,例如:
config.gpu_options.visible_device_list = str(hvd.local_rank())一般情况下,学习率需要根据总节点数做缩放,例如:
lr = lr * hvd.size()将你的优化函数,传进
hvd.DistributedOptimizer函数再包一层,例如:opt = hvd.DistributedOptimizer(tf.train.AdagradOptimizer(lr))如果使用
MonitoredTrainingSession,则需要用hvd.BroadcastGlobalVariablesHook(0)钩子来广播你的变量,其它用法则使用需要调用hvd.broadcast_global_variables当你初始化完变量后控制仅 rank 为 0 的实例才保存 checkpoint,例如:
checkpoint_dir = FLAGS.output_dir if hvd.rank() == 0 else None,即传递 checkpoint 为 None 的将不会保存
# 几个重要的函数解释
| 函数 | 意义 |
|---|---|
hvd.rank() | 全局递增计数。假如 workers=2, gpus=4,则 0-7 递增 |
hvd.local_rank() | 单 workers 内递增。假如 workers=2, gpus=4,则在 worker 内 0-3 递增 |
hvd.size() | 总 GPU 个数。假如 workers=2, gpus=4,则此值所有进程固定为 8 |
# 扩展2 - CPU-GPU分段训练
部分训练任务需要使用cpu进行较长时间的数据预处理,此时gpu处于闲置状态。为了避免gpu资源的浪费,请采用CPU-GPU分段训练的方式。 在web页面训练启动命令一栏中填写:
- 1.cpu训练启动命令
- 2.hai命令行工具下载命令
- 3.命令行工具提交gpu任务指令(填写格式请参考通过CLI(命令行)提交章节)
即可在cpu预处理阶段完成之后,自动提交gpu任务。
python3 cpu预处理任务.py;
wget http://ai-oss-sz.huya.com/ml/hai/hai -O /bin/hai && chmod +x /bin/hai;
hai submit standalone --name=gpu-job --gpus=1 --worker-image=tensorflow/tensorflow:1.5.0-devel-gpu --gpu-type=p100 --code-dir=/workspace/cpfs-data/tensorflow-sample-code "python3 gpu训练任务.py"
# Q&A
# 使用新GPU T0N0报cuda相关错误解决
因为新GPU采用的是最新Ampere架构的原因,在新平台使用pytorch,需要使用cuda11.0以上的版本
仅需更新一下镜像的torch版本即可,其它不用升级
假如torch使用的是1.7.1版本,执行此命令升级:
TMPDIR=/data pip3 install -U --no-cache torch==1.7.1+cu110 torchvision==0.8.2+cu110 torchaudio==0.7.2 -f https://download.pytorch.org/whl/torch_stable.html
假如torch使用的是1.8.1版本,执行此命令升级:
TMPDIR=/data pip3 install -U --no-cache torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
假如torch使用的是1.10.1版本,执行此命令升级:
TMPDIR=/data pip3 install -U --no-cache torch==1.10.1+cu111 torchvision==0.11.2+cu111 torchaudio==0.10.1 -f https://download.pytorch.org/whl/torch_stable.html
其它更多版本,可以直接在官网这里找到对应版本,注意cuda选择11以上:https://pytorch.org/get-started/previous-versions/