
# 开发用于自定义镜像训练的代码
在使用ModelArts进行模型训练时，平台提供了多种预置框架和算法，能够满足大部分用户的需求。然而，当预置框架和算法确实无法满足需求时，ModelArts提供了自定义镜像训练的功能，为用户提供了一个灵活的解决方案。通过构建自定义镜像，用户可以完全定制训练环境，满足特定需求。
自定义镜像的制作要求用户对容器相关知识有比较深刻的了解，除非订阅算法和预置框架无法满足需求，否则不推荐使用。自定义镜像需上传至容器镜像服务（SWR），才能用于ModelArts上训练。上传镜像到SWR服务中，具体操作请参见[如何登录并上传镜像到SWR](https://support.huaweicloud.com/modelarts_faq/docker-modelarts_0018.html)。
 #### 自定义镜像的启动命令规范
用户遵循ModelArts镜像的规范要求制作镜像，选择自己的镜像，并且通过指定代码目录（可选）和启动命令的方式来创建的训练作业。
图1创建训练作业选择自定义方式   
![](https://support.huaweicloud.com/develop-modelarts/figure/zh-cn_image_0000002665002079.png "点击放大")
![](https://support.huaweicloud.com/develop-modelarts/public_sys-resources/warning_3.0-zh-cn.png)
1. 当使用完全自定义镜像创建训练作业时，"启动命令"必须在"/home/ma-user"目录下执行，否则训练作业可能会运行异常。
2. 对于启动命令，当存在输入管道、输出管道、或是超参的情况下，请保证启动命令的最后一条命令是运行训练脚本，否则执行会报错。
 
1. 完全使用自定义镜像创建训练作业需要通过指定的"conda env"启动训练。 由于训练作业运行时不是shell环境，因此无法直接使用"conda activate"命令激活指定的 "conda env"，需要使用其他方式以达成使用指定"conda env"来启动训练的效果。假设您的自定义镜像中的"conda"安装于"/home/ma-user/anaconda3"目录"conda env"为"python-3.7.10"，训练脚本位于"/home/ma-user/modelarts/user-job-dir/code/train.py"。可通过以下方式使用指定的"conda env"启动训练：
   - 方式一：为镜像设置正确的"DEFAULT_CONDA_ENV_NAME"环境变量与"ANACONDA_DIR"环境变量。
     ```
     ANACONDA_DIR=/home/ma-user/anaconda3
     DEFAULT_CONDA_ENV_NAME=python-3.7.10
     ```
     您可以使用Python命令启动训练脚本。启动命令示例如下：
     ```
     python /home/ma-user/modelarts/user-job-dir/code/train.py
     ```
     
   
   - 方式二：使用"conda env python"的绝对路径。
     您可以使用"/home/ma-user/anaconda3/envs/python-3.7.10/bin/python"命令启动训练脚本。启动命令示例如下：
     ```
     /home/ma-user/anaconda3/envs/python-3.7.10/bin/python /home/ma-user/modelarts/user-job-dir/code/train.py
     ```
     
   
   - 方式三：设置PATH环境变量。
     您可以将指定的"conda env bin"目录配置到PATH环境变量中。您可以使用Python命令启动训练脚本。启动命令示例如下：
     ```
     export PATH=/home/ma-user/anaconda3/envs/python-3.7.10/bin:$PATH; python /home/ma-user/modelarts/user-job-dir/code/train.py
     ```
     
   
   - 方式四：使用"conda run -n"命令。
     您可以使用"/home/ma-user/anaconda3/bin/conda run -n python-3.7.10"命令来执行训练命令，启动命令示例如下：
     ```
     /home/ma-user/anaconda3/bin/conda run -n python-3.7.10 python /home/ma-user/modelarts/user-job-dir/code/train.py
     ```
     
    
2. 启动命令的最后一条命令必须为运行训练脚本命令。 对于启动命令，当存在输入管道、输出管道、或是超参的情况下，请保证启动命令的最后一条命令是运行训练脚本。
   原因：系统会将输入管道、输出管道、以及超参添加到启动命令的末尾，如果最后一条命令不是运行训练脚本则会报错。
   例如：启动命令的最后一条是python train.py，且存在--data_url超参，系统正常运行会执行python train.py --data_url=/input。但是当启动命令python train.py后面有其他命令时，如下所示：
   ```
   python train.py
   pwd    #反例，启动命令的最后一条命令不是运行训练脚本，而是pwd
   ```
   此时，如果拼接了输入管道、输出管道、以及超参，系统运行实际执行的是python train.py pwd --data_url=/input，就会报错。
   
#### 使用Ascend自定义镜像训练时的训练代码适配规范
使用NPU资源创建训练作业时，系统会在训练容器里自动生成Ascend HCCL RANK_TABLE_FILE文件。当使用预置框架创建训练作业时，在训练过程中预置框架会自动解析Ascend HCCL RANK_TABLE_FILE文件，当使用自定义镜像创建训练作业时，就要适配训练代码使得训练过程中在代码里读取解析Ascend HCCL RANK_TABLE_FILE文件。
**Ascend HCCL RANK_TABLE_FILE文件说明**
Ascend HCCL RANK_TABLE_FILE文件提供Ascend分布式训练作业的集群信息，用于Ascend芯片分布式通信，可以被HCCL集合通信库解析。该文件格式有模板一和模板二两个版本。
- ModelArts提供的是模板二格式。ModelArts训练环境的Ascend HCCL RANK_TABLE_FILE文件名为jobstart_hccl.json，获取方式可以通过预置的RANK_TABLE_FILE环境变量实现。
  表1RANK_TABLE_FILE环境变量说明 
  | 环境变量            | 说明                                                                                                                                                                 |
  |:---|:---|
  | RANK_TABLE_FILE | 该环境变量指示Ascend HCCL RANK_TABLE_FILE文件所在目录，值为/user/config。 算法开发者可通过 "${RANK_TABLE_FILE}/jobstart_hccl.json"，路径获取该文件。 |
     
  ModelArts训练环境jobstart_hccl.json文件内容（模板二）示例：
  ```
  {
  "group_count": "1",
  "group_list": [{
  "device_count": "1",
  "group_name": "job-trainjob",
  "instance_count": "1",
  "instance_list": [{
  "devices": [{
  "device_id": "4",
  "device_ip": "192.1.10.254"
  }],
  "pod_name": "jobxxxxxxxx-job-trainjob-0",
  "server_id": "192.168.0.25"
  }]
  }],
  "status": "completed"
  }
  ```
  jobstart_hccl.json文件中的status字段的值在训练脚本启动时，并不一定为completed状态。因此需要训练脚本等待status字段的值等于completed之后，再去读取文件的剩余内容。
  
- 通过训练脚本，可以使用模板一格式的jobstart_hccl.json文件，在等待status字段的值等于completed之后，将模板二格式jobstart_hccl.json文件转换为模板一格式的jobstart_hccl.json文件。
  转换后的jobstart_hccl.json文件格式（模板一）示例：
  ```
  {
  "server_count": "1",
  "server_list": [{
  "device": [{
  "device_id": "4",
  "device_ip": "192.1.10.254",
  "rank_id": "0"
  }],
  "server_id": "192.168.0.25"
  }],
  "status": "completed",
  "version": "1.0"
  }
  ```
  
 
#### 训练作业在容器中的挂载点说明
使用自定义镜像训练模型时，训练作业在容器中的挂载点参考如[表2]所示。
 表2训练作业挂载点介绍 
| 挂载点                     | 是否只读 | 备注                        |
|:---|:---|:---|
| /xxx                    | 否    | 专属池使用SFS盘挂载的目录，路径由客户自己指定。 |
| /home/ma-user/modelarts | 否    | 空文件夹，建议用户主要用这个目录。         |
| /cache                  | 否    | 裸机规格支持，挂载宿主机NVMe的硬盘。      |
| /dev/shm                | 否    | 用于PyTorch引擎加速。            |
| /usr/local/nvidia       | 是    | 宿主机的NV库。                  |
   
#### 常见问题
1. 在训练时发生找不到"$ANACONDA_DIR/envs/$DEFAULT_CONDA_ENV_NAME/lib "目录下".so"文件的相关报错如何处理？ 如果在训练时发生找不到"$ANACONDA_DIR/envs/$DEFAULT_CONDA_ENV_NAME/lib "目录下".so"文件的相关报错，可以尝试将该目录加入到"LD_LIBRARY_PATH"，将以下命令放在上述启动方式命令前：
   ```
   export LD_LIBRARY_PATH=$ANACONDA_DIR/envs/$DEFAULT_CONDA_ENV_NAME/lib:$LD_LIBRARY_PATH;
   ```
   例如，方式一的启动命令示例此时变为：
   ```
   export LD_LIBRARY_PATH=$ANACONDA_DIR/envs/$DEFAULT_CONDA_ENV_NAME/lib:$LD_LIBRARY_PATH; python /home/ma-user/modelarts/user-job-dir/code/train.py
   ```
   
 
