1# 映射数据文件到对应的脚本源码 2 3## 文档功能与适用场景 4 5 在MindSpore进行计算调试,怀疑遇到精度问题时可以选择dump文件进行对比。此时用户希望知道dump文件夹下的每个数据文件对应的Python源码。 6 本文的主要目的为指导用户使用该工具进行数据文件到python源码的映射。 7 此指导文档适合运行在 **Ascend硬件** 环境下的计算。 8 9## 辅助工具使用 10 11 1. 使用脚本的3步操作: 12 - 用户在训练脚本里设置context.set_context(mode=context.GRAPH_MODE, save_graphs=True),进行图文件的保存。 13 - 用户开启dump数据功能,参考<https://www.mindspore.cn/tutorial/training/zh-CN/r1.1/advanced_use/custom_debugging_info.html#dump> 14 - 获取dump数据文件的op_num,然后通过辅助脚本进行解析。如数据文件:`Default--network-TrainOneStepCell--network-WithLossCell--_backbone- 15 ResNet--layer2-SequentialCell--0-ResidualBlock--conv2-Conv2d--Cast-op954_input_0_shape_128_128_3_3_kNumberTypeFloat32_DefaultFormat.bin`. 16 可观察到Cast-op954,说明该算子的op_num为op954, 如下图所示。 17 ![image](./images/op_image.png) 18 脚本名: **[map_file_to_code.py](https://gitee.com/mindspore/mindspore/blob/r1.5/scripts/map_dump_file_to_code/map_file_to_code.py)**; 执行方式: 19 20 ```ruby 21 python3 map_file_to_code.py 22 --graph_path(-p) [the graph path, default is the current path](option) 23 --dump_op(-o) [Dump operator id, case insensitive, such as 'op954'.](required) 24 For example: 25 python3 map_file_to_code.py -p graph_path -o op954 26 ``` 27 28 2. 解析效果 29 解析文件时通常有2种情况: 30 ① 匹配时会显示出调用栈过程,需要用户在调用栈中查找自己的源码: 31 32 ```ruby 33 [INFO] Start to map the dump file to source code. 34 [INFO] Find operation 'Cast'. 35 In file /data1/jzg/mindspore/mindspore/nn/layer/conv.py(253)/ 36 output = self.conv2d(x, self.weight) 37 In file /data1/jzg/dump_to_code/resnet/scripts/train/src/resnet.py(166)/ 38 out = self.conv2(out) 39 In file /data1/jzg/mindspore/mindspore/nn/layer/container.py(173)/ 40 for cell in self.cell_list: 41 In file /data1/jzg/dump_to_code/resnet/scripts/train/src/resnet.py(323)/ # 用户代码行 42 c3 = self.layer2(c2) 43 In file /data1/jzg/mindspore/mindspore/train/amp.py(101)/ 44 out = self._backbone(data) 45 In file /data1/jzg/mindspore/mindspore/nn/wrap/cell_wrapper.py(247)/ 46 loss = self.network(*inputs) 47 In file /data1/jzg/mindspore/mindspore/train/dataset_helper.py(87)/ 48 return self.network(*outputs) 49 ``` 50 51 ② 未匹配,在图中未找对应节点的调用栈: 52 53 ```ruby 54 [INFO] Start to map the dump file to source code. 55 [WARNING] Cannot find cast's source code in ir file. # 未找到cast算子的信息 56 ``` 57 58 3. 手动代码查找 59 这里还会存在些特殊情况,需要用户进行自行查找。通过将dump的数据文件名中的'--'替换为'/'可获取到算子的full_name, 如下图所示: 60 ![image](./images/replace_symbol.png) 61 input和output文件名shape后面的数据为对应算子的输入输出shape信息。然后利用算子的full_name和输入输出信息回到源码中进行对应代码的查找。 62 举个例子说明如何手动在代码中查找指定full_name和shape的算子,例如full_name为: `Default/network/network/aspp/aspp_pooling/ResizeNearestNeighbor`,输入的shape为[8, 256, 1, 1], dtype为float32。 63 可以观察到其scope为: `Default/network/network/aspp/aspp_pooling`,算子名为: `ResizeNearestNeighbor`。注意:scope中会存在Default、network自动填充,Default表示正向,network为网络名。 64 查看以下用户定义的代码,首先我们先分析scope: `Default/network/network/aspp/aspp_pooling`。由network/aspp可定位到算子的定义与调用处分别为26行与31行,继续由`network/aspp/aspp_pooling`,可以定位到定义与调用处分别为4行与8行,然后通过算子名`ResizeNearestNeighbor`可以定位至定义与调用处分别为16行与19行。最后若存在相同scope下存在相同的算子名时,需要通过输入的shape进行进一步判断。 65 66 ```ruby 67 1 class ASPP(nn.Cell): 68 2 def __init__(self): 69 3 super(ASPP, self).__init__() 70 4 self.aspp_pooling = ASPPPooling() 71 5 self.drop = nn.Dropout(0.3) 72 6 73 7 def construct(self, x): 74 8 x = self.aspp_pooling(x) 75 9 x = self.drop(x) 76 10 return x 77 11 78 12 class ASPPPooling(nn.Cell): 79 13 def __init__(self): 80 14 super(ASPPPooling, self).__init__() 81 15 self.shape = P.Shape() 82 16 self.resizenearestneighbor = P.ResizeNearestNeighbor((size[2], size[3]), True) 83 17 def construct(self, x): 84 18 size = self.shape(x) 85 19 out = self.resizenearestneighbor(x) 86 20 return out 87 21 88 22 # 主结构 89 23 class DeepLabV3(nn.Cell): 90 24 def __init__(self, phase='train', num_classes=21, output_stride=16, freeze_bn=False): 91 25 super(DeepLabV3, self).__init__() 92 26 self.aspp = ASPP() 93 27 self.shape = P.Shape() 94 28 95 29 def construct(self, x): 96 30 size = self.shape(x) 97 31 out = self.aspp(x) 98 32 return out 99 ``` 100