diff --git a/debug/accuracy_tools/msprobe/core/grad_probe/constant.py b/debug/accuracy_tools/msprobe/core/grad_probe/constant.py index 189ec2d11b275b28d4577ff5ea9baca21b71d3ad..7cb96494289e36ffa3148f5bf53a7b8248f1feaa 100644 --- a/debug/accuracy_tools/msprobe/core/grad_probe/constant.py +++ b/debug/accuracy_tools/msprobe/core/grad_probe/constant.py @@ -33,6 +33,10 @@ class GradConst: # direction suffix DIR_SUFFIX = "dir.npy" + # input safety + BOUND_MINIMUM = -2**63 + BOUND_MAXIMUM = 2**63-1 + # file safty DATA_DIR_AUTHORITY = 0o750 DATA_FILE_AUTHORITY = 0o640 diff --git a/debug/accuracy_tools/msprobe/docs/17.grad_probe.md b/debug/accuracy_tools/msprobe/docs/17.grad_probe.md index 95330b7205daa9f3d5eddad8146af0d938923015..f510e908866755702a658675a76ca738ff736a78 100644 --- a/debug/accuracy_tools/msprobe/docs/17.grad_probe.md +++ b/debug/accuracy_tools/msprobe/docs/17.grad_probe.md @@ -21,9 +21,9 @@ ```json { "task": "grad_probe", - "dump_path": "./dump_path", - "rank": [], - "step": [], + "dump_path": "./dump_path", + "rank": [], + "step": [], "grad_probe": { "grad_level": "L1", "param_list": [], @@ -43,7 +43,7 @@ | step | step列表,表示需要导出数据的step列表。列表为空就表示导出所有step的数据。默认为空。(MindSpore静态图模式下,当前暂不支持指定step功能) | List[int] | 否 | | grad_level | 输出级别。决定导出数据的详细程度,级别越大导出数据越详细。可取值:L0, L1, L2。默认L1。|str | 否 | | param_list | 权重名称列表,表示需要监控的权重。列表为空就表示监控所有权重。默认为空。 | List[str] | 否 | - | bounds | 区间列表,用来划分区间以统计数值的分布。需要保证由数据小到大排列。可以使用默认值[-1, 0, 1]。 | List[float, int] | 否 | + | bounds | 区间列表,用来划分区间以统计数值的分布。需要保证由数据小到大排列,并且列表中的元素需要在int64范围内。可以使用默认值[-1, 0, 1]。 | List[float, int] | 否 | **不同级别的level的导出数据** @@ -53,18 +53,18 @@ | L0 | ("param_name", "MD5", "max", "min", "norm", "shape") | 否 | | L1 | ("param_name", "max", "min", "norm", "shape") | 是 | | L2 | ("param_name", *intervals, "=0", "max", "min", "norm", "shape") | 是 | - + intervals就是根据值分布bounds划分出的区间。 MindSpore静态图模式下,L0级别中暂不支持"MD5" - + **方向数据解释** - + 因为模型的参数往往非常大,所以存储真实数据是不可接受的,这里折衷一下,只存储梯度数据的正负号(一个布尔值),也就是方向。 - + **bounds和值分布解释** - + + 值分布:梯度数据落在各个区间的元素个数占总元素个数的比例。 - + bounds:一个列表,用来划分出区间以统计值分布。例如传入bounds = [-10, 0, 10],此时有一个 grad_value: Tensor = [9.3 , 5.4, -1.0, -12.3],依据 bounds 划分出 (-inf, -10]、(-10, 0]、(0, 10]、(10, inf) 四个区间,然后统计grad_value里的数据落在每个区间内的个数,得到 1、1、2、0。如下图所示: + + bounds:一个列表,用来划分出区间以统计值分布。例如传入bounds = [-10, 0, 10],此时有一个 grad_value: Tensor = [9.3 , 5.4, -1.0, -12.3],依据 bounds 划分出 (-inf, -10]、(-10, 0]、(0, 10]、(10, inf) 四个区间,然后统计grad_value里的数据落在每个区间内的个数,得到 1、1、2、0。如下图所示: ![Alt text](./img/grad_probe_image-1.png) 2. 插入代码。示例代码如下: @@ -143,7 +143,7 @@ GradComparator.compare_distributed("配置文件里写的dump_path", "配置文件里写的dump_path", "比对结果输出目录") ``` - + ### 比对结果 @@ -204,4 +204,4 @@ GradComparator.compare_distributed(dump_path1, dump_path2, output_path) | output_path |输出结果目录,不存在会新建。 | str | 是 | -# FAQ +# FAQ diff --git a/debug/accuracy_tools/msprobe/mindspore/grad_probe/global_context.py b/debug/accuracy_tools/msprobe/mindspore/grad_probe/global_context.py index a081d1fadc7aedc549cfa511e8dc509a0a3427d3..a8c3e76a1cea2a0ec34865511beed74147aacc0e 100644 --- a/debug/accuracy_tools/msprobe/mindspore/grad_probe/global_context.py +++ b/debug/accuracy_tools/msprobe/mindspore/grad_probe/global_context.py @@ -1,6 +1,6 @@ import os import threading -from typing import Dict, Union +from typing import Dict, Union, Tuple from msprobe.core.grad_probe.utils import check_str from msprobe.core.grad_probe.constant import GradConst @@ -38,7 +38,9 @@ class GlobalContext: raise ValueError("Invalid level set in config yaml file, level option: L0, L1, L2") self._set_input_list(config_dict, GradConst.PARAM_LIST, str) - self._set_input_list(config_dict, GradConst.BOUNDS, float) + def check_bounds(bound): + return GradConst.BOUND_MINIMUM <= bound and bound <= GradConst.BOUND_MAXIMUM + self._set_input_list(config_dict, GradConst.BOUNDS, (float, int), element_check=check_bounds) self._set_input_list(config_dict, GradConst.STEP, int) self._set_input_list(config_dict, GradConst.RANK, int) @@ -70,19 +72,29 @@ class GlobalContext: dump_rank_list = self.get_context(GradConst.RANK) return (not dump_rank_list) or (rank in dump_rank_list) - def _set_input_list(self, config_dict: Dict, name: str, dtype: Union[int, str, float]): - value = config_dict.get(name) + def _get_type_str(self, dtype: Union[int, str, float, Tuple[int, str, float]]): + if isinstance(dtype, tuple): + return "/".join([self._get_type_str(element) for element in dtype]) if dtype == int: type_str = "integer" elif dtype == float: type_str = "float" else: type_str = "string" + return type_str + + def _set_input_list(self, config_dict: Dict, name: str, + dtype: Union[int, str, float, Tuple[int, str, float]], element_check=None): + value = config_dict.get(name) + type_str = self._get_type_str(dtype) if value and isinstance(value, list): for val in value: if not isinstance(val, dtype): logger.warning(f"Invalid {name} which must be None or list of {type_str}") return + if element_check and not element_check(val): + logger.warning(f"Given {name} violates some specific rules.") + return self._setting[name] = value else: logger.warning(f"{name} is None or not a list with valid items, use default value.")