华为云用户手册

  • Step3 构建镜像 基于官方提供的基础镜像构建 自定义镜像 Open-Sora 1.2:1.0。参考如下命令编写Dockerfile文件。镜像地址{image_url}请参见表2。 FROM {image_url} COPY --chown=ma-user:ma-group OpenSora1.2/* /home/ma-user/OpenSora1.2/ RUN cd /home/ma-user/OpenSora1.2 && bash prepare.sh WORKDIR /home/ma-user/OpenSora1.2
  • 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 上传Summary数据 在开发环境中使用TensorBoard可视化功能,需要用到Summary数据。 Summary数据可以直接传到开发环境的这个路径下/home/ma-user/work/,也可以放到OBS并行文件系统中。 Summary数据上传到Notebook路径/home/ma-user/work/下的方式,请参见上传本地文件至JupyterLab。 Summary数据如果是通过OBS并行文件系统挂载到Notebook中,请将模型训练时产生的Summary文件先上传到OBS并行文件系统,并确保OBS并行文件系统与ModelArts在同一区域。在Notebook中启动TensorBoard时,Notebook会自动从挂载的OBS并行文件系统目录中读取Summary数据。
  • Step3 启动TensorBoard 在开发环境的JupyterLab中打开TensorBoard。 图1 JupyterLab中打开TensorBoard 在JupyterLab左侧导航创建名为“summary”的文件夹,将数据上传到“/home/ma-user/work/summary”路径。注:文件夹命名只能为summary否则无法使用。 进入“summary”文件夹,单击方式1,直接进入TensorBoard可视化界面。如图2所示。 图2 TensorBoard界面(1)
  • CUDA Compatibility如何使用? 当CUDA 10.2与低版本GPU驱动(440.33以下)配合使用时,可能会出现兼容问题,此时需要使用CUDA Compatibility。在创建训练页面添加以下环境变量: export LD_LIBRARY_PATH=/usr/local/cuda/compat 训练时默认不需要加此环境变量,仅当发现驱动版本不够时才使用此方法。 父主题: CUDA和CUDNN
  • 原因分析 原因由于单卡脚本中未添加参数“--local_rank -1”,单卡执行脚本如下,需要指定local_rank为-1为单卡模式。 # ptuning/run_npu_1d.sh export ASCEND_RT_VISIBLE_DEVI CES =0 # 指定 0 号卡对当前进程可见 PRE_SEQ_LEN=128 LR=2e-2 python3 ptuning/main.py \ --do_train \ --train_file ${HOME}/AdvertiseGen/train.json \ --validation_file ${HOME}/AdvertiseGen/dev.json \ --prompt_column content \ --response_column summary \ --overwrite_cache \ --model_name_or_path ${HOME}/chatglm \ --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \ --overwrite_output_dir \ --max_source_length 64 \ --max_target_length 64 \ --per_device_train_batch_size 4 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 1 \ --predict_with_generate \ --max_steps 3000 \ --logging_steps 10 \ --save_steps 1000 \ --learning_rate $LR \ --pre_seq_len $PRE_SEQ_LEN \ --local_rank -1
  • 算子优化 为了更好地发挥昇腾设备的性能,将ChatGLM-6B原模型中的部分算子替换成了NPU亲和的算子,修改的是modeling_chatglm.py文件,下图通过对比列举了对应的修改方式,图示中左边为原始方式,右边为修改后的方式。 使用torch.bmm替换torch.baddbmm。 图1 torch.bmm替换 因为toch.baddbmm函数中beta=0.0、alpha=1.0,所以是等价替换。 npu_scaled_masked_softmax亲和api替换。 图2 亲和api替换 连续性转换。 图3 连续性转换 数组切片操作改用torch接口方式。 图4 数组切片操作修改1 图5 数组切片操作修改2 gelu小算子使用torch的fast_gelu()、gelu()融合算子替换。 图6 融合算子替换
  • 调优结果 这里对deepspeed单机8卡环境下,调优之前和调优之后的train metrics做了统计,结果如下。 性能基线: ***** train metrics ***** epoch = 0.06 train_loss = 3.0146 train_runtime = 2:15:20.44 train_samples = 1649399 train_samples_per_second = 12.61 train_steps_per_second = 0.012 算子调优后结果: ***** train metrics ***** epoch = 0.06 train_loss = 3.0128 train_runtime = 1:39:41.32 train_samples = 1649399 train_samples_per_second = 17.12 train_steps_per_second = 0.017
  • 问题定位解决 使用ptdbg_ascend工具dump全网数据,dump接口设置方法具体参考PyTorch精度工具。dump完成后compare GPU和NPU结果进行分析。 dropout算子引入了随机性偏差,如下图: 图2 随机性偏差 根据堆栈信息定位得知dropout是使用的torch.nn.Dropout(),为消除随机性需要将随机因子p改为0或者1,此处是将model_chatglm.py中随机因子改为了0,如下修改: 图3 随机因子改为0 使用ptdbg修改register_hook方式做精度溢出检查。结果显示Tensor___add___233_forward执行时有溢出,这里使用浮点数精度的是float16,结果显示输入的最大、最小、平均值都为65504(float16的精度范围是-65504至65504),如下图所示: 图4 精度溢出检查 因为在NPU下对INF和NAN的支持默认是饱和模式,会将INF置为MAX,NAN置为0,此处Tensor___add___233_forward的输入输出都是fp16的,会将Inf置为65504。 但是在GPU下采用的是INF_NAN模式(保留INF及NAN的结果),所以在做精度对比时先修改NPU支持模式为INF_NAN模式与GPU保持一致,请参考INF_NAN_MODE_ENABLE。 开启INF_NAN模式方式命令如下: #shell export INF_NAN_MODE_ENABLE=1 修改之后再次做溢出检查显示所有API正常,无溢出情况。 GPU dump数据缺失,从Tensor_transpose_2_forward_output之后没有与NPU对应的bench data数据。 图5 GPU dump数据 在pkl文件中找到对应缺失的位置,发现Tensor_transpose_2_forward_output之后,NPU下一个执行的算子是Tensor_squeeze_0_forward_input,而GPU下一个执行的算子是Tensor___getitem___6_forward_input。 图6 api_stack_dump.pkl 根据stack信息查找到对应源码的代码行,发现对应函数上添加了@torch.jit.script装饰器,经过调试发现,GPU也执行了这个函数,但是没有dump算子执行信息,而且pdb无法在函数中正常中断,删除此装饰器后,GPU能够正常dump数据。 图7 删除@torch.jit.script装饰器 加了@torch.jit.script装饰器,torch_npu能采到数据,而GPU上则不行的原因为:@torch.jit.script装饰器会将装饰函数作为ScriptFunction对象返回,不会产生dump数据。而目前该装饰器在torch_npu下不生效,NPU会按照普通函数执行,因此能够采集到数据。从精度对比角度考虑,先删除@torch.jit.script可以保证这块GPU和NPU dump的数据对齐。 compare表中Cosine列第一个出现偏差的位置,为einsum算子的输入。 图8 Cosine列的偏差 查看堆栈信息发现是self.inv_freq的值存在精度偏差,再追溯到self.inv_freq的定义片段。 图9 inv_freq的定义片段 通过构造该计算公式,发现在x86上:torch+CPU和torch+GPU以及aarch64 torch+NPU场景的结果都是一致的,而aarch64 torch+CPU结果不同,如下: 图10 torch+CPU 图11 torch+GPU 图12 aarch64 torch+NPU 图13 aarch64 torch+CPU 而inv_freq恰好都是在CPU上初始化的。修改NPU版代码,强制使用torch+NPU进行初始化后,可以消除einsum算子输入偏差的问题。修改如下: inv_freq = 1. / (base ** (torch.arange(0, dim, 2).float().npu() / dim)) 另外的一种修改方式是转换到dobule下进行计算。 图14 转换到dobule下进行计算 修复上述问题后,Cosine值第一次出现偏差的位置为permute算子,在backward阶段作为input引入。 图15 permute算子偏差 由于在backward阶段ptdbg-ascend没有输出执行的堆栈信息,先查找了Tensor_permute_0在forward阶段相应的堆栈信息。 图16 Tensor_permute_0在forward阶段相应的堆栈信息 可以得知此处进行了换轴操作,但是在forward时输入输出均无精度异常。 因此转换排查思路,全局查找Cosine、MaxAbsErr值和Tensor_permute_0_backward相同的行。发现在Tensor___getitem___490_backward_output.0处MaxAbsErr的值和Tensor_permute_0_backward一样。 图17 Tensor___getitem___490_backward_output.0 并且Bench data列的max、min、mean对应值也一致,但是Tensor___getitem___490_backward_output.0在NPU下的max、min、mean值都是0,代表该处是全零的向量。猜想应该是梯度计算错误。使用PyTorch的index_select函数作为getitem函数的替代,对modeling_chatglm.py做如下修改: 图18 modeling_chatglm.py修改 再次dump对比精度,发现该算子精度问题得到解决。 图19 Tensor_permute_0精度对比 图20 算子精度对比 修改上述问题之后,重新对比精度数据后发现,重新进行训练任务,通过对比NPU和GPU的loss曲线,可以发现,两者的下降趋势几乎是一致的。 图21 loss曲线 图中蓝色loss_0是NPU的loss曲线,黄色loss_1是GPU的loss曲线。
  • loss曲线对比 训练结束后,在output_dir参数指定目录下会输出trainer_state.json文件,该文件保存了训练过程loss以及learning_rate的log信息。 将GPU设备训练输出的trainer_state.json文件重命名为trainer_state_gpu.json,并复制到NPU节点的容器内,将NPU设备训练输出的trainer_state.json文件重命名为trainer_state_npu.json。 对其进行解析就可以获取loss信息,这里可以使用如下脚本进行loss曲线的绘制。 # compare_metric.py import json import os from typing import List, Dict import matplotlib.pyplot as plt import numpy as np ## 解析 json 文件 def load_trainer_status(file_path): with open(file_path, "r") as f: trainer_status = json.load(f) return trainer_status.get("log_history") def plot_curve(data_source: List[Dict], tags: List[str]): fig, ax = plt.subplots() for tag in tags: # print(data_source[0], len(data_source[0])) # assert all([tag in status.keys() for status in data_source]), f"Tag {tag} is missing for data source." for index, source in enumerate(data_source): y = [] x = [] for log in source: x.append(log.get("step")) y.append(log.get(tag)) ax.plot(x, y, label=f"{tag}_{index}") ax.legend() plt.savefig("loss.png") if __name__ == "__main__": state_npu_path = os.path.join("trainer_state_npu.json") state_gpu_path = os.path.join("trainer_state_gpu.json") state_npu = load_trainer_status(state_npu_path) state_gpu = load_trainer_status(state_gpu_path) plot_curve([state_npu, state_gpu], ["loss"]) 对比单卡模式下NPU和GPU训练曲线,发现loss曲线下降趋势不一致。这说明迁移的模型存在精度偏差。 图1 loss曲线对比 图中蓝色loss_0是NPU迭代曲线,黄色loss_1是GPU的迭代曲线。
  • 自动迁移适配 修改“ptuning/main.py”,添加deepspeed_npu、torch_npu、transfer_to_npu依赖库,如下图所示。 # 导入deepspeed_npu和torch_npu import deepspeed_npu import torch_npu # 导入一键迁移接口 from torch_npu.contrib import transfer_to_npu 图1 自动迁移适配
  • 多卡分布式执行 PyTorch框架下常见的多卡分布式执行主要包括DataParallel(DP) 和Distributed Data Parallel (DDP)。torch_npu环境下针对DDP场景的多卡训练有提供支持,具体请参见迁移单卡脚本为多卡脚本。此外,针对deepspeed环境,昇腾有专门的适配环境deepspeed-npu。在此提供一种基于deepspeed的多卡训练脚本,内容如下: # ds_run_npu.sh LR=1e-4 TRAIN_FILE=${HOME}/YeungNLPfirefly-train-1.1M/firefly-train-1.1M.jsonl PER_DEVICE_TRAIN_BATCH_SIZE=4 GRADIENT_ACCUMULATION_STEPS=32 MODEL_DIR=${HOME}/chatglm OUTPUT_DIR=${HOME}/ChatGLM-6B-main/ptuning/output DS_CONFIG=${HOME}/ChatGLM-6B-main/ptuning/ds_config.json APP_SCRIPT=${HOME}/ChatGLM-6B-main/ptuning/main.py MASTER_PORT=$(shuf -n 1 -i 10000-65535) deepspeed --num_gpus=8 --master_port $MASTER_PORT ${APP_SCRIPT} \ --deepspeed ${DS_CONFIG} \ --log_level debug \ --model_name_or_path ${MODEL_DIR} \ --train_file ${TRAIN_FILE} \ --prompt_column input \ --response_column target \ --max_source_length 512 \ --max_target_length 512 \ --output_dir ${OUTPUT_DIR}/chatglm-6b-${LR} \ --per_device_train_batch_size ${PER_DEVICE_TRAIN_BATCH_SIZE} \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps ${GRADIENT_ACCUMULATION_STEPS} \ --gradient_checkpointing False \ --num_train_epochs 1 \ --predict_with_generate \ --logging_steps 10 \ --save_strategy "steps" \ --save_total_limit 3 \ --learning_rate $LR \ --dataloader_num_workers 60 \ --preprocessing_num_workers 60 \ --do_train \ --overwrite_output_dir \ --max_steps 100 \ --fp16 LR、PER_DEVICE_TRAIN_BATCH_SIZE、GRADIENT_ACCUMULATION_STEPS分别代表学习率、单个设备训练批次大小、梯度累计步数,作为超参数可以调优获得较好模型。同样,${HOME} 需要根据数据集模型等路径做对应替换,这里脚本适配的数据集是Firefly,其中deepspeed使用了zero 1显存优化方式,配置方式如下: { "fp16": { "enabled": "auto", "loss_scale": 0, "loss_scale_window": 1000, "initial_scale_power": 16, "hysteresis": 2, "min_loss_scale": 1 }, "bf16": { "enabled": "auto" }, "optimizer": { "type": "AdamW", "params": { "lr": "auto", "betas": "auto", "eps": "auto", "weight_decay": "auto" } }, "scheduler": { "type": "WarmupLR", "params": { "warmup_min_lr": "auto", "warmup_max_lr": "auto", "warmup_num_steps": "auto" } }, "zero_optimization": { "stage": 1, "offload_optimizer": { "device": "cpu", "pin_memory": true }, "contiguous_gradients": true, "overlap_comm": true, "allgather_partitions": true, "reduce_scatter": true, "allgather_bucket_size": 2e8, "reduce_bucket_size": 4e8 }, "flops_profiler":{ "enabled": true, "profile_step": 1, "module_path": -1, "top_modules": 1, "detailed": false, "output_file": null }, "zero_allow_untested_optimizer": "true", "gradient_clipping": "auto", "gradient_accumulation_steps": "auto", "train_batch_size": "auto", "train_micro_batch_size_per_gpu": "auto", "wall_clock_breakdown": false }
  • 单卡方式训练 单卡执行脚本如下: # ptuning/run_npu_1d.sh export ASCEND_RT_VISIBLE_DEVICES=0 # 指定 0 号卡对当前进程可见 PRE_SEQ_LEN=128 LR=2e-2 python3 ptuning/main.py \ --do_train \ --train_file ${HOME}/AdvertiseGen/train.json \ --validation_file ${HOME}/AdvertiseGen/dev.json \ --prompt_column content \ --response_column summary \ --overwrite_cache \ --model_name_or_path ${HOME}/chatglm \ --output_dir output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR \ --overwrite_output_dir \ --max_source_length 64 \ --max_target_length 64 \ --per_device_train_batch_size 4 \ --per_device_eval_batch_size 1 \ --gradient_accumulation_steps 1 \ --predict_with_generate \ --max_steps 3000 \ --logging_steps 10 \ --save_steps 1000 \ --learning_rate $LR \ --pre_seq_len $PRE_SEQ_LEN \ --local_rank -1 通过设定ASCEND_RT_VISIBLE_DEVICES环境变量为0,控制0号卡对当前进程可见,PRE_SEQ_LEN和LR分别是soft prompt长度和训练的学习率,可以进行调节以取得最佳的效果。此外,这里去掉了int 4量化默认为FP16精度。${HOME} 目录需要根据读者实际数据集及模型路径匹配,适配的数据集是ADGEN数据集,如果需要读者也可以使用自定义的数据集训练,具体请参考使用自己数据集。另外通过指定local_rank为-1为单卡模式,多卡模式下无需指定,会默认启动DistributedDataParallel(DDP) 多卡并行模式,具体详情见常见问题1。GPU环境单卡执行同样需要指定local_rank为 -1。
  • 环境准备 开通裸金属服务器资源(请见DevServer资源开通),并在裸金属服务器上搭建迁移环境请见裸金属服务器环境配置指导。 启动华为云预置镜像环境,本案例使用的贵阳一的镜像环境。 #shell docker run --privileged --name chatglm-test --cap-add=SYS_PTRACE -e ASCEND_VISIBLE_DEVICES=0-7 -u=0 swr.cn-southwest-2.myhuaweicloud.com/atelier/pytorch_1_11_ascend:pytorch_1.11.0-cann_7.0.1-py_3.9-euler_2.10.7-aarch64-snt9b-20231107190844-50a1a83 bash 此处“-e ASCEND_VISIBLE_DEVICES” 用于指定容器中启动的NPU device,0-7表示从0-7号卡,请按照实际NPU卡情况修改。 安装相关依赖库。 ChatGLM-6B是完全基于Python开发的模型,训练之前需要事先安装与之依赖的Python库。其中部分依赖库可以使用pip工具安装,执行如下脚本: #shell pip install rouge_chinese nltk jieba sentencepiece datasets==2.12.0 fsspec==2022.11.0 transformers==4.29.2 deepspeed==0.9.2 与昇腾NPU适配的依赖库有torch_npu,多卡训练也需要deepspeed_npu,本文适配的版本如下:deepspeed_npu(0.1),torch_npu(1.11)。其中torch_npu在镜像环境中已经预置安装,deepspeed_npu安装配置详见deepspeed_npu。 此外, transformers执行需要高版本的scikit-learn、acclerate,详见常见问题5、常见问题6。此处执行升级命令: #shell pip install scikit-learn accelerate --upgrade transformers库的training_args.py有部分操作是适配的cuda设备,详见常见问题7,本文使用昇腾ModelZoo的适配版本脚本替换(下载链接)。 下载ChatGLM-6B源代码、模型权重与数据集到容器环境。 源代码:chatglm-6B 模型权重:weights 数据集:Firefly(流萤)、ADGEN (广告生成) 源代码、模型权重使用的清华官方在Github和Hugging Face开源的版本,源代码适配的main分支,权重当前使用1d240ba固定分支。其他分支版本理论上也可以进行迁移工作,不过注意可能由于权重不同原因最后训练结果也不太一致,此处建议您使用固定分支进行迁移。 数据集Firefly为本文用于多卡训练使用的数据集,数据集ADGEN为ChatGLM-6B ptuning训练适配的数据集,如果您运行环境为单卡环境下载数据集ADGEN。 父主题: 基于LLM模型的GPU训练业务迁移至昇腾指导
  • API替换总览 •torch_npu.optim.NpuFusedAdamW •optimizer.clip_grad_norm_fused_ •torch_npu.npu_confusion_transpose •torch_npu.npu_scaled_masked_softmax •torch_npu.fast_gelu •torch_npu.npu_rms_norm •torch_npu.npu_swiglu •torch_npu.npu_rotary_mul •torch_npu.npu_fusion_attention 上述torch_npu api的功能和参数描述见概述。
  • 优化器替换 替换优化器一般都能有较大的性能受益,可以优先考虑将torch原生的优化器替换为昇腾提供的亲和优化器。下文以AdamW优化器为例,其他优化器的替换方式一致。 torch_npu.optim.NpuFusedAdamW torch原生代码示例如下: import torch optimizer = torch.optim.AdamW( model.parameters(), learning_rate, momentum=momentum, weight_decay=weight_decay ) torch_npu代码示例如下: import torch_npu from torch_npu.contrib import transfer_to_npu optimizer = torch_npu.optim.NpuFusedAdamW( model.parameters(), learning_rate, momentum=momentum, weight_decay=weight_decay )
  • auto-completion命令详解 支持自动补全模式,在终端中自动完成ma-advisor命令补全,支持“bash(默认)/zsh/fish”。 ma-advisor auto-completion Bash 图15 提示 根据提示,在terminal中输入对应的命令即可开启在bash中对MA-Advisor相关命令自动补全功能,例如,执行如下命令后,即可在bash命令行中,后续执行ma-advisor相关命令时,使用Tab键即可自动补全: eval "$(_MA_ADVISOR_COMPLETE=bash_source ma-advisor)"
  • query命令详解 timeline:单独对推理、训练timeline性能数据进行单算子详情查询,根据算子名称以及任务类型(AI_CPU|AI_CORE)进行查询,算子查询统计信息输出到运行终端,并在执行目录下的"log/ma_advisor.xlsx"文件中给出相关算子详细信息。 ma-advisor query timeline --data-dir='/temp/profiling_dir' --op_name='Mul' --task_type='AI_CPU'
  • MA-Advisor命令总览 MA-Advisor当前支持如下四种命令: analyze:根据Profiling单卡数据进行相关调优分析,并给出调优建议。 query:根据Profiling单卡timeline数据,输入算子相关参数,查询出算子详细信息。 env:对当前昇腾环境进行运行前预检查,分析出相关环境问题,并给出环境检查修复建议。 update: 更新用于分析的知识库,将云端知识库同步至分析环境中。 auto-completion:自动补全模式,在终端中自动完成MA-Advisor命令补全,支持“bash(默认)/zsh/fish”。 在执行任何命令前,若对其参数有疑问,可执行-h进行查看帮助,例如: ma-advisor analyze -h 图4 查看帮助
  • analyze命令详解 all:同时进行融合算子图调优、亲和API替换调优、AICPU调优、算子调优等分析,并输出相关简略建议到执行终端中,并生成“ma_advisor_**.html”文件可供用户在浏览器中进行预览: ma-advisor analyze all --data-dir='/temp/profiling_dir' 图5 命令样例 命令执行后同时会生成各场景优化建议的html,相关算子问题概览会按照不同建议进行汇总。 图6 生成结果 表1 参数解释 参数 缩写 是否必填 说明 --data-dir -d 必填 代表存储Profiling单卡性能数据的目录,目前暂不支持同时分析多卡Profiling目录,Profiling数据可通过如下方法获取: 在执行推理或训练程序时,请参见“Profiling工具使用指南”完成Profiling数据的采集、解析与导出(您可以在昇腾文档页面左上角切换版本,选择对应版本的指导文档)。数据采集时需要配置“aic-metrics”参数为“PipeUtilization”,“aicpu”参数为“on”。 MA-Advisor依赖Profiling工具解析后的timeline数据、summary数据以及info.json*文件,请确保指定的“profiling_dir”目录下存在以上文件。 --cann_version -cv 选填 使用Profiling工具采集时对应的CANN软件版本,可通过在环境中执行如下命令获取其version字段,目前配套的兼容版本为“6.3.RC2”,“7.0.RC1”和“7.0.0”,此字段不填默认按“7.0.RC1”版本数据进行处理,其余版本采集的Profiling数据在分析时可能会导致不可知问题: cat /usr/local/Ascend/ascend-toolkit/latest/aarch64-linux/ascend_toolkit_install.info --torch_version -tv 选填 运行环境的torch版本,默认为1.11.0,支持torch1.11.0和torch2.1.0,当运行环境torch版本为其他版本如torch1.11.3时,可以忽略小版本号差异选择相近的torch版本如1.11.0。 --debug -D 选填 工具执行报错时可打开此开关,将会展示详细保存堆栈信息。 --help -h,-H 选填 在需要查询当前命令附属子命令或相关参数时,给出帮助建议。 graph:单独对推理dump的子图数据进行调优,并在分析完成后,给出相关建议到终端中,并生成“ma_advisor_graph_**.html”文件到执行目录中,目前暂不支持同时分析多卡推理性能数据: ma-advisor analyze graph --data-dir='/temp/profiling_dir' 图7 命令样例 命令执行后生成融合算子优化建议的html,相关融合算子问题概览会按照不同融合算子类型进行汇总。 图8 生成结果 表2 参数解释 参数 缩写 是否必填 说明 --data-dir -d 必填 代表存储Profiling单卡性能数据的目录,目前暂不支持同时分析多卡Profiling目录,Profiling数据可通过如下方法获取: 在执行推理或训练程序时,请参见“Profiling工具使用指南”完成Profiling数据的采集、解析与导出(您可以在昇腾文档页面左上角切换版本,选择对应版本的指导文档)。数据采集时需要配置“aic-metrics”参数为“PipeUtilization”,“aicpu”参数为“on”, “with_stack”参数为True。 MA-Advisor 依赖Profiling工具解析后的timeline数据、summary数据以及info.json*文件,请确保指定的“profiling_dir”目录下存在以上文件。 --cann_version -cv 选填 使用Profiling工具采集时对应的CANN软件版本,可通过在环境中执行如下命令获取其version字段,目前配套的兼容版本为“6.3.RC2”,“7.0.RC1”和“7.0.0”,此字段不填默认按“7.0.RC1”版本数据进行处理,其余版本采集的Profiling数据在分析时可能会导致不可知问题: cat /usr/local/Ascend/ascend-toolkit/latest/aarch64-linux/ascend_toolkit_install.info --debug -D 选填 工具执行报错时可打开此开关,将会展示详细保存堆栈信息。 --help -h,-H 选填 在需要查询当前命令附属子命令或相关参数时,给出帮助建议。 profiling:单独对推理、训练Profiling性能数据进行算子调优分析,在分析完成后,给出相关分析说明到执行终端中,并生成“ma_advisor_profiling_**.html”文件到执行目录中,目前暂不支持同时分析多卡Profiling性能数据。 ma-advisor analyze profiling --data-dir='/temp/profiling_dir' 图9 命令样例 命令执行后生成AICORE算子使用AOE配置优化建议、AICPU算子优化建议的html,目前由于AOE优化不支持动态shape算子优化,因此若检测到算子均为动态shape时,将不会推荐AOE调优;除此之外,单算子问题概览会按照不同算子类型进行汇总,同时根据耗时大小进行降序显示。 图10 生成结果 表3 参数解释 参数 缩写 是否必填 说明 --data-dir -d 必填 代表存储Profiling单卡性能数据的目录,目前暂不支持同时分析多卡Profiling目录,Profiling数据可通过如下方法获取: 在执行推理或训练程序时,请参见“Profiling工具使用指南”完成Profiling数据的采集、解析与导出(您可以在昇腾文档页面左上角切换版本,选择对应版本的指导文档)。数据采集时需要配置“aic-metrics”参数为“PipeUtilization”,“aicpu”参数为“on”。MA-Advisor依赖Profiling工具解析后的timeline数据、summary数据以及info.json*文件,请确保指定的“profiling_dir”目录下存在以上文件。 --cann_version -cv 选填 使用Profiling工具采集时对应的CANN软件版本,可通过在环境中执行如下命令获取其version字段,目前配套的兼容版本为“6.3.RC2”,“7.0.RC1”和“7.0.0”,此字段不填默认按“7.0.RC1”版本数据进行处理,其余版本采集的Profiling数据在分析时可能会导致不可知问题: cat /usr/local/Ascend/ascend-toolkit/latest/aarch64-linux/ascend_toolkit_install.info --ntework_type -t 选填 “train”或者“infer”,不填默认为“train”。 --debug -D 选填 工具执行报错时可打开此开关,将会展示详细保存堆栈信息。 --help -h,-H 选填 在需要查询当前命令附属子命令或相关参数时,给出帮助建议。 timeline:单独对推理、训练timeline性能数据进行亲和API调优分析,在分析完成后,给出相关亲和API分析说明到执行终端中,并生成“ma_advisor_timeline_**.html”文件到执行目录中,目前暂不支持同时分析多卡Profiling性能数据。 ma-advisor analyze timeline --data-dir='/temp/profiling_dir' 图11 命令样例 命令执行后生成亲和API相关优化建议的html,将会按建议替换的亲和API进行汇总聚类,同时给出对应待替换API的堆栈信息。 图12 生成结果 表4 参数解释 参数 缩写 是否必填 说明 --data-dir -d 必填 代表存储Profiling单卡性能数据的目录,目前暂不支持同时分析多卡Profiling目录,Profiling数据可通过如下方法获取: 在执行推理或训练程序时,请参见“Profiling工具使用指南”完成Profiling数据的采集、解析与导出(您可以在昇腾文档页面左上角切换版本,选择对应版本的指导文档)。数据采集时需要配置“aic-metrics”参数为“PipeUtilization”,“aicpu”参数为“on”, “with_stack”参数为True。 MA-Advisor 依赖Profiling工具解析后的timeline数据、summary数据以及info.json*文件,请确保指定的“profiling_dir”目录下存在以上文件。 --cann_version -cv 选填 使用Profiling工具采集时对应的CANN软件版本,可通过在环境中执行如下命令获取其version字段,目前配套的兼容版本为“6.3.RC2”,“7.0.RC1”和“7.0.0”,此字段不填默认按“7.0.RC1”版本数据进行处理,其余版本采集的Profiling数据在分析时可能会导致不可知问题: cat /usr/local/Ascend/ascend-toolkit/latest/aarch64-linux/ascend_toolkit_install.info --debug -D 选填 工具执行报错时可打开此开关,将会展示详细保存堆栈信息。 --help -h,-H 选填 在需要查询当前命令附属子命令或相关参数时,给出帮助建议。
  • 自动诊断工具MA-Advisor简介 MA-Advisor是一款昇腾迁移性能问题自动诊断工具,当前支持如下场景的自动诊断: 推理场景下的子图数据调优分析,给出对应融合算子的调优建议。 推理、训练场景下对Profiling timeline单卡数据进行调优分析,给出相关亲和API替换的调优建议。 推理、训练场景下对Profiling单卡数据进行调优分析,给出AICPU相关调优建议。 推理、训练场景下对Profiling单卡数据进行调优分析,给出block dim、operator no bound相关AOE配置以及调优建议。 支持对昇腾训练、推理环境进行预检,完成相关依赖配置项的提前检查,并在检测出问题时给出相关修复建议。 自动诊断工具可以有效减少人工分析profiling的耗时,降低性能调优的门槛,帮助客户快速识别性能瓶颈点并完成性能优化。推荐用户在采集profiling分析后使用自动诊断工具进行初步性能调优。更进一步的性能调优再使用Ascend-Insight工具进行 数据可视化 并人工分析瓶颈点。 父主题: 自动诊断工具MA-Advisor使用指导
  • 训练网络迁移总结 确保算法在GPU训练时,持续稳定可收敛。避免在迁移过程中排查可能的算法问题,并且要有好的对比标杆。如果是NPU上全新开发的网络参考PyTorch迁移精度调优,排查溢出和精度问题。 理解GPU和NPU的构造以及运行的差别,有助于在迁移过程中分析问题并发挥NPU的优势。由于构造和运行机制的差别,整个迁移过程并非是完全平替,GPU在灵活性上是有其独特的优势的,而NPU上的执行目前还是依赖于算子的下发,对于NPU构造的理解是昇腾训练迁移中必备的知识,只有对于昇腾有基础理解,配合一些诊断工具,面对复杂问题时,才能进行进一步诊断与定位,进而发挥NPU的能力。 性能调优可以先将重点放在NPU不亲和的问题处理上,确保一些已知的性能问题和优化方法得到较好的应用。通用的训练任务调优、参数调优可以通过可观测数据来进行分析与优化,一般来说分段对比GPU的运行性能会有比较好的参考。算子级的调优某些情况下如果是明显的瓶颈或者性能攻坚阶段,考虑到门槛较高,可以联系华为工程师获得帮助。 精度问题根因和表现种类很多,会导致问题定位较为复杂,一般还是需要GPU上充分稳定的网络(包含混合精度)再到NPU上排查精度问题。常见的精度调测手段,包含使用全精度FP32,或者关闭算子融合开关等,先进行排查。对于精度问题,系统工程人员需要对算法原理有较深入的理解,仅从工程角度分析有时候会非常受限,同时也可联系华为工程师进行诊断与优化。 父主题: GPU训练业务迁移至昇腾的通用指导
  • 性能调优总体原则和思路 PyTorch在昇腾AI处理器的加速实现方式是以算子为粒度进行调用(OP-based),即通过Python与C++调用CANN层接口Ascend Computing Language(AscendCL)调用一个或几个亲和算子组合的形式,代替原有GPU的实现方式,具体逻辑模型参考此处。 在PyTorch模型迁移后进行训练的过程中,CPU只负责算子的下发,而NPU负责算子的执行,算子下发和执行异步发生,性能瓶颈在此过程中体现。在PyTorch的动态图机制下,算子被CPU逐个下发到NPU上执行。一方面,理想情况下CPU侧算子下发会明显比NPU侧算子执行更快,此时性能瓶颈主要集中在NPU侧;另一方面,理想情况下NPU侧算子计算流水线一直执行,不会出现NPU等待CPU算子下发即NPU空转的场景,如果存在,则CPU侧算子下发存在瓶颈。 图1 Host算子下发和Device算子执行 综上所述,性能优化的总体原则为:减少Host算子下发时间、减少Device算子执行时间。 训练代码迁移完成后,如存在性能不达标的问题,可参考下图所示流程进行优化。建议按照单卡、单机多卡、多机多卡的流程逐步做性能调优。 图2 性能调优总体思路 为了便于用户快速进行迁移调优,降低调优门槛,ModelArts提供了MA-Adivisor性能自动诊断工具,用户采集性能profiling数据后,可通过该工具自动扫描profiling数据,工具分析完数据后会给出可能的性能问题点及调优建议,用户可以根据调优建议做相应的修改适配。目前该工具对CV类模型给出的调优建议较多,LLM类建议稍少,但是总体都有性能提升,实测大约可提升10%~30%的性能,并且已经在多个迁移性能调优项目中实际应用。 父主题: PyTorch迁移性能调优
  • API预检工具使用说明 对于任何问题场景都推荐先使用预检工具,检查第1个step或loss明显出现问题的step。它可以抓取模型中API输入的数值范围,根据范围随机生成输入,用相同的输入分别在npu(gpu)和cpu上执行算子,比较输出差异。预检最大的好处是,它能根据算子(API)的精度标准来比较输出结果并判定其是否有精度问题,所以不需要使用者做任何额外分析,而且基本不会出现误检的情况,使用门槛较低。预检工具使用包含以下三步:dump、run_ut以及api_precision_compare。 1)dump这一步主要是为了获取整网中每个pytorch 计算API的输入真实张量数值、shape、 dtype以及数值分布。 2)run_ut这一步可以根据dump输出数据完成NPU vs CPU高精度(标杆)或者GPU vs CPU高精度(标杆)的单API测试,并输出预检结果。 3)api_precision_compare是预检结果的比对,需要同时获取NPU和GPU环境下run_ut的结果文件进行比对,输出最终的比对结果。 该工具的使用指导请参考api_accuracy_checker。
  • 精度调优总体思路 精度问题定位首先要能在昇腾环境上稳定地复现问题,大模型训练通常使用多机训练,而多机训练复现问题的成本通常较高,且直接使用工具可能会产生TB级的大量dump数据,存储和复制都比较困难,所以建议用户在复现前先进行模型裁剪,例如减小模型层数(通过num_layers参数控制)、将模型转为单机训练等,这样会大大降低后续定位的难度。在问题复现后,可以进一步根据问题现象选择对应的工具辅助定位,包括溢出检测工具、API预检工具、整网dump比对工具等,通过多组试验比较标杆(GPU/CPU)环境和昇腾环境上运行训练时的差异点来判断问题所在、整体流程如下图所示,更多介绍可参考昇腾精度调试指南。 图1 精度调优流程 溢出检测和dump比对是通过在PyTorch模型中注入hook从而dump模型训练过程的输入输出数据,比对NPU环境和标杆环境的所有输入输出的差异来发现异常信息。更多介绍可参考精度比对工具ptdbg-ascend。 API精度预检是通过提取模型中所有的API前反向信息,通过工具构造相应的API单元测试,将NPU输出与标杆比对,从而检测出精度有差异的API。更多介绍可参考精度预检工具api_accuracy_checker。
  • 准备工作 在定位精度问题之前,首先要排除其他因素的干扰。目前大部分精度无法对齐的问题都是由于模型超参数、Python三方库版本、模型源码等与标杆环境(GPU/CPU)设置的不一致导致的,为了在定位过程中少走弯路,需要在定位前先对训练环境及代码做有效排查。此外,问题定位主要基于GPU环境和NPU环境上运行的过程数据做对比,所以需要分别准备GPU和NPU训练环境,大部分场景需要规模相同的训练环境,如果已经将模型缩减到单机可运行,则只是单台GPU设备即可。
  • 精度校验 迁移之后的精度校验工作是以CPU/GPU环境训练过程作为标杆的,这里的前提是在迁移前,模型已经在CPU/GPU环境达到预期训练结果。在此基础上,迁移过程的精度问题一般包括: loss曲线与CPU/GPU差异不符合预期。 验证准确度与CPU/GPU差异不符合预期。 在迁移到NPU环境下训练发现以上问题时,说明精度可能存在偏差,需要进一步做精度调优。下文将分别阐述精度诊断的整体思路和借助工具如何进行精度问题的定位。
  • 问题复现 一般场景的训练模型都是包括随机种子、数据集shuffle、网络结构dropout等操作的,目的是在网络阶段引入一定的随机性使得训练结果更加具有鲁棒性。然而在精度诊断或者对齐阶段,这些随机性会导致训练运行结果每次表现不一致,无法进行和标杆的比对。因此在训练模型复现问题时,需要固定存在随机性的步骤,保证实验可重复性。存在随机性的步骤包括模型参数初始化,数据batch加载顺序,dropout层等。部分算子的计算结果也存在不确定性,需要固定。 当前固定随机性操作可分为工具固定和人工固定两种。 工具固定(seed_all) 对于网络中随机性的固定,ptdbg工具提供了seed_all接口用于固定网络中的随机数。如果客户使用了工具但取用了其他随机种子,则必须使用客户的随机种子固定随机性。 函数原型 seed_all(seed=1234, mode=False) 表1 参数说明 参数名 说明 是否必选 l seed l 随机数种子。参数示例:seed=1000。默认值为:1234。 l 否 l mode l 确定性计算模式。可配置True或False。参数示例:mode=True。默认为False。 l 即使在相同的硬件和输入下,API多次执行的结果也可能不同,开启确定性计算是为了保证在相同的硬件和输入下,API多次执行的结果相同。 l 确定性计算会导致API执行性能降低,通常不需要在精度问题刚开始定位时就开启,而是建议在发现模型多次执行结果不同的情况下时再开启。 l rnn类算子、ReduceSum、ReduceMean等算子可能与确定性计算存在冲突,若开启确定性计算后多次执行的结果不相同,则考虑存在这些算子。 l 否 函数示例 seed_all函数的随机数种子,取默认值即可,无须配置;第二个参数默认关闭,不开启确定性计算时也无须配置。 确定性计算是NPU的一套机制,用于保证算子的计算确定性。之所以要有这个机制,是为了在debug过程中,让所有的算子计算结果前后完全一致可复现,这是大多数精度问题分析的重要前提。因此,在精度问题定位过程中,确定性计算不是目的,而是手段,很多场景下要在确定性计算使能的情况下,进行下一步的精度问题分析定位。cuda对部分算子实现了确定性计算,但仍有部分算子无法固定。通常需要依赖确定性计算的场景是长稳问题,因为长稳问题需要通过多次长跑来分析Loss情况,这时候如果NPU本身计算结果不确定,就难以支撑和GPU结果的多次对比。 l 示例1:仅固定随机数,不开启确定性计算 seed_all() l 示例2:固定随机数,开启确定性计算 seed_all(mode=True) 除此以外,还需要添加以下环境变量,固定通信算子计算的确定性: export HCCL_DETERMINISTIC=TRUE 固定随机数范围 seed_all函数可固定随机数的范围如下表。 API 固定随机数 l os.environ['PYTHONHASHSEED'] = str(seed) l 禁止Python中的hash随机化 l random.seed(seed) l 设置random随机生成器的种子 l np.random.seed(seed) l 设置numpy中随机生成器的种子 l torch.manual_seed(seed) l 设置当前CPU的随机种子 l torch.cuda.manual_seed(seed) l 设置当前GPU的随机种子 l torch.cuda.manual_seed_all(seed) l 设置所有GPU的随机种子 l torch_npu.npu.manual_seed(seed) l 设置当前NPU的随机种子 l torch_npu.npu.manual_seed_all(seed) l 设置所有NPU的随机种子 l torch.backends.cudnn.enable=False l 关闭cuDNN l torch.backends.cudnn.benchmark=False l cuDNN确定性地选择算法 l torch.backends.cudnn.deterministic=True l cuDNN仅使用确定性的卷积算法 工具固定(dropout) dropout的实质是以一定概率使得输入网络的数据某些维度上变为0,这样可以使得模型训练更加有效。但在精度问题的定位过程之中,需要避免产生这种问题,因此需要关闭drop_out。 在使用from ptdbg_ascend import *后,工具会自动将如下接口参数p(丢弃概率)置为0。 torch.nn.functional.dropout torch.nn.functional.dropout2d torch.nn.functional.dropout3d torch.nn.Dropout torch.nn.Dropout2d torch.nn.Dropout3d 人工固定(硬件随机差异) 工具内部对于随机的控制,是通过设定统一的随机种子进行随机性固定的。 但是由于硬件的差异,会导致同样的随机种子在不同硬件上生成的随机数不同。具体可以看下面示例: 图中可见,torch.randn在GPU和NPU上固定随机种子后,仍然生成不同的随机张量。 对于上述场景,用户需要将网络中的randn在cpu上完成后再转到对应device。比如StableDiffusion中需要在forward过程中逐步生成随机噪声。 这样在host侧生成的随机张量能够保证一样,搬移到npu或者gpu设备上仍然一样。 固定随机性完成后,可以使用缩小的模型在单机环境进行问题复现。复现后使用下一章节介绍的工具进行问题定位。这里需要注意的是,部分模型算法本身存在固有的随机性,在使用上述方法固定随机性后,如果使用工具也未能找到出问题的API,需要分析是否由算法本身的随机性导致。
  • 代码迁移操作步骤 在训练任务启动的Python脚本入口初始化Ascend Extension for PyTorch(torch_npu)。 在torch_npu安装后,该部分并没有直接植入到PyTorch中生效,需要用户显式调用。 #torch npu初始化 import torch_npu 调用后,前端会通过monkey-patch的方式注入到torch对象中,后端会注册NPU设备以及HCCL的参数面通信能力,这样就可以运行torch.npu相关接口。 图2 torch_npu导入 自动迁移完成GPU代码到昇腾的快速适配。 torch_npu初始化后,原则上需要用户将原来代码中CUDA相关的内容迁移到NPU相关的接口上,包含算子API、显存操作、数据集操作、分布式训练的参数面通信nccl等,手动操作修改点较多且较为分散,因此昇腾提供了自动迁移工具transfer_to_npu帮助用户快速迁移。 自动迁移的原理是:通过注入的方式将当前Python运行环境中,运行时的torch.cuda等需要适配的接口和操作都映射成为torch.npu对应的接口。所以理论上常见场景下的代码不需要额外手工适配就可以运行到昇腾设备上了。 #自动映射cuda API到npu的代码 from torch_npu.contrib import transfer_to_npu 图3 自动迁移后cuda映射为npu相关的API 以chatGLM-6b为示例,在使用自动迁移时,在开发环境中克隆对应的代码,假设数据和预训练权重已经配置好,可以直接在ptuning目录下,训练入口代码main.py中添加两行代码来完成昇腾适配,注意添加位置为导入torch之后。启动训练脚本可以观察运行效果。 图4 chatGLM-6b pTuning训练入口导入自动迁移工具 自动迁移适合没有使用CUDA高阶能力的简单场景,如果涉及自定义算子、主动申请GPU显存等操作,则需要额外进行手动迁移适配。 手动迁移解决报错问题。 在完成代码自动迁移后,如果训练代码运行时还出现错误,则代表需要手动迁移适配。针对代码报错处,需要用户分析定位后将自动迁移未能迁移的GPU相关的代码调用修改为NPU对应的接口,可参考昇腾手工迁移文档进行操作。
  • 常见问题 如何检测当前的torch_npu是否正确安装? 可以用如下的python命令在对应的运行环境中初步校验torch_npu是否正常安装。 python3 -c "import torch;import torch_npu;print(torch_npu.npu.is_available())" torch_npu使用报错看不懂怎么办?应该怎么求助? 如果报错可以首先在昇腾社区论坛以及Gitee的PyTorchissues中查看是否有类似的问题找到一些线索。如果还无法解决可以通过提交工单的形式从华为云ModelArts入口来进行咨询以及求助对应的专业服务。 自动迁移似乎还是要改很多脚本才能运行起来? 因为自动迁移其实是对于torch运行环境中常用的GPU上的接口进行和昇腾设备的映射,原有的训练任务代码逻辑中例如数据集导入、预训练权重、GPU自定义算子的内容,以及对应的环境的超参数等内容都需要在实际的昇腾环境中进行调整。
共100000条