# 昇腾910上算子溢出问题分析

**1. 根因分析**

由于昇腾上部分算子不支持fp32（如 Conv，Pooling），或部分算子虽然支持fp32但性能极差，不得不切换成fp16（如MatMul），导致其必须走fp16，这增大了训练过程中算子溢出的风险，影响网络最终收敛的精度，这里给出算子溢出分析方法。

-   步骤1：开启溢出检测
    -   找到 异步dump 指导（也可以直接访问  [https://www.mindspore.cn/tutorials/experts/zh-CN/master/debug/dump.html?highlight=dump\#å¼æ­¥dump](https://www.mindspore.cn/tutorials/experts/zh-CN/master/debug/dump.html?highlight=dump#%25E5%25BC%2582%25E6%25AD%25A5dump)）

-   对于溢出检测，需要注意以下配置：

dump\_mode：设置为0，检测到所有算子

path：推荐设置到/home/ma-user/modelarts/outputs/output\_url\_0/ 目录下，DI训练时该目录会自动回传数据到obs，方便后续进行溢出检测分析

iteration：设置为all，检测所有迭代

op\_debug\_mode：设置为3，开启全部溢出检测

-   一个典型的溢出检测 data\_dump.json 配置为：

```
{
"common_dump_settings": {
"dump_mode": 0,
"path": "/home/ma-user/modelarts/outputs/output_url_0/bev/dump/",
"net_name": "bevnet",
"iteration": "all",
"saved_data": "tensor",
"input_output": 0,
"kernels": [],
"support_device": [0,1,2,3,4,5,6,7],
"op_debug_mode": 3,
"file_format": "npy"
}
```

-   步骤 2：查看溢出算子
-   在日志中搜索关键字 overflow infos，如果有算子溢出，则日志中会提示算子所在的代码行：

```
5290 [WARNING] DEVICEC517, ffff1c1b9160,python):2022-12-27-23:50:13.843.123 [mindspore/ccsrc/plugin/device/ascend/hal/device/ascend_kernel_runtime. cc:683]TaskFailCallback] Node run task overflow, node name: Gradients/Default/network-MultiTaskTrainonestepCelL/network-Modulewrapper/detection3d _head-DetHead/det_head-CenterPointHead/head-CenterHead/task_heads-CellList/0-SeparateHead/reg-SequentialCel1/1-_OutputTo32/_op-Conv2d/gradconv2D/Cast-op41878Task overflow infos task_id: 306, streamid: 17, tid:517, device_id: 1, retcode:207003 (aicore over flow
5291 The function call stack:
5292 Corresponding code candidate:
5293  In file /home/ma-user/mindspore/build/package/mindspore/ops/_grad/gradnn_ops.py:106/	dx = input_grad(dout, w, x_shape)/
5294 In file /home/ma-user/mindspore/build/package/mi ndspore/ops/_grad/grad _nn_ops.py: 107/	dw = filter_grad(dout, x, w_shape)/
5295 Corresponding forward node candidate:
5296 - In file /hone/na-user/mindspore/build/package/mi ndspore/nn/layer/ conv.py: 309/	output = self.conv2d(x, self.weight)/
5297 In file /home/na-user/mindspore/bui ld/package/mindspore/train/arp.py:671	return F.cast(self._opCx), mstype. float32)/	
5298 In file /hone/na-user/mindspore/build/package/mi ndspore/nn/layer/container.py:278/	for cell in self.cell_list:/
5299 In file /home/ma-user/rodelarts/user-job-dir/code/tasks/bev_task/uvp_rodule/models/det_ head/centerpoint/centerpoint_head.py:145/	return {'reg':self.reg(x), "height':self.height(x), 'dim':self.dim(x),'rot':self.rot(x), 'vel':self.vel(x),"heatrap':self.heatmap(x)}/
5300 In file /home/ra-user/nodelarts/user-job-dir/code/tasks/bev-task/uvp_module/nodels/det_head/centerpoint/centerpoint_head.py:239/	for task in self.task_heads:/
5301 In file /home/ma-user/nodelarts/user-job-dir/code/tasks/bev_task/uvp_module/models/det_head/centerpoint/centerpoint_ head.py:255/	return multi_apply(self.forward_single,feats)/
5302 In file /hone/ma-user/nodelarts/user- job-dir/code/tasks/bev_task/uvp_module/models/det_head/centerpoint/centerpoint_head.py: 255/	return multi_apply(self.forward_single,feats)/
5303 In file /home/ma-user/nodelarts/user-job-dir/code/tasks/bev_task/uvp_module/models/det_head/centerpoint/centerpoint_head.py:413/	pred_dict = self.head(bev_feat_map)/
5304 In file /home/ma-user/modlelarts/user-job-dir/code/tasks/bev_task/uvp_module/models/det_head/det_head.py:71/	det_output,ret_dict = self.det_headCdata_dict)/
5305 In file /hone/na-user/nodelarts/user-job-dir/code/uvpsandbox-api/uvpsandbox/uvpsandbox/nodule_wrapper. py: 40/	for net, node, inners, node-tasks in zip(self.nets, self.nodes, self.inner_nodes, self.nodes tasks):/
5306 In file /hone/ma-user/modelarts/user- job-dir/ code/uvpsandbox-api /uvpsandbox/uvpsandbox/frarework. py: 583/	net_outputs = self.network(img_data,f"labels":[labels], "img_info":img_info})/	5307 In File /hone/ma-user/mindspore/bui ld/package/mindspore/nn/wrap/loss_scale.py:336/	loss = self.network(*inputs)/
```

-   溢出的算子为 Cast-op41878 该算子为 Cast 算子，scope 名为 Gradients/Default/network-MultiTaskTrainOneStepCell/network-ModuleWrapper/detection3d\_head-DetHead/det\_head-CenterPointHead/head-CenterHead/task\_heads-CellList/0-SeparateHead/reg-SequentialCell/1-\_OutputTo32/\_op-Conv2d/gradConv2D/Cast-op41878（如果scope的名字以Gradients 开头，说明该算子是反向产生的算子）。根据 The function call stack: 提示，找到该算子对应的代码（反向算子需要先找到对应的正向算子）。
-   步骤3：分析溢出产生的原因
-   在步骤2中，我们可以找到具体溢出的算子和所在代码，这一步我们需要分析溢出产生的原因。首先需要找出溢出算子所在的rank，下载该rank 下的dump数据，一个标准的dump数据结构如下所示：

```
rank_xx
|-- bevnet           # 根目录，根据 data_dump.json 配置生成
|   |-- 0            # 每个step产生的dump文件，序号代表step数
|   |-- 1
|   |-- 17
|   |-- 2
|   `-- constants     # 网络中的常量，数据不随step数改变
|-- execution_order   # 网络中算子的执行顺序（如果有多个图，则产生多个文件）
|   |-- ms_execution_order_graph_0.csv
|   |-- ms_execution_order_graph_1.csv
|   |-- ms_execution_order_graph_17.csv
|   |-- ms_execution_order_graph_18.csv
|   |-- ms_execution_order_graph_19.csv
|   |-- ms_execution_order_graph_2.csv
|   `-- ms_global_execution_order_graph_17.csv
`-- graphs           # 网络中算子的图结构（如果有多个图，则产生多个文件）
    |-- ms_output_trace_code_graph_0.ir
    |-- ms_output_trace_code_graph_0.pb
    |-- ms_output_trace_code_graph_1.ir
    |-- ms_output_trace_code_graph_1.pb
    |-- ms_output_trace_code_graph_17.ir
    |-- ms_output_trace_code_graph_17.pb
    |-- ms_output_trace_code_graph_18.ir
    |-- ms_output_trace_code_graph_18.pb
    |-- ms_output_trace_code_graph_19.ir
    |-- ms_output_trace_code_graph_19.pb
    |-- ms_output_trace_code_graph_2.ir
    `-- ms_output_trace_code_graph_2.pb
8 directories, 21 files
```

-   一般我们只关注 rank\_xx/bevnet/x/ 下的数据，假设该目录下数据如下所示：

```
-rw-r--r--    1 root root	630912 Dec 28 10:00 Cast. Cast-op41877.309.17.1672156213076552. input.0.NCHW. npy
-rw-r--r--    1 root root	315520 Dec 28 10:00 Cast. Cast-op41877.309.17.1672156213076552.output.0.NCHW.npy
-rw-r--r--    1 root root	630912 Dec 28 10:00 Cast.Cast-op41878.306.17.1672156213045891. input.0.NCHW.npy
-rw-r--r--    1 root root	315520 Dec 28 10:00 Cast.Cast-op41878.306.17.1672156213045891.output.0.NCHW. npy
-rw-r--r--    1 root root           1577088 Dec 28 10:00 Cast. Cast-op41879.63.18.1672156213413591. input.0.NCHW.npy
-rw-r--r--    1 root root	788608 Dec 28 10:00 Cast.Cast-op41879.63.18.1672156213413591.output.0.NCHW.npy
-rw-r--r--    1 root root                2432 Dec 28 10:00 Conv2DBackpropInput. Conv2DBackpropInput-op26836.331.17.1672156213185043.input.0.NCHW.npy
-rw-r--r--    1 root root            315520 Dec 28 10:00 Conv2DBackpropInput. Conv2DBackpropInput-op26836.331.17.1672156213185043.input.1.NCHW.npy
-rw-r--r--    1 root root        10092672 Dec 28 10:00 Conv2DBackpropInput.Conv20BackoropInput-op26836.331.17.1672156213185043.output-0.NCHW.nDy
```

-   可以看到，Cast-op41878 的溢出数据被dump了出来，读取其中的数据，可以发现该算子的输入 104856.29 在cast之后变成了 65500.0 ，算子发生了溢出。

```
Python 3.8.6 (default,0ct 6 2020, 03:22:36)
[GCC 7.5.0] on linux
Tyре "help", "сopyright" , "credits" or "1icense" for more information.
>>> inport nunpy as np
>>> np.1oad("cast.Cast-op41878.306.17.1672156213045891. input.0.NCHW.npy").maxO
104856.29
>>> np.load("cast.Cast-op41878.306.17.1672156213045891.output.0.NCHW. npy").maxO)
65500.0
```

-   由于初始时 loss scale 的值比较大，导致初始梯度比较大，这里的溢出也是正常的，可以尝试调小初始loss scale 解决。

**2. 解决方案**

1.  对于发生在训练开始，在后期迭代不再出现的溢出，可以忽略或者调小初始loss scale。这是因为前期梯度较大，训练不稳定，如果配置了 LossScaleManager，这些溢出的step会被自动忽略，一般对最终的收敛影响不大。
2.  如果溢出的算子输入数据正常，正常计算时不应该引发溢出，此时请保留算子输入输出数据，需要与具体的算子开发负责人确认，该算子可能存在溢出误报的问题。
3.  对于MatMul、BatchMatMul、ReduceSum、ReduceMean 等容易引发溢出的算子，可以尝试在算子输入之前对数据进行缩放（缩小x倍），在算子计算后的某个合适位置进行复原（放大回x倍），这样在保证整个计算数学等价的情况下，避免溢出。

