静态图语法支持

Linux Ascend GPU CPU 模型开发 初级 中级 高级

查看源文件

概述

在Graph模式下,Python代码并不是由Python解释器去执行,而是将代码编译成静态计算图,然后执行静态计算图。

当前仅支持编译@ms_function装饰器修饰的函数、Cell及其子类的实例。 对于函数,则编译函数定义;对于网络,则编译construct方法及其调用的其他方法或者函数。

ms_function使用规则可参考文档:https://www.mindspore.cn/docs/api/zh-CN/r1.3/api_python/mindspore.html#mindspore.ms_function

Cell定义可参考文档:https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.3/cell.html

由于语法解析的限制,当前在编译构图时,支持的数据类型、语法以及相关操作并没有完全与Python语法保持一致,部分使用受限。

本文主要介绍,在编译静态图时,支持的数据类型、语法以及相关操作,这些规则仅适用于Graph模式。

以下所有示例都运行在Graph模式下的网络中,为了简洁,并未将网络的定义都写出来。

Tensor不支持在静态图里直接构造,可通过参数传入网络construct方法,或者作为网络属性在__init__方法构造,然后在construct方法使用。

数据类型

Python内置数据类型

当前支持的Python内置数据类型包括:NumberStringListTupleDictionary

Number

支持intfloatbool,不支持complex(复数)。

支持在网络里定义Number,即支持语法:y = 1y = 1.2y = True

不支持在网络里强转Number,即不支持语法:y = int(x)y = float(x)y = bool(x)

String

支持在网络里构造String,即支持语法y = "abcd"

不支持在网络里强转String,即不支持语法 y = str(x)

List

支持在网络里构造List,即支持语法y = [1, 2, 3]

不支持在网络里强转List,即不支持语法y = list(x)

计算图中最终需要输出的List会转换为Tuple输出。

  • 支持接口

    append: 向list里追加元素。

    示例如下:

    x = [1, 2, 3]
    x.append(4)
    

    结果如下:

    x: (1, 2, 3, 4)
    
  • 支持索引取值和赋值

    支持单层和多层索引取值以及赋值。

    取值和赋值的索引值仅支持int

    赋值时,所赋的值支持NumberStringTupleListTensor

    示例如下:

    x = [[1, 2], 2, 3, 4]
    
    m = x[0][1]
    x[1] = Tensor(np.array([1, 2, 3]))
    x[2] = "ok"
    x[3] = (1, 2, 3)
    x[0][1] = 88
    n = x[-3]
    

    结果如下:

    m: 2
    x: ([1, 88], Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]), 'ok', (1, 2, 3))
    n: Tensor(shape=[3], dtype=Int64, value=[1, 2, 3])
    

Tuple

支持在网络里构造Tuple,即支持语法y = (1, 2, 3)

不支持在网络里强转Tuple,即不支持语法y = tuple(x)

  • 支持索引取值

    索引值支持intsliceTensor,也支持多层索引取值,即支持语法data = tuple_x[index0][index1]...

    索引值为Tensor有如下限制:

    • tuple里存放的都是Cell,每个Cell要在tuple定义之前完成定义,每个Cell的入参个数、入参类型和入参shape要求一致,每个Cell的输出个数、输出类型和输出shape也要求一致。

    • 索引Tensor是一个dtypeint32的标量Tensor,取值范围在[-tuple_len, tuple_len)Ascend后端不支持负数索引。

    • 该语法不支持ifwhilefor控制流条件为变量的运行分支,仅支持控制流条件为常量。

    • 支持GPUAscend后端。

    intslice索引示例如下:

    x = (1, (2, 3, 4), 3, 4, Tensor(np.array([1, 2, 3])))
    y = x[1][1]
    z = x[4]
    m = x[1:4]
    n = x[-4]
    

    结果如下:

    y: 3
    z: Tensor(shape=[3], dtype=Int64, value=[1, 2, 3])
    m: ((2, 3, 4), 3, 4)
    n: (2, 3, 4)
    

    Tensor索引示例如下:

    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
            self.relu = nn.ReLU()
            self.softmax = nn.Softmax()
            self.layers = (self.relu, self.softmax)
    
        def construct(self, x, index):
            ret = self.layers[index](x)
            return ret
    

Dictionary

