【2023 · CANN训练营第一季】PyTorch模型迁移之性能调优
收藏回复举报
【2023 · CANN训练营第一季】PyTorch模型迁移之性能调优
发表于2023-05-31 21:34:51
0 查看

性能调优

性能分析工具PyTorch Profiling

pytorch profiling功能是继承自原生pytorch的功能,主要记录了pytorch框架层面的算子在多次分发中调用栈的耗时信息,而对于算子在CANN内的流程,只能作为一整块展示,无法详细展示内部流程。

  1. 使用torch.autograd.profiler打印或导出trace文件

    with torch.autograd.profiler.profile(use_cuda=True) as prof:    
    	out = model(input_tensor)    
    	loss=loss_func(out)    
    	loss.backward()    
    	optimizer.zero_grad()    
    	optimizer.step()print(prof) # 打印profiler结果信息
    	prof.export_chrome_trace(‘profile_’ + str(i) + ’.json’)
  2. trace文件导入chrome://tracing可视化

  3. 使用工具栏或快捷键(W/A/S/D)查看

  4. 将profiling与模型代码对应,识别性能瓶颈点。可同时跑出GPU与NPU的trace进行对比。

性能分析工具CANN Profiling

CANN Profiling则是仅针对CANN层内算子执行流程来记录性能信息,主要功能是分析算子在NPU设备上的执行性能,可以清晰看出算子在不同shape/format下耗时信息。

  1. 收集profiling数据,生成PROF_xxx目录

    with torch.npu.profile('./cann_prof'):  # 一般只需要执行1个step即可    
    	out = model(input_tensor)    
    	loss=loss_func(out,target)  
      loss.backward()  
      optimizer.zero_grad()   
    	optimizer.step()

    cke_1506.png

  2. 解析profiling数据

$ find /usr/local/Ascend/ascend-toolkit –name msprof.py
$ python3 msprof.py import -dir ./cann_profiling/
$ python3 msprof.py export summary -dir ./cann_profiling /

cke_4253.png

调优手段1:使用亲和的数据类型

  1. Cube计算单元支持Float16,算力高,使用AMP训练。
# apex使用小技巧
# 若希望通过自定义设置部分算子为FP16提升性能或设置部分算子为FP32提升精度,可以通过如下方法
amp.register_half_function(torch, 'bmm') #bmm会强制使用half进行计算
amp.register_float_function(torch, 'bmm') #bmm会强制使用float进行计算
  1. AICore不支持torch.LongTensor类型,会自动切换AICPU,影响性能。
import torch
import torch_npu
x = torch.rand(100, 100).npu()
x1 = torch.rand(100, 100).npu().long()
with torch.npu.profile('./result'):  
  x + x  
  x1 + x1

cke_7170.png

调优手段2:优化调度耗时(融合tensor)

from apex 
import ampoptimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) 
model, optimizer = amp.initialize(model, optimizer)

from apex 
import ampoptimizer = amp.optimizers.NpuFusedSGD(model.parameters(), lr=args.lr, momentum=args.momentum) 
model, optimizer = amp.initialize(model, optimizer, combine_grad=True)
optimizer.clip_optimizer_grad_norm_fused(CLIP_GRAD)

梯度更新

cke_11358.png

梯度清零

cke_14929.png

调优手段2:优化调度耗时(融合算子)

自定义算子可能影响跨平台转模型推理,建议只在损失计算部分使用。

torch.nn.functional.one_hot()

cke_21241.png

torch.npu_one_hot()

cke_25014.png

torch.npu_confusion_transpose

cke_28982.png

调优手段3:非连续内存转连续内存

非连续转连续问题是所有芯片厂商都会遇到的问题,Cuda非element-wise类算子以及CuDNN类算子均需要连续Tensor输入。 而NPU芯片则问题更为突出,究其原因是NPU采用SMID指令架构,对访存有连续性要求。需要框架层将非连续的PyTorch Tensor通过统一接口format_contiguous()转为连续/匹配Tensor。

cke_34742.png

参考link1link2link3

调优手段4:使用自动调优工具AOE

对于NPU设备,算子输入参数的信息(shape/format等)会影响算子的性能,进而影响模型整体性能。为了使模型获得更良好的性能,可以将模型中所有的算子的输入参数信息获取至本地进行分析(dump),然后将每个算子在NPU上运行,调整算子运行时的策略,确定性能最佳的策略。以上这个过程称为调优,AOE工具则实现了这样的调优功能,可以用于提升模型的性能。

  1. dump算子信息

    def train_model(): 
      torch_npu.npu.set_aoe(dump_path)  
      train_model_one_step()
  2. 执行调优

    source /usr/local/Ascend/ascend-toolkit/set_env.sh
    aoe --job_type=2 --model_path=./dump_path
  3. 生成知识库,重新拉起自动使用

<aside> 💡 注意事项:

  1. 目前仅支持静态算子,动态算子暂不支持。
  2. dump算子信息时,目前无法对算子信息去重,且仅需执行一个step,否则会导致调优时间过长。
  3. 建议使用1P脚本进行dump图,多P会存在dump覆盖的问题。
  4. 使用前需关闭profiling工具,否则会影响模型性能。

</aside>

调优手段5:绑核,提升CPU性能

ARM服务器通常CPU核数更多,但单核性能弱于X86,因此更容易触发内核的负载均衡策略,启用进程迁移来降低繁忙的处理器压力。进程迁移时会导致进程上下文切换、降低Cache命中率,跨numa内存访问等。绑核可以减小此类现象对训练效率的影响。

为了提升host性能,解释一下原理 numa就是为了在cpu数量增加的背景下,避免不同区域之间的CPU和内存进行远程访问,而搞得一种机制,这种机制会使得虚拟机的CPU和内存都使用同一个node区域内的,避免的不同node之间的cpu和内存的跨区域访问。 虚拟机的线程在当前分配的CPU中按需分配CPU资源。此时虚拟机线程占用的CPU核是固定的,虚拟机的线程被固定分配到的CPU上进行调度,从而避免了线程在不同的CPU核进行切换的时间。 在NUMA架构下,整个内存空间在物理上是分布式的,所有这些内存的集合就是整个系统的全局内存。每个核访问内存的时间取决于内存相对于处理器的位置,访问本地内存(本节点内)会更快一些。 不同节点间相距的距离不同,距离越远,跨NUMA内存访问的延时越大。应用程序运行时应减少跨NUMA访问内存。

cke_39153.png

taskset –c 0-23 python3 train.py

cke_47576.png

我要发帖子