diff --git a/tutorials/source_zh_cn/compile/operators.md b/tutorials/source_zh_cn/compile/operators.md index 3b87dfd6b8832ebe1aca9215678b110395238435..c6baaf4b87ff2947ffa5ee5167283df0aeb5d4c8 100644 --- a/tutorials/source_zh_cn/compile/operators.md +++ b/tutorials/source_zh_cn/compile/operators.md @@ -14,7 +14,7 @@ 说明: -- 在Python中`~`操作符对输入的整数按位取反; MindSpore对`~`的功能重新定义为对`Tensor(Bool)`的逻辑取反。 +- 在Python中`~`操作符对输入的整数按位取反。MindSpore对`~`的功能重新定义为对`Tensor(Bool)`的逻辑取反。 ## 二元算术运算符 @@ -36,9 +36,9 @@ 限制: -- 当左右操作数都为`number`类型时,不支持`float64` 和 `int32`间的运算。`+`、`-`、`*`、`/`、`%`、`**`、`//` 支持左右操作数的值同时为`bool`。 +- 当左右操作数都为`number`类型时,不支持`float64`和`int32`间的运算。`+`、`-`、`*`、`/`、`%`、`**`、`//`支持左右操作数的值同时为`bool`。 - 当任一操作数为`tensor`类型时,左右操作数的值不可同时为`bool`。 -- `list/tuple`和`number`进行`*`运算时表示将`list/tuple`复制`number`份后串联起来,`list`内的数据类型可以是图模式下支持的任意数据类型,也支持多层嵌套。`tuple`内的数据类型必须为`number`、`string`、`none`,也支持多层嵌套。 +- `list/tuple`和`number`进行`*`运算时表示将`list/tuple`复制`number`份后串联起来。`list`内的数据类型可以是图模式下支持的任意数据类型,也支持多层嵌套。`tuple`内的数据类型必须为`number`、`string`、`none`,也支持多层嵌套。 ## 赋值运算符 @@ -61,20 +61,17 @@ 限制: -- 当`AugAssign`的左右操作数都为`number`类型时,`number`的值不可为`bool` 类型。 - -- 当`AugAssign`的左右操作数都为`number`类型时,不支持`float64` 和 `int32`间的运算。 - +- 当`AugAssign`的左右操作数都为`number`类型时,`number`的值不可为`bool`类型。 +- 当`AugAssign`的左右操作数都为`number`类型时,不支持`float64`和`int32`间的运算。 - 当`AugAssign`的任一操作数为`tensor`类型时,左右操作数的值不可同时为`bool`。 - -- `list/tuple`和`number`进行`*=`运算时表示将`list/tuple`复制`number`份后串联起来,`list/tuple`内对象的元素可以包含任意图模式支持的类型,也支持多层嵌套。 +- `list/tuple`和`number`进行`*=`运算时表示将`list/tuple`复制`number`份后串联起来。`list/tuple`内对象的元素可以包含任意图模式支持的类型,也支持多层嵌套。 ## 逻辑运算符 | 逻辑运算符 | 支持类型 | | :--------- | :----------------------------------------------------------- | -| `and` | `String`、 `Number`、 `Tuple`、`List` 、`Dict`、`None`、标量、Tensor。 | -| `or` | `String`、 `Number`、 `Tuple`、`List` 、`Dict`、`None`、标量、Tensor。 | +| `and` | `String`、`Number`、`Tuple`、`List`、`Dict`、`None`、标量、Tensor。 | +| `or` | `String`、`Number`、`Tuple`、`List`、`Dict`、`None`、标量、Tensor。 | | `not` | `Number`、`Tuple`、`List`、只有一个成员的Tensor。 | 限制: @@ -85,21 +82,21 @@ | 比较运算符 | 支持类型 | | :--------- | :----------------------------------------------------------- | -| `in` | `Number` in `Tuple`、`String` in `Tuple`、`Tensor` in `Tuple`、`Number` in `List`、`String` in `List`、`Tensor` in `List`、`String` in `Dictionary`、`Number` in `Dictionary`、常量`Tensor` in `Dictionary`、 `Tuple` in `Dictionary`。| +| `in` | `Number` in `Tuple`、`String` in `Tuple`、`Tensor` in `Tuple`、`Number` in `List`、`String` in `List`、`Tensor` in `List`、`String` in `Dictionary`、`Number` in `Dictionary`、常量`Tensor` in `Dictionary`、`Tuple` in `Dictionary`。| | `not in` | 与`in`相同。 | -| `is` | 仅支持判断是`None`、 `True`或者`False`。 | -| `is not` | 仅支持判断不是`None`、 `True`或者`False`。 | +| `is` | 仅支持判断是`None`、`True`或者`False`。 | +| `is not` | 仅支持判断不是`None`、`True`或者`False`。 | | < | `Number` < `Number`、`Number` < `Tensor`、`Tensor` < `Tensor`、`Tensor` < `Number`。 | | <= | `Number` <= `Number`、`Number` <= `Tensor`、`Tensor` <= `Tensor`、`Tensor` <= `Number`。 | | > | `Number` > `Number`、`Number` > `Tensor`、`Tensor` > `Tensor`、`Tensor` > `Number`。 | | >= | `Number` >= `Number`、`Number` >= `Tensor`、`Tensor` >= `Tensor`、`Tensor` >= `Number`。 | -| != | `Number` != `Number`、`Number` != `Tensor`、`Tensor` != `Tensor`、`Tensor` != `Number`、`mstype` != `mstype`、`String` != `String`、`Tuple !` = `Tuple`、`List` != `List`。 | +| != | `Number` != `Number`、`Number` != `Tensor`、`Tensor` != `Tensor`、`Tensor` != `Number`、`mstype` != `mstype`、`String` != `String`、`Tuple` != `Tuple`、`List` != `List`。 | | == | `Number` == `Number`、`Number` == `Tensor`、`Tensor` == `Tensor`、`Tensor` == `Number`、`mstype` == `mstype`、`String` == `String`、`Tuple` == `Tuple`、`List` == `List`。 | 限制: -- 对于`<`、`<=`、`>`、`>=`、`!=`来说,当左右操作数都为`number`类型时,`number`的值不可为`bool` 类型。 -- 对于`<`、`<=`、`>`、`>=`、`!=`、`==`来说,当左右操作数都为`number`类型时,不支持`float64` 和 `int32`间的运算。 +- 对于`<`、`<=`、`>`、`>=`、`!=`来说,当左右操作数都为`number`类型时,`number`的值不可为`bool`类型。 +- 对于`<`、`<=`、`>`、`>=`、`!=`、`==`来说,当左右操作数都为`number`类型时,不支持`float64`和`int32`间的运算。 - 对于`<`、`<=`、`>`、`>=`、`!=`、`==`来说,当左右任一操作数为`tensor`类型时,左右操作数的值不可同时为`bool`。 - 对于`==`来说,当左右操作数都为`number`类型时,支持左右操作数同时为`bool`,不支持只有一个操作数为`bool`。 -- 对于`!=`、`==`来说除`mstype`外,其他取值均可和`None`进行比较来判空。 \ No newline at end of file +- 对于`!=`、`==`来说除`mstype`外,其他取值均可和`None`进行比较来判空。 diff --git a/tutorials/source_zh_cn/compile/python_builtin_functions.ipynb b/tutorials/source_zh_cn/compile/python_builtin_functions.ipynb index a695fae6b97fca20e5bdcdcfb8a9baf00ce47317..3130c884c526f21723066506d57f534e3d581695 100644 --- a/tutorials/source_zh_cn/compile/python_builtin_functions.ipynb +++ b/tutorials/source_zh_cn/compile/python_builtin_functions.ipynb @@ -81,7 +81,9 @@ "\n", "调用:`float(x=0)`。\n", "\n", - "入参:`x` - 需要被转换为浮点数的对象,支持类型为`int`、`float`、`bool`、`str`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 需要被转换为浮点数的对象,支持类型为`int`、`float`、`bool`、`str`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:转换后的浮点数值。\n", "\n", @@ -138,7 +140,9 @@ "\n", "调用:`bool(x=false)`。\n", "\n", - "入参:`x` - 需要被转换为布尔值的对象,支持类型为`int`、`float`、`bool`、`str`、`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 需要被转换为布尔值的对象,支持类型为`int`、`float`、`bool`、`str`、`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:转换后的布尔值。\n", "\n", @@ -194,7 +198,9 @@ "\n", "调用:`str(x='')`。\n", "\n", - "入参:`x` - 需要被转换为字符串的对象,支持类型为`int`、`float`、`bool`、`str`、`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 需要被转换为字符串的对象,支持类型为`int`、`float`、`bool`、`str`、`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:输入`x`转换后的字符串。\n", "\n", @@ -251,7 +257,9 @@ "\n", "调用:`tuple(x=())`。\n", "\n", - "入参:`x` - 需要被转换为元组的对象,支持类型为`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 需要被转换为元组的对象,支持类型为`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:按照`x`的第零维度拆分得到的元组。\n", "\n", @@ -305,7 +313,9 @@ "\n", "调用:`list(x=())`。\n", "\n", - "入参:`x` - 需要被转换为列表的对象,支持类型为`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 需要被转换为列表的对象,支持类型为`list`、 `tuple`、 `dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:按照`x`的第零维度拆分得到的列表。\n", "\n", @@ -464,7 +474,7 @@ "id": "b5d553d6", "metadata": {}, "source": [ - "在静态图模式下对象的属性可能会和动态图模式下有区别,建议使用`default`输入,或者在使用`getattr`前先使用`hasattr`进行校验。\n", + "在静态图模式下,对象的属性可能会和动态图模式下有区别。建议使用`default`输入,或者在使用`getattr`前先使用`hasattr`进行校验。\n", "\n", "其中`getattr(x.asnumpy(), \"shape\", np.array([0, 1, 2, 3, 4]))`属于高阶用法,更多介绍可见[AST扩展语法(LAX级别)](https://www.mindspore.cn/tutorials/zh-CN/master/compile/static_graph.html#ast%E6%89%A9%E5%B1%95%E8%AF%AD%E6%B3%95lax%E7%BA%A7%E5%88%AB)章节。\n", "\n", @@ -538,7 +548,9 @@ "\n", "调用:`len(sequence)`。\n", "\n", - "入参:`sequence` - `Tuple`、`List`、`Dictionary`、`Tensor`、`String`以及第三方对象(例如numpy.ndarray)。\n", + "入参:\n", + "\n", + "- `sequence` - `Tuple`、`List`、`Dictionary`、`Tensor`、`String`以及第三方对象(例如numpy.ndarray)。\n", "\n", "返回值:序列的长度,类型为`int`。当入参是`Tensor`时,返回的是`Tensor`第零维的长度。\n", "\n", @@ -672,7 +684,9 @@ "\n", "调用:`all(x)`。\n", "\n", - "入参:`x` - 可迭代对象,支持类型包括`tuple`、`list`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 可迭代对象,支持类型包括`tuple`、`list`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:布尔值,如果所有元素都为`True`,则返回`True`,否则返回`False`。\n", "\n", @@ -740,11 +754,13 @@ "\n", "## any\n", "\n", - "功能:判断输入中的元素是存在为真值。\n", + "功能:判断输入中的元素是否存在真值。\n", "\n", "调用:`any(x)`。\n", "\n", - "入参:`x` - 可迭代对象,支持类型包括`tuple`、`list`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 可迭代对象,支持类型包括`tuple`、`list`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:布尔值,如果所有元素都为`False`,则返回`False`,否则返回`True`。元素除了0,空,`False`外都算`True`。\n", "\n", @@ -883,7 +899,9 @@ "\n", "调用:`max(*data)`。\n", "\n", - "入参: - `*data` - 若`*data`为单输入,则会比较单个输入内的各个元素,此时`data`必须为可迭代对象。若存在多个输入,则比较每个输入。`data`有效类型为`int`、`float`、`bool`、`list`、`tuple`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `*data` - 若`*data`为单输入,则会比较单个输入内的各个元素,此时`data`必须为可迭代对象。若存在多个输入,则比较每个输入。`data`有效类型为`int`、`float`、`bool`、`list`、`tuple`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:最大值。\n", "\n", @@ -946,7 +964,9 @@ "\n", "调用:`min(*data)`。\n", "\n", - "入参: - `*data` - 若`*data`为单输入,则会比较单个输入内的各个元素,此时`data`必须为可迭代对象。若存在多个输入,则比较每个输入。`data`有效类型为`int`、`float`、`bool`、`list`、`tuple`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `*data` - 若`*data`为单输入,则会比较单个输入内的各个元素,此时`data`必须为可迭代对象。若存在多个输入,则比较每个输入。`data`有效类型为`int`、`float`、`bool`、`list`、`tuple`、`dict`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:最小值。\n", "\n", @@ -1074,7 +1094,9 @@ "\n", "调用:`abs(x)`。\n", "\n", - "入参: - `x` - 有效类型为`int`、`float`、`bool`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", + "入参:\n", + "\n", + "- `x` - 有效类型为`int`、`float`、`bool`、`Tensor`以及第三方对象(例如`numpy.ndarray`)。\n", "\n", "返回值:绝对值。\n", "\n", @@ -1184,7 +1206,9 @@ "\n", "调用:`zip(sequence, ...)`。\n", "\n", - "入参:`sequence` - 一个或多个序列(`Tuple`或`List`)。\n", + "入参:\n", + "\n", + "- `sequence` - 一个或多个序列(`Tuple`或`List`)。\n", "\n", "返回值:返回一个新的序列。\n", "\n", @@ -1347,7 +1371,7 @@ "source": [ "## super\n", "\n", - "功能:用于调用父类(超类)的一个方法,一般在`super`之后调用父类的方法。\n", + "功能:用于调用父类(超类)的一个方法,一般在`super`之后调用父类的方法。\n", "\n", "调用:\n", "\n", @@ -1478,7 +1502,9 @@ "\n", "调用:`print(arg, ...)`\n", "\n", - "入参:`arg` - 要打印的信息(`int` 、`float`、`bool`、`String`或`Tensor`,或者第三方库的数据类型)。\n", + "入参:\n", + "\n", + "- `arg` - 要打印的信息(`int` 、`float`、`bool`、`String`或`Tensor`,或者第三方库的数据类型)。\n", "\n", "返回值:无返回值。\n", "\n", @@ -1638,7 +1664,7 @@ "id": "b291b56d", "metadata": {}, "source": [ - "> type作为Python的原生函数还有另外一种使用方法,即type(name, bases, dict)返回name类型的类对象,由于该用法应用场景较少,因此暂不支持。" + "> type作为Python的原生函数还有另外一种使用方法,即type(name, bases, dict)返回name类型的类对象。由于该用法应用场景较少,因此暂不支持。" ] } ], diff --git a/tutorials/source_zh_cn/compile/statements.ipynb b/tutorials/source_zh_cn/compile/statements.ipynb index 952f4f8e6a70bebd4ddb3d39f3c34d0443c22467..3052c2637ee51a4f714f7885b7c6c8567245e708 100644 --- a/tutorials/source_zh_cn/compile/statements.ipynb +++ b/tutorials/source_zh_cn/compile/statements.ipynb @@ -13,7 +13,9 @@ "\n", "### raise语句\n", "\n", - "支持使用`raise`触发异常,`raise`语法格式:`raise[Exception [, args]]`。语句中的`Exception`是异常的类型,`args`是用户提供的异常参数,通常可以是字符串或者其他对象。目前支持的异常类型有:NoExceptionType、UnknownError、ArgumentError、NotSupportError、NotExistsError、DeviceProcessError、AbortedError、IndexError、ValueError、TypeError、KeyError、AttributeError、NameError、AssertionError、BaseException、KeyboardInterrupt、Exception、StopIteration、OverflowError、ZeroDivisionError、EnvironmentError、IOError、OSError、ImportError、MemoryError、UnboundLocalError、RuntimeError、NotImplementedError、IndentationError、RuntimeWarning。\n", + "支持使用`raise`触发异常。`raise`语法格式:`raise[Exception [, args]]`。语句中的`Exception`是异常的类型,`args`是用户提供的异常参数,通常可以是字符串或者其他对象。\n", + "\n", + "目前支持的异常类型有:NoExceptionType、UnknownError、ArgumentError、NotSupportError、NotExistsError、DeviceProcessError、AbortedError、IndexError、ValueError、TypeError、KeyError、AttributeError、NameError、AssertionError、BaseException、KeyboardInterrupt、Exception、StopIteration、OverflowError、ZeroDivisionError、EnvironmentError、IOError、OSError、ImportError、MemoryError、UnboundLocalError、RuntimeError、NotImplementedError、IndentationError、RuntimeWarning。\n", "\n", "图模式下的raise语法不支持`Dict`类型的变量。\n", "\n", @@ -151,7 +153,7 @@ "source": [ "### return语句\n", "\n", - "`return`语句通常是将结果返回调用的地方,`return`语句之后的语句不被执行。如果返回语句没有任何表达式或者函数没有`return`语句,则默认返回一个`None`对象。一个函数体内可以根据不同的情况有多个`return`语句。例如:" + "`return`语句通常是将结果返回调用的地方,`return`语句之后的语句不被执行。如果返回语句没有任何表达式,或者函数没有`return`语句,则默认返回一个`None`对象。一个函数体内可以根据不同的情况有多个`return`语句。例如:" ] }, { @@ -325,7 +327,7 @@ "\n", "限制:\n", "\n", - "- 如果`cond`不为常量,在不同分支中同一符号被赋予的变量或者常量的数据类型应一致,如果是被赋予变量或者常量数据类型是`Tensor`,则要求`Tensor`的type和shape也应一致。\n", + "- 如果`cond`不为常量,在不同分支中同一符号被赋予的变量或者常量的数据类型应一致。如果是被赋予变量或者常量数据类型是`Tensor`,则要求`Tensor`的type和shape也应一致。\n", "\n", "示例1:" ] @@ -493,7 +495,7 @@ "\n", "限制:\n", "\n", - "- 图的算子数量和`for`循环的迭代次数成倍数关系,`for`循环迭代次数过大可能会导致图占用内存超过使用限制。\n", + "- 图的算子数量和`for`循环的迭代次数成倍数关系。`for`循环迭代次数过大可能会导致图占用内存超过使用限制。\n", "\n", "- 不支持`for...else...`语句。\n", "\n", @@ -551,7 +553,7 @@ "\n", "限制:\n", "\n", - "- 如果`cond`不为常量,在循环体内外同一符号被赋值的变量或者常量的数据类型应一致,如果是被赋予数据类型`Tensor`,则要求`Tensor`的type和shape也应一致。\n", + "- 如果`cond`不为常量,在循环体内外同一符号被赋值的变量或者常量的数据类型应一致。如果是被赋予数据类型`Tensor`,则要求`Tensor`的type和shape也应一致。\n", "\n", "- 不支持`while...else...`语句。\n", "\n", @@ -659,7 +661,7 @@ "\n", "#### def关键字\n", "\n", - "`def`用于定义函数,后接函数标识符名称和原括号`()`,括号中可以包含函数的参数。\n", + "`def`用于定义函数,后接函数标识符名称和圆括号`()`,括号中可以包含函数的参数。\n", "使用方式:`def function_name(args): statements...`。\n", "\n", "示例如下:" @@ -995,7 +997,7 @@ "\n", "在图模式下,有限制地支持`with`语句。`with`语句要求对象必须有两个魔术方法:`__enter__()`和`__exit__()`。\n", "\n", - "值得注意的是with语句中使用的类需要有装饰器@ms.jit_class修饰或者继承于nn.Cell,更多介绍可见[使用jit_class](https://www.mindspore.cn/tutorials/zh-CN/master/compile/static_graph_expert_programming.html#使用jit-class)。\n", + "值得注意的是,with语句中使用的类需要有装饰器@ms.jit_class修饰或者继承于nn.Cell,更多介绍可见[使用jit_class](https://www.mindspore.cn/tutorials/zh-CN/master/compile/static_graph_expert_programming.html#使用jit-class)。\n", "\n", "示例如下:" ] diff --git a/tutorials/source_zh_cn/compile/static_graph.md b/tutorials/source_zh_cn/compile/static_graph.md index eb035627f8722c2873d261e22d0025cdda9408b1..4faf589d0a9741adf21466c04c17b17120155cca 100644 --- a/tutorials/source_zh_cn/compile/static_graph.md +++ b/tutorials/source_zh_cn/compile/static_graph.md @@ -191,7 +191,7 @@ API文档](https://www.mindspore.cn/docs/zh-CN/master/api_python/nn/mindspore.nn 支持在网络里定义`Number`,即支持语法:`y = 1`、`y = 1.2`、`y = True`。 当数据为常量时,编译期可以获取到数值,在网络中可以支持强制类型转换`Number`的语法:`y = int(x)`、`y = float(x)`、`y = bool(x)`。 -当数据为变量时,即需要在运行期才可以获取到数值,也支持使用int()、float()、bool()等内置函数[Python内置函数](https://www.mindspore.cn/tutorials/zh-CN/master/compile/python_builtin_functions.html)进行数据类型转换。例如: +当数据为变量时,即需要在执行期才可以获取到数值,也支持使用int()、float()、bool()等内置函数[Python内置函数](https://www.mindspore.cn/tutorials/zh-CN/master/compile/python_builtin_functions.html)进行数据类型转换。例如: ``` python import mindspore @@ -480,7 +480,7 @@ res: ('H', 'Spore', 'Hello!MindSpore', 'MindSporeMindSpore', True, 'My name is M 基础语法:`list_object.clear()`。 - 基础语义:清空`List`对象 `list_object`中包含的元素。 + 基础语义:清空`List`对象`list_object`中包含的所有元素。 目前,`List.clear`不支持inplace, 清空元素后将会生成一个新的对象。该操作后续将支持inplace。 @@ -922,7 +922,7 @@ API文档](https://www.mindspore.cn/docs/zh-CN/master/api_python/mindspore/minds 属性引用是后面带有一个句点加一个名称的原型。 -在MindSpore的Cell 实例中使用属性引用作为左值需满足如下要求: +在MindSpore的Cell实例中使用属性引用作为左值需满足如下要求: - 被修改的属性属于本`cell`对象,即必须为`self.xxx`。 - 该属性在Cell的`__init__`函数中完成初始化且其为Parameter类型。 @@ -1015,9 +1015,9 @@ ret:[[3. 3. 3. 3.]] #### 网络入参 -在对整网入参求梯度的时候,会忽略非`Tensor`的入参,只计算`Tensor`入参的梯度。 +在对整网入参求梯度时,会忽略非`Tensor`的入参,只计算`Tensor`入参的梯度。 -示例如下。整网入参`(x, y, z)`中,`x`和`z`是`Tensor`,`y`是非`Tensor`。因此,`grad_net`在对整网入参`(x, y, z)`求梯度的时候,会自动忽略`y`的梯度,只计算`x`和`z`的梯度,返回`(grad_x, grad_z)`。 +示例如下。整网入参`(x, y, z)`中,`x`和`z`是`Tensor`,`y`是非`Tensor`。因此,`grad_net`在对整网入参`(x, y, z)`求梯度时,会自动忽略`y`的梯度,只计算`x`和`z`的梯度,返回`(grad_x, grad_z)`。 ``` python import mindspore @@ -1061,7 +1061,7 @@ Graph Mode支持对Tensor的view和in-place操作与求导。 #### 支持view操作 -view操作是指创建一个新的张量,它与原始张量共享相同的数据存储,但具有不同的形状或排列方式,换句话说view操作不会复制数据,而是通过不同的视角来解释现有的数据,避免了不必要的内存分配和数据复制。 +view操作是指创建一个新的张量,它与原始张量共享相同的数据存储,但具有不同的形状或排列方式。换句话说,view操作不会复制数据,而是通过不同的视角来解释现有的数据,避免了不必要的内存分配和数据复制。 支持`Ascend`设备,使用`mindspore.jit`进行编译时,`jit_level=00`和`01`均支持。 @@ -1099,7 +1099,7 @@ assert (graph_grad_out == pynative_grad_out).all() #### 支持in-place操作 -in-place操作是指直接修改输入张量的内容,而不创建新的张量,其优点在于节省内存,尤其是在处理高维数据时,能显著减少额外的内存开销。 +in-place操作是指直接修改输入张量的内容,而不创建新的张量。其优点在于节省内存,尤其是在处理高维数据时,能显著减少额外的内存开销。 下面使用Tensor和Parameter相关用例对Graph Mode支持in-place操作和求导进行说明。 @@ -1291,7 +1291,7 @@ in-place操作是指直接修改输入张量的内容,而不创建新的张量 在Graph Mode的自动微分中,梯度的传递依赖于节点的连边关系,而view和in-place类算子作为原地操作类算子,会影响节点的连边关系,进而影响梯度的传递。 - 当计算图中存在view和in-place算子时,如果可以在图节点的表达上正确传播梯度,也就可以支持view inplace场景反向,否则当前支持不了,会存在相应的报错信息。 + 当计算图中存在view和in-place算子时,如果可以在图节点的表达上正确传播梯度,也就可以支持view inplace场景反向,否则当前不支持,会存在相应的报错信息。 示例如下: @@ -2054,7 +2054,7 @@ res: 2 net.m is 3 ``` - 注意,self对象支持属性修改和设置。若`__init__`内没有定义某个属性,对齐PYNATIVE模式,图模式也允许设置此属性。例如: + 注意,self对象支持属性修改和设置。若`__init__`内没有定义某个属性,对齐PyNative模式,图模式也允许设置此属性。例如: ``` python import mindspore @@ -2136,7 +2136,7 @@ assert out == 2 ### Annotation Type -对于运行时的扩展支持的语法,会产生一些无法被类型推导出的节点,比如动态创建Tensor等。这种类型称为`Any`类型。因为该类型无法在编译时推导出正确的类型,所以这种`Any`将会以一种默认最大精度`float64`进行运算,防止其精度丢失。为了能更好的优化相关性能,需要减少`Any`类型数据的产生。当用户可以明确知道当前通过扩展支持的语句会产生具体类型的时候,我们推荐使用`Annotation @jit.typing:`的方式进行指定对应Python语句类型,从而确定解释节点的类型避免`Any`类型的生成。 +对于运行时的扩展支持的语法,会产生一些无法被类型推导出的节点,比如动态创建Tensor等。这种类型称为`Any`类型。因为该类型无法在编译时推导出正确的类型,所以这种`Any`将会以一种默认最大精度`float64`进行运算,防止其精度丢失。为了能更好地优化相关性能,需要减少`Any`类型数据的产生。当用户可以明确知道当前通过扩展支持的语句会产生具体类型的时候,我们推荐使用`Annotation @jit.typing:`的方式进行指定对应Python语句类型,从而确定解释节点的类型避免`Any`类型的生成。 例如,[Tensor](https://www.mindspore.cn/docs/zh-CN/master/api_python/mindspore/mindspore.Tensor.html#mindspore.Tensor)类和[tensor](https://www.mindspore.cn/docs/zh-CN/master/api_python/mindspore/mindspore.tensor.html#mindspore.tensor)接口的区别就在于在`tensor`接口内部运用了Annotation Type机制。当`tensor`函数的`dtype`确定时,函数内部会利用`Annotation`指定输出类型从而避免`Any`类型的产生。`Annotation Type`的使用只需要在对应Python语句上面或者后面加上注释 diff --git a/tutorials/source_zh_cn/compile/static_graph_expert_programming.ipynb b/tutorials/source_zh_cn/compile/static_graph_expert_programming.ipynb index 9849ea0d980e6cdf502a658dafe579091096acd9..05d4a53e74387a161f2ebdbbc30e2231ac87bdd0 100644 --- a/tutorials/source_zh_cn/compile/static_graph_expert_programming.ipynb +++ b/tutorials/source_zh_cn/compile/static_graph_expert_programming.ipynb @@ -11,21 +11,21 @@ "[![下载样例代码](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_download_code.svg)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/tutorials/zh_cn/compile/mindspore_static_graph_expert_programming.py) \n", "[![查看源文件](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source.svg)](https://gitee.com/mindspore/docs/blob/master/tutorials/source_zh_cn/compile/static_graph_expert_programming.ipynb)\n", "\n", - "本章介绍常用的静态图优化的高级编程技巧,这些技巧能够有效地提高静态图的编译效率以及执行效率,并使程序运行地更加稳定。有关静态图编译的基础介绍,请见[Graph Mode加速](https://www.mindspore.cn/tutorials/zh-CN/master/beginner/accelerate_with_static_graph.html)。\n", + "本章介绍常用的静态图优化的高级编程技巧。这些技巧能够有效地提高静态图的编译效率、执行效率,并提升程序的稳定性。有关静态图编译的基础介绍,请见[Graph Mode加速](https://www.mindspore.cn/tutorials/zh-CN/master/beginner/accelerate_with_static_graph.html)。\n", "\n", "## 如何优化编译性能\n", "\n", "### 使用lazy_inline装饰器\n", "\n", - "神经网络模型的编译过程往往采用默认inline的方式,把层级的代码表达最终展开成一张扁平的计算图,一方面寻求最大的编译优化机会,另一方面也可以简化自动微分以及执行的逻辑。inline后形成的计算图包含了所有的计算节点,可以在更大的范围内进行优化,比如常量折叠、节点融合、并行分析等,也可以更好地实现内存分配,减少内存申请和性能开销。虽然inline优化对于运行期性能提升帮助非常大,但过度inline也带来了编译期的负担。例如随着计算图节点数量膨胀,执行pass的耗时也在急剧增长。\n", + "神经网络模型的编译过程往往采用默认inline的方式,把层级的代码表达最终展开成一张扁平的计算图,一方面寻求最大的编译优化机会,另一方面也可以简化自动微分以及执行的逻辑。inline后形成的计算图包含所有计算节点,可以在更大的范围内进行优化,比如常量折叠、节点融合、并行分析等。同时,也可以更好地实现内存分配,减少内存申请和性能开销。虽然inline优化对于运行期性能提升有很大帮助,但过度inline会增加编译期负担。例如,随着计算图节点数量膨胀,执行pass的耗时也在急剧增长。\n", "\n", - "为了减轻inline对编译性能带来的损耗,对于重复调用相同计算单元的场景(典型的场景是在for循环中调用同一个Cell类的不同实例),我们提供了Lazy Inline机制来减少编译时间。\n", + "为了减轻inline对编译性能的影响,对于重复调用相同计算单元的场景(典型的场景是在for循环中调用同一个Cell类的不同实例),我们提供了Lazy Inline机制来减少编译时间。\n", "\n", "#### 大模型pipeline并行场景\n", "\n", - "在大模型场景中,编译耗时问题尤为突出,一是大模型的模型结构层次深,节点数多;二是大模型在训练时,由于启用pipeline并行,导致模型规模和节点数进一步加大,如果原来图的规模是O,那开启pipeline并行,单节点图的规模变为(O/X)*Y,其中X为pipeline的stage数量,Y为micro batch的数量。以盘古13B网络为例,计算图中计算节点数量达到13.5万个,单次编译时长可接近3小时。\n", + "在大模型场景中,编译耗时问题尤为突出。一是大模型的模型结构层次深、节点数多;二是训练时启用pipeline并行,模型规模和节点数进一步增加。如果原来图的规模是O,那开启pipeline并行,单节点图的规模变为(O/X)*Y,其中X为pipeline的stage数量,Y为micro batch的数量。以盘古13B网络为例,计算图中计算节点数量达到13.5万个,单次编译时长可接近3小时。\n", "\n", - "类似盘古的大模型网络结构是由多层layer组成的。在开启pipeline并行时,各个micro batch的layer层结构是完全一样的。当开启pipeline并行时,`PipelineCell`使用for循环的方式来多次调用相同结构的layer,代码如下所示:" + "类似盘古的大模型网络结构由多层layer组成。开启pipeline并行时,各个micro batch的layer层结构完全相同。此时,`PipelineCell`通过for循环多次调用相同结构的layer,代码如下所示:" ] }, { @@ -56,9 +56,9 @@ "id": "9080abe3", "metadata": {}, "source": [ - "如果把循环体看作被频繁调用的子图,通过把它标记为Lazy Inline,告知编译器推迟inline处理,那么就可以在编译的大部分阶段大幅度减少计算图节点数量,从而获得性能收益。例如上面的代码,可以保留`network`实例的子图结构,不inline或者不提前inline。对此,我们提供了`@lazy_inline`装饰器来实现延迟inline。\n", + "如果把循环体看作被频繁调用的子图,通过把它标记为Lazy Inline,告知编译器推迟inline处理,那么就可以在编译的大部分阶段大幅度减少计算图节点数量,从而获得性能收益。例如上面的代码,可以保留`network`实例的子图结构,不inline或者延迟inline。对此,我们提供了`@lazy_inline`装饰器来实现延迟inline。\n", "\n", - "以Pangu_alpha网络为例,`PipelineCell`函数体中处理的`network`为`PanGUAlphaWithLoss`类的实例,为实现延迟inline,我们需要对`PanGUAlphaWithLoss`类的`__init__`函数加上`@lazy_inline`装饰器,以标记`PanGUAlphaWithLoss`类的子图结构需要被保留下来,不做inline或者延迟inline。如下所示:" + "以Pangu_alpha网络为例,`PipelineCell`函数体中处理的`network`为`PanGUAlphaWithLoss`类的实例。为实现延迟inline,我们需要在`PanGUAlphaWithLoss`类的`__init__`函数上加`@lazy_inline`装饰器,以标记该类的子图结构需要被保留,不进行inline或者延迟inline。如下所示:" ] }, { @@ -86,11 +86,11 @@ "source": [ "> 完整代码可以参考:[Pangu_alpha](https://gitee.com/mindspore/models/tree/master/official/nlp/Pangu_alpha)\n", "\n", - "还是以盘古13B网络为例,应用Lazy Inline方案后,计算图编译规模从13万+节点下降到2万+个节点,编译时间从3个小时下降到20分钟。\n", + "还是以盘古13B网络为例,应用Lazy Inline方案后,计算图节点数量从13万多个下降到2万多个,编译时间从3小时缩短到20分钟。\n", "\n", "#### 更加泛化的一般场景\n", "\n", - "`@lazy_inline`是`Cell::__init__`的装饰器,它会以`__init__`的所有参数生成Cell的`cell_init_args`属性值,`cell_init_args`值相同表明Cell类名和初始化参数值是一样的。而对于相同Cell类的实例,它们的weights还可能是不一样的,因此对于用`construct(self, x)`定义的网络结构,在实际编译时可以转换为`construct(x, self.cell_init_args, self.trainable_parameters())`。对于同一个Cell类的不同实例,如果`cell_init_args`是相同的,那么这两个实例可以复用同一个网络结构,如下所示:" + "`@lazy_inline`是`Cell::__init__`的装饰器,它会以`__init__`的所有参数生成Cell的`cell_init_args`属性。`cell_init_args`值相同,表示Cell类名和初始化参数值一致。对于相同Cell类的实例,它们的weights可能不同,因此对于`construct(self, x)`定义的网络结构,实际编译时可以转换为`construct(x, self.cell_init_args, self.trainable_parameters())`。对于同一个Cell类的不同实例,只要`cell_init_args`相同,就可以复用同一个网络结构,如下所示:" ] }, { @@ -109,7 +109,7 @@ "id": "efa1a2c5", "metadata": {}, "source": [ - "引入可复用计算图后,具有相同`cell_init_args`的Cell实例只需编译解析一次。所以对于更加泛化的调用同一个Cell类的不同实例的场景,只要`cell_init_args`是相同的,都可以加上`@lazy_inline`装饰器来加速编译。例如GPT网络:" + "引入可复用计算图后,具有相同`cell_init_args`的Cell实例只需编译解析一次。因此,在更通用的场景下,调用同一个Cell类的不同实例,只要`cell_init_args`相同,都可以加上`@lazy_inline`装饰器来加速编译。例如GPT网络:" ] }, { @@ -154,15 +154,15 @@ "source": [ "> 完整代码可以参考:[GPT](https://gitee.com/mindspore/models/tree/master/official/nlp/GPT)\n", "\n", - "GPT的网络结构由多层`Block`类的不同实例构成,这些`Block`的初始化参数都是同一个`config`,所以加上`@lazy_inline`装饰器后,这些`Block`实例都可以复用同一个网络结构,而且在大部分的编译阶段都不进行inline,从而可以大幅度减少编译时间。\n", + "GPT的网络结构由多层`Block`类的不同实例构成,这些`Block`的初始化参数都是同一个`config`。因此,加上`@lazy_inline`装饰器后,这些`Block`实例都可以复用同一个网络结构,并且在大部分编译阶段不会进行inline,从而大幅减少编译时间。\n", "\n", "#### 使用步骤\n", "\n", - "如上面的例子,在网络脚本中,往需要延迟inline和复用子图结构的Cell类的`__init__`函数加上`@lazy_inline`装饰器。\n", + "如上面的例子,在网络脚本中,需要延迟inline和复用子图结构的Cell类,其`__init__`函数需加上`@lazy_inline`装饰器。\n", "\n", "#### 使用限制\n", "\n", - "1. Cell 是以Cell的类名和`__init__`参数值生成Cell实例标识的,这是基于`__init__`的参数确定Cell 的所有属性,以及`construct`构图开始时的Cell属性和`__init__`执行完的属性一致为假设前提,因此Cell与构图有关的属性,在`__init__`执行完后不能进行更改。例如:\n", + "1. Cell以类名和`__init__`参数值生成Cell实例标识。假设`__init__`参数确定Cell 的所有属性,并且`construct`构图开始时Cell属性和`__init__`执行完后属性一致。因此,Cell与构图有关的属性,在`__init__`执行完后不能进行更改。例如:\n", "\n", " ```python\n", " from mindspore import nn\n", @@ -195,7 +195,7 @@ " ...\n", " ```\n", "\n", - "如上代码所示,网络Model中的某个`Block`实例,它的属性`x`在该实例初始化后被修改了,那么这个`Block`实例就无法准确复用同一个子图结构了。" + "如上代码所示,若网络Model中某个`Block`实例的属性`x`在初始化后被修改,则该`Block`实例无法准确复用同一个子图结构。" ] }, { @@ -203,7 +203,7 @@ "id": "00c363fd", "metadata": {}, "source": [ - "2. 一个Cell类的网络结构包含多个Cell_X类的实例,同时每个Cell_X类的网络结构又包含多个Cell_Y的实例的场景,如果往Cell_X和Cell_Y类的`__init__`函数上都加上`@lazy_inline`,那么只有最外层的Cell_X实例的网络结构被编译成可复用的计算图且被延迟inline,内层的Cell_Y实例的计算图还是会被inline。例如:\n", + "2. 一个Cell类的网络结构包含多个Cell_X类实例,同时每个Cell_X类的网络结构又包含多个Cell_Y实例,如果同时在Cell_X和Cell_Y类的`__init__`函数上加上`@lazy_inline`,那么只有最外层的Cell_X实例的网络结构会被编译成可复用的计算图并延迟inline,内层的Cell_Y实例的计算图还是会被inline。例如:\n", "\n", " ```python\n", " from mindspore import nn\n", @@ -240,7 +240,7 @@ " ...\n", " ```\n", "\n", - "后续有计划支持这种多层级的Lazy Inline机制。" + "后续计划支持多层级的Lazy Inline机制。" ] }, { @@ -252,7 +252,7 @@ "\n", "使用场景:使用HyperMap替换for循环来优化编译性能。\n", "\n", - "`HyperMap`是一个特殊的类,类对象构造时需要传入映射函数f,调用对象时需要传入f的n个参数序列,更多使用方法见:[HyperMap](https://www.mindspore.cn/docs/zh-CN/master/api_python/ops/mindspore.ops.HyperMap.html)。映射函数f必须是`MultitypeFuncGraph`类型, 可参考[MultitypeFuncGraph](https://www.mindspore.cn/docs/zh-CN/master/api_python/ops/mindspore.ops.MultitypeFuncGraph.html)。在使用for循环批量处理列表元素时,可以通过`HyperMap`等价语义替换来优化网络编译性能。" + "`HyperMap`是一个特殊的类,构造对象时需要传入映射函数f,调用对象时需要传入f的n个参数序列。更多使用方法见:[HyperMap](https://www.mindspore.cn/docs/zh-CN/master/api_python/ops/mindspore.ops.HyperMap.html)。映射函数f必须是`MultitypeFuncGraph`类型, 可参考[MultitypeFuncGraph](https://www.mindspore.cn/docs/zh-CN/master/api_python/ops/mindspore.ops.MultitypeFuncGraph.html)。在使用for循环批量处理列表元素时,可以通过`HyperMap`等价替换来优化网络编译性能。" ] }, { @@ -262,15 +262,15 @@ "source": [ "### 使用编译缓存\n", "\n", - "使用场景:在进行训练或者推理时,如果编译依赖的文件未作任何变更,通过使用编译缓存来缩短编译时间。\n", + "使用场景:在训练或推理时,如果编译依赖文件未发生变更,可以通过编译缓存来缩短编译时间。\n", "\n", - "编译缓存的本质是存储了网络模型的编译中间过程文件,当网络模型不变时,生产的编译中间过程文件也是一样的,因此可以复用上一次编程产生的中间过程文件。\n", + "编译缓存本质上是存储网络模型的编译中间过程文件。当网络模型不变时,生产的编译中间过程文件也是一样的,因此可以复用上一次生成的中间过程文件。\n", "\n", "通过设置环境变量[MS_COMPILER_CACHE_ENABLE](https://www.mindspore.cn/docs/zh-CN/master/api_python/env_var_list.html?highlight=MS_COMPILER_CACHE_ENABLE),可以指定是否保存和加载编译缓存。\n", "\n", "通过设置环境变量[MS_COMPILER_CACHE_PATH](https://www.mindspore.cn/docs/zh-CN/master/api_python/env_var_list.html?highlight=MS_COMPILER_CACHE_PATH),可以指定MindSpore编译缓存目录,用于存储图和算子编译过程生成的缓存文件。\n", "\n", - "一个通过使能编译缓存来优化编译性能的代码样例如下:" + "以下为通过使能编译缓存来优化编译性能的代码示例:" ] }, { @@ -314,7 +314,7 @@ "id": "8e66fb52", "metadata": {}, "source": [ - "上述测试样例是关闭编译缓存状态,执行上述测试样例2次,第1次耗时和第2次耗时如下(实际耗时与硬件环境有关,以下数据仅供参考):\n", + "上述测试样例为关闭编译缓存状态,执行两次后的耗时如下(实际耗时与硬件环境有关,以下数据仅供参考):\n", "\n", "```text\n", "Disable compile_cache cost time: 0.5485098361968994\n", @@ -373,7 +373,7 @@ "id": "0a76213d", "metadata": {}, "source": [ - "上述测试样例是开启编译缓存状态,执行上述测试样例2次,第1次耗时和第2次耗时如下(实际耗时与硬件环境有关,以下数据仅供参考):\n", + "上述测试样例为开启编译缓存状态,执行两次后的耗时如下(实际耗时与硬件环境有关,以下数据仅供参考):\n", "\n", "```text\n", "Enable compile_cache cost time: 0.6357541084289551\n", @@ -382,7 +382,7 @@ "\n", "可以看到,开启编译缓存时,第2次执行样例耗时只有第一次执行耗时的1/7左右。\n", "\n", - "说明:打开编译缓存功能时,第一次执行由于暂未生成缓存,所以会有 Warning:" + "说明:开启编译缓存功能时,第一次执行由于暂未生成缓存,所以会有如下Warning:" ] }, { @@ -772,13 +772,13 @@ "source": [ "### 使用select算子\n", "\n", - "使用场景:`Select`算子来替代if控制流语句,减少静态图子图生成,提高执行性能(也可以提高编译性能)。\n", + "使用场景:使用`Select`算子替代if控制流语句,减少静态图子图生成,提高执行性能(也可以提高编译性能)。\n", "\n", - "编写网络时,会经常使用到if语句,如果if语句的条件是变量条件,每个if语句都会产生额外的子图。在静态图模式下,子图数量越多,编译耗时越久,因此部分场景可以通过`Select`算子等价替换if语句来优化编译性能。\n", + "编写网络时,经常会用到if语句。如果if语句的条件为变量,每个if语句都会产生额外子图。在静态图模式下,子图数量越多,编译耗时越久,因此部分场景可以通过`Select`算子等价替换if语句来优化编译性能。\n", "\n", - "需要注意的是,使用`Select`算子替换if语句会影响网络的运行性能。一方面,`Select`算子会同时执行true分支和false分支,而if语句只执行其一个分支,因此使用if运行耗时相比使用`Select`算子耗时减少;另一方面,`Select`算子性能优于if语句产生的控制流算子,使用if运行耗时相比使用`Select`算子运行耗时增加。综合上述两种因素,最终运行性能变化情况需要结合实际情况判断。一般来讲,当分支中算子数量较少,建议使用`Select`算子;当分支中算子数量较多,建议使用if语句。\n", + "需要注意的是,使用`Select`算子替换if语句会影响网络的运行性能。一方面,`Select`算子会同时执行true分支和false分支,而if语句只执行其一个分支,因此使用if运行耗时较少;另一方面,`Select`算子性能优于if语句产生的控制流算子,使用if运行耗时反而可能增加。综合上述两种因素,最终运行性能变化情况需要结合实际情况判断。一般来讲,当分支中算子数量较少,建议使用`Select`算子;当分支中算子数量较多,建议使用if语句。\n", "\n", - "一个使用`Select`算子替代if语句来优化编译性能的代码样例如下:" + "以下为使用`Select`算子替代if语句来优化编译性能的代码示例:" ] }, { @@ -841,9 +841,9 @@ "\n", "使用场景:在处理无依赖关系的批量数据且相关的算子支持Vmap功能时,可以使用Vmap替代for循环处理批量数据来优化执行性能(也可以提高编译性能)。\n", "\n", - "MindSpore已支持Vmap特性。\n", + "MindSpore已支持Vmap功能。\n", "\n", - "一个使用Vmap替换for循环处理批量数据来优化编译性能的代码样例如下:\n", + "以下为使用Vmap替换for循环处理批量数据来优化编译性能的代码示例:\n", "\n", "代码的运行结果如下(实际耗时与硬件环境有关,以下数据仅供参考):" ] @@ -901,15 +901,15 @@ "id": "6ded0e87", "metadata": {}, "source": [ - "上述样例中,相当于需要批量处理100组Tensor数据,可以看到使用Vmap处理的性能超过使用for循环处理性能的30倍。\n", + "上述样例中,相当于需要批量处理100组Tensor数据。可以看到,使用Vmap处理的性能超过使用for循环处理性能的30倍。\n", "\n", "## 依赖控制保证执行序\n", "\n", - "如果函数的运行结果依赖或影响外部状态,则认为该函数具有副作用,比如函数会改变外部全局变量、函数的结果依赖全局变量的值。如果算子会改变输入参数的值或者算子的输出依赖全局参数的值,则认为这是带副作用的算子。\n", + "如果函数的运行结果依赖或影响外部状态,则认为该函数具有副作用,比如函数会改变外部全局变量、函数的结果依赖全局变量的值。如果算子会改变输入参数的值,或者算子的输出依赖全局参数的值,则认为这是带副作用的算子。\n", "\n", "根据内存属性和IO状态,将副作用划分为内存副作用和IO副作用。当前内存副作用主要有Assign、优化器算子等等,IO副作用主要有Print算子。详细可以查看算子定义,内存副作用算子在定义中有side_effect_mem属性,IO副作用算子在定义中有side_effect_io属性。\n", "\n", - "Depend用于处理依赖项操作。在大多数情况下,如果操作符有IO副作用或内存副作用,则将根据用户的语义执行它们,不需要另外使用Depend算子来保证执行顺序。在某些情况下,如果两个运算符A和B没有顺序依赖关系,并且A必须在B之前执行,我们建议使用Depend指定它们的执行顺序。使用方法如下:" + "Depend用于处理依赖项操作。在大多数情况下,如果操作符有IO副作用或内存副作用,则将根据用户的语义执行,不需要另外使用Depend算子来保证执行顺序。在某些情况下,如果两个运算符A和B没有顺序依赖关系,但A必须在B之前执行,建议使用Depend指定执行顺序。使用方法如下:" ] }, { @@ -948,7 +948,7 @@ "id": "ec290f5b", "metadata": {}, "source": [ - "值得说明的是,用于浮点数溢出状态检测的一组特殊算子它们存在隐含副作用,但又不属于IO副作用或内存副作用。此外,使用时还有严格的顺序要求,即:在使用NPUClearFloatStatus算子前需要保证NPUAllocFloatStatus已经执行,使用NPUGetFloatStatus算子前需要保证NPUClearFloatStatus已经执行。因为这些算子使用较少,目前的方案是保持它们的定义为无副作用形式,以Depend确保执行顺序。注意:此类浮点数溢出状态检测的算子仅在Ascend平台支持。如下:" + "值得说明的是,用于浮点数溢出状态检测的一组特殊算子存在隐含副作用,但又不属于IO副作用或内存副作用。此外,使用时还有严格的顺序要求:在使用NPUClearFloatStatus算子前需要保证NPUAllocFloatStatus已经执行,使用NPUGetFloatStatus算子前需要保证NPUClearFloatStatus已经执行。由于这些算子使用较少,目前的方案是将其定义为无副作用形式,以Depend确保执行顺序。注意:此类浮点数溢出状态检测的算子仅在Ascend平台支持。如下:" ] }, { @@ -1004,18 +1004,18 @@ "source": [ "## 优化冗余显存拷贝操作\n", "\n", - "在函数式编程中,通过参数和返回值之外的渠道和外界存在数据交换的函数,被称为非纯函数,被认为是存在副作用的。在MindSpore框架内部,针对副作用的问题会插入Load算子,该算子属于虚拟算子,不需要在后端执行,不占用显存,仅用于表示需要读取全局变量的值。在图模式下,需要编译完整个图之后才将图中的各个算子下发到后端执行,使用Load算子多次读取全局变量,而不是多次使用真实算子多次保存全局变量的值,这样可以减少显存的消耗。\n", + "在函数式编程中,通过参数和返回值之外的渠道和外界进行数据交换的函数,被称为非纯函数,被认为是存在副作用的。在MindSpore框架内部,针对副作用的问题会插入Load算子,该算子属于虚拟算子,不需要在后端执行,不占用显存,仅用于表示需要读取全局变量的值。在图模式下,需要编译完整个图之后才将图中的各个算子下发到后端执行。使用Load算子多次读取全局变量,而不是多次使用真实算子多保存全局变量的值,这样可以减少显存消耗。\n", "\n", - "但是,全局变量的值可能是变化的,如果没有真实算子保存值,某些场景下会存在精度问题。针对这种情况,MindSpore框架内部会插入真实算子,占用一定的显存来保存全局变量的值,从而避免出现精度问题。\n", + "但是,全局变量的值可能是变化的,如果没有真实算子保存值,某些场景下会出现精度问题。针对这种情况,MindSpore框架内部会插入真实算子,占用一定的显存来保存全局变量的值,从而避免精度问题。\n", "\n", - "我们提供了MS_DEV_SIDE_EFFECT_LOAD_ELIM开关来优化显存占用的程度,即设置export MS_DEV_SIDE_EFFECT_LOAD_ELIM=0/1/2/3。\n", + "MindSpore提供了MS_DEV_SIDE_EFFECT_LOAD_ELIM开关来优化显存占用程度,可以通过设置export MS_DEV_SIDE_EFFECT_LOAD_ELIM=0/1/2/3进行调整。设置规则如下:\n", "\n", - "- 当将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为0时,表示对框架内部的Load算子都插入真实算子,即占用显存最多,保证网络精度没有问题。\n", - "- 当将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为1或者没有设置值时(即默认模式),表示对框架内部的Load算子可能出现精度问题的场景保守地插入真实算子,保证网络精度没有问题。\n", - "- 当将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为2,在损耗一定编译性能的前提下,尽量少地插入真实算子,优化显存较多,且保证网络精度没有问题。\n", - "- 当将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为3,不插入真实算子,不保证网络的精度,显存消耗最少。\n", + "- 当设置为0时,表示对框架内部的Load算子都插入真实算子,显存占用最多,保证网络精度。\n", + "- 当设置为1或者没有设置值(即默认模式)时,表示仅在可能出现精度问题的场景保守地插入真实算子,保证网络精度。\n", + "- 当设置为2时,在损耗一定编译性能的前提下,尽量少地插入真实算子,优化显存占用,且保证网络精度。\n", + "- 当设置为3时,不插入真实算子,不保证网络精度,显存消耗最少。\n", "\n", - "我们可以通过用例和生成的中间表示(即IR)来进一步理解。" + "我们可以通过用例和生成的中间表示(IR)来进一步理解。" ] }, { @@ -1070,9 +1070,9 @@ "id": "60c7ca19", "metadata": {}, "source": [ - "如上用例,通过设置保存中间文件,即:export MS_DEV_SAVE_GRAPHS=1,可以得到中间文件IR,为了便于查看,我们将得到的中间文件简化如下:\n", + "如上用例,通过设置export MS_DEV_SAVE_GRAPHS=1保存中间文件,可以得到中间文件IR。为了便于查看,我们将得到的中间文件简化如下:\n", "\n", - "在未对框架内部的Load算子插入真实算子时的IR文件如下,可以看到存在3个Load算子,均是取不同时机的para2_param这个全局变量的值,而这个全局变量会通过Assign算子修改值。即3个Load取到的值是不同的。而如果我们没有对Load算子插入真实算子,即没有对不同时机下的para2_param这个全局变量的值进行保存,那么得到的最终结果是不对的。即这种情况在MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为3,内存占用最少,但结果存在精度问题。" + "在未对框架内部的Load算子插入真实算子时,IR文件如下。可以看到存在3个Load算子,分别获取para2_param全局变量在不同时间点的值,而该变量会被Assign算子修改。即3个Load获取的值是不同的。如果我们没有对Load算子插入真实算子,即未保存para2_param全局变量在不同时间点的值,则最终结果是不对的。此时MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为3,内存占用最少,但结果存在精度问题。" ] }, { @@ -1117,7 +1117,7 @@ "id": "e7378662", "metadata": {}, "source": [ - "将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为0,1,2时,可以得到简化后的IR图如下。由于该场景中的Load算子均需要插入真实算子来保存每次Assign算子修改后的值,所以MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为0,1,2得到的IR文件是一致的。更多复杂的情况下,MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为0,1,2时可能是不同的,在此不再一一展开。" + "将MS_DEV_SIDE_EFFECT_LOAD_ELIM设置为0、1或2时,可以得到简化后的IR图如下。由于该场景中的Load算子均需要插入真实算子来保存每次Assign算子修改后的值,因此设置为0、1、2时得到的IR文件是一致的。更多复杂的情况下,设置为0、1、2时可能是不同的,在此不再一一展开。" ] }, {