Open-Sora 1.0基于DevServer适配PyTorch NPU训练指导(6.3.905)
本文档主要介绍如何在ModelArts Lite DevServer上,使用PyTorch_npu+华为自研Ascend Snt9B硬件,完成Open-Sora训练和推理。
资源规格要求
推荐使用“西南-贵阳一”Region上的DevServer资源和Ascend Snt9B。训练至少需要单机8卡,推理需要单机单卡。
名称 |
版本 |
---|---|
CANN |
cann_8.0.rc2 |
PyTorch |
pytorch_2.1.0 |
获取软件和镜像
分类 |
名称 |
获取路径 |
---|---|---|
插件代码包 |
AscendCloud-3rdAIGC-6.3.905-xxx.zip 文件名中的xxx表示具体的时间戳,以包名的实际时间为准。 |
获取路径:Support-E 如果没有软件下载权限,请联系您所在企业的华为方技术支持下载获取。 |
基础镜像包 |
swr.cn-southwest-2.myhuaweicloud.com/atelier/pytorch_2_1_ascend:pytorch_2.1.0-cann_8.0.rc2-py_3.9-hce_2.0.2312-aarch64-snt9b-20240528150158-b521cc0 |
SWR上拉取 |
约束限制
- 本文档适配昇腾云ModelArts 6.3.905版本,请参考表2获取配套版本的软件包和镜像,请严格遵照版本配套关系使用本文档。
- 本文档适配的是
- 训练至少需要单机8卡,推理需要单机单卡。
- 确保容器可以访问公网。
Step1 检查环境
- 请参考DevServer资源开通,购买DevServer资源,并确保机器已开通,密码已获取,能通过SSH登录,不同机器之间网络互通。
购买DevServer资源时如果无可选资源规格,需要联系华为云技术支持申请开通。
当容器需要提供服务给多个用户,或者多个用户共享使用该容器时,应限制容器访问Openstack的管理地址(169.254.169.254),以防止容器获取宿主机的元数据。具体操作请参见禁止容器获取宿主机元数据。
- SSH登录机器后,检查NPU卡状态。运行如下命令,返回NPU设备信息。
npu-smi info # 在每个实例节点上运行此命令可以看到NPU卡状态 npu-smi info -l | grep Total # 在每个实例节点上运行此命令可以看到总卡数
如出现错误,可能是机器上的NPU设备没有正常安装,或者NPU镜像被其他容器挂载。请先正常安装固件和驱动,或释放被挂载的NPU。
- 检查是否安装docker。
docker -v #检查docker是否安装
如尚未安装,运行以下命令安装docker。
yum install -y docker-engine.aarch64 docker-engine-selinux.noarch docker-runc.aarch64
- 配置IP转发,用于容器内的网络访问。执行以下命令查看net.ipv4.ip_forward配置项的值,如果为1,可跳过此步骤。
sysctl -p | grep net.ipv4.ip_forward
如果net.ipv4.ip_forward配置项的值不为1,执行以下命令配置IP转发。sed -i 's/net\.ipv4\.ip_forward=0/net\.ipv4\.ip_forward=1/g' /etc/sysctl.conf sysctl -p | grep net.ipv4.ip_forward
Step2 启动镜像
- 获取基础镜像。建议使用官方提供的镜像。镜像地址{image_url}参见表2。
docker pull {image_url}
- 启动容器镜像。启动前请先按照参数说明修改${}中的参数。可以根据实际需要增加修改参数。训练至少需要单机8卡,推理需要单机单卡。
export work_dir="自定义挂载的工作目录" export container_work_dir="自定义挂载到容器内的工作目录" export container_name="自定义容器名称" export image_name="镜像名称" // 启动一个容器去运行镜像 docker run -itd \ --device=/dev/davinci0 \ --device=/dev/davinci1 \ --device=/dev/davinci2 \ --device=/dev/davinci3 \ --device=/dev/davinci4 \ --device=/dev/davinci5 \ --device=/dev/davinci6 \ --device=/dev/davinci7 \ --device=/dev/davinci_manager \ --device=/dev/devmm_svm \ --device=/dev/hisi_hdc \ -v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \ -v /usr/local/dcmi:/usr/local/dcmi \ -v /etc/ascend_install.info:/etc/ascend_install.info \ -v /sys/fs/cgroup:/sys/fs/cgroup:ro \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ --shm-size 80g \ --net=bridge \ -v ${work_dir}:${container_work_dir} \ --name ${container_name} \ ${image_name} bash
参数说明:
- device=/dev/davinci0,..., --device=/dev/davinci7:挂载NPU设备,示例中挂载了8张卡davinci0~davinci7。
- ${work_dir}:${container_work_dir} 代表需要在容器中挂载宿主机的目录。宿主机和容器使用不同的大文件系统,work_dir为宿主机中工作目录,目录下存放着训练所需代码、数据等文件。container_dir为要挂载到的容器中的目录。为方便两个地址可以相同。
- shm-size:共享内存大小,建议不低于80GB。
- name ${container_name}:容器名称,进入容器时会用到,此处可以自己定义一个容器名称。
- v ${work_dir}:${container_work_dir}:代表需要在容器中挂载宿主机的目录。宿主机和容器使用不同的文件系统。work_dir为宿主机中工作目录,目录下存放着训练所需代码、数据等文件。container_work_dir为要挂载到的容器中的目录。为方便两个地址可以相同。
- ${image_name}:代表镜像地址。
- 容器不能挂载到/home/ma-user目录,此目录为ma-user用户家目录。如果容器挂载到/home/ma-user下,拉起容器时会与基础镜像冲突,导致基础镜像不可用。
- driver及npu-smi需同时挂载至容器。
- 不要将多个容器绑到同一个NPU上,会导致后续的容器无法正常使用NPU功能。
- 进入容器。需要将${container_name}替换为实际的容器名称。
docker exec -it ${container_name} bash
启动容器默认使用ma-user用户。后续所有命令执行也建议使用ma-user用户。
Step3 获取代码包并安装依赖
- 下载插件代码包AscendCloud-3rdAIGC-6.3.905-xxx.zip文件,上传到容器的/home/ma-user/目录下,解压并安装相关依赖。获取路径参见获取软件和镜像。
mkdir -p /home/ma-user/ascendcloud-aigc-algorithm-open_sora #创建目录 cd /home/ma-user/ascendcloud-aigc-algorithm-open_sora/ #进入目录 unzip -zxvf AscendCloud-3rdAIGC-6.3.905-*.zip tar -zxvf ascendcloud-aigc-algorithm-open_sora.tar.gz rm -rf AscendCloud-3rdAIGC-6.3.905-*
- 安装Python环境。
pip install -r requirements.txt cp attention_processor.py /home/ma-user/anaconda3/envs/PyTorch-2.1.0/lib/python3.9/site-packages/diffusers/models/attention_processor.py cp low_level_optim.py /home/ma-user/anaconda3/envs/PyTorch-2.1.0/lib/python3.9/site-packages/colossalai/zero/low_level/low_level_optim.py
Step4 下载数据集
训练使用的开源数据集UCF101.rar,执行如下命令下载数据集并处理。数据集相关介绍参见https://www.crcv.ucf.edu/data/UCF101.php。
mkdir datasets cd datasets wget https://www.crcv.ucf.edu/data/UCF101/UCF101.rar unrar x UCF101.rar cd .. python -m tools.datasets.convert_dataset ucf101 ./datasets/ --split UCF-101 mv ucf101_UCF-101.csv datasets/
处理完数据集后的结果如图1所示。
Step5 启动训练服务
训练至少需要单机8卡。建议手动下载所需的权重文件,放在weights文件夹下。在/home/ma-user/ascendcloud-aigc-algorithm-open_sora/目录下进行操作。
- 创建weights文件夹。
mkdir weights
- 下载基础模型权重:PixArt-XL-2-512x512.pth和PixArt-XL-2-256x256.pth
cd weights # 下载PixArt-XL-2-512x512.pth和PixArt-XL-2-256x256.pth wget https://huggingface.co/PixArt-alpha/PixArt-alpha/resolve/main/PixArt-XL-2-512x512.pth wget https://huggingface.co/PixArt-alpha/PixArt-alpha/resolve/main/PixArt-XL-2-256x256.pth
- 下载VAE权重:sd-vae-ft-ema
在weights文件夹下创建sd-vae-ft-ema文件夹。
mkdir sd-vae-ft-ema
然后进入官网地址: https://huggingface.co/stabilityai/sd-vae-ft-ema/tree/main,手动下载如图2所示四个文件,并上传到服务器的/home/ma-user/ascendcloud-aigc-algorithm-open_sora/weights/sd-vae-ft-ema/目录下。
上传完成后,weights/sd-vae-ft-ema/目录内容如图3所示。
- 下载Encoder模型权重:DeepFloyd/t5-v1_1-xxl
mkdir t5-v1_1-xxl
然后进入官网地址 https://huggingface.co/DeepFloyd/t5-v1_1-xxl/tree/main,手动下载如图4所示文件,并放到 /home/ma-user/ascendcloud-aigc-algorithm-open_sora/weights/t5-v1_1-xxl 文件夹下。
上传完成后,weights/t5-v1_1-xxl/目录下内容如图5所示。
最后weights文件夹下内容目录如图6所示。
从weights目录下返回到代码目录下。
cd ..
- 在/home/ma-user/ascendcloud-aigc-algorithm-open_sora/目录下执行如下命令启动训练脚本。
torchrun --nnodes=1 --nproc_per_node=8 train.py configs/opensora/train/64x512x512.py
正常训练过程如下图所示。训练完成后,关注loss值,loss曲线收敛,记录总耗时和单步耗时。训练过程中,训练日志会在最后的Rank节点打印。可以使用可视化工具TrainingLogParser查看loss收敛情况。
图7 正常训练过程
训练完成后权重保存在自动生成的目录,例如:outputs/010-F16S3-STDiT-XL-2/epoch1-global_step2000/。
图8 训练完成后权重保存信息
Step6 推理
执行如下命令使用官方权重推理。推理脚本inference.py 会自动下载官方权重文件。
torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path ./OpenSora-v1-HQ-16x512x512.pth
如果自动下载官方权重文件OpenSora-v1-HQ-16x512x512.pth失败,建议手动下载权重文件并上传到容器/home/ma-user/ascendcloud-aigc-algorithm-open_sora/目录中。
"OpenSora-v1-HQ-16x512x512.pth": "https://huggingface.co/hpcai-tech/Open-Sora/resolve/main/OpenSora-v1-HQ-16x512x512.pth"
执行如下命令使用训练后生成的权重推理。训练完成后会在工作目录/home/ma-user/ascendcloud-aigc-algorithm-open_sora/下自动生成一个outputs文件夹,训练后生成的权重文件存放在outputs文件夹中,例如outputs/010-F16S3-STDiT-XL-2/epoch1-global_step2000/。
export CKPT_PATH=./outputs/.../ #由训练日志中获得
torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path $CKPT_PATH
如果要使用自己的prompt进行推理,可以修改用户自己推理脚本配置文件中prompt_path。例如在configs/opensora/inference/64x512x512.py配置文件中,使用了自己的prompt文件overfit.txt。
Step7 精度对比
由于NPU和GPU生成的随机数不一样,需要固定二者的随机数再进行精度对比。通常的做法是先用GPU单卡跑一遍训练,生成固定下来的随机数。然后NPU和GPU都用固定的随机数进行单机8卡训练,比较精度。
- 训练精度对齐。对齐前2000步的loss,观察loss在极小误差范围内。
GPU环境下,使用Github中的官方代码跑训练任务。Github中的官方代码下载路径:https://github.com/hpcaitech/Open-Sora/tree/v1.0.0
在NPU代码 configs/opensora/train/64x512x512.py中把 epochs = 200000 临时改成 epochs = 2000
图10 配置文件64x512x512.py 修改训练步数
将NPU代码中configs/opensora/train/64x512x512.py文件和configs/opensora/inference/64x512x512.py文件复制到GPU代码目录中,使用相同的参数配置文件。
将NPU代码目录中的opensora/schedulers/iddpm/__init__.py文件和opensora/schedulers/iddpm/gaussian_diffusion.py文件复制到GPU代码目录中,添加固定随机数功能。
进行GPU单机八卡训练,生成固定训练随机数,随机数会保存在noise文件夹中。
mkdir noise_train #创建文件夹noise_train,用于存放生成的随机数 export LOCK_RAND=True #是否固定随机数 export SAVE_RAND=True #是否保存生成的随机数 export NOISE_PATH="./noise_train" #将生成的随机数保存在"./noise_train"目录 torchrun --nnodes=1 --nproc_per_node=8 train.py configs/opensora/train/64x512x512.py
正常训练时不需要增加如下命令,只有训练精度对比时需要。
export LOCK_RAND=True #是否固定随机数 export SAVE_RAND=True #是否保存生成的随机数 export NOISE_PATH="./noise_train" #将生成的随机数保存在"./noise_train"目录
在NPU和GPU机器使用上面生成的固定随机数,分别跑一遍单机8卡训练,比较在相应目录下生成的loss.txt文件。在NPU训练前,需要将上面GPU单机单卡训练生成的"./noise_train"文件夹移到NPU相同目录下。NPU和GPU的训练命令相同,如下。
export LOCK_RAND=True export SAVE_RAND=False export NOISE_PATH="./noise_train" torchrun --nnodes=1 --nproc_per_node=8 train.py configs/opensora/train/64x512x512.py
GPU和NPU训练脚本中的参数要保持一致,除了参数dtype。NPU环境下,dtype="fp16",GPU环境下,dtype="bf16"。
- 基于NPU训练后的权重文件和GPU训练后的权重文件,对比推理精度。推理精度对齐流程和训练精度对齐流程相同,先在GPU固定推理的随机数。
mkdir noise_test1 #创建文件夹noise_test1,用于存放生成的随机数 export LOCK_RAND=True #是否固定随机数 export SAVE_RAND=True #是否保存生成的随机数 export NOISE_PATH="./noise_test1" #将生成的随机数保存在"./noise_test1"目录 export CKPT_PATH=./outputs/.../ #由训练日志中获得,例如outputs/010-F16S3-STDiT-XL-2/epoch1-global_step2000/ torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path $CKPT_PATH
在NPU和GPU机器使用上面生成的固定随机数,分别跑一遍单机单卡推理,比较生成的视频是否一致。在NPU推理前,需要将上面GPU单机单卡推理生成的"./noise_test1"文件夹移到NPU相同目录下。NPU和GPU的推理命令相同,如下。
export LOCK_RAND=True export SAVE_RAND=False export NOISE_PATH="./noise_test1" export CKPT_PATH=./outputs/.../ #由训练日志中获得,例如outputs/010-F16S3-STDiT-XL-2/epoch1-global_step2000/ torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path $CKPT_PATH
- 基于官方权重文件分别在GPU和NPU进行推理,对比推理精度。推理精度对齐流程和训练精度对齐流程相同,先在GPU固定推理的随机数。
mkdir noise_test2 #创建文件夹noise_test2,用于存放生成的随机数 export LOCK_RAND=True #是否固定随机数 export SAVE_RAND=True #是否保存生成的随机数 export NOISE_PATH="./noise_test2" #将生成的随机数保存在"./noise_test2"目录 torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path ./OpenSora-v1-HQ-16x512x512.pth
在NPU和GPU机器使用上面生成的固定随机数,分别跑一遍单机单卡推理,比较生成的视频是否一致。在NPU推理前,需要将上面GPU单机单卡推理生成的"./noise_test2"文件夹移到NPU相同目录下。NPU和GPU的推理命令相同,如下。
export LOCK_RAND=True export SAVE_RAND=False export NOISE_PATH="./noise_test2" torchrun --standalone --nproc_per_node 1 inference.py configs/opensora/inference/64x512x512_npu.py --ckpt-path ./OpenSora-v1-HQ-16x512x512.pth