From 31be8e0b47598cb0237b76f1296fd3eaf8d47099 Mon Sep 17 00:00:00 2001 From: cai-weiwei1989 <734267852@qq.com> Date: Mon, 22 Apr 2024 10:58:06 +0800 Subject: [PATCH 1/4] =?UTF-8?q?[ptdbg]=E6=AD=A3=E7=BD=91=E6=AF=94=E5=AF=B9?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=BB=9F=E8=AE=A1=E9=87=8F=E6=AF=94=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...03\275\350\257\264\346\230\216_v6.0.T1.md" | 2185 +++++++++++++++++ 1 file changed, 2185 insertions(+) create mode 100644 "debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" diff --git "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" new file mode 100644 index 000000000..2251ab702 --- /dev/null +++ "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" @@ -0,0 +1,2185 @@ +# **PyTorch精度工具使用指南** + +本文主要介绍PyTorch精度工具ptdbg_ascend的使用以及精度比对场景示例。 + +ptdbg_ascend工具的原理及安装请参见《[PyTorch精度工具](https://gitee.com/ascend/att/blob/master/debug/accuracy_tools/ptdbg_ascend/README.md)》。 + +ptdbg_ascend工具主要支持PyTorch API精度数据dump、溢出检测、精度比对以及parse数据解析功能。其中dump和溢出检测功能支持使用debugger和register_hook方式进行精度数据的dump和溢出检测,推荐使用debugger方式。 + +## PyTorch精度比对总体流程 + +1. 准备CPU或GPU训练工程。 + +2. 在环境下安装ptdbg_ascend工具。 + +3. 在训练脚本内插入ptdbg_ascend工具dump接口。 + +4. 执行训练dump数据。 + +5. 将CPU或GPU训练工程迁移为NPU训练工程。 + + 请参见《[PyTorch模型迁移和训练指南](https://www.hiascend.com/document/detail/zh/canncommercial/63RC1/modeldevpt/ptmigr/ptmigr_0001.html)》。 + +6. 在NPU环境下安装ptdbg_ascend工具。 + +7. 在NPU训练脚本内插入ptdbg_ascend工具dump接口。 + +8. NPU环境下执行训练dump数据。 + +9. 创建并配置精度比对脚本,例如compare.py。 + +10. 执行CPU或GPU dump与NPU dump数据的精度比对。 + +11. 比对结果分析。 + +## 快速入门(debugger方式) + +本章节主要介绍通过ptdbg_ascend工具进行精度比对和分析,主要使用“**debugger方式dump和溢出检测**”和“**CPU或GPU与NPU精度数据比对**”章节中介绍的ptdbg_ascend工具接口。 + +### 单卡场景精度比对 + +**精度分析建议** + +PyTorch训练场景的精度问题分析建议参考以下思路进行精度比对和比对结果分析: + +1. 整网比对:dump整网数据并进行精度比对,初步定位异常范围。 + + 不推荐使用整网dump比对,若模型数据庞大(比如达到T级别),整网dump可能导致磁盘不足,需要预留足够的存储空间,或者分多次dump。 + +2. 缩小范围:根据Accuracy Reached or Not找出不符合精度标准的API。 + +3. 范围比对:对不符合精度标准的API重新dump详细信息。 + +4. 分析原因并优化:分析API精度不符合标准的原因并进行优化调整。 + +5. 整网比对:重新进行整网比对,判断优化后的API是否已符合精度标准以及是否出现新的精度问题。 + +6. 重复1~5步,直到不存在精度问题为止。 + +**精度分析示例** + +1. dump整网数据。 + + 分别dump CPU或GPU以及NPU数据,在PyTorch训练脚本插入dump接口,示例代码如下(下面以NPU为例,CPU或GPU dump基本相同): + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./npu_dump", hook_name="dump", step=[0]) + debugger.configure_hook(mode="api_stack") + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + +2. 比对整网数据。 + + 第1步中的NPU dump数据目录为npu_dump,假设GPU dump数据目录为gpu_dump;dump将生成pkl数据文件api_stack_dump.pkl和npy数据目录api_stack_dump。 + + 创建并配置精度比对脚本,以创建compare.py为例,示例代码如下: + + ```python + from ptdbg_ascend import * + dump_result_param={ + "npu_pkl_path": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", + "bench_pkl_path": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", + "npu_dump_data_dir": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump", + "bench_dump_data_dir": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump", + "is_print_compare_log": True + } + compare(dump_result_param, "./output", stack_mode=True) + ``` + + 执行比对: + + ```bash + python3 compare.py + ``` + + 在output目录下生成结果文件,包括:`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt` + +3. 找出存在问题的API。 + + 1. 根据`advisor_{timestamp}.txt`或打屏信息的提示,可找到存在精度问题的算子(Suspect Nodes)和专家建议(Expert Advice) + + ![auto_analyze_log](img/auto_analyze_log.png) + + 2. 根据第2步结果文件`compare_result_{timestamp}.csv`中的Accuracy Reached or No字段显示为NO的API,针对该API执行后续比对操作,分析该API存在的精度问题。 + +4. (可选)提取指定API的堆栈信息和dump数据统计信息。 + + 通过parse接口可以清晰的显示特定API的堆栈信息和dump数据统计信息,结合堆栈信息分析代码中可能存在的精度问题。 + + 创建并配置提取脚本,以创建parse.py为例,示例代码如下: + + ```python + from ptdbg_ascend import * + + # 提取dump信息中第1次调用的API:Torch_batch_normal的堆栈信息及数据统计信息 + parse("./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", "Torch_batch_normal_1_forward") + ``` + + 执行提取: + + ```bash + python3 parse.py + ``` + + + +5. (可选)指定API对其底层ACL数据进行dump。 + + - dump指定前向API的ACL级别数据 + + ```python + debugger = PrecisionDebugger(dump_path="./npu_dump", hook_name="dump", step=[0]) + debugger.configure_hook(mode="acl", scope=["Tensor_permute_1_forward"], acl_config='./dump.json') + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + + - dump指定反向API的ACL级别数据 + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./npu_dump", hook_name="dump", step=[0]) + # dump指定反向API的ACL级别数据、bool和整型的tensor以及浮点、bool和整型的标量 + debugger.configure_hook(mode="acl", scope=["Functional_conv2d_1_backward"], acl_config="./dump.json", backward_input=["./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump/Functional_conv2d_1_backward_input.0.npy"]) + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + +6. (可选)重新比对。 + + 根据第4或5步的dump数据重新配置compare.py并执行比对,可以对单API模型进行问题复现。 + +**注意事项** + +* dump_mode="acl"场景下,会增加npu的内存消耗,请谨慎开启。 +* 部分API存在调用嵌套关系,比如functional.batch_norm实际调用torch.batch_norm,该场景会影响acl init初始化多次,导致功能异常。 + +### 溢出检测场景 + +溢出检测是针对NPU的PyTorch API,检测是否存在溢出的情况。当前仅支持识别aicore浮点溢出。 + +溢出检测原理:针对溢出阶段,开启acl dump模式,重新对溢出阶段执行,落盘数据。 + +建议按照如下步骤操作: + +1. 在NPU环境下安装ptdbg_ascend工具。 + +2. 在NPU训练脚本内插入ptdbg_ascend工具溢出检测接口。 + + - 示例1:全量溢出检测 + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./overflow_dump", hook_name="overflow_check", step=[0]) + debugger.configure_hook(overflow_nums=-1) + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + + 多卡使用时各卡单独计算溢出次数。 + + - 示例2:dump指定前向API的ACL级别溢出数据 + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./overflow_dump", hook_name="overflow_check", step=[0]) + debugger.configure_hook(mode="acl", acl_config="./dump.json") + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + + - 示例3:dump指定反向API的ACL级别的溢出数据 + + 1. 进行全量溢出检测 + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./overflow_dump", hook_name="overflow_check", step=[0]) + debugger.configure_hook(overflow_nums=-1) + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + + + + 2. dump指定反向API的ACL级别的溢出数据 + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./overflow_dump", hook_name="dump", step=[0]) + debugger.configure_hook(mode="acl", scope=["Functional_conv2d_1_backward"], acl_config="./dump.json", backward_input=["./overflow_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump/Functional_conv2d_1_backward_input.0.npy"]) + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + + 针对前向溢出API,可以通过overflow_nums,配置允许的溢出次数,并将每次溢出API的全部ACL数据dump下来,到达指定溢出次数后停止,停止后会看到堆栈打印包含如下字段。 + + ```bash + ValueError: [overflow xxx times]: dump file is saved in 'xxxxx.pkl'. + ``` + + 其中xxx times为用户设置的次数,xxxxx.pkl为文件生成路径。 + +3. NPU环境下执行训练dump溢出数据。 + + 针对输入正常但输出存在溢出的API,会训练执行目录下将溢出的API信息dump并保存为`forward_info_{pid}.json`和`backward_info_{pid}.json`,通过[Ascend模型精度预检工具](https://gitee.com/ascend/att/tree/master/debug/accuracy_tools/api_accuracy_checker)对json文件进行解析,输出溢出API为正常溢出还是非正常溢出,从而帮助用户快速判断。 + + 精度预检工具执行命令如下: + + ```bash + # 下载att代码仓后执行如下命令 + export PYTHONPATH=$PYTHONPATH:$ATT_HOME/debug/accuracy_tools/ + cd $ATT_HOME/debug/accuracy_tools/api_accuracy_checker/run_ut + python run_overflow_check.py -forward ./forward_info_0.json + ``` + + 反向过程溢出的API暂不支持精度预检功能。 + + 当重复执行溢出检测dump操作时,需要删除上一次dump目录下的溢出检测dump数据,否则将因重名而报错。 + +**注意事项** + +* dump_mode="acl"场景下,会增加npu的内存消耗,请谨慎开启。 +* 部分API存在调用嵌套关系,比如functional.batch_norm实际调用torch.batch_norm,该场景会影响acl init初始化多次,导致功能异常。 +* 混合精度动态loss scale场景下,正常训练会有"Gradient overflow. SKipping step"日志,添加溢出检测后日志消失,可以通过设置环境变量export OVERFLOW_DEBUG_MODE_ENABLE=1,并将register_hook位置调整amp.initialize之前解决。此功能需要cann包配套支持,不支持版本执行报错EZ3003。 + +## 场景化示例 + +本章节主要介绍通过ptdbg_ascend工具进行精度比对和分析,主要使用“**CPU或GPU及NPU精度数据dump**”和“**CPU或GPU与NPU精度数据比对**”章节中介绍的ptdbg_ascend工具接口。 + +### 多卡场景精度比对 + +精度工具支持多卡场景的精度比对,多卡场景的dump步骤与单卡场景完全一致,请参见“**单卡场景精度比对**”章节,不同的是多卡数据精度比对时需要使用“compare_distributed”函数进行比对。 + +**大模型场景下dump推荐使用debugger方式的手动模式。** + +如下示例: + +说明:多机多卡场景需要每个设备单独执行比对操作。 + +假设NPU dump npy数据目录为npu_dump/ptdbg_dump_v4.0,GPU dump npy数据目录为gpu_dump/ptdbg_dump_v4.0。 + +1. 创建比对脚本,例如compare_distributed.py,拷贝如下代码。 + + ```python + from ptdbg_ascend import * + compare_distributed('./npu_dump/ptdbg_dump_v4.0/step0', './gpu_dump/ptdbg_dump_v4.0/step0', './output') + ``` + + dump数据目录须指定到step级。 + +2. 执行比对: + + ```bash + python3 compare_distributed.py + ``` + +两次运行须用相同数量的卡,传入`compare_distributed`的两个文件夹下须有相同个数的rank文件夹,且不包含其他无关文件,否则将无法比对。 + +**多卡set_dump_path注意事项** + +多卡一般为多进程,须保证每个进程都正确调用PrecisionDebugger或set_dump_path,或把PrecisionDebugger或set_dump_path插入到import语句后,如: + +```python +from ptdbg_ascend import * +debugger = PrecisionDebugger(dump_path="./npu_dump", hook_name="dump", step=[0]) +``` + +或 + +```python +from ptdbg_ascend import * +seed_all() +set_dump_path('./dump_resnet') +``` + +如此可保证set_dump_path在每个进程都被调用。 + +**多卡register_hook注意事项** + +register_hook需要在set_dump_path之后调用,也需要在每个进程上被调用,建议在搬运模型数据到卡之后调用。识别方法如下: + +- 找到训练代码中遍历epoch的for循环或遍历数据集的for循环,把register_hook放到循环开始前即可。 +- 找到训练代码中调用DDP或者DistributedDataParallel的代码行,把register_hook放到该代码行所在的代码块之后。 +- 若代码中均无以上两种情况,需要保证register_hook在模型定义之后插入,并配置rank参数。rank参数获取rank_id请参见“**[rank_id获取方法](https://gitee.com/ascend/att/blob/master/debug/accuracy_tools/ptdbg_ascend/doc/rank_id获取方法.md)**”。 + +### NPU vs NPU精度比对 + +对于NPU vs NPU场景,是针对同一模型,进行迭代(模型、API版本升级或设备硬件升级)时存在的精度下降问题,对比相同模型在迭代前后版本的API计算数值,进行问题定位。 + +一般情况下迭代涉及NPU自定义算子,因此,可以仅dump NPU自定义算子进行比对。比对精度问题分析请参见“**单卡场景精度比对**”章节。 + +工具当前支持dump NPU自定义算子如下: + +| 序号 | NPU自定义算子 | +| :--- | ----------------------------------------------- | +| 1 | torch_npu.one_ | +| 2 | torch_npu.npu_sort_v2 | +| 3 | torch_npu.npu_transpose | +| 4 | torch_npu.npu_broadcast | +| 5 | torch_npu.npu_dtype_cast | +| 6 | torch_npu.empty_with_format | +| 7 | torch_npu.npu_one_hot | +| 8 | torch_npu.npu_stride_add | +| 9 | torch_npu.npu_ps_roi_pooling | +| 10 | torch_npu.npu_roi_align | +| 11 | torch_npu.npu_nms_v4 | +| 12 | torch_npu.npu_iou | +| 13 | torch_npu.npu_nms_with_mask | +| 14 | torch_npu.npu_pad | +| 15 | torch_npu.npu_bounding_box_encode | +| 16 | torch_npu.npu_bounding_box_decode | +| 17 | torch_npu.npu_batch_nms | +| 18 | torch_npu.npu_slice | +| 19 | torch_npu._npu_dropout | +| 20 | torch_npu.npu_indexing | +| 21 | torch_npu.npu_ifmr | +| 22 | torch_npu.npu_max | +| 23 | torch_npu.npu_scatter | +| 24 | torch_npu.npu_layer_norm_eval | +| 25 | torch_npu.npu_alloc_float_status | +| 26 | torch_npu.npu_confusion_transpose | +| 27 | torch_npu.npu_bmmV2 | +| 28 | torch_npu.fast_gelu | +| 29 | torch_npu.npu_sub_sample | +| 30 | torch_npu.npu_deformable_conv2d | +| 31 | torch_npu.npu_mish | +| 32 | torch_npu.npu_anchor_response_flags | +| 33 | torch_npu.npu_yolo_boxes_encode | +| 34 | torch_npu.npu_grid_assign_positive | +| 35 | torch_npu.npu_normalize_batch | +| 36 | torch_npu.npu_masked_fill_range | +| 37 | torch_npu.npu_linear | +| 38 | torch_npu.npu_bert_apply_adam | +| 39 | torch_npu.npu_giou | +| 40 | torch_npu.npu_ciou | +| 41 | torch_npu.npu_diou | +| 42 | torch_npu.npu_sign_bits_pack | +| 43 | torch_npu.npu_sign_bits_unpack | +| 44 | torch_npu.npu_flash_attention | +| 45 | torch_npu.npu_scaled_masked_softmax | +| 46 | torch_npu.npu_rotary_mul | +| 47 | torch_npu.npu_roi_align | +| 48 | torch_npu.npu_roi_alignbk | +| 49 | torch_npu.npu_ptiou | +| 50 | torch_npu.npu_fusion_attention | +| 51 | torch_npu.npu_dropout_with_add_softmax | +| 52 | torch_npu.npu_random_choice_with_mask | +| 53 | torch_npu.npu_rotated_iou | +| 54 | torch_npu.npu_conv2d | +| 55 | torch_npu.npu_conv3d | +| 56 | torch_npu.npu_softmax_cross_entropy_with_logits | +| 57 | torch_npu.npu_all_gather_base_mm | +| 58 | torch_npu.npu_swiglu | +| 59 | torch_npu.npu_rms_norm | +| 60 | torch_npu.npu_mm_reduce_scatter_base | +| 61 | torch_npu.npu_mm_all_reduce_base | +| 62 | torch_npu.npu_conv_transpose2d | +| 63 | torch_npu.npu_convolution | +| 64 | torch_npu.npu_convolution_transpose | +| 65 | torch_npu.npu_min | +| 66 | torch_npu.npu_nms_rotated | +| 67 | torch_npu.npu_reshape | +| 68 | torch_npu.npu_rotated_box_decode | +| 69 | torch_npu.npu_rotated_box_encode | +| 70 | torch_npu.npu_rotated_overlaps | +| 71 | torch_npu.npu_silu | +| 72 | torch_npu.npu_fused_attention_score | +| 73 | torch_npu.npu_multi_head_attention | +| 74 | torch_npu.npu_gru | +| 75 | torch_npu.npu_incre_flash_attention | +| 76 | torch_npu.npu_prompt_flash_attention | +| 77 | torch_npu.npu_lstm | +| 78 | torch_npu.npu_apply_adam | + +### 通信API的数据dump + +通信类API数据可以使用全量dump方式获取,若只dump通信类API数据,可以使用如下示例: + +```python +debugger.configure_hook(mode="api_list", api_list=["distributed"]) +``` + +或 + +```python +set_dump_switch("ON", mode="api_list", api_list=["distributed"]) +``` + +通信类API支持列表: + +| 序号 | Distributed | +| :--- | -------------------- | +| 1 | send | +| 2 | recv | +| 3 | broadcast | +| 4 | all_reduce | +| 5 | reduce | +| 6 | all_gather | +| 7 | gather | +| 8 | isend | +| 9 | irecv | +| 10 | scatter | +| 11 | reduce_scatter | +| 12 | _reduce_scatter_base | +| 13 | _all_gather_base | + +### 单卡场景精度比对(register_hook方式) + +**精度分析建议** + +PyTorch训练场景的精度问题分析建议参考以下思路进行精度比对和比对结果分析: + +1. 整网比对:dump整网数据并进行精度比对,初步定位异常范围。 +2. 缩小范围:根据Accuracy Reached or Not找出不符合精度标准的API。 +3. 范围比对:对不符合精度标准的API重新dump。 +4. 分析原因并优化:分析API精度不符合标准的原因并进行优化调整。 +5. 整网比对:重新进行整网比对,判断优化后的API是否已符合精度标准以及是否出现新的精度问题。 +6. 重复1~5步,直到不存在精度问题为止。 + +**精度分析示例** + +1. dump整网数据。 + + 分别dump CPU或GPU以及NPU数据,在PyTorch训练脚本插入dump接口,示例代码如下(下面以NPU为例,CPU或GPU dump基本相同): + + ```python + from ptdbg_ascend import * + + # 在main函数开始前固定随机数 + seed_all() + + # 配置dump数据目录路径和名称 + set_dump_path("./npu_dump", dump_tag='all') + + # 注册dump回调函数 + register_hook(model, acc_cmp_dump) + + ... + + # 在第一个迭代开始的位置开启dump和堆栈模式,同时为保证数据完整性开启dump bool和整型的tensor以及浮点、bool和整型的标量 + set_dump_switch("ON", mode="api_stack", filter_switch="OFF") + + ... + + # 在第一个迭代结束的位置关闭dump + set_dump_switch("OFF") + ``` + +2. 比对整网数据。 + + 第1步中的NPU dump数据文件为npu_dump.pkl,假设NPU dump npy数据目录为npu_dump,GPU dump数据文件为gpu_dump.pkl,GPU dump npy数据目录为gpu_dump。 + + 创建并配置精度比对脚本,以创建compare.py为例,示例代码如下: + + ```python + from ptdbg_ascend import * + dump_result_param={ + "npu_pkl_path": "./npu_dump/all_v4.0/step0/rank0/api_stack_dump.pkl", + "bench_pkl_path": "./gpu_dump/all_v4.0/step0/rank0/api_stack_dump.pkl", + "npu_dump_data_dir": "./npu_dump/all_v4.0/step0/rank0/api_stack_dump", + "bench_dump_data_dir": "./gpu_dump/all_v4.0/step0/rank0/api_stack_dump", + "is_print_compare_log": True + } + compare(dump_result_param, "./output", stack_mode=True) + ``` + + 执行比对: + + ```bash + python3 compare.py + ``` + + 在output目录下生成结果文件,包括:`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt` + +3. 找出存在问题的API。 + + 1. 根据`advisor_{timestamp}.txt`或打屏信息的提示,可找到存在精度问题的算子(Suspect Nodes)和专家建议(Expert Advice) + + ![auto_analyze_log](img/auto_analyze_log.png) + + 2. 根据第2步结果文件`compare_result_{timestamp}.csv`中的Accuracy Reached or No字段显示为NO的API,针对该API执行后续比对操作,分析该API存在的精度问题。 + +4. (可选)提取指定API的堆栈信息和dump数据统计信息。 + + 通过parse接口可以清晰的显示特定API的堆栈信息和dump数据统计信息,结合堆栈信息分析代码中可能存在的精度问题。 + + 创建并配置提取脚本,以创建parse.py为例,示例代码如下: + + ```python + from ptdbg_ascend import * + + # 提取dump信息中第1次调用的API:Torch_batch_normal的堆栈信息及数据统计信息 + parse("./npu_dump/all_v4.0/step0/rank0/api_stack_dump.pkl", "Torch_batch_normal_1_forward") + ``` + + 执行提取: + + ```bash + python3 parse.py + ``` + + + +5. (可选)指定API对其底层ACL数据进行dump。 + + - dump指定前向API的ACL级别数据 + + ```python + from ptdbg_ascend import * + + # 固定随机数,开启确定性计算 + seed_all(mode=True) + set_dump_path("./dump_path", dump_tag='forward') + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + + # dump指定前向API的ACL级别数据、bool和整型的tensor以及浮点、bool和整型的标量 + set_dump_switch("ON", mode="acl", scope=["Tensor_permute_1_forward"], filter_switch="OFF") + + ... + + set_dump_switch("OFF") + ``` + + - dump指定反向API的ACL级别数据 + + ```python + from ptdbg_ascend import * + + # 固定随机数,开启确定性计算 + seed_all(mode=True) + set_dump_path("./dump_path", dump_tag='backward') + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + + # dump指定反向API的ACL级别数据、bool和整型的tensor以及浮点、bool和整型的标量 + set_dump_switch("ON", mode="acl", scope=["Functional_conv2d_1_backward"], filter_switch="OFF") + set_backward_input(["./npu_dump/all_v4.0/step0/rank0/api_stack_dump/Functional_conv2d_1_backward_input.0.npy"]) + + ... + + set_dump_switch("OFF") + ``` + +6. (可选)重新比对。 + + 根据第4或5步的dump数据重新配置compare.py并执行比对,可以对单API模型进行问题复现。 + +**注意事项** + +* dump_mode="acl"场景下,会增加npu的内存消耗,请谨慎开启。 +* 部分API存在调用嵌套关系,比如functional.batch_norm实际调用torch.batch_norm,该场景会影响acl init初始化多次,导致功能异常。 + +### 溢出检测场景(register_hook方式) + +溢出检测是针对NPU的PyTorch API,检测是否存在溢出的情况。当前仅支持识别aicore浮点溢出。 + +溢出检测原理:针对溢出阶段,开启acl dump模式,重新对溢出阶段执行,落盘数据。 + +建议按照如下步骤操作: + +1. 在NPU环境下安装ptdbg_ascend工具。 + +2. 在NPU训练脚本内插入ptdbg_ascend工具溢出检测接口。 + + - 示例1:全量溢出检测 + + ```python + from ptdbg_ascend import * + seed_all() + # 配置溢出数据目录路径和名称 + set_dump_path("./overflow_dump") + ... + # 设置检测到3次溢出后退出训练 + register_hook(model, overflow_check, overflow_nums=3) + + ... + ``` + + 多卡使用时各卡单独计算溢出次数。 + + - 示例2:dump指定API的ACL级别溢出数据 + + ```python + from ptdbg_ascend import * + seed_all() + # 配置溢出数据目录路径和名称 + set_dump_path("./overflow_dump") + ... + # dump指定API的ACL级别溢出数据 + register_hook(model, overflow_check, dump_mode='acl', dump_config='./dump.json') + + # 在期望溢出检测的step位置开始前打开溢出检测开关 + set_overflow_check_switch("ON") + + ... + + # 在step结束的位置关闭溢出检测开关 + set_overflow_check_switch("OFF") + + ... + ``` + + - 示例3:dump指定反向API的ACL级别的溢出数据 + + 1. 进行全量溢出检测 + + ```python + from ptdbg_ascend import * + seed_all() + # 配置溢出数据目录路径和名称 + set_dump_path("./overflow_dump") + ... + # 设置检测到3次溢出后退出训练 + register_hook(model, overflow_check) + + ... + ``` + + 2. dump指定反向API的ACL级别的溢出数据 + + ```python + from ptdbg_ascend import * + seed_all() + # 配置溢出数据目录路径和名称 + set_dump_path("./overflow_dump") + ... + # dump指定反向API的ACL级别溢出数据 + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + set_dump_switch("ON", mode="acl", scope=["Functional_conv2d_1_backward"]) + set_backward_input(["./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump/Functional_conv2d_1_backward_input.0.npy"]) + ``` + + 针对前向溢出API,可以通过overflow_nums,配置允许的溢出次数,并将每次溢出API的全部ACL数据dump下来,到达指定溢出次数后停止,停止后会看到堆栈打印包含如下字段。 + + ```bash + ValueError: [overflow xxx times]: dump file is saved in 'xxxxx.pkl'. + ``` + + 其中xxx times为用户设置的次数,xxxxx.pkl为文件生成路径。 + +3. NPU环境下执行训练dump溢出数据。 + + 针对输入正常但输出存在溢出的API,会训练执行目录下将溢出的API信息dump并保存为`forward_info_{pid}.json`和`backward_info_{pid}.json`,通过 [Ascend模型精度预检工具](https://gitee.com/ascend/att/tree/master/debug/accuracy_tools/api_accuracy_checker)对json文件进行解析,输出溢出API为正常溢出还是非正常溢出,从而帮助用户快速判断。 + + 精度预检工具执行命令如下: + + ```bash + # 下载att代码仓后执行如下命令 + export PYTHONPATH=$PYTHONPATH:$ATT_HOME/debug/accuracy_tools/ + cd $ATT_HOME/debug/accuracy_tools/api_accuracy_checker/run_ut + python run_overflow_check.py -forward ./forward_info_0.json + ``` + + 反向过程溢出的API暂不支持精度预检功能。 + + 当重复执行溢出检测dump操作时,需要删除上一次dump目录下的溢出检测dump数据,否则将因重名而报错。 + +**注意事项** + +* dump_mode="acl"场景下,会增加npu的内存消耗,请谨慎开启。 +* 部分API存在调用嵌套关系,比如functional.batch_norm实际调用torch.batch_norm,该场景会影响acl init初始化多次,导致功能异常。 +* 混合精度动态loss scale场景下,正常训练会有"Gradient overflow. SKipping step"日志,添加溢出检测后日志消失,可以通过设置环境变量export OVERFLOW_DEBUG_MODE_ENABLE=1,并将register_hook位置调整amp.initialize之前解决。此功能需要cann包配套支持,不支持版本执行报错EZ3003。 + +## debugger方式dump和溢出检测(推荐) + +### PrecisionDebugger模块 + +**功能说明** + +PrecisionDebugger模块包含dump和溢出检测功能的总体配置项。可以指定dump目录,设置dump或溢出检测功能,指定dump的卡和迭代。 + +可以在from ptdbg_ascend import *和模型初始化之间的任意位置添加该模块。 + +**原型** + +```python +PrecisionDebugger(dump_path=None, hook_name=None, rank=None, step=[], enable_dataloader=False, model=None): +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ----------------- | ------------------------------------------------------------ | -------- | +| dump_path | 设置dump数据目录路径,参数示例:"./dump_path"。数据类型:str。
默认在dump_path目录下生成`ptdbg_dump_{version}`目录,并在该目录下生成`dump.pkl`文件以及`dump`数据文件保存目录。
当**configure_hook**函数配置了mode参数时,`dump.pkl`文件以及`dump`数据文件保存目录名称添加mode参数值为前缀,详情请参见“**dump数据存盘说明**”。
未配置dump_path时,也可以通过环境变量ASCEND_WORK_PATH配置dump路径,此时dump数据将落盘在${ASCEND_WORK_PATH}/dump_data下,自定义配置dump_path优先级高于环境变量,dump_path和环境变量需要二选一。 | 否 | +| hook_name | dump模式,可取值"dump"和"overflow_check",表示dump和溢出检测功能,二选一。参数示例:hook_name="dump"。数据类型:str。 | 是 | +| rank | 指定对某张卡上的数据进行dump或溢出检测,默认未配置(表示dump所有卡的数据),须根据实际卡的Rank ID配置。应配置为大于0的正整数,且须根据实际卡的Rank ID配置,若所配置的值大于实际训练所运行的卡的Rank ID,则dump数据为空,比如当前环境Rank ID为0到7,实际训练运行0到3卡,此时若配置Rank ID为4或不存在的10等其他值,此时dump数据为空。数据类型:int。 | 否 | +| step | 指定dump某个step的数据,默认未配置,表示dump所有step数据。dump特定step时,须指定为训练脚本中存在的step。step为list格式,可配置逐个step,例如:step=[0,1,2];也可以配置step范围,例如:step=list(range(0,9)),表示dump第0到第8个step。数据类型:List[int]。 | 否 | +| enable_dataloader | 自动控制开关,可取值True(开启)或False(关闭),默认为False。配置为True后自动识别dump step参数指定的迭代,并在该迭代执行完成后退出训练,此时start和stop函数可不配置,开启该开关要求训练脚本是通过torch.utils.data.dataloader方式加载数据;配置为False则需要配置start和stop函数,并在最后一个stop函数后或一个step结束的位置添加debugger.step()。数据类型:bool。 | 否 | +| model | 开启init dump模式,传入网络模型实例化的对象,配置该参数后,dump操作仅dump网络中init方法里调用的方法(nn.Module类),不会对所有API进行dump。参数示例: model=net,net为网络模型实例化的对象名称。默认未配置。
配置该参数时,PrecisionDebugger模块请在模型实例化之后调用。数据类型:torch.nn.Module。
该模式不支持“溢出检测”、”ACL级别数据dump“和“模块级精度数据dump”。此模式下dump文件名前缀为网络中定义的模块名或层名。 | 否 | + +#### init dump模式示例代码和数据落盘说明 + +**示例代码** + +```python +import os +import torch +import torch.nn as nn +import torch_npu +from ptdbg_ascend import * + +torch.npu.set_device("npu:0") + + +class Net(nn.Module): + + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=5, stride=1, padding=2) + self.relu1 = nn.ReLU() + self.bn1 = nn.BatchNorm2d(16) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + output = self.relu1(x) + return output + +if __name__ == "__main__": + net = Net().npu() + # model参数传入net, 开启init dump 功能 + debugger = PrecisionDebugger(dump_path="./dump", hook_name="dump", model=net) + debugger.configure_hook(mode="api_stack") + debugger.start() + x = torch.randn(1, 1, 28, 28).npu() + out = net(x) + loss = out.sum() + loss.backward() + debugger.stop() +``` + +**落盘数据说明** + +该模式下dump数据命名格式为:`{Layer_name}_{Module_name}_{call_num}_{forward/backward}_{input/output}.npy` + +``` +# 按照上述用例代码进行dump,落盘数据命名示例如下: +conv1_Conv2d_0_forward_input.0.npy +conv1_Conv2d_0_forward_output.npy +relu1_ReLU_0_forward_input.0.npy +....... +bn1_BatchNorm2d_0_backward_output.2.npy +``` + +### configure_hook函数(可选) + +**功能说明** + +设置dump范围。 + +建议在**PrecisionDebugger**模块与模型初始化之间的任意位置添加,不添加此函数时默认使用mode="api_stack" dump整网数据。 + +**原型** + +dump: + +```python +debugger.configure_hook(mode="api_stack", scope=[], api_list=[], filter_switch="OFF", acl_config=None, backward_input=[], input_output_mode=["all"], summary_only=False, summary_mode="all") +``` + +溢出检测: + +```python +debugger.configure_hook(mode=None, acl_config=None, overflow_nums=1, need_replicate=False) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ----------------- | ------------------------------------------------------------ | -------- | +| mode | dump模式。可取值"all"、"list"、"range"、"stack"、"acl"、"api_list"、"api_stack",各参数含义请参见本节的“**函数示例**”。参数示例:mode="list"。默认为"api_stack"。该参数配置值将作为dump数据文件名的前缀,详情请参见“**dump数据存盘说明**”。数据类型:str。 | 否 | +| scope或api_list | dump范围。根据model配置的模式选择dump的API范围,mode="api_list"时,需要配置api_list=[],其他模式有需要时配置scope=[]。参数示例:scope=["Tensor_permute_1_forward", "Tensor_transpose_2_forward"]、api_list=["relu"]。默认为空。数据类型:List[str]。 | 否 | +| filter_switch | dump bool和整型的tensor以及浮点、bool和整型的标量的过滤开关。可取值"ON"(表示开启过滤,即不dump)或"OFF"(表示关闭过滤)。参数示例:filter_switch="ON"。默认不配置,即filter_switch="OFF",表示dump上述数据。数据类型:str。 | 否 | +| acl_config | acl dump的配置文件。mode="acl"时,该参数必选;mode为其他值时,该参数不选。参数示例:acl_config='./dump.json'。dump.json配置文件详细介绍请参见“**dump.json配置文件说明**”。数据类型:str。 | 否 | +| backward_input | 该输入文件为首次运行训练dump得到反向API输入的.npy文件。例如若需要dump Functional_conv2d_1 API的反向过程的输入输出,则需要在dump目录下查找命名包含Functional_conv2d_1、backward和input字段的.npy文件。数据类型:str。 | 否 | +| input_output_mode | dump数据过滤。可取值"all"、"forward"、"backward"、"input"和"output",表示仅保存dump的数据中文件名包含"forward"、"backward"、"input"和"output"的前向、反向、输入或输出的.npy文件。参数示例input_output_mode=["backward"]或input_output_mode=["forward", "backward"]。默认为["all"],即保存所有dump的数据。除了all参数只能单独配置外,其他参数可以自由组合。数据类型:list。 | 否 | +| summary_only | dump npy文件过滤,可取值True或False,配置为True后仅dump保存API统计信息的pkl文件,参数示例:summary_only=False,默认为False。数据类型:bool。 | 否 | +| summary_mode | 控制dump文件输出的模式,可取值md5(dump仅输出包含md5值的pkl文件,用于验证数据的完整性)、summary(dump仅输出包含API统计信息的pkl文件)、all(dump输出包含API统计信息的pkl文件以及具体的npy文件),参数示例:summary_mode="md5",默认为"all"。summary_only=True时,不允许配置该参数。数据类型:str。 | 否 | +| overflow_nums | 控制溢出次数,表示第N次溢出时,停止训练,过程中检测到溢出API对应ACL数据均dump。参数示例:overflow_nums=3。配置overflow_check时可配置,默认不配置,即检测到1次溢出,训练停止,配置为-1时,表示持续检测溢出直到训练结束。数据类型:int。 | 否 | +| need_replicate | 过程dump数据生成开关,执行溢出检测时,dump目录下会生成forward_real_data和backward_real_data的过程dump数据目录,可取值True(生成)或False(不生成),默认不生成。数据类型:bool。 | 否 | + +**函数示例** + +configure_hook可配置多种dump模式,示例如下: + +说明: + +以下均以dump部分API数据为例,API名可以从首次dump整网数据的结果csv文件中的NPU Name或Bench Name列获取。 + +以下仅为该函数配置示例,完整代码请参见“**示例代码**”章节。 + +- 示例1:dump指定API列表 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="list", scope=["Tensor_permute_1_forward", "Tensor_transpose_2_forward", "Torch_relu_3_backward"]) + ``` + +- 示例2:dump指定范围 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="range", scope=["Tensor_abs_1_forward", "Tensor_transpose_3_forward"]) + ``` + +- 示例3:STACK模式,只dump堆栈信息 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="stack", scope=["Tensor_abs_1_forward", "Tensor_transpose_3_forward"]) + ``` + +- 示例4:dump指定前向API的ACL级别数据 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="acl", scope=["Tensor_permute_1_forward"], acl_config="./dump.json") + ``` + +- 示例5:dump指定反向API的ACL级别数据 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="acl", scope=["Functional_conv2d_1_backward"], acl_config="./dump.json", backward_input=["./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump/Functional_conv2d_1_backward_input.0.npy"]) + ``` + +- 示例6:dump指定某一类API的API级别输入输出数据 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="api_list", api_list=["relu"]) + ``` + + mode="api_list"时不配置scope。 + +- 示例7:dump全部API级别输入输出数据以及相应堆栈信息 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(mode="api_stack") + ``` + + mode="api_stack"时不配置scope。 + +- 示例8: dump全部API级别输入输出数据并包含bool和整型的tensor以及浮点、bool和整型的标量,配置为OFF,会dump bool和整型数据 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(filter_switch="OFF") + ``` + + 配置filter_switch="OFF"同时也可以配置mode、scope和api_list,除dump ACL级别数据。 + +- 示例9:仅保存dump的数据文件名包含“backward”的反向.npy文件 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(input_output_mode=["backward"]) + ``` + +- 示例10:仅dump pkl文件 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + debugger.configure_hook(summary_only=True) + ``` + +- 示例11:溢出检测dump + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="overflow_check", step=[0]) + debugger.configure_hook(overflow_nums=1) + ``` + + dump执行时会在**PrecisionDebugger**模块的dump_path参数指定的目录下生成ptdbg_dump_{version}目录,保存溢出数据。 + + 多卡场景时,需要检测到至少有一张卡溢出次数达到overflow_nums时,训练结束。 + + 仅支持NPU环境。 + +- 示例11:dump溢出API的ACL级别数据 + + ```python + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="overflow_check", step=[0]) + debugger.configure_hook(mode="acl", acl_config="./dump.json") + ``` + + 该场景会在原有数据基础上,额外在dump.json文件配置的dump_path目录下生成一份ACL算子数据,该数据可通过“**ptdbg_ascend.parse**”工具进行解析。 + + 仅支持NPU环境。 + +### start函数(可选) + +**功能说明** + +dump或溢出检测启动函数。 + +在模型初始化之后的任意位置添加。 + +**原型** + +```python +debugger.start() +``` + +该函数为类函数,可以使用debugger.start()也可以使用PrecisionDebugger.start()。 + +### stop函数(可选) + +**功能说明** + +dump或溢出检测停止函数。 + +在**start**函数之后的任意位置添加。 + +**原型** + +```python +debugger.stop() +``` + +该函数为类函数,可以使用debugger.stop()也可以使用PrecisionDebugger.stop()。 + +### 示例代码(自动模式) + +**需要保证用户训练代码是通过torch.utils.data.dataloader方式加载数据。** + +- 示例1:开启dump + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0,2], enable_dataloader=True) + # 请勿将以上初始化流程插入到循环代码中 + ``` + +- 示例2:开启溢出检测dump + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="overflow_check", step=[0,2], enable_dataloader=True) + # 请勿将以上初始化流程插入到循环代码中 + ``` + +### 示例代码(手动模式) + +一般情况下使用自动模式可以快速方便进行dump操作,但个别大模型可能在部分卡的训练操作中没有调用dataloader,这会导致自动模式无法dump指定迭代的数据,此时需要关闭自动模式手动在迭代前后插入start()和stop()函数,并在最后一个stop函数后或一个step结束的位置添加debugger.step()以标识dump结束。 + +- 示例1:开启dump + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="dump", step=[0]) + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + +- 示例2:开启溢出检测dump + + ```python + from ptdbg_ascend import * + debugger = PrecisionDebugger(dump_path="./dump_path", hook_name="overflow_check", step=[0]) + # 请勿将以上初始化流程插入到循环代码中 + + # 模型初始化 + # 下面代码也可以用PrecisionDebugger.start()和PrecisionDebugger.stop() + debugger.start() + + # 需要dump的代码片段1 + + debugger.stop() + debugger.start() + + # 需要dump的代码片段2 + + debugger.stop() + debugger.step() + ``` + +## register_hook方式dump和溢出检测 + +### 总体说明 + +- 本节主要介绍CPU或GPU及NPU精度数据dump和溢出检测所需要的函数以及示例。 + +- ptdbg_ascend工具默认情况下仅dump PyTorch模型的API输入输出数据进行精度比对,若在比对结果中发现某个API下可能存在ACL的精度问题,那么可以选择dump该API的ACL级别数据进行精度分析。 + +- 某些torch api的输出不是Tensor类型的数据。对于此类API的反向过程进行ACL dump,工具会在运行日志中给出对应的Warning(is not of tensor type and cannot be automatically derived)提示。如若想要进行该类API反向ACL dump,可以通过手动构建单API用例的方式进行ACL dump,具体用例可参见“**[反向ACL dump用例说明](https://gitee.com/ascend/att/blob/master/debug/accuracy_tools/ptdbg_ascend/doc/%E5%8F%8D%E5%90%91ACL%20dump%E7%94%A8%E4%BE%8B%E8%AF%B4%E6%98%8E.md)**”。 + +- 工具性能:dump数据量较小时(小于5G),参考dump速度0.1GB/s;dump数据量较大时,参考dump速度0.2GB/s。 + 推荐环境配置:独占环境,CPU核心数192,固态硬盘(IO速度参考:固态硬盘 > 500MB/s,机械硬盘60 ~ 170MB/s)。 + + 用户环境性能弱于标准约束或非独占使用的比对速度酌情向下浮动。Dump速度的计算方式:Dump数据量/(单个step添加Dump耗时-原始单个step耗时)。 + +### 约束 +- 进行CPU或GPU数据dump时,请安装torch包而非torch_npu包,避免工具无法识别使用场景,导致失败。 + +- TASK_QUEUE_ENABLE环境变量会导致API下发和执行异步进行,因此在ACL dump前需要将TASK_QUEUE_ENABLE关闭,即export TASK_QUEUE_ENABLE=0。 + +- 不建议在PyTorch训练脚本中同时添加dump接口和性能数据采集(如Ascend PyThon Profiler)接口,二者可能相互影响导致数据不准确。 + +### seed_all + +**功能说明** + +固定随机数。通过固定随机数保证模型的输入或输出一致。在训练主函数开始前调用,避免随机数固定不全。 + +使用form ptdbg import *后自动导入该函数,代码无需再次添加,若需要修改随机数种子和确定性计算模式,则需要通过添加该函数修改。 + +**函数原型** + +```python +seed_all(seed=1234, mode=False) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ------ | ------------------------------------------------------------ | -------- | +| seed | 随机数种子。参数示例:seed=1000。默认值为:1234。数据类型:int。 | 否 | +| mode | 确定性计算模式。可配置True或False。参数示例:mode=True。默认为False。数据类型:bool。
即使在相同的硬件和输入下,API多次执行的结果也可能不同,开启确定性计算是为了保证在相同的硬件和输入下,API多次执行的结果相同。
确定性计算会导致API执行性能降低,建议在发现模型多次执行结果不同的情况下开启。
rnn类算子、ReduceSum、ReduceMean等算子可能与确定性计算存在冲突,若开启确定性计算后多次执行的结果不相同,则考虑存在这些算子。 | 否 | + +**函数示例** + +seed_all函数的随机数种子,取默认值即可,无须配置;第二个参数默认关闭,不开启确定性计算时也无须配置。 + +- 示例1:仅固定随机数,不开启确定性计算 + + ```python + seed_all() + ``` + +- 示例2:固定随机数,开启确定性计算 + + ```python + seed_all(mode=True) + ``` + +**固定随机数范围** + +seed_all函数可固定随机数的范围如下表。 + +| API | 固定随机数 | +| ---------------------------------------- | --------------------------- | +| os.environ['PYTHONHASHSEED'] = str(seed) | 禁止Python中的hash随机化 | +| random.seed(seed) | 设置random随机生成器的种子 | +| np.random.seed(seed) | 设置numpy中随机生成器的种子 | +| torch.manual_seed(seed) | 设置当前CPU的随机种子 | +| torch.cuda.manual_seed(seed) | 设置当前GPU的随机种子 | +| torch.cuda.manual_seed_all(seed) | 设置所有GPU的随机种子 | +| torch_npu.npu.manual_seed(seed) | 设置当前NPU的随机种子 | +| torch_npu.npu.manual_seed_all(seed) | 设置所有NPU的随机种子 | +| torch.backends.cudnn.enable=False | 关闭cuDNN | +| torch.backends.cudnn.benchmark=False | cuDNN确定性地选择算法 | +| torch.backends.cudnn.deterministic=True | cuDNN仅使用确定性的卷积算法 | + +需要保证CPU或GPU以及NPU的模型输入完全一致,dump数据的比对才有意义,seed_all并不能保证模型输入完全一致,如下表所示场景需要保证输入的一致性。 + +| 场景 | 固定方法 | +| --------------- | ------------- | +| 数据集的shuffle | 关闭shuffle。 | +| dropout | 关闭dropout。 | + +关闭shuffle示例: + +```python +train_loader = torch.utils.data.DataLoader( + train_dataset, + batch_size = batch_size, + shuffle = False, + num_workers = num_workers +) +``` + +关闭dropout: + +在使用from ptdbg import *后,工具会自动将torch.nn.functional.dropout、torch.nn.functional.dropout2d、torch.nn.functional.dropout3d、torch.nn.Dropout、torch.nn.Dropout2d、torch.nn.Dropout3d的接口参数p置为0。 + +### set_dump_path + +**功能说明** + +设置数据保存目录。建议在seed_all函数之后调用且需要保证训练进程能够调用该函数;多卡时须保证每个进程都能调用该函数。 + +**函数原型** + +```python +set_dump_path(fpath=None, dump_tag='ptdbg_dump') +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| -------- | ------------------------------------------------------------ | -------- | +| fpath | 设置数据目录路径。参数示例:'./dump_path'。数据类型:str。
默认在dump_path目录下生成`ptdbg_dump_{version}`目录,并在该目录下生成`dump.pkl`文件以及`dump`数据文件保存目录。
当set_dump_switch函数配置了mode参数时,`dump.pkl`文件以及`dump`数据文件保存目录名称添加mode参数值为前缀,详情请参见“**dump数据存盘说明**”。
未配置fpath时,也可以通过环境变量ASCEND_WORK_PATH配置dump路径,此时数据将落盘在${ASCEND_WORK_PATH}/dump_data下,自定义配置dump_path优先级高于环境变量,fpath和环境变量需要二选一。 | 否 | +| dump_tag | 设置数据目录名称。参数示例:dump_tag='dump_conv2d'。默认数据目录命名为ptdbg_dump_{version}。数据类型:str。
{version}为当前安装ptdbg_ascend工具版本。目录结构参见“**dump数据存盘说明**”。
配置该参数会将生成的`ptdbg_dump_{version}`目录名称变更为dump_tag配置的值,如`dump_conv2d_{version}`。 | 否 | + +**函数示例** + +- 示例1:设置数据目录路径 + + ```python + set_dump_path('./dump_path') + ``` + +- 示例2:设置数据目录名称 + + ```python + set_dump_path('./dump_path', dump_tag='dump_conv2d') + ``` + + +若以相同的数据目录多次dump,则会因同名导致覆盖;多次dump建议配置不同的dump_tag。 + +### register_hook + +**功能说明** + +注册工具钩子函数。在set_dump_path之后调用。 + +dump操作必选。 + +**函数原型** + +```python +register_hook(model, hook, overflow_nums=overflow_nums, dump_mode=dump_mode, dump_config=dump_config_file) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ------------- | ------------------------------------------------------------ | -------- | +| model | 传入网络模型实例化的对象。参数示例: model=net,net为网络模型实例化的对象名称。数据类型:torch.nn.Module。 | 是 | +| hook | 注册工具的dump和溢出检测钩子。可取值overflow_check(表示溢出检测)和acc_cmp_dump(表示dump数据),二选一。数据类型:Callable。 | 是 | +| overflow_nums | 控制溢出次数,表示第N次溢出时,停止训练,过程中检测到溢出API对应ACL数据均dump。参数示例:overflow_nums=3。配置overflow_check时可配置,默认不配置,即检测到1次溢出,训练停止,配置为-1时,表示持续检测溢出直到训练结束。数据类型:int。 | 否 | +| dump_mode | 控制针对溢出API的dump模式,可取值"acl"或"api"。配置acl时,表示dump ACL级别的溢出数据,此时set_dump_path参数不生效,dump数据目录由dump_config的.json文件配置。参数示例:dump_mode="acl"。默认不配置,即dump API级别的溢出数据。数据类型:str。 | 否 | +| dump_config | acl dump的配置文件。dump_mode="acl"时,该参数必选;dump_mode="api"时,该参数不选。参数示例:dump_config='./dump.json'。数据类型:str。 | 否 | + +**函数示例** + +- 示例1:注册工具钩子函数 + + ```python + register_hook(model, acc_cmp_dump) + ``` + +- 示例2:dump指定API的ACL级别数据 + + ```python + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + ``` + + 需要配置set_dump_switch的mode="acl"以及scope指定为前向或反向API,请参见“**set_dump_switch”**的示例。 + + 该场景set_dump_path不生效,由dump_config中的dump.json文件配置dump数据目录。 + +- 示例3:溢出检测dump + + ```python + register_hook(model, overflow_check, overflow_nums=3) + ``` + + dump执行时会在set_dump_path的fpath参数指定的目录下生成ptdbg_dump_{version}目录,保存溢出数据。 + + 多卡场景时,需要检测到至少有一张卡溢出次数达到overflow_nums时,训练结束。 + + 仅支持NPU环境。 + +- 示例4:dump指定API的ACL级别溢出数据 + + ```python + register_hook(model, overflow_check, dump_mode='acl', dump_config='./dump.json') + ``` + + 该场景会在原有数据基础上,额外在dump.json文件配置的dump_path目录下生成一份ACL算子数据,该数据可通过“**ptdbg_ascend.parse**”工具进行解析。 + + 仅支持NPU环境。 + +### set_dump_switch + +**功能说明** + +设置dump范围。建议在register_hook函数之后的脚本内任意位置插入,但进行精度问题排查建议参照“场景化示例 > 单卡场景精度比对”章节的顺序,先从第一个迭代开始的位置调用并dump整网数据。 + +dump操作必选。 + +**函数原型** + +```python +def set_dump_switch(switch, mode="all", scope=[], api_list=[], filter_switch="OFF", dump_mode=["all"], summary_only=False): +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| --------------- | ------------------------------------------------------------ | -------- | +| switch | dump开关。可取值"ON"或"OFF"。须在选定dump开始的位置配置set_dump_switch("ON");dump结束的位置设置set_dump_switch("OFF")。数据类型:str。 | 是 | +| mode | dump模式。可取值"all"、"list"、"range"、"stack"、"acl"、"api_list"、"api_stack",各参数含义请参见本节的“**函数示例**”。参数示例:mode="list"。默认为"all"。该参数配置值将作为dump数据文件名的前缀,详情请参见“**dump数据存盘说明**”。数据类型:str。 | 否 | +| scope或api_list | dump范围。根据model配置的模式选择dump的API范围。参数示例:scope=["Tensor_permute_1_forward", "Tensor_transpose_2_forward"]、api_list=["relu"]。默认为空。数据类型:List[str]。 | 否 | +| filter_switch | dump bool和整型的tensor以及浮点、bool和整型的标量的过滤开关。可取值"ON"或"OFF"。参数示例:filter_switch="ON"。默认不配置,即filter_switch="OFF",表示dump上述数据。数据类型:str。 | 否 | +| dump_mode | dump数据过滤。可取值"all"、"forward"、"backward"、"input"和"output",表示仅保存dump的数据中文件名包含"forward"、"backward"、"input"和"output"的前向、反向、输入或输出的.npy文件。参数示例dump_mode=["backward"]或dump_mode=["forward", "backward"]。默认为all,即保存所有dump的数据。除了all参数只能单独配置外,其他参数可以自由组合。数据类型:List[str]。 | 否 | +| summary_only | dump npy文件过滤,可取值True或False,配置为True后仅dump保存API统计信息的pkl文件,参数示例:summary_only=False,默认为False。数据类型:bool。 | 否 | + +**推荐配置** + +```python +set_dump_switch("ON", mode="api_stack", filter_switch="OFF") +``` + +开启dump数据和堆栈模式,同时为保证数据完整性开启dump bool和整型的tensor以及浮点、bool和整型的标量。 + +**函数示例** + +set_dump_switch可配置多种dump模式,示例如下: + +说明:以下均以dump部分API数据为例,API名可以从首次dump整网数据的结果csv文件中的NPU Name或Bench Name列获取。 + +- 示例1:dump指定API列表 + + ```python + set_dump_switch("ON", mode="list", scope=["Tensor_permute_1_forward", "Tensor_transpose_2_forward", "Torch_relu_3_backward"]) + ``` + +- 示例2:dump指定范围 + + ```python + set_dump_switch("ON", mode="range", scope=["Tensor_abs_1_forward", "Tensor_transpose_3_forward"]) + ``` + +- 示例3:STACK模式,只dump堆栈信息 + + ```python + set_dump_switch("ON", mode="stack", scope=["Tensor_abs_1_forward", "Tensor_transpose_3_forward"]) + ``` + +- 示例4:dump指定前向API的ACL级别数据 + + ```python + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + set_dump_switch("ON", mode="acl", scope=["Tensor_permute_1_forward"]) + ``` + + 需要配置register_hook的dump_mode='acl'和dump_config配置文件。 + +- 示例4:dump指定反向API的ACL级别数据 + + ```python + register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') + set_dump_switch("ON", mode="acl", scope=["Functional_conv2d_1_backward"]) + set_backward_input(["./npu_dump/dump_conv2d_v4.0/step0/rank0/dump/Functional_conv2d_1_backward_input.0.npy"]) + ``` + + 需要配置register_hook的dump_mode='acl'和dump_config配置文件,并通过set_backward_input设置反向API输入的.npy文件。 + +- 示例5:dump指定某一类API的API级别输入输出数据 + + ```python + set_dump_switch("ON", mode="api_list", api_list=["relu"]) + ``` + + mode="api_list"时不配置scope。 + +- 示例6:dump全部API级别输入输出数据以及相应堆栈信息 + + ```python + set_dump_switch("ON", mode="api_stack") + ``` + + mode="api_stack"时不配置scope。 + +- 示例7: dump全部API级别输入输出数据并包含bool和整型的tensor以及浮点、bool和整型的标量,配置为OFF,会dump bool和整型数据 + + ```python + set_dump_switch("ON", filter_switch="OFF") + ``` + + 配置filter_switch="OFF"同时也可以配置mode、scope和api_list,除dump ACL级别数据。 + +- 示例8:仅保存dump的数据文件名包含“backward”的反向.npy文件 + + ```python + set_dump_switch("ON", dump_mode=["backward"]) + ``` + +- 示例9:仅dump pkl文件 + + ```python + set_dump_switch("ON", summary_only=True) + ``` + +以上示例均需要在结束dump的位置插入set_dump_switch("OFF")。 + +set_dump_switch配置mode为all或api_stack时,结束dump后,在dump目录下会自动生成compare_data.py比对脚本模板,示例如下: + +```python +from ptdbg_ascend import compare + +pkl_path = "%s" +dump_data_dir = "%s" + +dump_path_param = { + "npu_pkl_path": , + "bench_pkl_path": , + "npu_dump_data_dir": , + "bench_dump_data_dir": , + "is_print_compare_log": True +} + +compare(dump_path_param, output_path="", stack_mode="%s") +``` + +pkl_path和dump_data_dir字段会自动识别pkl和dump目录的路径,用户需要判断当前dump的环境是NPU、CPU或GPU,并将pkl_path和dump_data_dir字段填入下方dump_path_param函数对应的字段中,例如当前设备为NPU,那么填写方式如下: + +```python +from ptdbg_ascend import compare + +pkl_path = "%s" +dump_data_dir = "%s" + +dump_path_param = { + "npu_pkl_path": pkl_path, + "bench_pkl_path": , + "npu_dump_data_dir": dump_data_dir, + "bench_dump_data_dir": , + "is_print_compare_log": True +} + +compare(dump_path_param, output_path="", stack_mode="%s") +``` + +此时,另一侧数据的路径,需要用户另外识别并填入。 + +### set_overflow_check_switch + +**功能说明** + +置溢出检测范围。默认不配置该函数,全量进行溢出检测。 + +仅支持NPU环境。 + +**函数原型** + +```python +set_overflow_check_switch(switch, filter_switch='OFF') +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ------------- | ------------------------------------------------------------ | -------- | +| switch, | 检测开关。可取值"ON"或"OFF"。如果只在特定的step溢出检测,则在期望溢出检测的step位置开始前插入set_overflow_check_switch("ON"),在step结束的位置插入set_overflow_check_switch("OFF")。数据类型:str。 | 是 | +| filter_switch | dump bool和整型的tensor以及浮点、bool和整型的标量的过滤开关。可取值"ON"或"OFF"。参数示例:filter_switch="ON"。默认不配置,即filter_switch="OFF",表示dump上述数据。数据类型:str。 | 否 | + +**函数示例** + +- 示例1:指定范围溢出检测 + + ```python + register_hook(model, overflow_check) + set_overflow_check_switch("ON") + + ... + + set_overflow_check_switch("OFF") + ``` + + 该场景set_dump_path不生效,dump执行时会在当前目录自动生成ptdbg_dump_{version}目录,保存溢出数据。 + +- 示例2:前向API的ACL级别范围溢出检测 + + ```python + register_hook(model, overflow_check, dump_mode='acl', dump_config='./dump.json') + set_overflow_check_switch("ON") + + ... + + set_overflow_check_switch("OFF") + ``` + + 该场景set_dump_path不生效,由dump_config中的dump.json文件配置溢出数据目录。 + +### set_backward_input + +**功能说明** + +设置反向ACL级别dump时需要的反向输入的.npy文件。 + +**函数原型** + +```python +set_backward_input(backward_input) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| -------------- | ------------------------------------------------------------ | -------- | +| backward_input | 该输入文件为首次运行训练dump得到反向API输入的.npy文件。例如若需要dump Functional_conv2d_1 API的反向过程的输入输出,则需要在dump目录下查找命名包含Functional_conv2d_1、backward和input字段的.npy文件。数据类型:str。 | 是 | + +**函数示例** + +```python +register_hook(model, acc_cmp_dump, dump_mode='acl', dump_config='./dump.json') +set_dump_switch("ON", mode="acl", scope=["Functional_conv2d_1_backward"]) +set_backward_input(["./npu_dump/dump_conv2d_v4.0/step0/rank0/dump/Functional_conv2d_1_backward_input.0.npy"]) +``` + +## dump.json配置文件说明 + +**dump.json配置示例** + +```python +{ + "dump": + { + "dump_list":[], + "dump_path":"./dump/output", + "dump_mode":"all", + "dump_op_switch":"on" + } +} +``` + +**dump.json参数说明** + +| 字段名 | 说明 | +| -------------- | ------------------------------------------------------------ | +| dump_list | 待dump数据的API模型。为空,无需配置。 | +| dump_path | dump数据文件存储到运行环境的目录,主要用于指定ACL dump数据路径。支持配置绝对路径或相对路径。dump_path须为已存在目录。 | +| dump_mode | dump数据模式,配置如下:
- output:dump API的输出数据。默认值。
- input:dump API的输入数据。
- all:dump API的输入、输出数据。 | +| dump_op_switch | 单API模型dump数据开关,配置如下: * off:关闭单API模型dump,默认值。 * on:开启单API模型dump。 | + +**dump目录说明** + +配置register_hook的dump_config后,采集的dump数据会在{dump_path}/{time}/{deviceid}/{model_id}目录下生成,例如“/home/HwHiAiUser/output/20200808163566/0/0” + +```bash +├── 20230131172437 +│   └── 1 +│   ├── 0 +│   │   ├── Add.Add.45.0.1675157077183551 +│   │   ├── Cast.trans_Cast_0.31.0.1675157077159449 +│   │   ├── Cast.trans_Cast_5.43.0.1675157077180129 +│   │   ├── MatMul.MatMul.39.0.1675157077172961 +│   │   ├── Mul.Mul.29.0.1675157077155731 +│   │   ├── NPUAllocFloatStatus.NPUAllocFloatStatus.24.0.1675157077145262 +│   │   ├── TransData.trans_TransData_1.33.0.1675157077162791 +│   │   └── TransData.trans_TransData_4.41.0.1675157077176648 +│   ├── 1701737061 +│   │   └── Cast.trans_Cast_2.35.0.1675157077166214 +│   ├── 25 +│   │   └── NPUClearFloatStatus.NPUClearFloatStatus.26.0.1675157077150342 +│   └── 68 +│   └── TransData.trans_TransData_3.37.0.1675157077169473 +``` + +## 模块级精度数据dump + +### 总体说明 + +大模型场景下,通常不是简单的利用自动迁移能力实现GPU到NPU的训练脚本迁移,而是会对NPU网络进行一系列针对性的适配,因此,常常会造成迁移后的NPU模型存在部分子结构不能与GPU原始模型完全对应。模型结构不一致导致API调用类型及数量不一致,若直接按照API粒度进行精度数据dump和比对,则无法完全比对所有的API。 + +本节介绍的功能是对模型中的大粒度模块进行数据dump,使其比对时,对于无法以API粒度比对的模块可以直接以模块粒度进行比对。 + +模块指的是继承自nn.Module类模块,通常情况下这类模块就是一个小模型,可以被视为一个整体,dump数据时以模块为粒度进行dump。 + +### module_dump + +**功能说明** + +开启模块级精度数据dump。 + +模块级精度数据dump时必选。 + +**函数原型** + +```python +module_dump(module, module_name) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ----------- | ------------------------------------------------------------ | -------- | +| module | 网络中实例化好的nn.Module类对象。数据类型:torch.nn.Module。 | 是 | +| module_name | 用户自定义的该model名称。主要用于dump数据文件的命名,便于在比对时识别模块级数据。数据类型:str。 | 是 | + +### module_dump_end + +**功能说明** + +结束模块级精度数据dump。 + +模块级精度数据dump时必选。 + +**函数原型** + +```python +module_dump_end() +``` + +### 示例代码 + +```python +# 根据需要import包 +import os +import torch +import torch.nn as nn +import torch_npu +import torch.nn.functional as F +from ptdbg_ascend import * + +torch.npu.set_device("npu:0") +# 定义一个简单的网络 +class ModuleOP(nn.Module): + def __init__(self) -> None: + super().__init__() + self.linear_1 = nn.Linear(in_features=8, out_features=4) + self.linear_2 = nn.Linear(in_features=4, out_features=2) + def forward(self, x): + x1 = self.linear_1(x) + x2 = self.linear_2(x1) + r1 = F.relu(x2) + return r1 + +if __name__ == "__main__": + module = ModuleOP() + + # 注册工具 + pdbg = PrecisionDebugger("./dump_data/npu", hook_name="dump") + pdbg.start() + + x = torch.randn(10, 8) + module_dump(module, "MyModuleOP") # 开启模块级精度数据dump + out = module(x) + module_dump_end() # 结束模块级精度数据dump + loss = out.sum() + loss.backward() + pdbg.stop() +``` + +## dump数据存盘说明 + +dump结果目录结构示例如下: + +```bash +├── dump_path +│ └── ptdbg_dump_{version} +│ ├── step0 +│ | ├── rank0 +│ | │ ├── dump +| | | | ├── Tensor_permute_1_forward.npy +| | | | ├── MyModule_0_forward_input.npy # 开启模块级精度数据dump时存在模块级的dump数据文件 +| | | | ... +| | | | └── Fcuntion_linear_5_backward_output.npy +│ | │ └── dump.pkl +│ | ├── rank1 +| | | ├── dump +| | | | └── ... +| | | └── dump.pkl +│ | ├── ... +│ | | +| | └── rank7 +│ ├── step1 +│ | ├── ... +│ ├── step2 +``` + +dump过程中,npy文件在对应算子或者模块被执行后就会落盘,而pkl文件则需要在正常执行PrecisionDebugger.stop()或set_dump_switch("OFF")后才会被落盘保存,异常的程序终止会保存终止前被执行算子的相关npy文件,但是不会生成pkl文件。 + +其中`ptdbg_dump_{version}`为默认命名,debugger方式dump不支持修改该文件夹名称,使用set_dump_path函数则支持通过dump_tag参数修改文件夹名称;rank为设备上各卡的ID,每张卡上dump的数据会生成对应dump目录。 + +**精度比对dump场景** + +精度比对dump场景的结果如下: + +* dump.pkl文件:包含dump数据的API名称(命名格式为:`{api_type}_{api_name}_{API调用次数}_{前向反向}_{input/output}.{参数序号}`)、dtype、 shape、各数据的max、min、mean、L2norm统计信息以及当配置summary_mode="md5"时的md5数据。 + + 其中,“参数序号”表示该API下的第n个参数,例如1,则为第一个参数,若该参数为list格式,则根据list继续排序,例如1.1,表示该API的第1个参数的第1个子参数;L2norm表示2范数(平方根)。 + +* dump目录:目录下为npy格式的dump数据。 + + npy文件保存的前缀和PyTorch对应关系如下 + + | 前缀 | Torch模块 | + | ----------- | ------------------- | + | Tensor | torch.Tensor | + | Torch | torch | + | Functional | torch.nn.functional | + | NPU | NPU亲和算子 | + | VF | torch._VF | + | Aten | torch.ops.aten | + | Distributed | torch.distributed | + +当configure_hook或set_dump_switch配置mode参数(例如:mode="api_stack" )时,dump结果的文件名会添加api_stack前缀,dump结果如下: + +* api_stack_dump.pkl +* api_stack_dump目录 + +**溢出检测dump场景** + +PrecisionDebugger模块的hook_name参数或register_hook函数设置了overflow_check时,检测API溢出,dump结果的文件名格式为:`{api_type}_{api_name}_{API调用次数}_{前向反向}_{当前溢出次数}`,dump结果示例如下: + +* `Tensor_add_1_forward_1.pkl` +* `Tensor_add_1_forward_1`目录 + +## 工具支持的API列表 + +ptdbug_ascend工具维护固定的API支持列表,若需要删除或增加dump的API,可以在[support_wrap_ops.yaml](../src/python/ptdbg_ascend/hook_module/support_wrap_ops.yaml)文件内手动修改,如下示例: + +```bash +functional: # functional为算子类别,找到对应的类别,在该类别下按照下列格式删除或添加API + - conv1d + - conv2d + - conv3d +``` + +## CPU或GPU与NPU精度数据比对 + +### 总体说明 + +- 本节主要介绍CPU或GPU与NPU精度数据比对的函数以及示例。 + +- 比对函数均通过单独创建精度比对脚本执行,可支持单卡和多卡场景的精度数据比对。 + +- 工具性能:比对数据量较小时(参考值单份文件小于10GB),参考比对速度0.1GB/s;比对数据量较大时,参考比对速度0.3GB/s。 + 推荐环境配置:独占环境,CPU核心数192,固态硬盘(IO速度参考:固态硬盘 > 500MB/s,机械硬盘60 ~ 170MB/s)。 + + 用户环境性能弱于标准约束或非独占使用的比对速度酌情向下浮动。比对速度的计算方式:两份比对文件大小/比对耗时。 + +### 约束 + +- NPU自研API,在CPU或GPU若没有对应的API,该API的dump数据不比对。 + +- NPU与CPU或GPU的计算结果误差可能会随着模型的执行不断累积,最终会出现同一个API因为输入的数据差异较大而无法比对的情况。 + +- CPU或GPU与NPU中两个相同的API会因为调用次数不同导致无法比对或比对到错误的API,不影响整体运行,该API忽略。 + +### compare_distributed + +**功能说明** + +将CPU或GPU与NPU的dump文件进行比对,支持单卡和多卡,可同时比对多卡的dump数据。多机场景需要每个设备单独执行比对操作。可自动检索和匹配对应卡和进程所dump的数据文件,再调用compare进行比对。单机单卡时与compare函数二选一。 + +**函数原型** + +```python +compare_distributed(npu_dump_dir, bench_dump_dir, output_path, **kwargs) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| -------------- | ------------------------------------------------------------ | -------- | +| npu_dump_dir | 配置NPU环境下的dump目录。dump数据目录须指定到step级。参数示例:'./npu_dump/ptdbg_dump_v4.0/step0'。register_hook方式可通过set_dump_path函数的dump_tag参数修改该目录名称。数据类型:str。 | 是 | +| bench_dump_dir | 配置CPU、GPU或NPU环境下的dump目录。参数示例:'./gpu_dump/ptdbg_dump_v4.0/step0'。register_hook方式可通过set_dump_path函数的dump_tag参数修改该目录名称。数据类型:str。 | 是 | +| output_path | 配置比对结果csv文件存盘目录。需要预先创建output_path目录。参数示例:'./output'。文件名称基于时间戳自动生成,格式为:`compare_result_rank{npu_ID}-rank{cpu/gpu/npu_ID}_{timestamp}.csv`。数据类型:str。 | 是 | +| **kwargs | 支持compare的所有可选参数。 | 否 | + +**函数示例** + +创建比对脚本,例如compare_distributed.py,拷贝如下代码,具体参数请根据实际环境修改。 + +```python +from ptdbg_ascend import * +compare_distributed('./npu_dump/ptdbg_dump_v4.0/step0', './gpu_dump/ptdbg_dump_v4.0/step0', './output') +``` + +dump数据目录须指定到step级。 + +### compare + +**功能说明** + +将CPU或GPU与NPU的dump文件进行比对,仅支持单机单卡。 + +**函数原型** + +```python +compare(input_param, output_path, stack_mode=False, auto_analyze=True, fuzzy_match=False) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ------------ | ------------------------------------------------------------ | -------- | +| input_param | 配置dump数据文件及目录。数据类型:dict。配置参数包括:
- "npu_pkl_path":指定NPU dump目录下的.pkl文件。参数示例:"npu_pkl_path": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl"。必选。
- "bench_pkl_path":指定CPU、GPU或NPU dump目录下的.pkl文件。参数示例:"bench_pkl_path": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl"。必选。
- "npu_dump_data_dir":"指定NPU dump目录下的dump数据目录。参数示例:"npu_dump_data_dir": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump"。可选,仅比对pkl文件时不选。
- "bench_dump_data_dir":"指定CPU、GPU或NPU dump目录下的dump数据目录。参数示例:"npu_dump_data_dir": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump"。可选,仅比对pkl文件时不选。
- "is_print_compare_log":配置是否开启日志打屏。可取值True或False。可选。 | 是 | +| output_path | 配置比对结果csv文件存盘目录。参数示例:'./output'。文件名称基于时间戳自动生成,格式为:`compare_result_{timestamp}.csv`。数据类型:str。 | 是 | +| stack_mode | 配置stack_mode的开关。仅当dump数据时配置debugger.configure_hook或set_dump_switch的mode="api_stack"时需要开启。可取值True或False,参数示例:stack_mode=True,默认为False。数据类型:bool。 | 否 | +| auto_analyze | 自动精度分析,开启后工具自动针对比对结果进行分析,识别到第一个精度不达标节点(在比对结果文件中的“Accuracy Reached or Not”列显示为No),并给出问题可能产生的原因(打屏展示并生成advisor_{timestamp}.txt文件)。可取值True或False,参数示例:auto_analyze=False,默认为True。数据类型:bool。 | 否 | +| fuzzy_match | 模糊匹配。开启后,对于网络中同一层级且命名仅调用次数不同的API,可匹配并进行比对。可取值True或False,参数示例:fuzzy_match=True,默认为False。数据类型:bool。 | 否 | + +**函数示例** + +单机单卡场景下创建比对脚本,例如compare.py,拷贝如下代码,具体参数请根据实际环境修改。 + +```python +from ptdbg_ascend import * +dump_result_param={ +"npu_pkl_path": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", +"bench_pkl_path": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", +"npu_dump_data_dir": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump", +"bench_dump_data_dir": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump", +"is_print_compare_log": True +} +compare(dump_result_param, output_path="./output", stack_mode=True) +``` + +### pkl文件比对 + +若使用**compare**或**compare_distributed**函数创建的比对脚本中,input_param参数只配置了npu_pkl_path和bench_pkl_path或使用summary_only方式dump时,可以进行pkl文件的比对,此时比对dump.pkl文件中的统计信息,开启后的比对结果文件生成Max diff、Min diff、Mean diff和L2norm diff,表示NPU dump数据中API的输入或输出与标杆数据输入或输出的最大值、最小值、平均值以及L2范数的差。可以通过该值判断API是否存在精度问题:当某个API的输入和输出的Max diff、Min diff、Mean diff和L2norm diff均为0或无限趋于0,那么可以判断该API无精度问题,反之则可能存在精度问题。 + +**比对脚本示例** + +```python +from ptdbg_ascend import compare +dump_result_param={ +"npu_pkl_path": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", +"bench_pkl_path": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/api_stack_dump.pkl", +"is_print_compare_log": True +} +compare(dump_result_param, output_path="./output", stack_mode=True) +``` + +### parse + +**功能说明** + +解析并提取dump信息中的堆栈信息及数据统计信息。 + +**函数原型** + +```python +parse(pkl_file, module_name_prefix) +``` + +**参数说明** + +| 参数名 | 说明 | 是否必选 | +| ------------------ | ------------------------------------------------------------ | -------- | +| pkl_file | 指定dump数据文件中的pkl文件名。参数示例:"./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump.pkl"。数据类型:str。 | 是 | +| module_name_prefix | 指定待提取的API接口前缀。参数示例:"Torch_norm_1_forward"。数据类型:str。 | 是 | +**函数示例** + +创建堆栈信息及数据统计信息提取脚本,例如parse.py,拷贝如下代码,具体参数请根据实际环境修改。 + +```python +from ptdbg_ascend import * +parse("./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump.pkl", "Torch_batch_normal_1_forward") +``` + +### 计算精度评价指标 + +PyTorch精度比对是以CPU或GPU的计算结果为标杆,计算Cosine(余弦相似度)、MaxAbsErr(最大绝对误差)和MaxRelativeErr(最大相对误差),根据这两个结果判断API在运行时是否存在精度问题。 + +计算精度评价指标: + +1. Cosine:通过计算两个向量的余弦值来判断其相似度,数值越接近于1说明计算出的两个张量越相似,实际可接受阈值为大于0.99。在计算中可能会存在nan,主要由于可能会出现其中一个向量为0。 + +2. MaxAbsErr:当最大绝对误差越接近0表示其计算的误差越小,实际可接受阈值为小于0.001。 + +3. MaxRelativeErr:当最大相对误差越接近0表示其计算的误差越小。 + + 当dump数据中存在0或Nan时,比对结果中最大相对误差则出现inf或Nan的情况,属于正常现象。 + +4. One Thousandth Err Ratio(双千分之一)、Five Thousandths Err Ratio(双千分之五)精度指标:是指NPU的Tensor中的元素逐个与对应的标杆数据对比,相对误差大于千分之一、千分之五的比例占总元素个数的比例小于千分之一、千分之五。该数据仅作为精度下降趋势的参考,并不参与计算精度是否通过的判定。 + +精度比对结果csv文件中只需要通过Accuracy Reached or Not来判断计算精度是否达标,判断标准如下: + +1. Cosine < 0.99 且 MaxAbsError > 0.001时,精度不达标,标记为“No”。 +2. Cosine < 0.9,精度不达标,标记为“No”。 +3. MaxAbsError > 1,精度不达标,标记为“No”。 +5. 其余情况下记为精度达标,标记为“Yes”。 + +## ptdbg_ascend.parse数据解析功能 + +ptdbg_ascend.parse为命令行交互式界面解析工具,提供更多的数据解析功能并且展示结果。 + +使用场景:本工具主要用于比对前后两次NPU ACL层级dump数据的一致性。 + +### 进入parse交互式界面 + +安装ptdbg_ascend工具后,可以通过使用命令 **python -m ptdbg_ascend.parse** 进入交互式界面,如下所示: + +```bash +python -m ptdbg_ascend.parse +Parse >>> +``` + +可在parse的界面中执行Shell命令,以及如下场景的相关解析命令: + +- 支持指定ACL层级算子数据比对。 +- 支持指定ACL层级算子数据转换及展示。 +- 支持交互式指定pkl文件中API对应dump数据查看。 +- 支持API进行可选层级比对和打印(统计级和像素级)。 + +Ctrl+C可以退出parse交互式界面。不退出parse交互式界面若需要执行非该界面下的内置Shell命令,且命令与parse交互式界面命令冲突时,非该界面命令需要使用run命令,在相关命令前加上run前缀,如下示例: + +```bash +python -m ptdbg_ascend.parse +Parse >>> run vim cli.py +Parse >>> vim cli.py +``` + +以上各场景详细介绍请参见下文章节。 + +### ACL层级算子数据批量转换 + +本功能会将原有待比对dump数据目录下的dump数据按照算子名和时间戳进行梳理并分类,之后再将dump数据转为为npy文件。 + +依赖:CANN包中的msaccucmp工具,需要安装Ascend-CANN-toolkit,详见《[CANN 软件安装指南](https://gitee.com/link?target=https%3A%2F%2Fwww.hiascend.com%2Fdocument%2Fdetail%2Fzh%2Fcanncommercial%2F700%2Fenvdeployment%2Finstg%2Finstg_0001.html)》。 + +输入以下比对命令进行数据转换。 + +```bash +cad -m my_dump_path [-out output_path] [-asc msaccucmp_path] +``` + +| 参数名称 | 说明 | 是否必选 | +| -------- | ------------------------------------------------------------ | -------- | +| -m | 待转换ACL dump数据目录。需要指定到ACL dump数据的deviceid级目录。 | 是 | +| -out | 结果输出目录,须指定已存在的目录,默认为./parse_data/acl_batch_convert。未指定时保存在默认路径下,比对结束后会打印log提示输出结果存放路径。 | 否 | +| -asc | 指定msaccucmp路径,默认路径为:/usr/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py。 | 否 | + +**示例** + +```bash +# 传入待比对数据目录 +Parse >>> cad -m /home/xxx/my_dump_path/20000124003856/0 +# 转换结果打印 +...... +╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +# 转换前的dump文件 +│ SrcFile: /home/xxx/my_dump_path/20000124003856/0/272/TransData.trans_TransData_22.112.21.948645536672764 │ +# 转换后的npy文件 +│ - TransData.trans_TransData_22.112.21.948645536672764.output.0.npy │ +│ - TransData.trans_TransData_22.112.21.948645536672764.input.0.npy │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +...... +[INFO] The comparison result have been written to "./parse_data/acl_batch_convert". +``` + +输出结果: + +原dump数据目录: + +```bash +├── /home/xxx/my_dump_path/20000124003856/0/ +│ ├── 272 +│ │ ├── {op_type}.{op_name}.{task_id}.{stream_id}.{timestamp} +│ │ ... +│ ├── 512 +│ ... +``` + +转换后: + +```bash +├── ./parse_data/acl_batch_convert/{timestamp} +│ ├── {op_name1} +│ │ ├── {timestamp1} +│ │ | ├── {op_type}.{op_name}.{task_id}.{stream_id}.{timestamp}.{input/output}.{参数序号}.npy +│ │ | │ ... +│ │ ├── {timestamp2} +│ │ | ... +│ ├── {op_name2} +│ ├── ... +``` + +### ACL层级算子数据比对 + +本功能主要用于比对前后两次NPU ACL层级dump数据的一致性。 + +本功能支持批量比对,若需要进行批量比对,需要先将两份待比对的NPU ACL层级dump数据进行“**ACL层级算子数据批量转换**”,可以使两份数据更好的匹配;若直接进行dump数据的比对,建议只比对单个dump数据文件。 + +输入以下比对命令进行数据比对。 + +```bash +vc -m my_dump_path -g golden_dump_path [-out output_path] [-cmp_path msaccucmp_path] +``` + +| 参数名称 | 说明 | 是否必选 | +| --------- | ------------------------------------------------------------ | -------- | +| -m | 待比对ACL dump数据目录。如果比对单个算子,需要指定到ACL dump数据的model_id级目录;如果批量比对,则指定到cad转换后的timestamp级目录。 | 是 | +| -g | 标杆ACL dump数据目录。如果比对单个算子,需要指定到ACL dump数据的model_id级目录;如果批量比对,则指定到cad转换后的timestamp级目录。 | 是 | +| -out | 结果输出目录,须指定已存在的目录,默认为./parse_data/acl_batch_comapre。未指定时保存在默认路径下,比对结束后会打印log提示输出结果存放路径。 | 否 | +| -cmp_path | 指定msaccucmp路径,默认路径为:/usr/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py | 否 | + +输出结果:batch_compare_{timestamp}.csv文件。 + +**示例** + +```bash +# 传入待比对数据目录以及标杆数据目录 +Parse >>> vc -m ./my_dump_path -g ./golden_data_path +[INFO]Compare result is saved in : parse_data/acl_batch_comapre/batch_compare_1707271118.csv +``` + +### ACL算子数据的npy转换 + +依赖:CANN包中的msaccucmp工具,需要安装Ascend-CANN-toolkit,详见《[CANN 软件安装指南](https://gitee.com/link?target=https%3A%2F%2Fwww.hiascend.com%2Fdocument%2Fdetail%2Fzh%2Fcanncommercial%2F700%2Fenvdeployment%2Finstg%2Finstg_0001.html)》。 + +输入以下转换命令进行数据转换, 将ACL级别dump数据转为npy文件。 + +```bash +dc -n file_name/file_path [-f format] [-out output_path] +``` + +| 参数名称 | 说明 | 是否必选 | +| --------- | ------------------------------------------------------------ | -------- | +| -n | 需转换的dump数据文件或dump数据文件目录。 | 是 | +| -f | 开启format转换,指定该参数时需要配置format格式。当前内置的Format转换支持如下类型:
FRACTAL_NZ转换NCHW
FRACTAL_NZ转换成NHWC
FRACTAL_NZ转换ND
HWCN转换FRACTAL_Z
HWCN转换成NCHW
HWCN转换成NHWC
NC1HWC0转换成HWCN
NC1HWC0转换成NCHW
NC1HWC0转换成NHWC
NCHW转换成FRACTAL_Z
NCHW转换成NHWC
NHWC转换成FRACTAL_Z
NHWC转换成HWCN
NHWC转换成NCHW
NDC1HWC0转换成NCDHW | 否 | +| -out | 结果输出目录。 | 否 | +| -cmp_path | 指定msaccucmp路径,默认路径为:/usr/local/Ascend/ascend-toolkit/latest/tools/operator_cmp/compare/msaccucmp.py | 否 | + +[^]: 若传入单个dump文件,则转换单个文件,若传入dump文件目录则转换目录下所有dump文件。 + +- 输出结果:npy文件。 +- 若指定-out参数需要用户传入输出路径,并且路径需要已存在。 +- 若未指定输出目录, 则比对结束后将结果保存在默认目录 “./parse_data/convert_result”中,比对结束后会打印log提示输出结果存放路径及转换结果。 + +- 输入以下命令,展示npy数据统计信息。 + + ```bash + pt -n file_path + ``` + + | 参数名称 | 说明 | 是否必选 | + | -------- | ------------- | -------- | + | -n | npy文件路径。 | 是 | + + 打印统计信息:shape, dtype, max, min和mean。默认在npy文件路径下将该数据保存为txt文件。 + +**示例1** + +```bash +# 传入需转换的dump文件目录 +Parse >>> dc -n ./dump_data/ +...... +# 转换结果 +╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ SrcFile: ./dump_data/ +│ - Add.fp32_vars_add_2fp32_vars_Relu_9.31.5.1636595794731103.input.0.npy │ +│ - Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.output.0.npy │ +│ - Add.fp32_vars_add_2fp32_vars_Relu_9.31.5.1636595794731103.input.1.npy │ +│ - Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.input.1.npy │ +│ - Add.fp32_vars_add_3fp32_vars_Relu_12.40.5.1636595794846124.input.1.npy │ +│ - Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.input.0.npy │ +│ - Add.fp32_vars_add_3fp32_vars_Relu_12.40.5.1636595794846124.input.0.npy │ +│ - Add.fp32_vars_add_2fp32_vars_Relu_9.31.5.1636595794731103.output.0.npy │ +│ - Add.fp32_vars_add_3fp32_vars_Relu_12.40.5.1636595794846124.output.0.npy │ +╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +**示例2** + +```bash +# 查看某个dump数据块的数据信息 +# 默认会将数据中的tensor保存成 txt +Parse >>> pt -n ./parse_data/dump_convert/Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.output.0.npy +...... +# 打印统计信息 +[Shape: (1, 16, 56, 56, 16)] [Dtype: float16] [Max: 452.0] [Min: -408.5] [Mean: -3.809] +Path: ./parse_data/dump_convert/Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.input.0.npy +TextFile:./parse_data/dump_convert/Add.fp32_vars_add_1fp32_vars_Relu_6.24.5.1636595794631347.input.0.npy.txt +``` + +### pkl文件中指定API的dump数据信息查看 + +输入以下命令,解析并输出pkl文件中指定api的统计信息。 + +```bash +pk -f pkl_path -n api_name +``` + +| 参数名称 | 说明 | 是否必选 | +| -------- | ----------------- | -------- | +| -f | 指定pkl文件路径。 | 是 | +| -n | 指定API名称。 | 是 | + +- 输出结果:打印统计信息(shape, dtype, max和min mean)。 +- 若pkl文件中存在相应的堆栈信息,则会打印堆栈信息。 + +**示例** + +```bash +# 传入pkl文件及api名称 +Parse >>> pk -f ./torch_dump/ptdbg_v3.2/rank0/api_stack_dump.pkl -n Functional_conv2d_0_forward +...... +# 打印统计信息及堆栈(pkl文件不包含堆栈则不会打印堆栈) + +Statistic Info: + [Functional_conv2d_0_forward_input.0][dtype: torch.float32][shape: [2, 1, 2, 2]][max: 1.576936960220337][min: -0.9757485389709473][mean: 0.4961632490158081] + [Functional_conv2d_0_forward_input.1][dtype: torch.float32][shape: [2, 1, 2, 2]][max: 0.20064473152160645][min: -0.47102075815200806][mean: -0.20796933770179749] + [Functional_conv2d_0_forward_input.2][dtype: torch.float32][shape: [2]][max: 0.17380613088607788][min: -0.16853803396224976][mean: 0.0026340484619140625] + [Functional_conv2d_0_forward_output][dtype: torch.float32][shape: [2, 2, 1, 1]][max: 0.02364911139011383][min: -1.762906551361084][mean: -0.6710853576660156] +``` + +### API可选层级比对 + +输入以下命令, 进行统计级和像素级比对。 + +```bash +cn -m my_data*.npy -g gloden*.npy [-p num] [-al atol] [-rl rtol] +``` + +- 统计级比对:对tensor整体进行余弦值及相对误差的计算。 +- 像素级比对:对输入的两个npy文件进行逐元素比对。若两个tensor对应元素的相对误差或绝对误差大于**误差阈值**(-al和-rl配置)则被标记为错误数据。 + +| 参数名称 | 说明 | 是否必选 | +| -------- | ----------------------------------------------- | -------- | +| -m | 待比对数据。 | 是 | +| -g | 标杆数据。 | 是 | +| -p | 设置比对结束后打印错误元素的个数,默认值20。 | 否 | +| -al | 判定数据存在精度问题的绝对误差阈值,默认0.001。 | 否 | +| -rl | 判定数据存在精度问题的相对误差阈值,默认0.001。 | 否 | +| -s | 将npy文件保存成txt文件,用于查看,默认开启。 | 否 | + +输出结果: + +- 统计级比对结果。 +- 两个文件的统计信息(shape, dtype, max, min和mean)。 +- 错误数据打印表格。 + +**示例** + +```bash +# 对比两个tensor的数据 +Parse >>> cn -m Add.InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.323.1619494134703053.output.0.npy -g InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.0.1619492699305998.npy -p 10 -s -al 0.002 -rl 0.005 + Error Item Table Top Item Table +┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓ ┏━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ +┃ Index ┃ Left ┃ Right ┃ Diff ┃ ┃ Index ┃ Left ┃ Right ┃ Diff ┃ +┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩ ┡━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ +│ 155 │ 0.024600908 │ 0.022271132 │ 0.002329776 │ │ 0 │ -0.9206961 │ -0.9222216 │ 0.0015255213 │ +│ 247 │ 0.015752593 │ 0.017937578 │ 0.0021849852 │ │ 1 │ -0.6416973 │ -0.64051837 │ 0.0011789203 │ +│ 282 │ -0.0101207765 │ -0.007852031 │ 0.0022687456 │ │ 2 │ -0.35383835 │ -0.35433492 │ 0.0004965663 │ +│ 292 │ 0.019581757 │ 0.02240482 │ 0.0028230622 │ │ 3 │ -0.18851271 │ -0.18883198 │ 0.00031927228 │ +│ 640 │ -0.06593232 │ -0.06874806 │ 0.0028157383 │ │ 4 │ -0.43508735 │ -0.43534422 │ 0.00025686622 │ +│ 1420 │ 0.09293677 │ 0.09586689 │ 0.0029301196 │ │ 5 │ 1.4447614 │ 1.4466647 │ 0.0019032955 │ +│ 1462 │ -0.085207745 │ -0.088047795 │ 0.0028400496 │ │ 6 │ -0.3455438 │ -0.3444429 │ 0.0011008978 │ +│ 1891 │ -0.03433288 │ -0.036525503 │ 0.002192624 │ │ 7 │ -0.6560242 │ -0.6564579 │ 0.0004336834 │ +│ 2033 │ 0.06828873 │ 0.07139922 │ 0.0031104907 │ │ 8 │ -2.6964858 │ -2.6975214 │ 0.0010356903 │ +│ 2246 │ -0.06376442 │ -0.06121233 │ 0.002552092 │ │ 9 │ -0.73746175 │ -0.73650354 │ 0.00095820427 │ +└───────┴───────────────┴──────────────┴──────────────┘ └───────┴─────────────┴─────────────┴───────────────┘ +╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ Left: | +│ |- NpyFile: ./dump/temp/decode/Add.InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.323.1619494134703053.output.0.npy | +│ |- TxtFile: ./dump/temp/decode/Add.InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.323.1619494134703053.output.0.npy.txt | +│ |- NpySpec: [Shape: (32, 8, 8, 320)] [Dtype: float32] [Max: 5.846897] [Min: -8.368301] [Mean: -0.72565556] | +│ DstFile: │ +│ |- NpyFile: ./dump/cpu/InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.0.1619492699305998.npy | +│ |- TxtFile: ./dump/cpu/InceptionV3_InceptionV3_Mixed_7a_Branch_0_add_3.0.1619492699305998.npy.txt | +│ |- NpySpec: [Shape: (32, 8, 8, 320)] [Dtype: float32] [Max: 5.8425903] [Min: -8.374472] [Mean: -0.7256237] │ +│ NumCnt: 655360 │ +│ AllClose: False │ +│ CosSim: 0.99999493 │ +│ ErrorPer: 0.023504638671875 (rl= 0.005, al= 0.002) │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +``` + +## FAQ + +[FAQ](https://gitee.com/ascend/att/blob/master/debug/accuracy_tools/ptdbg_ascend/doc/FAQ.md) -- Gitee From 86e759395f909d98748094d0badbc6d01dee2a24 Mon Sep 17 00:00:00 2001 From: cai-weiwei1989 <734267852@qq.com> Date: Tue, 23 Apr 2024 11:56:31 +0800 Subject: [PATCH 2/4] =?UTF-8?q?[ptdbg]=E4=BD=BF=E7=94=A8=E6=89=8B=E5=86=8C?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E9=87=8F=E6=AF=94=E5=AF=B9=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=B7=A5=E5=85=B7=E5=8C=96=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=BB=BA=E8=AE=AE=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doc/img/compare_result_pkl.png | Bin 0 -> 25217 bytes .../doc/img/compare_result_pkl_md5.png.png | Bin 0 -> 20464 bytes ...03\275\350\257\264\346\230\216_v6.0.T1.md" | 24 +++++++++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl.png create mode 100644 debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl_md5.png.png diff --git a/debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl.png b/debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl.png new file mode 100644 index 0000000000000000000000000000000000000000..c64e9380c6d9c01bb2ad18c81e430ead0800bb7d GIT binary patch literal 25217 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 BKN0`{ literal 0 HcmV?d00001 diff --git a/debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl_md5.png.png b/debug/accuracy_tools/ptdbg_ascend/doc/img/compare_result_pkl_md5.png.png new file mode 100644 index 0000000000000000000000000000000000000000..81ba1935e69218467b006f05dfffbe54f3f04cb4 GIT binary patch literal 20464 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 literal 0 HcmV?d00001 diff --git "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" index 2251ab702..129b12640 100644 --- "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" +++ "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" @@ -111,7 +111,7 @@ PyTorch训练场景的精度问题分析建议参考以下思路进行精度比 3. 找出存在问题的API。 - 1. 根据`advisor_{timestamp}.txt`或打屏信息的提示,可找到存在精度问题的算子(Suspect Nodes)和专家建议(Expert Advice) + 1. 根据`advisor_{timestamp}.txt`或打屏信息的提示,可找到存在精度问题的算子(Suspect Nodes)和专家建议(Expert Advice)。 ![auto_analyze_log](img/auto_analyze_log.png) @@ -1830,10 +1830,12 @@ compare(dump_result_param, output_path="./output", stack_mode=True) ### pkl文件比对 -若使用**compare**或**compare_distributed**函数创建的比对脚本中,input_param参数只配置了npu_pkl_path和bench_pkl_path或使用summary_only方式dump时,可以进行pkl文件的比对,此时比对dump.pkl文件中的统计信息,开启后的比对结果文件生成Max diff、Min diff、Mean diff和L2norm diff,表示NPU dump数据中API的输入或输出与标杆数据输入或输出的最大值、最小值、平均值以及L2范数的差。可以通过该值判断API是否存在精度问题:当某个API的输入和输出的Max diff、Min diff、Mean diff和L2norm diff均为0或无限趋于0,那么可以判断该API无精度问题,反之则可能存在精度问题。 +若使用**compare**或**compare_distributed**函数创建的比对脚本中,input_param参数只配置了npu_pkl_path和bench_pkl_path或使用summary_only、summary_mode(取值为md5或summary)方式dump时,可以进行pkl文件的比对,此时比对dump.pkl文件中的统计信息,开启后的比对结果文件生成Max diff、Min diff、Mean diff和L2norm diff,表示NPU dump数据中API的输入或输出与标杆数据输入或输出的最大值、最小值、平均值以及L2范数的差。可以通过该值判断API是否存在精度问题:当某个API的输入和输出的Max diff、Min diff、Mean diff和L2norm diff均为0或无限趋于0,那么可以判断该API无精度问题,反之则可能存在精度问题。 **比对脚本示例** +以compare.py为例。 + ```python from ptdbg_ascend import compare dump_result_param={ @@ -1844,6 +1846,22 @@ dump_result_param={ compare(dump_result_param, output_path="./output", stack_mode=True) ``` +**比对结果** + +pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt`文件。其中`advisor_{timestamp}.txt`主要对`compare_result_{timestamp}.csv`中可能存在精度问题的API提出修改建议;`compare_result_{timestamp}.csv`主要有如下两种情况: + +- configure_hook配置summary_only=True、summary_mode=summary或不配置前面两个参数直接比对pkl文件: + + ![compare_result_pkl](./img/compare_result_pkl.png) + + 上图是对pkl文件中NPU及标杆API的统计信息进行比对,判断可能存在精度问题的API,文件中记录NPU及标杆API的基本信息和统计信息,其中需要关注Result列,包含结果:Waring(NPU与标杆统计信息的比对中存在相对误差大于0.5,则需要重点检查该API);为空(相对误差小于等于0.5,可以不需要重点关注,但不代表不存在精度问题);Nan(表示统计信息数据没有匹配上)。 + +- configure_hook配置summary_mode=md5: + + ![compare_result_pkl_md5.png](./img/compare_result_pkl_md5.png.png) + + 上图是对pkl文件中NPU及标杆API的MD5信息进行比对,判断API数据的完整性,文件中记录NPU及标杆API的基本信息和MD5信息,其中需要关注Result列,包含结果:Pass(表示NPU与标杆的MD5值一致,即API数据完整);Different(表示NPU与标杆的MD5值不一致,即API数据不完整,可以通过NPU_Stack_Info列API调用栈查询该API的详细信息);Nan(表示MD5信息数据没有匹配上)。 + ### parse **功能说明** @@ -1873,7 +1891,7 @@ parse("./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump.pkl", "Torch_batch_normal_1_f ### 计算精度评价指标 -PyTorch精度比对是以CPU或GPU的计算结果为标杆,计算Cosine(余弦相似度)、MaxAbsErr(最大绝对误差)和MaxRelativeErr(最大相对误差),根据这两个结果判断API在运行时是否存在精度问题。 +PyTorch精度比对是以CPU或GPU的计算结果为标杆,通过计算精度评价指标判断API在运行时是否存在精度问题。 计算精度评价指标: -- Gitee From 4fb958e7a246796357eb921ffe280852eb87179e Mon Sep 17 00:00:00 2001 From: cai-weiwei1989 <734267852@qq.com> Date: Tue, 23 Apr 2024 12:00:15 +0800 Subject: [PATCH 3/4] =?UTF-8?q?[ptdbg]=E4=BD=BF=E7=94=A8=E6=89=8B=E5=86=8C?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E9=87=8F=E6=AF=94=E5=AF=B9=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=B7=A5=E5=85=B7=E5=8C=96=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=BB=BA=E8=AE=AE=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" index 129b12640..0065a8400 100644 --- "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" +++ "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" @@ -1848,7 +1848,7 @@ compare(dump_result_param, output_path="./output", stack_mode=True) **比对结果** -pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt`文件。其中`advisor_{timestamp}.txt`主要对`compare_result_{timestamp}.csv`中可能存在精度问题的API提出修改建议;`compare_result_{timestamp}.csv`主要有如下两种情况: +pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt`文件。其中`advisor_{timestamp}.txt`主要对`compare_result_{timestamp}.csv`中可能存在精度问题(Result为Waring)的API提出修改建议;`compare_result_{timestamp}.csv`主要有如下两种情况: - configure_hook配置summary_only=True、summary_mode=summary或不配置前面两个参数直接比对pkl文件: -- Gitee From 6a6d9f6ef4a5d26e4f5322601c4d907d9bcec4f3 Mon Sep 17 00:00:00 2001 From: cai-weiwei1989 <734267852@qq.com> Date: Tue, 23 Apr 2024 14:56:42 +0800 Subject: [PATCH 4/4] =?UTF-8?q?[ptdbg]=E4=BD=BF=E7=94=A8=E6=89=8B=E5=86=8C?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E9=87=8F=E6=AF=94=E5=AF=B9=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E5=B7=A5=E5=85=B7=E5=8C=96=E5=88=86=E6=9E=90?= =?UTF-8?q?=E5=BB=BA=E8=AE=AE=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" index 0065a8400..56e5b64eb 100644 --- "a/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" +++ "b/debug/accuracy_tools/ptdbg_ascend/doc/ptdbg_ascend\347\262\276\345\272\246\345\267\245\345\205\267\345\212\237\350\203\275\350\257\264\346\230\216_v6.0.T1.md" @@ -1848,7 +1848,7 @@ compare(dump_result_param, output_path="./output", stack_mode=True) **比对结果** -pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt`文件。其中`advisor_{timestamp}.txt`主要对`compare_result_{timestamp}.csv`中可能存在精度问题(Result为Waring)的API提出修改建议;`compare_result_{timestamp}.csv`主要有如下两种情况: +pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestamp}.txt`文件。其中`advisor_{timestamp}.txt`主要对`compare_result_{timestamp}.csv`中可能存在精度问题(Result为Waring)的API提出定位建议;`compare_result_{timestamp}.csv`主要有如下两种情况: - configure_hook配置summary_only=True、summary_mode=summary或不配置前面两个参数直接比对pkl文件: @@ -1860,7 +1860,7 @@ pkl文件比对同样生成`compare_result_{timestamp}.csv`和`advisor_{timestam ![compare_result_pkl_md5.png](./img/compare_result_pkl_md5.png.png) - 上图是对pkl文件中NPU及标杆API的MD5信息进行比对,判断API数据的完整性,文件中记录NPU及标杆API的基本信息和MD5信息,其中需要关注Result列,包含结果:Pass(表示NPU与标杆的MD5值一致,即API数据完整);Different(表示NPU与标杆的MD5值不一致,即API数据不完整,可以通过NPU_Stack_Info列API调用栈查询该API的详细信息);Nan(表示MD5信息数据没有匹配上)。 + 上图是对pkl文件中NPU及标杆API的MD5信息进行比对,判断API数据的完整性,文件中记录NPU及标杆API的基本信息和MD5信息,其中需要关注Result列,包含结果:Pass(表示NPU与标杆的MD5值一致,即API数据完整);Different(表示NPU与标杆的MD5值不一致,即API数据不完全一致,可以通过NPU_Stack_Info列API调用栈查询该API的详细信息);Nan(表示MD5信息数据没有匹配上)。 ### parse -- Gitee