From eeacd35c9e56417a09eb031f09ca89a4683e7420 Mon Sep 17 00:00:00 2001 From: yangxinxian <947098055@qq.com> Date: Mon, 2 Dec 2024 20:11:19 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../msprobe/docs/06.data_dump_MindSpore.md | 243 +++++++++++------- .../dynamic_graph_quick_start_example.md | 211 +++++++++++++++ 2 files changed, 365 insertions(+), 89 deletions(-) create mode 100644 debug/accuracy_tools/msprobe/docs/data_dump_Mindspore/dynamic_graph_quick_start_example.md diff --git a/debug/accuracy_tools/msprobe/docs/06.data_dump_MindSpore.md b/debug/accuracy_tools/msprobe/docs/06.data_dump_MindSpore.md index d3b438c42..27a960ed6 100644 --- a/debug/accuracy_tools/msprobe/docs/06.data_dump_MindSpore.md +++ b/debug/accuracy_tools/msprobe/docs/06.data_dump_MindSpore.md @@ -1,23 +1,64 @@ -# MindSpore 场景的精度数据采集 -msprobe 工具主要通过在训练脚本内添加 dump 接口、启动训练的方式采集精度数据。目前,静态图场景仅支持 kernel 级数据采集,对应 config.json 配置中的 "L2" level;动态图场景支持cell、API、kernel级数据采集,对应 config.json 配置中的 "L0"、"L1" 、"L2"、"mix" level。 +# msprobe 工具 MindSpore场景精度数据采集指南 -需要注意,**动态图 kernel 级**("L2" level)精度数据采集对象为被 PSJit 或 PIJit 装饰的 Cell 或 function 内的算子,其被装饰部分实际以**静态图**模式执行,所以此场景下的工具使用方式与静态图场景完全相同。下文无特殊说明时,介绍的动态图场景不包括 kernel 级("L2" level)dump 情形。 -精度数据采集功能的配置示例见[MindSpore 静态图场景下 task 配置为 statistics](https://gitee.com/ascend/mstt/blob/master/debug/accuracy_tools/msprobe/docs/03.config_examples.md#21-task-%E9%85%8D%E7%BD%AE%E4%B8%BA-statistics)、[MindSpore 静态图场景下 task 配置为 tensor](https://gitee.com/ascend/mstt/blob/master/debug/accuracy_tools/msprobe/docs/03.config_examples.md#22-task-%E9%85%8D%E7%BD%AE%E4%B8%BA-tensor)、[MindSpore 动态图场景下 task 配置为 statistics](https://gitee.com/ascend/mstt/blob/master/debug/accuracy_tools/msprobe/docs/03.config_examples.md#31-task-%E9%85%8D%E7%BD%AE%E4%B8%BA-statistics)、[MindSpore 动态图场景下 task 配置为 tensor](https://gitee.com/ascend/mstt/blob/master/debug/accuracy_tools/msprobe/docs/03.config_examples.md#32-task-%E9%85%8D%E7%BD%AE%E4%B8%BA-tensor)。 +## 1. 专业名词解释 -动态图 API 级 dump 时,本工具提供固定的 API 支持列表,仅支持对列表中的 API 进行精度数据采集。一般情况下,无需修改该列表,而是通过config.json中的scope/list字段进行 dump API 指定。若需要改变 API 支持列表,可以在 `msprobe/mindspore/dump/hook_cell/support_wrap_ops.yaml` 文件内手动修改,如下示例: +* **静态图**:在编译时就确定网络结构,静态图模式拥有较高的训练性能,但难以调试。 +* **动态图**:运行时动态构建网络,相较于静态图模式虽然易于调试,但难以高效执行。 +* **高阶 API**:如 `mindspore.train.Model`,封装了训练过程的高级接口。 +* **JIT(Just-In-Time 编译)**:MindSpore提供JIT(just-in-time)技术进一步进行性能优化。JIT模式会通过AST树解析的方式或者Python字节码解析的方式,将代码解析为一张中间表示图(IR,intermediate representation)。IR图作为该代码的唯一表示,编译器通过对该IR图的优化,来达到对代码的优化,提高运行性能。与动态图模式相对应,这种JIT的编译模式被称为静态图模式。 +* **Primitive op**:MindSpore 中的基本算子,通常由 `mindspore.ops.Primitive` 定义,提供底层的算子操作接口。 + + +## 2. 工具安装 + +请参见[《msprobe 工具安装指南》](./01.installation.md)。 + + +## 3. 快速入门 + +以下通过一个简单的示例,展示如何在 MindSpore 中使用 msprobe 工具进行精度数据采集。 + +您可以参考 [动态图快速入门示例](./data_dump_Mindspore/dynamic_graph_quick_start_example.md) 了解详细步骤。 + +## 4. 概述 + +msprobe 工具通过在训练脚本中添加 `PrecisionDebugger` 接口并启动训练的方式,采集模型在运行过程中的精度数据。该工具支持对MindSpore的静态图和动态图场景进行不同Level等级的精度数据采集。 + + +## 5. 场景介绍 + +### 5.1 静态图场景 +在静态图场景下,msprobe 仅支持 **L2 Level** 的数据采集。 +- **L2 Level(Kernel 级)** :采集底层算子的输入输出数据,适用于深入分析算子级别的精度问题。 + +采集方式请参见[示例代码 > 静态图场景](#71-静态图场景)。详细介绍请参见[《config.json 配置文件介绍》](./02.config_introduction.md#11-通用配置)中的“level 参数”和[《config.json 配置示例》](./03.config_examples.md#2-mindspore-静态图场景) 中的“MindSpore 静态图场景”。 + +### 5.2 动态图场景 +在动态图场景下,msprobe 支持 **L0** 、**L1** 、**mix** 、**L2 Level** 的数据采集,具体分为以下几种情况: +- **使用高阶 API(如 `Model 高阶API`)** : + - 需要使用 `MsprobeStep` 回调类来控制数据采集的启停,适用于 **L0** 、**L1** 、**mix** 、**L2** 数据采集。 + +- **未使用高阶 API** : + - 手动在训练循环中调用 `start`、`stop`、`step` 等接口,适用于 **L0** 、**L1** 、**mix** 、**L2** 数据采集。 + +采集方式请参见[示例代码 > 动态图场景](#72-动态图场景-)。 + +> **注意** :动态图模式下,使用 `PSJit` 或 `PIJit` 装饰的部分实际以静态图模式执行,此时的 **Kernel 级(L2 Level)** 数据采集方式与静态图场景相同。 +- **L0 Level(Cell 级)** :采集 `Cell` 对象的数据,适用于需要分析特定网络模块的情况。 + +- **L1 Level(API 级)** :采集 MindSpore API 的输入输出数据,适用于定位 API 层面的精度问题。 + +- **mix(模块级 + API 级)** :在 `L0` 和 `L1` 级别的基础上同时采集模块级和 API 级数据,适用于需要分析模块和 API 层面精度问题的场景。 -```yaml -ops: # ops为算子类别,找到对应的类别,在该类别下按照下列格式删除或添加API - - adaptive_avg_pool1d - - adaptive_avg_pool2d - - adaptive_avg_pool3d -``` -## 1 接口介绍 +详细介绍请参见[《config.json 配置文件介绍》](./02.config_introduction.md#11-通用配置)中的“level 参数”和[《config.json 配置示例》](./03.config_examples.md#3-mindspore-动态图场景) 中的“MindSpore 动态图场景”。 -### 1.1 msprobe.mindspore.PrecisionDebugger + +## 6 接口介绍 + +### 6.1 msprobe.mindspore.PrecisionDebugger **功能说明**:通过加载 dump 配置文件的方式来确定 dump 操作的详细配置。 @@ -31,7 +72,7 @@ PrecisionDebugger(config_path=None) 1. config_path:指定 dump 配置文件路径,string 类型。参数示例:"./config.json"。未配置该路径时,默认使用 [config.json](../config.json) 文件的默认配置,配置选项含义可见 [config.json 介绍](./02.config_introduction.md)。 -#### 1.1.1 start +#### 6.1.1 start **功能说明**:启动精度数据采集。需在模型执行模式(静态图/动态图、O0/O1/O2编译等级)设置后调用。静态图场景下,必须在模型初始化及 mindspore.communication.init 调用前添加;动态图场景下,如果没有使用 [Model](https://gitee.com/link?target=https%3A%2F%2Fwww.mindspore.cn%2Ftutorials%2Fzh-CN%2Fr2.3.1%2Fadvanced%2Fmodel.html) 高阶 API 进行训练,则需要与 stop 函数一起添加在 for 循环内,否则只有需要传入model参数时,才使用该接口。 @@ -43,9 +84,9 @@ start(model=None) **参数说明**: -1. model:指具体的 mindspore.nn.Cell,默认不配置。Cell级别("L0" level)dump 时,传入 model 可以采集 model 内的所有Cell 对象数据。API级别("L1" level)dump 时,传入 model 可以采集 model 内包含 primitive op 对象在内的所有 API 数据,若不传入 model 参数,则只采集非 primitive op 的 API 数据。 +1. model:指具体的 mindspore.nn.Cell对象,默认不配置。Cell级别("L0" level)dump 时,传入 model 可以采集 model 内的所有Cell 对象数据。API级别("L1" level)dump 时,传入 model 可以采集 model 内包含 primitive op 对象在内的所有 API 数据,若不传入 model 参数,则只采集非 primitive op 的 API 数据。 "mix" level dump 时,必须传入 model 参数。 -#### 1.1.2 stop +#### 6.1.2 stop **功能说明**:停止数据采集。在 **start** 函数之后的任意位置添加。需要与 start 函数一起添加在 for 循环内。若需要 dump 反向数据,则需要添加在反向计算代码之后。**仅未使用 Model 高阶 API 的动态图场景支持。** @@ -55,7 +96,7 @@ start(model=None) stop() ``` -#### 1.1.3 step +#### 6.1.3 step **功能说明**:在最后一个 **stop** 函数后或一个 step 训练结束的位置添加。**仅未使用 Model 高阶 API 的动态图场景支持。** @@ -65,13 +106,13 @@ stop() step() ``` -#### 1.1.4 forward_backward_dump_end +#### 6.1.4 forward_backward_dump_end **功能说明**:在 **start** 函数和在 **stop** 函数之间调用,表示采集 **start** 到 **forward_backward_dump_end**之间的L1级别的正反向数据。 **仅支持L1级别数据采集场景。** -**L1级别数据中的jit数据采集行为不受此接口影响** +**L1级别数据中的jit数据采集行为不受此接口影响。** **仅未使用 Model 高阶 API 的动态图场景支持。** @@ -81,9 +122,9 @@ step() forward_backward_dump_end() ``` -### 1.2 msprobe.mindspore.common.utils.MsprobeStep +### 6.2 msprobe.mindspore.common.utils.MsprobeStep -**功能说明**:MindSpore Callback类,自动在每个step开始时调用start()接口,在每个step结束时调用stop()、step()接口。实现使用 Model 高阶 API 的动态图场景下 L0、L1 级别的精度数据采集控制,控制粒度为单个 **Step** ,而 PrecisionDebugger.start, PrecisionDebugger.stop 接口的控制粒度任意训练代码段。 +**功能说明**:MindSpore Callback类,自动在每个step开始时调用start()接口,在每个step结束时调用stop()、step()接口。实现使用 Model 高阶 API 的动态图场景下 L0、L1、mix 级别的精度数据采集控制,控制粒度为单个 **Step** ,而 PrecisionDebugger.start, PrecisionDebugger.stop 接口的控制粒度任意训练代码段。 **原型**: @@ -95,7 +136,7 @@ MsprobeStep(debugger) 1. debugger:PrecisionDebugger对象。 -### 1.3 msprobe.mindspore.seed_all +### 6.3 msprobe.mindspore.seed_all **功能说明**:用于固定网络中的随机性和开启确定性计算。 @@ -110,28 +151,36 @@ seed_all(seed=1234, mode=False, rm_dropout=True) 2. mode:确定性计算使能,可配置 True 或 False,默认值:False,非必选。参数示例:mode=True。该参数设置为 True 后,将会开启算子确定性运行模式与归约类通信算子(AllReduce、ReduceScatter、Reduce)的确定性计算。注意:确定性计算会导致API执行性能降低,建议在发现模型多次执行结果不同的情况下开启。 -3. rm_dropout:控制dropout失效的开关。可配置 True 或 False,默认值:True,非必选。参数示例:rm_dropout=True。该参数设置为 True 后,将会使mindspore.ops.Dropout,mindspore.ops.Dropout2D,mindspore.ops.Dropout3D,mindspore.mint.nn.Dropout和mindspore.mint.nn.functional.dropout失效,以避免随机dropout对dump结果产生影响。建议在采集mindspore数据前开启。注意:通过rm_dropout控制dropout失效或生效需要在初始化Dropout实例前调用才能生效。 +3. rm_dropout:控制dropout失效的开关。可配置 True 或 False,默认值:True,非必选。参数示例:rm_dropout=True。该参数设置为 True 后,将会使mindspore.ops.Dropout,mindspore.ops.Dropout2D,mindspore.ops.Dropout3D,mindspore.mint.nn.Dropout和mindspore.mint.nn.functional.dropout失效,以避免因随机dropout造成的网络随机性。建议在采集mindspore数据前开启。注意:通过rm_dropout控制dropout失效或生效需要在初始化Dropout实例前调用才能生效。 -## 2 示例代码 -### 2.1 MindSpore 静态图场景 -```Python + +## 7. 示例代码 + +### 7.1 静态图场景 + +```python import mindspore as ms ms.set_context(mode=ms.GRAPH_MODE, device_target="Ascend") from msprobe.mindspore import PrecisionDebugger debugger = PrecisionDebugger(config_path="./config.json") debugger.start() -# 请勿将以上初始化流程置于模型实例化或mindspore.communication.init调用后 +# 请勿将以上初始化流程置于模型实例化或 mindspore.communication.init 调用后 +# 模型定义和训练代码 # ... + ``` -### 2.2 MindSpore 动态图场景 +### 7.2 动态图场景 -#### 2.2.1 未使用 Model 高阶 API(非 L2 级别) +#### 7.2.1 L0 ,L1, mix 级别 -```Python +##### 7.2.1.1 未使用 Model 高阶 API + + +```python import mindspore as ms ms.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend") @@ -143,60 +192,66 @@ debugger = PrecisionDebugger(config_path="./config.json") model = Network() # 数据集迭代的地方往往是模型开始训练的地方 for data, label in data_loader: - debugger.start() # 进行L1级别下非primitive op采集时调用 - # debugger.start(model) # 进行L0级别或L1级别下primitive op的数据采集时调用 - # 如下是模型每个step执行的逻辑 + debugger.start() # 进行 L1 级别下非 primitive op 采集时调用 + # debugger.start(model) # 进行 L0, mix 级别或 L1 级别下 primitive op 的数据采集时调用 + # 如下是模型每个 step 执行的逻辑 grad_net = ms.grad(model)(data) # ... - debugger.stop() # 关闭数据dump - debugger.step() # 结束一个step的dump + debugger.stop() # 关闭数据 dump + debugger.step() # 更新迭代数 ``` -#### 2.2.2 未使用 Model 高阶 API(L2 级别) +##### 7.2.1.2 使用 Model 高阶 API -```Python + +```python import mindspore as ms +from mindspore.train import Model ms.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend") from msprobe.mindspore import PrecisionDebugger +from msprobe.mindspore.common.utils import MsprobeStep debugger = PrecisionDebugger(config_path="./config.json") -debugger.start() -# 请勿将以上初始化流程置于模型实例化或mindspore.communication.init调用后 # 模型、损失函数的定义以及初始化等操作 # ... + model = Network() -# 数据集迭代的地方往往是模型开始训练的地方 -for data, label in data_loader: - # 如下是模型每个step执行的逻辑 - grad_net = ms.grad(model)(data) - # ... +# 只有进行 L0 级别下 Cell 对象,mix 级别,L1 级别下 primitive op 的数据采集时才需要调用 +# debugger.start(model) +trainer = Model(model, loss_fn=loss_fn, optimizer=optimizer, metrics={'accuracy'}) +trainer.train(1, train_dataset, callbacks=[MsprobeStep(debugger)]) ``` -#### 2.2.3 使用 Model 高阶 API(非 L2 级别) +#### 7.2.2 L2 级别 -```Python +##### 7.2.2.1 未使用 Model 高阶 API + + +```python import mindspore as ms -from mindspore.train import Model ms.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend") from msprobe.mindspore import PrecisionDebugger -from msprobe.mindspore.common.utils import MsprobeStep debugger = PrecisionDebugger(config_path="./config.json") +debugger.start() +# 请勿将以上初始化流程置于模型实例化或 mindspore.communication.init 调用后 # 模型、损失函数的定义以及初始化等操作 # ... - model = Network() -# 只有进行L0级别下Cell对象或L1级别下primitive op的数据采集时才需要调用 -# debugger.start(model) -trainer = Model(model, loss_fn=loss_fn, optimizer=optimizer, metrics={'accuracy'}) -trainer.train(1, train_dataset, callbacks=[MsprobeStep(debugger)]) +# 数据集迭代的地方往往是模型开始训练的地方 +for data, label in data_loader: + # 如下是模型每个 step 执行的逻辑 + grad_net = ms.grad(model)(data) + # ... ``` -#### 2.2.4 使用 Model 高阶 API(L2 级别) -```Python +##### 7.2.2.2 使用 Model 高阶 API + + +```python import mindspore as ms from mindspore.train import Model ms.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend") @@ -204,7 +259,7 @@ ms.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend") from msprobe.mindspore import PrecisionDebugger debugger = PrecisionDebugger(config_path="./config.json") debugger.start() -# 请勿将以上初始化流程置于模型实例化或mindspore.communication.init调用后 +# 请勿将以上初始化流程置于模型实例化或 mindspore.communication.init 调用后 # 模型、损失函数的定义以及初始化等操作 # ... @@ -214,29 +269,17 @@ trainer = Model(model, loss_fn=loss_fn, optimizer=optimizer, metrics={'accuracy' trainer.train(1, train_dataset) ``` -## 3 dump 结果文件介绍 - -### 3.1 MindSpore 静态图场景 - -训练结束后,工具将 dump 的数据保存在 dump_path 参数指定的目录下。 - -- jit_level 为O0/O1时: - - dump 结果目录请参见 MindSpore 官网中的[同步 Dump 数据对象目录](https://www.mindspore.cn/tutorials/experts/zh-CN/r2.3.1/debug/dump.html#%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1%E7%9B%AE%E5%BD%95%E5%92%8C%E6%95%B0%E6%8D%AE%E6%96%87%E4%BB%B6%E4%BB%8B%E7%BB%8D)。 - -- jit_level 为O2时: +## 8. dump 结果文件介绍 - dump 结果目录请参见 MindSpore 官网中的[异步 Dump 数据对象目录](https://www.mindspore.cn/tutorials/experts/zh-CN/r2.3.1/debug/dump.html#%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1%E7%9B%AE%E5%BD%95%E5%92%8C%E6%95%B0%E6%8D%AE%E6%96%87%E4%BB%B6%E4%BB%8B%E7%BB%8D-1)。 +### 8.1 静态图场景 -jit_level 请参见 [mindspore.set_context](https://www.mindspore.cn/docs/zh-CN/r2.3.1/api_python/mindspore/mindspore.set_context.html) 中的 jit_config 参数。 +训练结束后,数据将保存在 `dump_path` 指定的目录下,目录结构请参见 MindSpore 官方文档中的[数据对象目录](https://www.mindspore.cn/docs/zh-CN/r2.4.0/model_train/debug/dump.html)。 -### 3.2 MindSpore 动态图场景 +### 8.2 动态图场景 -训练结束后,工具将 dump 的数据保存在dump_path参数指定的目录下。 +dump 结果目录结构示例如下: -dump结果目录结构示例如下: - -```bash +```lua ├── dump_path │ ├── step0 │ | ├── rank0 @@ -247,9 +290,10 @@ dump结果目录结构示例如下: | | | | ├── Tensor.__add__.0.forward.output.0.npy | | | | ... | | | | ├── Jit.AlexNet.0.forward.input.0.npy +| | | | ├── Primitive.conv2d.Conv2D.0.forward.input.0.npy | | | | └── Cell.relu.ReLU.forward.0.input.0.npy # config.json文件配置level为L0时dump的cell模块级数据,命名格式为{Cell}_{cell_name}_{class_name}_{前向反向}.{index}.{input/output}.{参数序号} -│ | | ├── dump.json # 保存前反向算子、算子的统计量信息或溢出算子信息。包含dump数据的API名称(命名格式为:{api_type}_{api_name}_{API调用次数}_{前向反向}_{input/output}.{参数序号})、dtype、 shape、各数据的max、min、mean、L2norm统计信息以及当配置summary_mode="md5"时的CRC-32数据。其中,“参数序号”表示该API下的第n个参数,例如1,则为第一个参数,若该参数为list格式,则根据list继续排序,例如1.1,表示该API的第1个参数的第1个子参数;L2norm表示L2范数(平方根) -│ | | ├── stack.json # 算子调用栈信息 +│ | | ├── dump.json # 保存前反向API、API的统计量信息或溢出API信息。包含dump数据的API名称(命名格式为:{api_type}_{api_name}_{API调用次数}_{前向反向}_{input/output}.{参数序号})、dtype、 shape、各数据的max、min、mean、L2norm统计信息以及当配置summary_mode="md5"时的CRC-32数据。其中,“参数序号”表示该API下的第n个参数,例如1,则为第一个参数,若该参数为list格式,则根据list继续排序,例如1.1,表示该API的第1个参数的第1个子参数;L2norm表示L2范数(平方根),cell级别dump几乎一致,这里不过多赘述。 +│ | | ├── stack.json # API 调用栈信息 │ | | └── construct.json # 分层分级结构,level为L1时,construct.json内容为空 │ | ├── rank1 | | | ├── dump_tensor_data @@ -265,23 +309,44 @@ dump结果目录结构示例如下: │ ├── step2 ``` -dump 过程中,npy 文件在对应算子或者模块被执行后就会落盘,而 json 文件则需要在正常执行 PrecisionDebugger.stop() 后才会写入完整数据,异常的程序终止会保存终止前被执行算子的相关 npy 文件,可能会导致 json 文件中数据丢失。 +* `rank`:设备 ID,每张卡的数据保存在对应的 `rank{ID}` 目录下。非分布式场景下没有 rank ID,目录名称为 rank。 +* `dump_tensor_data`:保存采集到的张量数据。 +* `dump.json`:记录模块或 API 的统计信息。 +* `stack.json`:API调用栈信息。 +* `construct.json`:分层分级结构信息。 -其中 rank 为设备上各卡的 ID,每张卡上 dump 的数据会生成对应 dump 目录。非分布式场景下没有 rank ID,目录名称为 rank。 +dump 过程中,npy 文件在对应API或者模块被执行后就会落盘,而 json 文件则需要在正常执行 PrecisionDebugger.stop() 后才会写入完整数据,因此,程序异常终止时,被执行API对应的 npy 文件已被保存,但 json 文件中的数据可能丢失。 动态图场景下使能 PSJit 或 PIJit,装饰特定 Cell 或 function,被装饰的部分会全部/部分使能**静态图**流程。 - PSJit 场景下 config.json 文件配置 level 为 L1 时,被 PSJit 装饰的部分也作为 API 被 dump 到对应目录;配置 level 为 L2 时,则只会 dump 用户网络中静态图流程下的相关 kernel,其结果目录同jit_level 为 O0/O1 时的静态图 dump 相同。 - PIJit 场景下 config.json 文件配置 level 为 L1 时,会被还原为动态图,按 API 粒度进行 dump;配置 level 为 L2 时,则只会 dump 用户网络中静态图流程下的相关 kernel。 -npy 文件保存的前缀和 MindSpore 对应关系如下: - -| 前缀 | MindSpore 模块 | -| -------------- | ---------------------------- | -| Tensor | mindspore.Tensor | -| Functional | mindspore.ops | -| Primitive | mindspore.ops.Primitive | -| Mint | mindspore.mint | -| MintFunctional | mindspore.mint.nn.functional | -| Jit | mindspore.jit | -| Cell | mindspore.nn.Cell | + +npy文件名的前缀含义如下: + +| 前缀 | 含义 | +| -------------- |------------------------------| +| Tensor | mindspore.Tensor API数据 | +| Functional | mindspore.ops API数据 | +| Primitive | mindspore.ops.Primitive API数据 | +| Mint | mindspore.mint API数据 | +| MintFunctional | mindspore.mint.nn.functional API数据 | +| Jit | 被"jit"装饰的模块或函数数据 | +| Cell | mindspore.nn.Cell 类(模块)数据 | + + + +## 9.补充说明 + +### 9.1 修改 API 支持列表 + +动态图 API 级 dump 时,本工具提供固定的 API 支持列表,仅支持对列表中的 API 进行精度数据采集。一般情况下,无需修改该列表,而是通过config.json中的scope/list字段进行 dump API 指定。若需要改变 API 支持列表,可以在 `msprobe/mindspore/dump/hook_cell/support_wrap_ops.yaml` 文件内手动修改,如下示例: + +```yaml +ops: + - adaptive_avg_pool1d + - adaptive_avg_pool2d + - adaptive_avg_pool3d +``` + diff --git a/debug/accuracy_tools/msprobe/docs/data_dump_Mindspore/dynamic_graph_quick_start_example.md b/debug/accuracy_tools/msprobe/docs/data_dump_Mindspore/dynamic_graph_quick_start_example.md new file mode 100644 index 000000000..543d26065 --- /dev/null +++ b/debug/accuracy_tools/msprobe/docs/data_dump_Mindspore/dynamic_graph_quick_start_example.md @@ -0,0 +1,211 @@ +# 动态图精度数据采集快速入门示例 + +本示例将展示如何在 MindSpore 动态图模式下使用 msprobe 工具进行精度数据采集。 + +## 1. 配置文件 + +请在当前目录下创建一个名为 `config.json` 的配置文件,内容如下: + +```json +{ + "task": "statistics", + "dump_path": "./output", + "rank": [], + "step": ["0-2"], + "level": "L1", + "statistics": { + "scope": [], + "list": [], + "data_mode": [ + "all" + ], + "summary_mode": "statistics" + } +} + +``` +以上配置参数详细介绍和使用请参见[《config.json 配置文件介绍》](../02.config_introduction.md)和[《config.json 配置示例》](../03.config_examples.md#3-mindspore-动态图场景) 中的“MindSpore动态图场景”。 + +## 2. 模型脚本 + +在当前目录下创建一个 Python 脚本文件,例如 `alexnet_model.py`,将以下代码粘贴进去: + +```python +import os +import numpy as np +import mindspore as ms +from mindspore import nn, ops +from mindspore import context +from mindspore import Tensor +from msprobe.mindspore import PrecisionDebugger, seed_all + +# 设置随机种子以确保结果可重现 +seed_all(seed=1234, mode=False, rm_dropout=True) + +# 配置文件路径 +script_dir = os.path.dirname(os.path.abspath(__file__)) +config_path = os.path.join(script_dir, 'config.json') + +# 初始化精度调试器 +debugger = PrecisionDebugger(config_path=config_path) + +# 设置 MindSpore 设备上下文 +context.set_context(mode=ms.PYNATIVE_MODE, device_target="Ascend", device_id=0) + +# 定义卷积层 +def conv_layer(in_channels, out_channels, kernel_size, stride=1, padding=0, pad_mode="valid", has_bias=True): + return nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, + has_bias=has_bias, pad_mode=pad_mode) + +# 定义全连接层 +def fc_layer(input_channels, out_channels, has_bias=True): + return nn.Dense(input_channels, out_channels, has_bias=has_bias) + + +class AlexNet(nn.Cell): + """ + AlexNet 模型定义 + + 参数: + - num_classes: 分类数量 + - channel: 输入通道数(图像的颜色通道数) + - phase: 模型运行阶段('train' 或 'test') + - include_top: 是否包含全连接层的顶部(最后的分类层) + """ + def __init__(self, num_classes=10, channel=3, phase='train', include_top=True): + super(AlexNet, self).__init__() + + # 卷积层 + self.conv1 = conv_layer(channel, 64, 11, stride=4, pad_mode="same") + self.conv2 = conv_layer(64, 128, 5, pad_mode="same") + self.conv3 = conv_layer(128, 192, 3, pad_mode="same") + self.conv4 = conv_layer(192, 256, 3, pad_mode="same") + self.conv5 = conv_layer(256, 256, 3, pad_mode="same") + + # 激活函数和池化层 + self.relu = nn.ReLU() + self.max_pool2d = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode='valid') + + # 如果包括顶部(全连接层) + self.include_top = include_top + if self.include_top: + self.flatten = nn.Flatten() + self.fc1 = fc_layer(256 * 28 * 28, 4096) + self.fc2 = fc_layer(4096, 4096) + self.fc3 = fc_layer(4096, num_classes) + + # 数学操作 + self.add = ops.Add() + self.mul = ops.Mul() + + def construct(self, x): + """定义前向传播过程""" + + x = self.conv1(x) + x = self.add(x, 0.1) # 偏置加法 + x = self.mul(x, 2.0) # 乘法操作 + x = self.relu(x) # ReLU 激活函数 + x = ops.celu(x) + x = x + 2 + + # 打印每层输出形状,调试时可使用 + print(f"After Conv1: {x.shape}") + + x = self.max_pool2d(x) # Max pooling 操作 + print(f"After MaxPool: {x.shape}") # 打印池化后的形状 + + x = self.conv2(x) + x = self.relu(x) + + x = self.conv3(x) + x = self.relu(x) + + x = self.conv4(x) + x = self.relu(x) + + x = self.conv5(x) + x = self.relu(x) + + # 打印卷积层后的形状,调试时使用 + print(f"After Conv5: {x.shape}") + + # 可选的全连接层部分 + if self.include_top: + x = self.flatten(x) + x = self.fc1(x) + x = self.fc2(x) + x = self.fc3(x) + + return x + +# 前向函数 +def forward_fn(data, label): + out = net(data) + loss = criterion(out, label) + return loss + +# 训练步骤 +def train_step(data, label): + loss, grads = grad_fn(data, label) + optimizer(grads) + return loss + +# 测试模型 +if __name__ == "__main__": + net = AlexNet() + optimizer = nn.SGD(net.trainable_params(), learning_rate=0.01) + criterion = nn.MSELoss() + + grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters) + + # 生成数据和标签 + batch_size = 1 + num_classes = 10 + data = np.random.normal(1, 1, (batch_size, 3, 227, 227)).astype(np.float32) + label = np.random.randint(0, num_classes, (batch_size,)).astype(np.float32) # 注意此处类型应为 float32 + + # 转换为 MindSpore 张量 + data = Tensor(data) + label = Tensor(label) + + steps = 5 + for i in range(steps): + debugger.start(net) # 启动调试器 + loss = train_step(data, label) # 执行训练步骤 + print(f"Step {i}, Loss: {loss}") + debugger.stop() # 停止调试器 + debugger.step() # 计数步数 +``` + +## 3. 运行训练脚本 + +在命令行中执行以下命令: + +```bash +python alexnet_model.py +``` + +## 4. 查看采集结果 + +执行训练命令后,工具会将模型训练过程中的精度数据采集下来。 + +日志中打印出现如下信息表示数据采集成功,即可手动停止模型训练查看采集数据。 + +```markdown +**************************************************************************** +* msprobe ends successfully. * +**************************************************************************** +``` + +## 5. 数据分析 + +在 `dump_path` 参数指定的路径下(本例中为 `./output`),会出现如下目录结构,后续精度数据分析操作可使用 msprobe 工具的精度预检和精度比对等功能,详细流程请参见[《msprobe使用手册》](../../README.md#2-精度预检)。: + +```bash +output/ +└── step0 + └── rank + ├── construct.json # level为L0时,保存Cell的层级关系信息。当前场景为空 + ├── dump.json # 保存API前反向输入输出数据的统计量信息 + └── stack.json # 保存API的调用栈 +``` \ No newline at end of file -- Gitee From 41e881eeab0a6f595bbb6ea6b94d5e0dcfce9ff5 Mon Sep 17 00:00:00 2001 From: yangxinxian <947098055@qq.com> Date: Mon, 2 Dec 2024 21:24:16 +0800 Subject: [PATCH 2/4] Update test_multi_api_accuracy_checker.py --- .../test_multi_api_accuracy_checker.py | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py index 7939f7eac..80a39595d 100644 --- a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py +++ b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py @@ -94,65 +94,6 @@ class TestMultiApiAccuracyChecker(unittest.TestCase): "[Device 0] Exception occurred while running and comparing API_1 forward API. Detailed exception information: Test exception." ) - def test_process_forward_success(self): - """测试 process_forward 成功执行时,返回正确的输出列表。""" - # 设置 current_device_id - self.checker.current_device_id = 0 - - api_info = MagicMock() - api_info.check_forward_info.return_value = True - - forward_inputs_aggregation = MagicMock() - forward_output_list = MagicMock() - - with patch.object(self.checker, 'prepare_api_input_aggregation', return_value=forward_inputs_aggregation), \ - patch.object(self.checker, 'run_and_compare_helper', return_value=forward_output_list): - result = self.checker.process_forward("API_1", api_info) - - self.assertEqual(result, forward_output_list) - - @patch('msprobe.mindspore.api_accuracy_checker.multi_api_accuracy_checker.logger') - def test_process_backward_no_backward_info(self, mock_logger): - """测试当 check_backward_info 返回 False 时,process_backward 返回 None 并记录调试日志。""" - # 设置 current_device_id - self.checker.current_device_id = 1 - - api_info = MagicMock() - api_info.check_backward_info.return_value = False - - result = self.checker.process_backward("API_2", api_info) - - self.assertEqual(result, Const.EXCEPTION_NONE) - mock_logger.debug.assert_called_with( - "[Device 1] API: API_2 lacks backward information, skipping backward check." - ) - - def test_init(self): - # 测试初始化方法 - self.assertIsInstance(self.checker.manager, Manager().__class__) - self.assertIsInstance(self.checker.multi_data_manager, MultiDataManager) - self.assertEqual(self.checker.args, self.args) - - @patch('msprobe.mindspore.api_accuracy_checker.multi_api_accuracy_checker.context') - def test_process_on_device_no_output(self, mock_context): - # 测试当 forward 和 backward 返回 None 时的行为 - with patch.object(self.checker.multi_data_manager, 'is_unique_api', return_value=True), \ - patch.object(self.checker.multi_data_manager, 'record') as mock_record, \ - patch.object(self.checker.multi_data_manager, 'save_results') as mock_save_results, \ - patch.object(self.checker, 'process_forward', return_value=None), \ - patch.object(self.checker, 'process_backward', return_value=None): - device_id = 0 - api_infos = [('API_1', MagicMock())] - progress_queue = Queue() - - self.checker.process_on_device(device_id, api_infos, progress_queue) - - # 验证 record 未被调用 - mock_record.assert_not_called() - - # 验证 save_results 被调用 - mock_save_results.assert_called_once_with('API_1') - def tearDown(self): # 清理资源 if hasattr(self.checker, 'manager'): -- Gitee From 6a24703db8e21119c57f4d2324aa16beb994ab18 Mon Sep 17 00:00:00 2001 From: yangxinxian <947098055@qq.com> Date: Mon, 2 Dec 2024 21:25:48 +0800 Subject: [PATCH 3/4] Update test_multi_api_accuracy_checker.py --- .../test_multi_api_accuracy_checker.py | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py index 80a39595d..46f401a0e 100644 --- a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py +++ b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py @@ -74,26 +74,6 @@ class TestMultiApiAccuracyChecker(unittest.TestCase): "[Device 0] Exception occurred while getting forward API inputs for API_1. Skipping forward check. Detailed exception information: Test exception." ) - @patch('msprobe.mindspore.api_accuracy_checker.multi_api_accuracy_checker.logger') - def test_process_forward_run_and_compare_exception(self, mock_logger): - """测试当 run_and_compare_helper 抛出异常时,process_forward 返回 None 并记录警告日志。""" - # 设置 current_device_id - self.checker.current_device_id = 0 - - api_info = MagicMock() - api_info.check_forward_info.return_value = True - - forward_inputs_aggregation = MagicMock() - - with patch.object(self.checker, 'prepare_api_input_aggregation', return_value=forward_inputs_aggregation), \ - patch.object(self.checker, 'run_and_compare_helper', side_effect=Exception("Test exception")): - result = self.checker.process_forward("API_1", api_info) - - self.assertEqual(result, Const.EXCEPTION_NONE) - mock_logger.warning.assert_called_with( - "[Device 0] Exception occurred while running and comparing API_1 forward API. Detailed exception information: Test exception." - ) - def tearDown(self): # 清理资源 if hasattr(self.checker, 'manager'): -- Gitee From b955790b17c1139ed67412dd474c273ef5b3f968 Mon Sep 17 00:00:00 2001 From: yangxinxian <947098055@qq.com> Date: Mon, 2 Dec 2024 21:30:05 +0800 Subject: [PATCH 4/4] Update test_multi_api_accuracy_checker.py --- .../test_multi_api_accuracy_checker.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py index 46f401a0e..cee0f9fe5 100644 --- a/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py +++ b/debug/accuracy_tools/msprobe/test/mindspore_ut/api_accuracy_checker/test_multi_api_accuracy_checker.py @@ -57,23 +57,6 @@ class TestMultiApiAccuracyChecker(unittest.TestCase): "[Device 0] API: API_1 lacks forward information, skipping forward check." ) - @patch('msprobe.mindspore.api_accuracy_checker.multi_api_accuracy_checker.logger') - def test_process_forward_prepare_exception(self, mock_logger): - """测试当 prepare_api_input_aggregation 抛出异常时,process_forward 返回 None 并记录警告日志。""" - # 设置 current_device_id - self.checker.current_device_id = 0 - - api_info = MagicMock() - api_info.check_forward_info.return_value = True - - with patch.object(self.checker, 'prepare_api_input_aggregation', side_effect=Exception("Test exception")): - result = self.checker.process_forward("API_1", api_info) - - self.assertEqual(result, Const.EXCEPTION_NONE) - mock_logger.warning.assert_called_with( - "[Device 0] Exception occurred while getting forward API inputs for API_1. Skipping forward check. Detailed exception information: Test exception." - ) - def tearDown(self): # 清理资源 if hasattr(self.checker, 'manager'): -- Gitee