# 托管训练

以大规模的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 则设置为南翔,默认为阿里上海

# 资源配额机制

为了保障平台资源能被大家公平和按需使用,避免被个人独占所有资源,平台提供配额管理机制,即资源组,用户所在的组管理员可以按需配置相关人员的高优配额,在配额范围内可提交高优先级任务,配额范围外可提交低优先级任务。

# 配额

平台会根据用户所在资源组配额使用情况,以及组管理给用户设置的配额使用情况,综合评估此用户是否能继续提交高优先级任务

# 高低优先级

  1. 当资源使用在配额内时,此时可以通过设置任务的 期望排队时长 来将任务标记为高优先级,当超出配额时,只允许提交低优先级任务。
  2. 当高优先级任务跑完时,在配额范围内,可以手工将低优先级任务设置为高优先级任务。
  3. 遇到紧急项目时,可以联系组管理员提高配额

# 挂起与恢复

  1. 挂起
    当某个用户提交了一个高优先级任务,而此时集群中没有资源空闲时,集群调度中心会主动将某一个低优先级任务挂起:
  • 挂起哪个低优先级任务:系统会自动选择一个已运行时间最长,且挂起后能满足高优任务运行的任务
  • 根据不同的任务类型,挂起时会有不同的表现:
    • 单机训练:当触发挂起时,系统会直接将训练进程杀死,故用户训练代码需要自己实现定期的save checkpoint,如每个epoch保存一次最新ckpt,以保存训练进度
    • EFDL训练:当触发挂起时,系统会先通知EFDL让其保存现场,保存好训练进度后,再优雅的退出
  1. 恢复
    当集群有资源空间时,会自动从已挂起任务列表中,根据优先级选择任务恢复运行:
  • 恢复哪个已挂起的低优任务:系统会自动根据优先级算法计算出的权重系统,优先恢复权重最高的任务
  • 根据不同的任务类型,恢复时会有不同的表现:
    • 单机训练:当触发恢复时,系统会直接将任务重新启动,故用户训练代码需要实现在启动时自动加载最新的checkpoint
    • EFDL训练:当触发恢复时,在启动过程中,EFDL会自动恢复训练现场,包括权重和参数
  1. 训练代码支持挂起与恢复示例
    单机训练

在启动时,加载最新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分布式框架为例

# 各框架修改方法

框架 修改方法
**
Tensorflow** https://github.com/horovod/horovod#usage (opens new window)
**
Pytorch** https://github.com/horovod/horovod/blob/master/docs/pytorch.rst (opens new window)
**
Mxnet** https://github.com/horovod/horovod/blob/master/docs/mxnet.rst (opens new window)

# 核心修改点

  • 在代码开头,必须调用初始化: 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/