PyTorch训练/在线推理场景性能分析
PyTorch训练/在线推理场景下,推荐通过Ascend PyTorch Profiler接口采集并解析性能数据,用户可以根据结果自行分析和识别性能瓶颈。
Ascend PyTorch Profiler是针对PyTorch框架开发的性能分析工具,通过在PyTorch训练脚本中添加Ascend PyTorch Profiler接口,执行训练的同时采集性能数据,完成训练后直接输出可视化的性能数据文件,提升了性能分析效率。Ascend PyTorch Profiler接口可全面采集PyTorch训练场景下的性能数据,主要包括PyTorch层算子信息、CANN层算子信息、底层NPU算子信息、以及算子内存占用信息等,可以全方位分析PyTorch训练时的性能状态。
前提条件
- 请确保完成使用前准备。
- 准备好基于PyTorch 1.11.0或更高版本开发的训练模型以及配套的数据集,并按照《PyTorch模型迁移和训练指南》中的“迁移适配”完成PyTorch原始模型向昇腾AI处理器的迁移。
采集并解析性能数据
- 使用Ascend PyTorch Profiler接口开启PyTorch训练时的性能数据采集。
在训练脚本(如train_*.py文件)内添加如下示例代码进行性能数据采集参数配置,之后启动训练。下列示例代码中,加粗字段为需要配置的参数、方法、类和函数。
- 示例一(使用torch_npu.profiler.profile类采集性能数据):
import torch import torch_npu ... experimental_config = torch_npu.profiler._ExperimentalConfig( export_type=torch_npu.profiler.ExportType.Text, aic_metrics=torch_npu.profiler.AiCMetrics.PipeUtilization, profiler_level=torch_npu.profiler.ProfilerLevel.Level1, l2_cache=False, data_simplification=False ) with torch_npu.profiler.profile( activities=[ torch_npu.profiler.ProfilerActivity.CPU, torch_npu.profiler.ProfilerActivity.NPU ], schedule=torch_npu.profiler.schedule(wait=1, warmup=1, active=2, repeat=2, skip_first=10), on_trace_ready=torch_npu.profiler.tensorboard_trace_handler("./result"), record_shapes=True, profile_memory=True, with_stack=True, with_flops=False, experimental_config=experimental_config) as prof: for step in range(steps): train_one_step(step, steps, train_loader, model, optimizer, criterion) prof.step()
或
import torch import torch_npu ... experimental_config = torch_npu.profiler._ExperimentalConfig( export_type=torch_npu.profiler.ExportType.Text, aic_metrics=torch_npu.profiler.AiCMetrics.ArithmeticUtilization, profiler_level=torch_npu.profiler.ProfilerLevel.Level1 ) prof = torch_npu.profiler.profile( activities=[ torch_npu.profiler.ProfilerActivity.CPU, torch_npu.profiler.ProfilerActivity.NPU ], schedule=torch_npu.profiler.schedule(wait=0, warmup=0, active=1, repeat=1, skip_first=1), on_trace_ready=torch_npu.profiler.tensorboard_trace_handler("./result"), experimental_config=experimental_config) prof.start() for step in range(steps): train_one_step() prof.step() prof.stop()
除了使用tensorboard_trace_handler导出性能数据外,还可以使用以下方式导出:import torch import torch_npu ... with torch_npu.profiler.profile() as prof: for step in range(steps): train_one_step(step, steps, train_loader, model, optimizer, criterion) prof.export_chrome_trace('./chrome_trace_14.json')
- 示例二(使用torch_npu.profiler._KinetoProfile类采集性能数据):
import torch import torch_npu ... prof = torch_npu.profiler._KinetoProfile(activities, record_shape, profile_memory, with_stack, experimental_config) for epoch in range(epochs): trian_model_step() if epoch == 0: prof.start() if epoch == 1: prof.stop() prof.export_chrome_trace("result_dir/trace.json")
该方式不支持使用schedule和tensorboard_trace_handler导出性能数据。
- 示例中的接口详细介绍请参见Ascend PyTorch Profiler接口采集。
- 性能数据会占据一定的磁盘空间,可能存在磁盘写满导致服务器不可用的风险。性能数据所需空间跟模型的参数、采集开关配置、采集的迭代数量有较大关系,须用户自行保证落盘目录下的可用磁盘空间。
- 示例一(使用torch_npu.profiler.profile类采集性能数据):
- 查看采集到的PyTorch训练性能数据结果文件。
训练结束后,在torch_npu.profiler.tensorboard_trace_handler接口指定的目录下生成Ascend PyTorch Profiler接口的采集结果目录。
└── localhost.localdomain_139247_20230628101435_ascend_pt // 解析结果目录,命名格式:{worker_name}_{时间戳}_ascend_pt,默认情况下{worker_name}为{hostname}_{pid} ├── profiler_info.json // 多卡或集群场景命名规则为profiler_info_{Rank_ID}.json,用于记录Profiler相关的元数据 ├── ASCEND_PROFILER_OUTPUT // Ascend PyTorch Profiler接口采集性能数据 │ ├── ascend_pytorch_profiler_{rank_id}.db // export_type=torch_npu.profiler.ExportType.Db时该目录下仅生成.db文件,其他.json和.csv文件不生成,使用Ascend Insight工具展示 │ ├── analysis.db // 多卡或集群等存在通信的场景下,设置export_type=torch_npu.profiler.ExportType.Db时该目录下仅生成.db文件,其他.json和.csv文件不生成,使用Ascend Insight工具展示 │ ├── communication.json // 为多卡或集群等存在通信的场景性能分析提供可视化数据基础,配置experimental_config的profiler_level=torch_npu.profiler.ProfilerLevel.Level1或profiler_level=torch_npu.profiler.ProfilerLevel.Level2生成 │ ├── communication_matrix.json // 通信小算子基本信息文件,配置experimental_config的profiler_level=torch_npu.profiler.ProfilerLevel.Level1或profiler_level=torch_npu.profiler.ProfilerLevel.Level2生成 │ ├── data_preprocess.csv // 配置experimental_config profiler_level=torch_npu.profiler.ProfilerLevel.Level2生成 │ ├── kernel_details.csv │ ├── l2_cache.csv // 配置experimental_config的l2_cache=True生成 │ ├── memory_record.csv │ ├── npu_module_mem.csv │ ├── operator_details.csv │ ├── operator_memory.csv │ ├── step_trace_time.csv // 迭代中计算和通信的时间统计 │ ├── op_statistic.csv // AI Core和AI CPU算子调用次数及耗时数据 │ ├── api_statistic.csv // 配置experimental_config的profiler_level=torch_npu.profiler.ProfilerLevel.Level1或profiler_level=torch_npu.profiler.ProfilerLevel.Level2生成 │ └── trace_view.json ├── FRAMEWORK // 框架侧的性能原始数据,无需关注,data_simplification=True时删除此目录 │ ├── torch.memory_usage │ ├── torch.op_mark │ ├── torch.op_range │ ├── torch.python_func_call // with_stack=True时生成 │ └── torch.python_module_call // with_stack=True时生成 └── PROF_000001_20230628101435646_FKFLNPEPPRRCFCBA // CANN层的性能数据,命名格式:PROF_{数字}_{时间戳}_{字符串},data_simplification=True时,仅保留此目录下的原始性能数据,删除其他数据 ├── analyze // 配置experimental_config的profiler_level=torch_npu.profiler.ProfilerLevel.Level1或profiler_level=torch_npu.profiler.ProfilerLevel.Level2生成 ├── device_* ├── host ├── mindstudio_profiler_log └── mindstudio_profiler_output ├── localhost.localdomain_139247_20230628101435_ascend_pt_op_args // 算子信息统计文件目录,配置experimental_config的record_op_args=True生成 ├── 进程ID │ ├── operator_name+data_type+timestamp.json // 算子信息统计文件
- 使用TensorBoard工具进行性能数据分析。
- 安装依赖。
- 安装方式:
- 查看是否安装成功。
pip3 list | grep torch-tb
显示如下信息表示安装成功。torch-tb-profiler-ascend {version}
- 启动工具。
tensorboard --logdir=./result
--logdir指定待解析的性能数据目录。
若是远程服务器启动TensorBoard想要在本机查看性能数据,需使用--bind_all参数。
tensorboard --logdir=./result --bind_all
回显如下:I0630 14:08:16.533923 281470215713104 plugin.py:454] Monitor runs begin I0630 14:08:16.536316 281470215713104 plugin.py:470] Find run directory /home/pzr I0630 14:08:16.539052 281470299730256 plugin.py:552] Load run .. I0630 14:08:16.561225 281470299730256 loader.py:73] started all processing TensorBoard 2.11.0 at http://localhost:6006/ (Press CTRL+C to quit) I0630 14:08:43.961050 281470299730256 plugin.py:556] Run .. loaded I0630 14:08:43.961973 281470257721680 plugin.py:493] Add run ..
加粗位置的URL地址即是用与查看结果数据的页面地址。
- 查看性能数据。
将回显中加粗的URL复制,并使用浏览器访问(若为远端服务器则需要将域名“localhost”替换为远端服务器的IP),进入TensorBoard工具界面。
图1 工具页面工具界面通过左侧侧边栏进行视图切换:
- Runs(红框①)用于切换展示的性能数据文件。
- Views(红框②)用于切换右侧性能数据详细视图,TensorBoard主要通过该功能进行性能数据分析,详细分析方法见下文“性能分析方法”。
- Workers(红框③)、Spans(红框④)用于切换不同进程和不同时间产生的数据。
性能分析方法
TensorBoard工具主要通过如下视图来展示PyTorch性能数据:
- Trace View:主要展示从上层应用下发到下层NPU算子的过程中所有算子的执行耗时以及上下层算子直接的调用关系,因此,该视图主要通过观察各个层级上的耗时长短、间隙等判断对应组件、算子是否存在性能问题。
- Kernel View:包含在NPU上执行的所有算子的信息,主要用于进一步确认高耗时算子。
- Operator View:统计PyTorch算子在Host侧(下发)和Device侧(执行)的耗时,同样通过耗时判断性能问题,并且可以通过Call stack找到该算子对应的底层调用关系从而定位到具体代码行。
- Memory View:主要展示PTA(PyTorch Adapter)和GE内存申请情况信息,以及分配给底层算子的详细信息,可以找出占用内存最大的算子。
- Distributed View:主要展示分布式运行时,多节点之间的HCCL计算和通信的性能瓶颈和通信效率。
- DiffView:主要展示两份NPU性能数据差异,可用于分析性能变化趋势和变化点。
详细示例请参见性能分析(Trace View)、性能分析(Kernel View)、性能分析(Operator View)、性能分析(Memory View)、性能分析(Distributed View)和性能分析(DiffView)。
集群场景多卡间算子性能统计
集群场景下,多卡间的算子情况,只能通过查看每张卡各自的性能数据来了解,不能直观的对比各卡之间算子的性能差异。为了直观查看格卡之间算子的性能差异,请通过cluster_kernels_analysis工具的cluster_op_summary_analysis.py脚本,快速统计并展示各卡之间TopN算子的性能数据。
性能分析(Trace View)
如图2所示,trace数据主要展示如下区域:
- 区域1:应用层数据,包含上层应用算子的耗时信息。此处为PyTorch框架层数据。
- 区域2:CANN层数据,主要包含AscendCL、Runtime等组件以及Node(算子)的耗时数据。
- 区域3:底层NPU数据,,主要包含Ascend Hardware下各个Stream任务流的耗时数据和迭代轨迹数据、HCCL和Overlap Analysis通信数据以及其他昇腾AI处理器系统数据。
- 区域4:展示trace中各算子、接口的详细信息(单击各个trace事件时展示,即图中的色块)。
开启“Flow events”下的选项后,上下层算子之间通过连线方式展示下发到执行的对应关系,主要包括的对应关系有:
- async_npu:应用层算子 > Ascend Hardware的NPU算子的下发执行关系。
- async_task_queue:应用层Enqueue > Dequeue的入队列到出队列对应关系,仅PyTorch场景。
- HostToDevice:CANN层Node(算子) > AscendHardware的NPU算子的下发执行关系(Host到Device)。
- HostToDevice:CANN层Node(算子) > HCCL通信算子的下发执行关系(Host到Device)。
- fwdbwd:前向API > 反向API,仅PyTorch场景。
Trace View下的性能数据建议通过观察各个层级上的耗时长短、间隙等判断对应组件、算子是否存在性能问题。
- 示例一:算子下发瓶颈识别
建议的优化方式有:增加batch size、绑核&高性能模式、使用NPU亲和优化器、融合算子优化。
- 示例二:原生优化器耗时
开启混合精度时,原生优化器耗时过长,如图5所示。
请使用华为亲和优化器接口apex.optimizers.NpuFusedxxx替代原生优化器来提升性能,如下所示。
样例源代码:
optimizer = torch.optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=32.0)
修改后代码:
optimizer = apex.optimizers.NpuFused.SGD(model.parameters(), lr=args.lr, momentum=args.momentum) model, optimizer = amp.initialize(model, optimizer, opt_level='O2', loss_scale=32.0, combine_grad=True)
- 示例三:kernel耗时
如图6所示,选中所有NPU栏目的色块,trace会自动帮助统计不同名称kernel的总耗时、平均耗时、调用次数等指标。如图7所示,单击Average Wall Duration进行倒序排序,查看耗时Top的kernel,观察发现MaskedScatter、DynamicRNN、MIX_AIC、MaskedSelect为明显性能较差的算子。再结合Wall Duration字段,查看该算子耗时占所有kernel总耗时的比例,判定该算子的优化能够带来的性能收益,以确定优先优化的kernel。
- 示例四:转换类算子插入识别
通过示例三的方式找出耗时Top的kernel,若Top算子存在转换类算子,如图8示例。
则可通过调用栈(Call stack)信息定位到具体的代码行。单击算子的名称跳转到对应算子的详细信息,如图9示例。
查看Events(s)列的Incoming flow表示Link列下的算子为trans_TransData_87的上游算子,单击Link列下的其中一个Incoming flow对应算子torch_to_npu,跳转至图10。
从torch_to_npu明细的From字段信息可以看出,Slice算子在trace中的第7.820 ms为torch_to_npu的上游算子,如图11所示。
从Slice明细的Call stack字段信息可以读取到具体调用的代码行。
可以删除过多的转换类算子或参见《PyTorch模型迁移和训练指南》中的“性能调优 > 通用优化方法 > NPU亲和适配优化 > 其他常用优化操作”进行转换类算子优化。
性能分析(Kernel View)
Kernel View为kernel_details.csv文件的TensorBoard可视化呈现,包含在NPU上执行的所有算子的信息,如图12所示。
左侧饼图统计不同名称的kernel总耗时占比;右侧饼图统计在不同加速核上执行时间的占比;下方列表Group By选择Statistic时,展示按kernel的名称汇总统计的执行信息。
列表Group By选择All时,展示所有kerenl执行的明细信息,如图13所示。
可以根据左侧饼图查看耗时多的算子,根据下方列表的Duration排序确认高耗时的算子。
性能分析(Operator View)
Operator View为operator_details.csv文件的TensorBoard可视化呈现,是统计PyTorch算子在Host侧(下发)和Device侧(执行)的耗时,如图14所示。
- Device Self Duration饼图统计由该算子直接下发,在Device上执行的总耗时。
- Device Total Duration饼图统计由该算子及其内部调用的其他算子下发,在Device上执行的总耗时。
- Host Self Duration饼图统计该算子在Host上执行的总耗时,不包括内部调用的其他算子。
- Host Total Duration饼图统计该算子及其内部调用的其他算子在Host上执行的总耗时。
下方列表为上方饼图的明细呈现,如图15所示。
Group By选择Operator+Input Shape时,列表展示算子的输入Shape信息,如图16所示。
可以先根据耗时信息判断高耗时且存在性能瓶颈的算子,再通过单击View CallStack,呈现算子调用栈信息。以图17为例,MatMul有4种不同的调用栈,单击View call frames,可查看具体的调用栈信息。
通过调用栈信息找到具体调用的代码行。
性能分析(Memory View)
Memory View为operator_memory.csv和memory_record.csv文件的TensorBoard可视化呈现,包含算子级(PTA、GE、PTA+GE)、进程级(APP)和组件级内存申请情况信息,如图18所示。
- Group By选择Operator时,展示算子在NPU上执行时的内存占用折线图和明细表,其中内存由PTA和GE申请。
- Group By选择Component时,展示算子级、进程级内存占用折线图和组件级内存占用明细表。
用户可以在内存折线图上进行选择,并通过在折线图上拖动鼠标左键来放大所选范围,右键单击会将绘图重置为初始状态。
- Allocated是当前PyTorch中生命周期未结束的Tensor的内存总和。
- Active是在Allocated的基础上加上Tensor生命周期结束但未被内存池及时回收的部分(跨流依赖导致延迟释放的内存)。
从图18中可以看出算子在每个时刻否内存占用情况,一般来说对一个完整的迭代进行性能数据采集即可看到这个迭代算子内存的生命周期(迭代开始前的内存申请是模型初始化时的内存申请)。
根据算子的内存申请及内存时间,分析相关内存问题,将内存峰值减小。
可以从耗内存最大的算子开始排查,从而减小NPU内存的使用。
从图19中可以看出各个组件申请情况,通过记录每个时刻的内存情况找出内存占用的峰值,包含字段:
- Component:组件名称(由于PTA和GE数据已在折线图中呈现,此字段不展示这两个组件信息)。
- Peak Memory Usage(MB):组件内存占用峰值。
- Time(ms):达到该峰值的时刻(若存在多个相同峰值则取首次达到峰值时刻)。
性能分析(Distributed View)
Distributed View是以communication.json或communication_matrix.json和step_trace_time.csv文件为基础提取的TensorBoard可视化呈现,用于分析分布式运行时,多节点之间的HCCL计算和通信的性能瓶颈和通信效率,如图20所示。
- 图中Step可选择各个迭代的信息,Worker可选择当前迭代各个节点的信息。
- 图中Computation/Communication Overview坐标轴的每个柱状图表示每个节点的计算和通信时间统计,包含字段:
- Computation:计算时间,NPU上算子的计算总时间减去计算和通信重叠的时间。
- Overlapping:计算和通信重叠的时间。更多重叠代表计算和通信之间更好的并行性。理想情况下,通信与计算完全重叠。
- Communication:通信时间,通信总时间减去计算和通信重叠的时间。
- Other:迭代总时间减去计算和通信时间。可能包括初始化、数据加载、CPU计算等。
通过该Computation/Communication Overview,可以了解到每个节点的计算通信比,以及节点之间的负载平衡。例如,如果一个节点的计算+重叠时间远大于其他节点,则可能存在负载平衡问题,或者该节点可能存在性能瓶颈。
- 图中Synchronizing/Communication Overview坐标轴的每个柱状图表示每个节点的同步和通信时间统计,包含字段:
- Data Transfer Time:数据传输时间:总通信时间中用于实际数据交换的时间。
- Synchronizing Time:同步时间,总通信时间中用于等待和同步其他节点数据的时间。
从这个角度,可以了解通信的效率(总通信时间中有多少比例真正用于交换数据,有多少只是等待和同步其他节点数据)。
- 图中Communication Operations Stats为通信操作统计,总结了每个节点中所有通信操作的详细统计信息,包含字段:
- Calls:本次运行中调用该操作员的次数。
- Total Transit Size (bytes):此类型算子中传输的总数据大小。
- Avg Transit Size (bytes):此类型算子中传输的平均数据大小。
- Elapse Time (us):此类型算子的总延迟。
- Avg Elapse Time (us):此类型算子的平均延迟。
- Transit Time (us):此类型算子实际用于数据传输的总时间。
- Avg Transit Time (us):此类型算子实际用于数据传输的平均时间。
性能分析(DiffView)
DiffView是以trace_view.json文件为基础提取的TensorBoard可视化呈现,可以将两份NPU性能数据进行比较。
进行数据比对需要采集两份性能数据,可以是相同设备不同迭代、相同设备进行网络优化前后、相同设备不同卡之间、相同网络不同硬件平台。如图21所示。
Baseline为基准数据Experimental为待验证的比对数据,Runs指定设备平台、Workers指定不同Profiler进程(即不同的Profiler结果目录,可以是两个迭代分别生成、网络优化前后分别采集或两个卡采集的两份性能数据)、Spans指定同一Profiler进程中不同时间多次采集的时间戳。


完成Baseline和Experimental配置后,在右侧生成DiffView和Operator View。
- DiffView_Execution Comparsion:
- DiffView_Execution Diff:差异视图,由红蓝两块区域构成。横坐标与上方视图Execution Comparsion一致,蓝色区域为在当前部分Experimental数据减去Baseline数据得到的耗时差,红色区域则为前一耗时差与当前耗时差的累加值。
- Operator View: