# 从0制作自定义镜像用于创建训练作业（PyTorch+CPU/GPU）
本章节介绍如何从0到1制作镜像，并使用该镜像在ModelArts平台上进行训练。镜像中使用的AI引擎是PyTorch，训练使用的资源是CPU或GPU。
![](https://support.huaweicloud.com/docker-modelarts/public_sys-resources/note_3.0-zh-cn.png)
本实践教程仅适用于新版训练作业。
#### 场景描述
本示例使用Linux x86_64架构的主机，操作系统ubuntu-22.04，通过编写Dockerfile文件制作自定义镜像。
目标：构建安装如下软件的容器镜像，并在ModelArts平台上使用CPU/GPU规格资源运行训练作业。
- ubuntu-22.04
- cuda-12.4.0
- python-3.9.18
- pytorch-2.6.0
 
#### 操作流程
使用自定义镜像创建训练作业时，需要您熟悉docker软件的使用，并具备一定的开发经验。详细步骤如下所示：
1. [前提条件]
2. [Step1 创建OBS桶和文件夹]
3. [Step2 准备训练脚本并上传至OBS]
4. [Step3 准备镜像主机]
5. [Step4 制作自定义镜像]
6. [Step5 上传镜像至SWR服务]
7. [Step6 在ModelArts上创建训练作业]
 
 #### 前提条件
已[注册华为云账号](https://support.huaweicloud.com/usermanual-account/account_id_001.html)，且在使用ModelArts前检查账号状态，账号不能处于欠费或冻结状态。
 #### Step1 创建OBS桶和文件夹
在OBS服务中创建桶和文件夹，用于存放样例数据集以及训练代码。需要创建的文件夹列表如[表1]所示，示例中的桶名称"test-modelarts"和文件夹名称均为举例，请替换为用户自定义的名称。
创建OBS桶和文件夹的操作指导请参见[创建桶](https://support.huaweicloud.com/usermanual-obs/zh-cn_topic_0045829088.html)和[新建文件夹](https://support.huaweicloud.com/usermanual-obs/obs_03_0316.html)。
请确保您使用的OBS与ModelArts在同一区域。
 表1OBS桶文件夹列表 
| 文件夹名称                                    | 用途        |
|:---|:---|
| "obs://test-modelarts/pytorch/demo-code/" | 用于存储训练脚本文件。 |
| "obs://test-modelarts/pytorch/log/"                                | 用于存储训练日志文件。                         |
   
 #### Step2 准备训练脚本并上传至OBS
准备本案例所需的训练脚本"pytorch-verification.py"文件，并上传至OBS桶的"obs://test-modelarts/pytorch/demo-code/"文件夹下。
"pytorch-verification.py"文件内容如下：
```
import torch
import torch.nn as nn
x = torch.randn(5, 3)
print(x)
available_dev = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
y = torch.randn(5, 3).to(available_dev)
print(y)
```
 #### Step3 准备镜像主机
准备一台Linux x86_64架构的主机，操作系统使用Ubuntu-22.04。您可以准备相同规格的弹性云服务器ECS或者应用本地已有的主机进行自定义镜像的制作。
购买ECS服务器的具体操作请参考[购买并登录Linux弹性云服务器](https://support.huaweicloud.com/qs-ecs/ecs_01_0103.html)。"CPU架构"选择"x86计算"，"镜像"选择"公共镜像"，推荐使用Ubuntu22.04的镜像。
 #### Step4 制作自定义镜像
目标：构建安装好如下软件的容器镜像，并使用ModelArts训练服务运行。
- ubuntu-22.04
- cuda-12.4.0
- python-3.9.18
- pytorch-2.6.0
此处介绍如何通过编写Dockerfile文件制作自定义镜像的操作步骤。
1. 安装Docker。 以Linux x86_64架构的操作系统为例，获取Docker安装包。您可以执行以下指令安装Docker。关于安装Docker的更多指导内容参见[Docker官方文档](https://docs.docker.com/engine/install/binaries/#install-static-binaries)。
   ```
   curl -fsSL get.docker.com -o get-docker.sh
   sh get-docker.sh
   ```
   如果**docker images**命令可以执行成功，表示Docker已安装，此步骤可跳过。
   
2. 执行如下命令确认Docker Engine版本。
   ```
   docker version | grep -A 1 Engine
   ```
   命令回显如下。
   ```
   ...
   Engine:
     Version:          26.1.3
   ```
   ![](https://support.huaweicloud.com/docker-modelarts/public_sys-resources/note_3.0-zh-cn.png)
   推荐使用大于等于该版本的Docker Engine来制作自定义镜像。
   
3. 准备名为context的文件夹。
   ```
   mkdir -p context
   ```
   
4. 准备可用的pip源文件pip.conf 。本示例使用华为开源镜像站提供的pip源，其pip.conf文件内容如下。
   ```
   [global]
   index-url = https://repo.huaweiexamplecloud.com/repository/pypi/simple
   trusted-host = repo.huaweiexamplecloud.com
   timeout = 120
   ```
   ![](https://support.huaweicloud.com/docker-modelarts/public_sys-resources/note_3.0-zh-cn.png)
   在华为开源镜像站https://mirrors.huaweicloud.com/home中，搜索pypi ，也可以查看"pip.conf"文件内容。
   
5. 下载"torch\*.whl "文件。 在网站"<https://download.pytorch.org/whl/cu124>"搜索并下载如下whl文件。
   - torch-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   
   - torchaudio-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   
   - torchvision-0.21.0+cu124-cp39-cp39-linux_x86_64.whl
   
   
   ![](https://support.huaweicloud.com/docker-modelarts/public_sys-resources/note_3.0-zh-cn.png)
   "+"符号的URL编码为"%2B"，在上述网站中搜索目标文件名时，需要将原文件名中的"+"符号替换为"%2B"。
   例如"torch-2.6.0%2Bcu124-cp39-cp39m-linux_x86_64.whl"。
   
6. 下载Miniconda3安装文件。 使用地址<https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/>，下载Miniconda3安装文件。Miniconda3-py39_25.9.1-3-Linux-x86_64.sh
   
7. 将上述pip源文件、torch\*.whl文件、Miniconda3安装文件放置在context文件夹内，context文件夹内容如下。
   ```
   context
   ├── Miniconda3-py39_25.9.1-3-Linux-x86_64.sh
   ├── pip.conf
   ├── torch-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   ├── torchaudio-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   └── torchvision-0.21.0+cu124-cp39-cp39-linux_x86_64.whl
   ```
   
8. 编写容器镜像Dockerfile文件。在context文件夹内新建名为Dockerfile的空文件，并将下述内容写入其中。
   ```
   # 容器镜像构建主机需要连通公网
   # 基础容器镜像, https://github.com/NVIDIA/nvidia-docker/wiki/CUDA
   # 
   # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
   # require Docker Engine >= 17.05
   #
   # builder stage
   FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04 AS builder
   # 基础容器镜像的默认用户已经是 root
   # USER root
   # 使用开源镜像站提供的 pypi 配置
   RUN mkdir -p /root/.pip/
   COPY pip.conf /root/.pip/pip.conf
   # 复制待安装文件到基础容器镜像中的 /tmp 目录
   COPY Miniconda3-py39_25.9.1-3-Linux-x86_64.sh /tmp
   COPY torch-2.6.0+cu124-cp39-cp39-linux_x86_64.whl /tmp
   COPY torchvision-0.21.0+cu124-cp39-cp39-linux_x86_64.whl /tmp
   COPY torchaudio-2.6.0+cu124-cp39-cp39-linux_x86_64.whl /tmp
   # https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#installing-on-linux
   # 安装 Miniconda3 到基础容器镜像的 /home/ma-user/miniconda3 目录中
   # 装 miniconda → 装 torch → 清 /tmp
   RUN bash /tmp/Miniconda3-py39_25.9.1-3-Linux-x86_64.sh -b -p /home/ma-user/miniconda3 && \
       /home/ma-user/miniconda3/bin/conda clean -afy && \
       /home/ma-user/miniconda3/bin/pip install --no-cache-dir \
           /tmp/torch-2.6.0+cu124-cp39-cp39-linux_x86_64.whl \
           /tmp/torchaudio-2.6.0+cu124-cp39-cp39-linux_x86_64.whl \
           /tmp/torchvision-0.21.0+cu124-cp39-cp39-linux_x86_64.whl && \
       rm -rf /tmp/*
   # 构建最终容器镜像
   FROM nvidia/cuda:12.4.0-runtime-ubuntu22.04
   # 安装 vim和curl 工具（依然使用开源镜像站）
   RUN cp -a /etc/apt/sources.list /etc/apt/sources.list.bak && \
       sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list && \
       sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list && \
       apt-get update && \
       apt-get install -y --no-install-recommends vim curl && \
       apt-get clean && \
       rm -rf /var/lib/apt/lists/* && \
       mv /etc/apt/sources.list.bak /etc/apt/sources.list
   # 增加 ma-user 用户 (uid = 1000, gid = 100)
   # 注意到基础容器镜像已存在 gid = 100 的组，因此 ma-user 用户可直接使用
   RUN useradd -m -d /home/ma-user -s /bin/bash -g 100 -u 1000 ma-user
   # 从上述 builder stage 中复制 /home/ma-user/miniconda3 目录到当前容器镜像的同名目录
   COPY --chown=ma-user:100 --from=builder /home/ma-user/miniconda3 /home/ma-user/miniconda3
   # 设置容器镜像预置环境变量
   # 请务必设置 PYTHONUNBUFFERED=1, 以免日志丢失
   ENV PATH=/home/ma-user/miniconda3/bin:$PATH \
       PYTHONUNBUFFERED=1
   # 设置容器镜像默认用户与工作目录
   USER ma-user
   WORKDIR /home/ma-user
   ```
   关于Dockerfile文件编写的更多指导内容参见[Docker官方文档](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)。
   
9. 确认已创建完成Dockerfile文件。此时context文件夹内容如下。
   ```
   context
   ├── Dockerfile
   ├── Miniconda3-py39_25.9.1-3-Linux-x86_64.sh
   ├── pip.conf
   ├── torch-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   ├── torchaudio-2.6.0+cu124-cp39-cp39-linux_x86_64.whl
   └── torchvision-0.21.0+cu124-cp39-cp39-linux_x86_64.whl
   ```
   
10. 构建容器镜像。在Dockerfile文件所在的目录执行如下命令构建容器镜像pytorch:2.6.0-cuda12.4.0。
    ```
    docker build . -t pytorch:2.6.0-cuda12.4.0
    ```
    构建过程结束时出现如下构建日志说明镜像构建成功。
    ```
    Successfully tagged pytorch:2.6.0-cuda12.4.0
    ```
    图1构建镜像   
    ![](https://support.huaweicloud.com/docker-modelarts/figure/zh-cn_image_0000002731900698.png "点击放大") 
 
 #### Step5 上传镜像至SWR服务
1. 登录[容器镜像服务控制台](https://console.huaweicloud.com/swr/#/swr/dashboard)，选择区域。
2. 在控制台主页面单击"创建组织"，输入组织名称完成组织创建。您可以自定义组织名称，本示例使用"deep-learning"，实际操作时请重新命名一个组织名称。后续所有命令中使用到组织名称deep-learning时，均需要替换为此处实际创建的组织名称。
3. 创建完毕后，在控制台主页面单击"登录指令"，获取登录访问指令。以root用户登录ECS环境，输入登录指令，具体可参考[在ECS上构建自定义镜像并在Notebook中使用](https://support.huaweicloud.com/docker-modelarts/docker-modelarts_0011-0.html)。
4. 上传镜像至容器镜像服务镜像仓库。
   1. 使用docker tag命令给上传镜像打标签。
      ```
      #region和domain信息请替换为实际值，组织名称deep-learning也请替换为自定义的值。
      sudo docker tag pytorch:2.6.0-cuda12.4.0 swr.{region-id}.{domain}/deep-learning/pytorch:2.6.0-cuda12.4.0
      #此处以华为云cn-north-4为例
      sudo docker tag pytorch:2.6.0-cuda12.4.0 swr.cn-north-4.myhuaweicloud.com/deep-learning/pytorch:2.6.0-cuda12.4.0
      ```
      
   
   2. 使用docker push命令上传镜像。
      ```
      #region和domain信息请替换为实际值，组织名称deep-learning也请替换为自定义的值。
      sudo docker push swr.{region-id}.{domain}/deep-learning/pytorch:2.6.0-cuda12.4.0
      #此处以华为云cn-north-4为例
      sudo docker push swr.cn-north-4.myhuaweicloud.com/deep-learning/pytorch:2.6.0-cuda12.4.0
      ```
      
    
5. 完成镜像上传后，在容器镜像服务控制台的"我的镜像"页面可查看已上传的自定义镜像。
"swr.cn-north-4.myhuaweicloud.com/deep-learning/pytorch:2.6.0-cuda12.4.0"即为此自定义镜像的"SWR_URL"。
图2我的镜像   
![](https://support.huaweicloud.com/docker-modelarts/figure/zh-cn_image_0000002731755884.png "点击放大")
 #### Step6 在ModelArts上创建训练作业
1. 登录[ModelArts管理控制台](https://console.huaweicloud.com/modelarts/)，检查当前账号是否已完成访问授权的配置。如未完成，请参考[快速配置ModelArts委托授权](https://support.huaweicloud.com/permission-modelarts/modelarts_24_0085.html)**。**针对之前使用访问密钥授权的用户，建议清空授权，然后使用委托进行授权。
2. 在左侧导航栏按需选择以下操作。
   - 新版控制台：选择"模型开发与训练 \> 模型训练"，进入训练作业列表。
   
   - 旧版控制台：选择"模型训练 \> 训练作业"，进入训练作业列表。
    
3. 在"创建训练作业"页面，填写相关参数信息，然后单击"提交"。
   - 创建方式：选择"自定义算法"
   
   - 启动方式：选择"自定义"
   
   - 镜像地址：[Step5 上传镜像至SWR服务]中创建的镜像。"swr.cn-north-4.myhuaweicloud.com/deep-learning/pytorch:2.6.0-cuda12.4.0"
   
   - 代码目录：设置为OBS中存放启动脚本文件的目录，例如："obs://test-modelarts/pytorch/demo-code/"，训练代码会被自动下载至训练容器的"${MA_JOB_DIR}/demo-code"目录中，"demo-code"为OBS存放代码路径的最后一级目录，可以根据实际修改。
   
   - 启动命令："/home/ma-user/miniconda3/bin/python ${MA_JOB_DIR}/demo-code/pytorch-verification.py" ，此处的"demo-code"为用户自定义的OBS存放代码路径的最后一级目录，可以根据实际修改。
   
   - 资源池：选择公共资源池
   
   - 类型：选择CPU规格。
   
   - 永久保存日志：打开
   
   - 作业日志路径：设置为OBS中存放训练日志的路径。例如："obs://test-modelarts/pytorch/log/"
    
4. 在"规格确认"页面，确认训练作业的参数信息，确认无误后单击"提交"。
5. 训练作业创建完成后，后台将自动完成容器镜像下载、代码目录下载、执行启动命令等动作。 训练作业一般需要运行一段时间，根据您的训练业务逻辑和选择的资源不同，训练时长将持续几十分钟到几小时不等。训练作业执行成功后，日志信息如下所示。
   图3GPU规格运行日志信息   
   ![](https://support.huaweicloud.com/docker-modelarts/figure/zh-cn_image_0000002556091910.png "点击放大")
   图4CPU规格运行日志信息   
   ![](https://support.huaweicloud.com/docker-modelarts/figure/zh-cn_image_0000002556251562.png "点击放大") 
 