支持在网络里构造Dictionary,即支持语法y = {"a": 1, "b": 2},当前仅支持String作为key值。

计算图中最终需要输出的Dictionary,会取出所有的value组成Tuple输出。

  • 支持接口

    keys:取出dict里所有的key值,组成Tuple返回。

    values:取出dict里所有的value值,组成Tuple返回。

    示例如下:

    x = {"a": Tensor(np.array([1, 2, 3])), "b": Tensor(np.array([4, 5, 6])), "c": Tensor(np.array([7, 8, 9]))}
    y = x.keys()
    z = x.values()
    

    结果如下:

    y: ("a", "b", "c")
    z: (Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]), Tensor(shape=[3], dtype=Int64, value=[4, 5, 6]), Tensor(shape=[3], dtype=Int64, value=[7, 8, 9]))
    
  • 支持索引取值和赋值

    取值和赋值的索引值都仅支持String。赋值时,所赋的值支持NumberTupleTensor

    示例如下:

    x = {"a": Tensor(np.array([1, 2, 3])), "b": Tensor(np.array([4, 5, 6])), "c": Tensor(np.array([7, 8, 9]))}
    y = x["b"]
    x["a"] = (2, 3, 4)
    

    结果如下:

    y: Tensor(shape=[3], dtype=Int64, value=[4, 5, 6])
    x: {"a": (2, 3, 4), Tensor(shape=[3], dtype=Int64, value=[4, 5, 6]), Tensor(shape=[3], dtype=Int64, value=[7, 8, 9])}
    

MindSpore自定义数据类型

当前MindSpore自定义数据类型包括:TensorPrimitiveCell

Tensor

当前不支持在网络里构造Tensor,即不支持语法x = Tensor(args...)

可以通过@constexpr装饰器修饰函数,在函数里生成Tensor

关于@constexpr的用法可参考:https://www.mindspore.cn/docs/api/zh-CN/r1.3/api_python/ops/mindspore.ops.constexpr.html

对于网络中需要用到的常量Tensor,可以作为网络的属性,在init的时候定义,即self.x = Tensor(args...),然后在construct里使用。

如下示例,通过@constexpr生成一个shape = (3, 4), dtype = int64Tensor

@constexpr
def generate_tensor():
    return Tensor(np.ones((3, 4)))

