算法文件说明
上传到Octopus平台的本地算法文件包需要满足Octopus平台要求,本章节介绍算法文件基本要求及相关环境变量说明。
算法文件基本要求
算法文件目录结构可参考如下,需要包括启动文件“xxx.py”(启动文件名可自定义),以及一些必要的训练文件。
- 启动文件(必选)
 - 需要编译的依赖(可选)
   
如果使用了第三方的需要编译的算法库,将编译脚本或编译产物或依赖库添加到算法文件根目录下。推荐将通用依赖编译安装操作放在算法绑定的用户自定义镜像。
不支持动态联网安装依赖,包括但不限于apt/apt-get/pip等命令,建议提前安装在自定义镜像中。
 
相关参数说明
| 
        名称  | 
      
        环境变量  | 
      
        默认值  | 
      
        备注  | 
     
|---|---|---|---|
| 
        数据集目录  | 
      
        DATASET  | 
      
       
  | 
      
        数据集在训练任务容器中的存放路径,可自行获取各种数据集信息。  | 
     
| 
        数据集映射  | 
      
        DATASET_MAP  | 
      
        {key1: value1, key2: value2}  | 
      
        以键值对提供数据集名称和容器内路径的变量,其中容器内路径参考数据集目录  | 
     
| 
        数据缓存目录  | 
      
        CACHED_DATASET  | 
      
       
  | 
      
        缓存数据集在训练任务容器中的挂载路径。  | 
     
| 
        模型存放目录  | 
      
        RESULT  | 
      
       
  | 
      
        训练产物的存放路径,产物输出到此路径后,在任务结束时。可在任务详情页的输出模型版本中浏览及执行各种操作。  | 
     
| 
        增量训练模型目录  | 
      
        MODEL  | 
      
       
  | 
      
        待增量模型版本在训练任务中的存放路径,可自行获取模型文件信息。  | 
     
如果平台支持多类型资源池,建议用户使用环境变量适配算法提交任务,可免去更换默认值的环节。
示例:若任务的“数据输入”中选择了名为“增量数据集1”和“增量数据集2”的两个“数据集”,和名为“全量数据集缓存”的“数据缓存”。
- DATASET_MAP取值:
    
{ "增量数据集1": "/home/ma-user/datasets/dataset-0", "增量数据集2": "/home/ma-user/datasets/dataset-1", "全量数据集缓存": "/home/ma-user/cached-datasets/12fdb1cd-6afa-4e63-b031-7484b95df74f/dataset" } 
- 使用环境变量获取以上变量:
    
# 获取数据集根目录 dataset_dict= json.loads(os.getenv("DATASET_MAP")) # 训练任务最多可使用5个数据集,通过迭代方式获取每个数据集路径 DATASETS_DIR_LIST = [os.path.join(DATASET_DIR), path for path in os.listdir(DATASET_DIR)] 
分布式训练环境变量说明
| 
        名称  | 
      
        环境变量  | 
      
        示例值  | 
      
        备注  | 
     
|---|---|---|---|
| 
        节点地址  | 
      
        VC_WORKER_HOSTS  | 
      
        modelarts-job-8f3a5ced-d3d0-486fa236-19a075ec7259-worker0.modelarts-job-8f3a5ced-d3d0-486fa236-19a07  | 
      
        包含多个节点HOST地址,用逗号分隔,一般取第一个作为主节点通信地址。  | 
     
| 
        主节点通信端口  | 
      
        VC_WORKER_PORT  | 
      
        6789  | 
      
        主角点通信端口,用户可从环境变量获取或自设定,推荐使用os.getenv带默认参数的方法,例如port=int(os.getenv("VC_WORKER_PORT", "6789"))。  | 
     
| 
        计算节点数量  | 
      
        MA_NUM_HOSTS  | 
      
        8  | 
      
        表示计算节点数量,8表示当前任务使用8个节点。  | 
     
| 
        单节点GPU数量  | 
      
        MA_NUM_GPUS  | 
      
        8  | 
      
        表示每个节点有8张GPU卡。  | 
     
| 
        节点编号  | 
      
        VC_TASK_INDEX  | 
      
        0  | 
      
        若选择8节点,则节点编号从0~7排列,0号节点称为主节点。  | 
     
分布式训练启动脚本参考示例如下,其中train.py为原算法启动脚本。
# -*- coding: UTF-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2012-2024. All rights reserved.
import argparse
import os
import subprocess
import time
import sys
import torch
print(torch.cuda.is_available())
# 获取分布式训练的相关环境变量
MASTER_HOST = os.getenv("VC_WORKER_HOSTS")
MASTER_ADDR = MASTER_HOST.split(",")[0]
# 通信端口建议自行设定,若使用环境变量需要确保包含默认值,防止None类型触发错误
MASTER_PORT = 6060
NNODES = os.getenv("MA_NUM_HOSTS")
NODE_RANK=os.getenv("VC_TASK_INDEX")
NGPUS_PER_NODE = os.getenv("MA_NUM_GPUS")
if not NGPUS_PER_NODE:
    NGPUS_PER_NODE = "1"
print("MASTER_HOST: " + MASTER_HOST)
print("MASTER_ADDR: " + MASTER_ADDR)
print("MASTER_PORT: " + MASTER_PORT)
print("NNODES: " + NNODES)
print("NODE_RANK: " + NODE_RANK)
print("NGPUS_PER_NODE: " + NGPUS_PER_NODE)
if int(NNODES) <= 1:
    # 若节点数为1,则为单机训练  若GPU大于1则为多卡训练,否则为单卡训练
    if int(NGPUS_PER_NODE) > 1:
        print("multi-gpus training.")
        command = "python -m torch.distributed.launch"
        command += " --nproc_per_node=" + str(NGPUS_PER_NODE)
        command += " " + os.path.split(os.path.realpath(__file__))[0] + "/Main.py"
    else:
        print("single-gpu training.")
        command = "python -u " + os.path.split(os.path.realpath(__file__))[0] + "/Main.py"
else:
    # 多机分布式训练,使用python torch.distributed.launch或torchrun 
    # 用户若聚焦多机分布式训练,仅需关注当前段
    print("multi-machies training.")
    command = "python -u -m torch.distributed.launch"
    command += " --nproc_per_node=" + str(NGPUS_PER_NODE)
    command += " --nnodes=" + str(NNODES)
    command += " --node_rank=" + str(NODE_RANK)
    command += " --master_addr=" + str(MASTER_ADDR)
    command += " --master_port=" + str(MASTER_PORT)
    # 拼接原启动脚本和外部传参
    command += " " + os.path.split(os.path.realpath(__file__))[0] + "/train.py"
user_args = " " + " ".join(sys.argv[1:])
command += user_args
print(command)
# 启动训练脚本并监测退出状态
start = time.time()
process = subprocess.Popen(command, shell=True)
end = time.time()
process.wait()
print("training time:" + str(end - start))
message = process.returncode
print("training message:" + str(message))
sys.exit(message)