下面将介绍下Tensor支持的属性和接口。

  • 支持属性:

    shape:获取Tensor的shape,返回一个Tuple

    dtype:获取Tensor的数据类型,返回一个MindSpore定义的数据类型。

  • 支持接口:

    all:对Tensor通过all操作进行归约,仅支持Bool类型的Tensor

    any:对Tensor通过any操作进行归约,仅支持Bool类型的Tensor

    view:将Tensorreshape成输入的shape

    expand_as:将Tensor按照广播规则扩展成与另一个Tensor相同的shape

    示例如下:

    x = Tensor(np.array([[True, False, True], [False, True, False]]))
    x_shape = x.shape
    x_dtype = x.dtype
    x_all = x.all()
    x_any = x.any()
    x_view = x.view((1, 6))
    
    y = Tensor(np.ones((2, 3), np.float32))
    z = Tensor(np.ones((2, 2, 3)))
    y_as_z = y.expand_as(z)
    

    结果如下:

    x_shape: (2, 3)
    x_dtype: Bool
    x_all: Tensor(shape=[], dtype=Bool, value=False)
    x_any: Tensor(shape=[], dtype=Bool, value=True)
    x_view: Tensor(shape=[1, 6], dtype=Bool, value=[[True, False, True, False, True, False]])
    
    y_as_z: Tensor(shape=[2, 2, 3], dtype=Float32, value=[[[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]])
    

Primitive

当前支持在网络里构造Primitive及其子类的实例,即支持语法reduce_sum = ReduceSum(True)

但在构造时,参数只能通过位置参数方式传入,不支持通过键值对方式传入,即不支持语法reduce_sum = ReduceSum(keep_dims=True)

当前不支持在网络调用Primitive及其子类相关属性和接口。

Primitive定义可参考文档:https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.3/operators.html

当前已定义的Primitive可参考文档:https://www.mindspore.cn/docs/api/zh-CN/r1.3/api_python/mindspore.ops.html

Cell

当前支持在网络里构造Cell及其子类的实例,即支持语法cell = Cell(args...)

但在构造时,参数只能通过位置参数方式传入,不支持通过键值对方式传入,即不支持在语法cell = Cell(arg_name=value)

当前不支持在网络调用Cell及其子类相关属性和接口,除非是在Cell自己的contrcut中通过self调用。

Cell定义可参考文档:https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.3/cell.html

当前已定义的Cell可参考文档:https://www.mindspore.cn/docs/api/zh-CN/r1.3/api_python/mindspore.nn.html

运算符

算术运算符和赋值运算符支持NumberTensor运算,也支持不同dtypeTensor运算。

之所以支持,是因为这些运算符会转换成同名算子进行运算,这些算子支持了隐式类型转换。

规则可参考文档:https://www.mindspore.cn/docs/note/zh-CN/r1.3/operator_list_implicit.html

算术运算符

算术运算符

支持类型

+

Number + NumberTensor + TensorTensor + NumberTuple + TupleString + StringList + List

-

Number - NumberTensor - TensorTensor - Number

*

Number * NumberTensor * TensorTensor * Number

/

Number / NumberTensor / TensorTensor / Number

%

Number % NumberTensor % TensorTensor % Number

**

Number ** NumberTensor ** TensorTensor ** Number

//

Number // NumberTensor // TensorTensor // Number

~

~Tensor[Bool]

赋值运算符

赋值运算符

支持类型

=

标量、Tensor

+=

Number += NumberTensor += TensorTensor += NumberTuple += TupleString += String

-=

Number -= NumberTensor -= TensorTensor -= Number

*=

Number *= NumberTensor *= TensorTensor *= Number

/=

Number /= NumberTensor /= TensorTensor /= Number

%=

Number %= NumberTensor %= TensorTensor %= Number

**=

Number **= NumberTensor **= TensorTensor **= Number

//=

Number //= NumberTensor //= TensorTensor //= Number

逻辑运算符

逻辑运算符

支持类型

and

Number and NumberTensor and Tensor

or

Number or NumberTensor orTensor

not

not Number、not Tensor、not tuple

成员运算符

成员运算符

支持类型

in

Number in tupleString in tupleTensor in TupleNumber in ListString in ListTensor in ListString in Dictionary

not in

in相同。

身份运算符

身份运算符

支持类型

is

仅支持判断是NoneTrue或者False

is not

仅支持判断不是NoneTrue或者False

表达式

条件控制语句

单if

使用方式:

  • if (cond): statements...

  • x = y if (cond) else z

参数:cond – 支持类型NumberTupleListStringNoneTensorFunction,也可以是计算结果类型是其中之一的表达式。

限制:

  • 在构图时,如果if未能消除,则if分支return的数据类型和shape,与if分支外return的数据类型和shape必须一致。

  • 当只有if时,if分支变量更新后数据类型和shape,与更新前数据类型和shape必须一致。

  • 当即有if又有else时,if分支变量更新后数据类型和shape,与else分支更新后数据类型和shape必须一致。

  • 不支持高阶微分场景。

  • 不支持elif语句。

示例1:

if x > y:
  return m
else:
  return n

if分支返回的melse分支返回的n,二者数据类型和shape必须一致。

示例2:

if x > y:
  out = m
else:
  out = n
return out

if分支更新后outelse分支更新后out,二者数据类型和shape必须一致。

并列if

使用方式:

  • if (cond1):statements else:statements...if (cond2):statements...

参数:cond1cond2– 与单if一致。

限制:

  • 继承单if所有限制。

  • 计算图总if数量不超过50个。

  • if数量过多会导致编译时间过长,减少if数量有助于提升编译效率。

示例:

if x > y:
  out = x
else:
  out = y
if z > x:
  out = out + 1
return out

嵌套if

使用方式:

  • if (cond1):if (cond2):statements...

参数:cond1cond2– 与单if一致。

限制:

  • 继承单if所有限制。

  • 计算图if数量不超过50个。

  • if数量过多会导致编译时间过长,减少if数量有助于提升编译效率。

示例:

if x > y:
  z = z + 1
  if z > x:
    return m
else:
  return n

循环语句

for

使用方式:

  • for i in sequence

参数:sequence – 遍历序列(TupleList)

限制:

  • 图的算子数量和for循环的迭代次数成倍数关系,for循环迭代次数过大可能会导致图占用内存超过使用限制。

示例:

z = Tensor(np.ones((2, 3)))
x = (1, 2, 3)
for i in x:
  z += i
return z

结果如下:

z: Tensor(shape=[2, 3], dtype=Int64, value=[[7, 7], [7, 7], [7, 7]])

单while

使用方式:

  • while (cond)

参数:cond – 与单if一致。

限制:

  • 在构图时,如果while未能消除,则whilereturn的数据类型和shape,与whilereturn的数据类型和shape必须一致。

  • while内变量更新后数据类型和shape,与更新前数据类型和shape必须一致。

  • 不支持训练场景。

示例1:

while x < y:
  x += 1
  return m
return n

while内返回的mwhile外返回的n数据类型必须和shape一致。

示例2:

out = m
while x < y:
  x += 1
  out = out + 1
return out

while内,out更新后和更新前的数据类型和shape必须一致。

并列while

使用方式:

  • while (cond1):statements while (cond2):statemetns...

参数:cond1cond2– 与单if一致。

限制:

  • 继承单while所有限制。

  • 并列while总数不超过50个。

  • while数量过多会导致编译时间过长,减少while数量有助于提升编译效率。

示例:

out = m
while x < y:
  x += 1
  out = out + 1
while out > 10:
  out -= 10
return out

嵌套while

使用方式:

  • while (cond1):while (cond2):statements...

参数:cond1cond2– 与单if一致。

限制:

  • 继承单while所有限制。

  • 嵌套while总数不超过50个。

  • while数量过多会导致编译时间过长,减少while数量有助于提升编译效率。

示例:

out = m
while x < y:
  while z < y:
    z += 1
    out = out + 1
  x += 1
return out

循环嵌套条件控制语句

if in for

使用方式:

  • for i in sequence:if (cond)

参数:

cond – 与单if一致。

sequence – 遍历序列(TupleList)

限制:

  • 继承单if所有限制。

  • 继承for所有限制。

  • cond为变量时,不能有if (cond):returnif (cond):continueif (cond):break语句。

  • if数量和for循环的迭代次数成倍数关系,for循环迭代次数过大可能会导致编译时间过长。

示例如下:

z = Tensor(np.ones((2, 3)))
x = (1, 2, 3)
for i in x:
  if i < 3:
    z += i
return z

结果如下:

z: Tensor(shape=[2, 3], dtype=Int64, value=[[4, 4], [4, 4], [4, 4]])

if in while

使用方式:

  • while (cond1):if (cond2)

参数:cond1cond2– 与单if一致。

限制:

  • 继承单if单while所有限制。

  • cond2为变量时,不能有if (cond2):returnif (cond2):continueif (cond2):break语句。

示例:

out = m
while x < y:
  if z > 2*x:
    out = out + 1
  x += 1
return out

函数定义语句

def关键字

用于定义函数。

使用方式:

def function_name(args): statements...

示例如下:

def number_add(x, y):
  return x + y
ret = number_add(1, 2)

结果如下:

ret: 3

lambda表达式

用于生成函数。

使用方式:lambda x, y: x + y

示例如下:

number_add = lambda x, y: x + y
ret = number_add(2, 3)

结果如下:

ret: 5

函数

Python内置函数

当前支持的Python内置函数包括:lenisinstancepartialmaprangeenumeratesuperpow

len

功能:求序列的长度。

调用:len(sequence)

入参:sequenceTupleListDictionary或者Tensor

返回值:序列的长度,类型为int。当入参是Tensor时,返回的是Tensor第0维的长度。

示例如下:

x = (2, 3, 4)
y = [2, 3, 4]
d = {"a": 2, "b": 3}
z = Tensor(np.ones((6, 4, 5)))
x_len = len(x)
y_len = len(y)
d_len = len(d)
z_len = len(z)

结果如下:

x_len: 3
y_len: 3
d_len: 2
z_len: 6

isinstance

功能:判断对象是否为类的实例。区别于算子Isinstance,该算子的第二个入参是MindSpore的dtype模块下定义的类型。

调用:isinstance(obj, type)

入参:

  • obj – MindSpore支持类型的一个实例。

  • typeboolintfloatstrlisttupledictTensorParameter,或者是一个只包含这些类型的tuple

返回值:objtype的实例,返回True,否则返回False

示例如下:

x = (2, 3, 4)
y = [2, 3, 4]
z = Tensor(np.ones((6, 4, 5)))
x_is_tuple = isinstance(x, tuple)
y_is_list= isinstance(y, list)
z_is_tensor = isinstance(z, Tensor)

结果如下:

x_is_tuple: True
y_is_list: True
z_is_tensor: True

partial

功能:偏函数,固定函数入参。

调用:partial(func, arg, ...)

入参:

  • func – 函数。

  • arg – 一个或多个要固定的参数,支持位置参数和键值对传参。

返回值:返回某些入参固定了值的函数。

示例如下:

def add(x, y):
  return x + y

add_ = partial(add, x=2)
m = add_(y=3)
n = add_(y=5)

结果如下:

m: 5
n: 7

map

功能:根据提供的函数对一个或者多个序列做映射,由映射的结果生成一个新的序列。 如果多个序列中的元素个数不一致,则生成的新序列与最短的那个长度相同。

调用:map(func, sequence, ...)

入参:

  • func – 函数。

  • sequence – 一个或多个序列(Tuple或者List)。

返回值:返回一个Tuple

示例如下:

def add(x, y):
  return x + y

elements_a = (1, 2, 3)
elements_b = (4, 5, 6)
ret = map(add, elements_a, elements_b)

结果如下:

ret: (5, 7, 9)

zip

功能:将多个序列中对应位置的元素打包成一个个元组,然后由这些元组组成一个新序列, 如果各个序列中的元素个数不一致,则生成的新序列与最短的那个长度相同。

调用:zip(sequence, ...)

入参:sequence – 一个或多个序列(TupleList)`。

返回值:返回一个Tuple

示例如下:

elements_a = (1, 2, 3)
elements_b = (4, 5, 6)
ret = zip(elements_a, elements_b)

结果如下:

ret: ((1, 4), (2, 5), (3, 6))

range

功能:根据起始值、结束值和步长创建一个Tuple

调用:

  • range(start, stop, step)

  • range(start, stop)

  • range(stop)

入参:

  • start – 计数起始值,类型为int,默认为0。

  • stop – 计数结束值,但不包括在内,类型为int

  • step – 步长,类型为int,默认为1。

返回值:返回一个Tuple

示例如下:

x = range(0, 6, 2)
y = range(0, 5)
z = range(3)

结果如下:

x: (0, 2, 4)
y: (0, 1, 2, 3, 4)
z: (0, 1, 2)

enumerate

功能:生成一个序列的索引序列,索引序列包含数据和对应下标。

调用:

  • enumerate(sequence, start)

  • enumerate(sequence)

入参:

  • sequence – 一个序列(TupleListTensor)。

  • start – 下标起始位置,类型为int,默认为0。

返回值:返回一个Tuple

示例如下:

x = (100, 200, 300, 400)
y = Tensor(np.array([[1, 2], [3, 4], [5 ,6]]))
m = enumerate(x, 3)
n = enumerate(y)

结果如下:

m: ((3, 100), (4, 200), (5, 300), (5, 400))
n: ((0, Tensor(shape=[2], dtype=Int64, value=[1, 2])), (1, Tensor(shape=[2], dtype=Int64, value=[3, 4])), (2, Tensor(shape=[2], dtype=Int64, value=[5, 6])))

super

功能:用于调用父类(超类)的一个方法,一般在super之后调用父类的方法。

调用:

  • super().xxx()

  • super(type, self).xxx()

入参:

  • type – 类。

  • self – 对象。

返回值:返回父类的方法。

示例如下:

class FatherNet(nn.Cell):
  def __init__(self, x):
      super(FatherNet, self).__init__(x)
      self.x = x

  def construct(self, x, y):
      return self.x * x

  def test_father(self, x):
      return self.x + x

class SingleSubNet(FatherNet):
def __init__(self, x, z):
    super(SingleSubNet, self).__init__(x)
    self.z = z

def construct(self, x, y):
    ret_father_construct = super().construct(x, y)
    ret_father_test = super(SingleSubNet, self).test_father(x)
    return ret_father_construct, ret_father_test

pow

功能:求幂。

调用:pow(x, y)

入参:

  • x – 底数, NumberTensor

  • y – 幂指数, NumberTensor

返回值:返回xy次幂,NumberTensor

示例如下:

x = Tensor(np.array([1, 2, 3]))
y = Tensor(np.array([1, 2, 3]))
ret = pow(x, y)

结果如下:

ret: Tensor(shape=[3], dtype=Int64, value=[1, 4, 27]))

print

功能:用于打印。

调用:print(arg, ...)

入参:arg – 要打印的信息(intfloatboolStringTensor)。 当打印的数据是intfloat或者bool时,会将其包成一个0-D的tensor打印出来。

返回值:无返回值。

示例如下:

x = Tensor(np.array([1, 2, 3]))
y = 3
print("x", x)
print("y", y)

结果如下:

x Tensor(shape=[3], dtype=Int64, value=[1, 2, 3]))
y Tensor(shape=[], dtype=Int64, value=3))

函数参数

  • 参数默认值:目前不支持默认值设为Tensor类型数据,支持intfloatboolNonestrtuplelistdict类型数据。

  • 可变参数:支持带可变参数网络的推理和训练。

  • 键值对参数:目前不支持带键值对参数的函数求反向。

  • 可变键值对参数:目前不支持带可变键值对的函数求反向。

网络定义

网络入参

整网(最外层网络)入参支持boolintfloatTensormstype.number(mstype.bool_、mstype.int、mstype.float、mstype.uint),以及只包含这些类型对象的list或者tuple,和value值是这些类型的dict

在对整网入参求梯度的时候,会忽略非Tensor的入参,只计算Tensor入参的梯度,例如整网入参(x, y, z)中,xzTensory是非Tensor时,在对整网入参求梯度的时候,只会计算xz的梯度,返回(grad_x, grad_z)

如果网络里要使用其他类型,可在初始化网络的时候,传入该类型对象,作为网络属性保存起来,然后在construct里使用。 内层调用的网络入参无此限制。

示例如下:

class Net(nn.Cell):
    def __init__(self, flag):
        super(Net, self).__init__()
        self.flag = flag

    def construct(self, x, y, z):
        if self.flag == "ok":
            return x + y + z
        return x - y - z

class GradNet(nn.Cell):
    def __init__(self, net):
        super(GradNet, self).__init__()
        self.grad_all = C.GradOperation(get_all=True)
        self.forward_net = net

    def construct(self, x, y, z):
        return self.grad_all(self.forward_net)(x, y, z)

flag = "ok"
input_x = Tensor(np.ones((2, 3)).astype(np.float32))
input_y = 2
input_z = Tensor(np.ones((2, 3)).astype(np.float32) * 2)

net = Net(flag)
grad_net = GradNet(net)
ret = grad_net(input_x, input_y, input_z)

上面定义的Net网络里,在初始化时传入一个str,作为网络的属性保存起来,然后在construct里使用self.flag这个属性。

整网入参xzTensoryint数,grad_net在对整网入参(x, y, z)求梯度时,会自动忽略y的梯度,只计算xz的梯度,ret = (grad_x, grad_z)

网络实例类型

网络构造组件

类别

内容

Cell实例

mindspore/nn/*、自定义Cell

Cell实例的成员函数

Cell的construct中可以调用其他类成员函数。

dataclass实例

使用@dataclass装饰的类。

Primitive算子

mindspore/ops/operations/*

Composite算子

mindspore/ops/composite/*

constexpr生成算子

使用@constexpr生成的值计算算子。

函数

自定义Python函数、前文中列举的系统函数。

网络使用约束

  1. 不允许修改网络的非Parameter类型数据成员。

    示例如下:

    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
            self.num = 2
            self.par = Parameter(Tensor(np.ones((2, 3, 4))), name="par")
    
        def construct(self, x, y):
            return x + y
    

    上面所定义的网络里,self.num不是一个Parameter,不允许被修改,而self.par是一个Parameter,可以被修改。

  2. construct函数里,使用未定义的类成员时,不会像Python解释器那样抛出AttributeError,而是作为None处理。

    示例如下:

    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
    
        def construct(self, x):
            return x + self.y
    

    上面所定义的网络里,construct里使用了并未定义的类成员self.y,此时会将self.y作为None处理。