静态图语法支持

查看源文件

概述

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

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

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

Cell定义可参考文档:https://www.mindspore.cn/docs/zh-CN/r1.8/api_python/nn/mindspore.nn.Cell.html

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

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

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

数据类型

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"

可以通过str()的方式进行将常量转换成字符串,支持str.format() 对字符串进行格式化,但是不支持format内部参数为变量和kwargs输入场景。

例如:

from mindspore import ms_function

@ms_function()
def test_str_format():
    x = "{} is zero".format(0)
    return x

x = test_str_format()
print(x)

结果如下:

0 is zero

List

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

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

需要注意的是MindSpore的List取值由于将其转换成了ListGetItem 算子,该算子返回的始终为原List的一个拷贝,所以有时可能会和Python的List的引用表示有差异。

比如:

原生Python:

>>> a = [[1,2,3],4,5]
>>> b = a[0]
>>> b[0] = 123123
>>> a
[[123123, 2, 3], 4, 5]

MindSpore:

from mindspore import ms_function

@ms_function
def test_list():
    x = [[1,2,3],4,5]
    b = x[0]
    b[0] = 123123
    return x

x = test_list()
print('x:{}'.format(x))

结果如下:

x: ((1, 2, 3), 4, 5)
  • 支持接口

    append: 向list里追加元素。

    示例如下:

    from mindspore import ms_function
    
    @ms_function()
    def test_list():
        x = [1, 2, 3]
        x.append(4)
        return x
    
    x = test_list()
    print('x:{}'.format(x))
    

    结果如下:

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

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

    索引值仅支持intsliceslice内部数据必须为编译时能够确定的常量,即不能为计算后的Tensor。 赋值时,所赋的值支持NumberStringTupleListTensor。 当前切片赋值右值为Tensor时,需要将Tenor转换为List,在MindSpore静态图模式下这种转化目前是通过JIT Fallback实现,所以暂时不能支持变量场景。

    示例如下:

    import mindspore as ms
    from mindspore import ms_function
    import numpy as np
    
    t = ms.Tensor(np.array([1, 2, 3]))
    
    @ms_function()
    def test_index():
        x = [[1, 2], 2, 3, 4]
        m = x[0][1]
        z = x[1::2]
        x[1] = t
        x[2] = "ok"
        x[3] = (1, 2, 3)
        x[0][1] = 88
        n = x[-3]
        return m, z, x, n
    
    m, z, x, n = test_index()
    print('m:{}'.format(m))
    print('z:{}'.format(z))
    print('x:{}'.format(x))
    print('n:{}'.format(n))
    

    结果如下:

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

Tuple

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

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

关于Tuple取值的引用类型问题与List相同,请见List的相关介绍。

  • 支持索引取值

    索引值支持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索引示例如下:

    import mindspore as ms
    from mindspore import ms_function
    import numpy as np
    
    t = ms.Tensor(np.array([1, 2, 3]))
    
    @ms_function()
    def test_index():
        x = (1, (2, 3, 4), 3, 4, t)
        y = x[1][1]
        z = x[4]
        m = x[1:4]
        n = x[-4]
        return y, z, m, n
    
    y, z, m, n = test_index()
    print('y:{}'.format(y))
    print('z:{}'.format(z))
    print('m:{}'.format(m))
    print('n:{}'.format(n))
    

    结果如下:

    y:3
    z:[1 2 3]
    m:((2, 3, 4), 3, 4)
    n:(2, 3, 4)
    

    Tensor索引示例如下:

    import mindspore as ms
    from mindspore import nn
    
    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
    
    x = ms.Tensor([-1.0], ms.float32)
    
    net = Net()
    ret = net(x, 0)
    print('ret:{}'.format(ret))
    

    结果如下:

    ret:[0.]
    

Dictionary

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

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

  • 支持接口

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

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

    items:取出dict里每一对keyvalue组成的Tuple,组成Tuple返回。

    示例如下:

    import mindspore as ms
    from mindspore import ms_function
    import numpy as np
    
    x = {"a": ms.Tensor(np.array([1, 2, 3])), "b": ms.Tensor(np.array([4, 5, 6])), "c": ms.Tensor(np.array([7, 8, 9]))}
    
    @ms_function()
    def test_dict():
        y = x.keys()
        z = x.values()
        q = x.items()
        return y, z, q
    
    y, z, q = test_dict()
    print('y:{}'.format(y))
    print('z:{}'.format(z))
    print('q:{}'.format(q))
    

    结果如下:

    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]))
    q:[('a', Tensor(shape=[3], dtype=Int64, value= [1, 2, 3])), ('b', Tensor(shape=[3], dtype=Int64, value= [4, 5, 6])), ('c', Tensor(shape=[3], dtype=Int64, value= [7, 8, 9]))]
    
  • 支持索引取值和赋值

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

    示例如下:

    import mindspore as ms
    from mindspore import ms_function
    import numpy as np
    
    x = {"a": ms.Tensor(np.array([1, 2, 3])), "b": ms.Tensor(np.array([4, 5, 6])), "c": ms.Tensor(np.array([7, 8, 9]))}
    
    @ms_function()
    def test_dict():
        y = x["b"]
        x["a"] = (2, 3, 4)
        return x, y
    
    x, y = test_dict()
    print('x:{}'.format(x))
    print('y:{}'.format(y))
    

    结果如下:

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

MindSpore自定义数据类型

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

Tensor

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

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

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

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

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

import mindspore as ms
from mindspore.ops import constexpr

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

x = generate_tensor()
print('x:{}'.format(x))

结果如下:

x:[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]]

下面将介绍下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

    示例如下:

    import mindspore as ms
    from mindspore import ms_function
    import numpy as np
    
    x = ms.Tensor(np.array([[True, False, True], [False, True, False]]))
    y = ms.Tensor(np.ones((2, 3), np.float32))
    z = ms.Tensor(np.ones((2, 2, 3)))
    
    x_shape = x.shape
    x_dtype = x.dtype
    x_all = x.all()
    x_any = x.any()
    x_view = x.view((1, 6))
    y_as_z = y.expand_as(z)
    
    print('x_shape:{}'.format(x_shape))
    print('x_dtype:{}'.format(x_dtype))
    print('x_all:{}'.format(x_all))
    print('x_any:{}'.format(x_any))
    print('x_view:{}'.format(x_view))
    print('y_as_z:{}'.format(y_as_z))
    

    结果如下:

    x_shape:(2, 3)
    x_dtype:Bool
    x_all:False
    x_any:True
    x_view:[[ True False  True False  True False]]
    y_as_z:[[[1. 1. 1.]
      [1. 1. 1.]]
    
     [[1. 1. 1.]
      [1. 1. 1.]]]
    

Primitive

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

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

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

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

Cell

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

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

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

Cell定义可参考文档:https://www.mindspore.cn/docs/zh-CN/r1.8/api_python/nn/mindspore.nn.Cell.html

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

Parameter

Parameter是变量张量,代表在训练网络时,需要被更新的参数。

Parameter的定义和使用参考:https://www.mindspore.cn/docs/zh-CN/r1.8/api_python/mindspore/mindspore.Parameter.html#mindspore.Parameter

原型

原型代表编程语言中最紧密绑定的操作。

属性引用

属性引用是后面带有一个句点加一个名称的原型。

在MindSpore的Cell 实例中使用属性引用作为左值需满足如下要求:

  • 被修改的属性属于本cell对象,即必须为self.xxx

  • 该属性在Cell的__init__函数中完成初始化且其为Parameter类型。

示例如下:

import mindspore as ms
from mindspore import ms_function, nn
import numpy as np
from mindspore.ops import constexpr

class Net(nn.Cell):
    def __init__(self):
        super().__init__()
        self.weight = ms.Parameter(ms.Tensor(3, ms.float32), name="w")
        self.m = 2

    def construct(self, x, y):
        self.weight = x  # 满足条件可以修改
        # self.m = 3  # self.m 非Parameter类型禁止修改
        # y.weight = x  # y不是self,禁止修改
        return x

net = Net()
ret = net(1, 2)
print('ret:{}'.format(ret))

结果如下:

ret:1

索引取值

对序列TupleListDictionaryTensor的索引取值操作(Python称为抽取)。

Tuple的索引取值请参考本文的Tuple章节。

List的索引取值请参考本文的List章节。

Dictionary的索引取值请参考本文的Dictionary章节。

Tensor的索引取请参考:https://www.mindspore.cn/docs/zh-CN/r1.8/note/index_support.html#索引取值

调用

所谓调用就是附带可能为空的一系列参数来执行一个可调用对象(例如:CellPrimitive)。

示例如下:

import mindspore as ms
from mindspore import nn, ops
import numpy as np

class Net(nn.Cell):
    def __init__(self):
        super().__init__()
        self.matmul = ops.MatMul()

    def construct(self, x, y):
        out = self.matmul(x, y)  # Primitive调用
        return out

x = ms.Tensor(np.ones(shape=[1, 3]), ms.float32)
y = ms.Tensor(np.ones(shape=[3, 4]), ms.float32)
net = Net()
ret = net(x, y)
print('ret:{}'.format(ret))

结果如下:

ret:[[3. 3. 3. 3.]]

运算符

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

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

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

单目算术运算符

单目算术运算符

支持类型

+

NumberTensor,取正值。

-

NumberTensor,取负值。

~

Tensor, 且其数据类型为Bool。成员逐个取反。

说明:

  • 在Python中~操作符对输入的整数按位取反; MindSpore对~的功能重新定义为对Tensor(Bool)的逻辑取反。

二元算术运算符

二元算术运算符

支持类型

+

Number + NumberString + StringNumber + TensorTensor + NumberTuple + TensorTensor + TupleList + TensorTensor+ListList+ListTensor + TensorTuple + Tuple

-

Number - NumberTensor - TensorNumber - TensorTensor - NumberTuple - TensorTensor - TupleList - TensorTensor - List

*

Number * NumberTensor * TensorNumber * TensorTensor * NumberList * NumberNumber * ListTuple * NumberNumber * TupleTuple * TensorTensor * TupleList * TensorTensor * List

/

Number / NumberTensor / TensorNumber / TensorTensor / NumberTuple / TensorTensor / TupleList / TensorTensor / List

%

Number % NumberTensor % TensorNumber % TensorTensor % NumberTuple % TensorTensor % TupleList % TensorTensor % List

**

Number ** NumberTensor ** TensorNumber ** TensorTensor ** NumberTuple ** TensorTensor ** TupleList ** TensorTensor ** List

//

Number // NumberTensor // TensorNumber // TensorTensor // NumberTuple // TensorTensor // TupleList // TensorTensor // List

限制:

  • 当左右操作数都为Number类型时,Number的值不可为Bool 类型。

  • 当左右操作数都为Number类型时,不支持Float64Int32间的运算。

  • 当任一操作数为Tensor类型时,左右操作数的值不可同时为Bool

  • List/TupleNumber进行*运算时表示将List/Tuple复制Number份后串联起来,List/Tuple内的数据类型必须为NumberStringNone或由以上类型构成的List/Tuple

赋值运算符

赋值运算符

支持类型

=

MindSpore支持的Python内置数据类型和MindSpore自定义数据类型

+=

Number += NumberString += StringNumber += TensorTensor += NumberTuple += TensorTensor += TupleList += TensorTensor += ListList += ListTensor += TensorTuple += Tuple

-=

Number -= NumberTensor -= TensorNumber -= TensorTensor -= NumberTuple -= TensorTensor -= TupleList -= TensorTensor -= List

*=

Number *= NumberTensor *= TensorNumber *= TensorTensor *= NumberList *= NumberNumber *= ListTuple *= NumberNumber *= TupleTuple *= TensorTensor *= TupleList *= TensorTensor *= List

/=

Number /= NumberTensor /= TensorNumber /= TensorTensor /= NumberTuple /= TensorTensor /= TupleList /= TensorTensor /= List

%=

Number %= NumberTensor %= TensorNumber %= TensorTensor %= NumberTuple %= TensorTensor %= TupleList %= TensorTensor %= List

**=

Number **= NumberTensor **= TensorNumber **= TensorTensor **= NumberTuple **= TensorTensor **= TupleList **= TensorTensor **= List

//=

Number //= NumberTensor //= TensorNumber //= TensorTensor //= NumberTuple //= TensorTensor //= TupleList //= TensorTensor //= List

限制:

  • 对于 =来说,不支持下列场景:

    construct函数中仅支持创建CellPrimitive类型对象,使用xx = Tensor(...)的方式创建Tensor会失败。

    construct函数中仅支持为self 的Parameter类型的属性赋值, 详情参考:属性引用

  • AugAssign的左右操作数都为Number类型时,Number的值不可为Bool 类型。

  • AugAssign的左右操作数都为Number类型时,不支持Float64Int32间的运算。

  • AugAssign的任一操作数为Tensor类型时,左右操作数的值不可同时为Bool

  • List/TupleNumber进行*=运算时表示将List/Tuple复制Number份后串联起来,List/Tuple内的数据类型必须为NumberStringNone或由以上类型构成的List/Tuple

逻辑运算符

逻辑运算符

支持类型

and

StringNumberTupleListDictNone、标量、Tensor。

or

StringNumberTupleListDictNone、标量、Tensor。

not

NumberTupleList、只有一个成员的Tensor。

限制:

  • 当and/or的左操作数是Tensor类型时,左右操作数类型必须保持一致且Tensor成员个数只能有一个。

  • 当and/or的左操作数不是Tensor类型时,右操作数可以为支持的任意类型。

比较运算符

比较运算符

支持类型

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

<

Number < NumberNumber < TensorTensor < TensorTensor < Number

<=

Number <= NumberNumber <= TensorTensor <= TensorTensor <= Number

>

Number > NumberNumber > TensorTensor > TensorTensor > Number

>=

Number >= NumberNumber >= TensorTensor >= TensorTensor >= Number

!=

Number != NumberNumber != TensorTensor != TensorTensor != Numbermstype != mstypeString != StringTuple ! = TupleList != List

==

Number == NumberNumber == TensorTensor == TensorTensor == Numbermstype == mstypeString == StringTuple == TupleList == List

限制:

  • 对于<<=>>=!=来说,当左右操作数都为Number类型时,Number的值不可为Bool 类型。

  • 对于<<=>>=!===来说,当左右操作数都为Number类型时,不支持Float64Int32间的运算。

  • 对于<<=>>=!===来说,当左右任一操作数为Tensor类型时,左右操作数的值不可同时为Bool

  • 对于==来说,当左右操作数都为Number类型时,支持左右操作数同时为Bool,不支持只有一个操作数为Bool

  • 对于!===来说除mstype外,其他取值均可和None进行比较来判空。

  • 不支持链式比较,如: a>b>c

复合语句

条件控制语句

if语句

使用方式:

  • if (cond): statements...

  • x = y if (cond) else z

参数:cond – 支持Bool类型的变量,也支持类型为NumberListTupleDictString类型的常量。

限制:

  • 如果cond不为常量,在不同分支中同一符号被赋予的变量或者常量的数据类型应一致,如果是被赋予变量或者常量数据类型是Tensor,则要求Tensor的type和shape也应一致。

  • if的使用数量不能超过100个。

示例1:

import mindspore as ms
from mindspore import ms_function

x = ms.Tensor([1, 2], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 'xx'
n = 'yy'

@ms_function()
def test_cond(x, y):
    if (x > y).any():
        return m
    else:
        return n

ret = test_cond(x, y)
print('ret:{}'.format(ret))

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

结果如下:

ret:xx

示例2:

import mindspore as ms
from mindspore import ms_function

x = ms.Tensor([1, 2], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 'xx'
n = 'yy'

@ms_function()
def test_cond(x, y):
    out = 'init'
    if (x > y).any():
        out = m
    else:
        out = n
    return out

ret = test_cond(x, y)
print('ret:{}'.format(ret))

if分支中out被赋值的变量或者常量melse分支中out被赋值的变量或者常量n的数据类型必须一致。

结果如下:

ret:xx

示例3:

import mindspore as ms
from mindspore import ms_function

x = ms.Tensor([1, 2], ms.int32)
y = ms.Tensor([0, 3], ms.int32)
m = 'xx'

@ms_function()
def test_cond(x, y):
    out = 'init'
    if (x > y).any():
        out = m
    return out

ret = test_cond(x, y)
print('ret:{}'.format(ret))

if分支中out被赋值的变量或者常量mout初始赋值的变量或者常量init的数据类型必须一致。

结果如下:

ret:xx

循环语句

for语句

使用方式:

  • for i in sequence  statements...

  • for i in sequence  statements... if (cond) break

  • for i in sequence  statements... if (cond) continue

参数:sequence – 遍历序列(TupleListrange等)

限制:

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

  • 不支持for...else...语句。

示例:

import mindspore as ms
from mindspore import ms_function
import numpy as np

z = ms.Tensor(np.ones((2, 3)))

@ms_function()
def test_cond():
    x = (1, 2, 3)
    for i in x:
        z += i
    return z

ret = test_cond()
print('ret:{}'.format(ret))

结果如下:

ret:[[7. 7. 7.]
 [7. 7. 7.]]

while语句

使用方式:

  • while (cond)  statements...

  • while (cond)  statements... if (cond1) break

  • while (cond)  statements... if (cond1) continue

参数:cond – 支持Bool类型的变量,也支持类型为NumberListTupleDictString类型的常量。

限制:

  • 如果cond不为常量,在循环体内外同一符号被赋值的变量或者常量的数据类型应一致,如果是被赋予数据类型Tensor,则要求Tensor的type和shape也应一致。

  • 不支持while...else...语句

  • 如果cond不为常量, 循环体内部不能更新循环体外的NumberListTuple类型数据, 不能更改Tensor类型数据的shape。

  • while的数量不能超过100个。

示例1:

from mindspore import ms_function

m = 1
n = 2

@ms_function()
def test_cond(x, y):
    while x < y:
        x += 1
        return m
    return n

ret = test_cond(1, 5)
print('ret:{}'.format(ret))

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

结果如下:

ret:1

示例2:

from mindspore import ms_function

m = 1
n = 2

def ops1(a, b):
    return a + b

@ms_function()
def test_cond(x, y):
    out = m
    while x < y:
        x += 1
        out = ops1(out, x)
    return out

ret = test_cond(1, 5)
print('ret:{}'.format(ret))

while内,out在循环体内被赋值的变量op1的输出类型和初始类型m必须一致。

结果如下:

ret:15

函数定义语句

def关键字

用于定义函数。

使用方式:

def function_name(args): statements...

示例如下:

from mindspore import ms_function

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

@ms_function()
def test(x, y):
    return number_add(x, y)

ret = test(1, 5)
print('ret:{}'.format(ret))

结果如下:

ret: 6

限制:

  • 函数必须有返回语句。

  • 最外层网络模型的construct函数不支持kwargs,即不支持 def  construct(**kwargs):

  • 不支持变参和非变参的混合使用,即不支持 def function(x, y, *args):def function(x = 1, y = 1, **kwargs):

lambda表达式

用于生成函数。

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

示例如下:

from mindspore import ms_function

@ms_function()
def test(x, y):
    number_add = lambda x, y: x + y
    return number_add(x, y)

ret = test(1, 5)
print('ret:{}'.format(ret))

结果如下:

ret: 6

列表生成式和生成器表达式

支持列表生成式(List Comprehension)和生成器表达式(Generator Expression)。

列表生成式

用于生成列表。由于编译器会自动把List类型转换成Tuple类型,经过编译后最终输出类型为Tuple。

使用方式:参考Python语法说明。

示例如下:

from mindspore import ms_function

@ms_function()
def test(x, y):
    l = [x * x for x in range(1, 11) if x % 2 == 0]
    return l

ret = test(1, 5)
print('ret:{}'.format(ret))

结果如下:

ret:(4, 16, 36, 64, 100)

限制:

不支持多层嵌套迭代器的使用方式。

限制用法示例如下(使用了两层迭代器):

l = [y for x in ((1, 2), (3, 4), (5, 6)) for y in x]

会提示错误:

TypeError:  The `generators` supports one `comprehension` in ListComp/GeneratorExp, but got 2 comprehensions.

生成器表达式

用于生成列表,与列表生成式动作完全一致,最终的输出类型同样是Tuple。此表达式即刻产生List值,与Python解释器中列表生成式的动作有所差异。

使用方式:同列表生成式。

示例如下:

from mindspore import ms_function

@ms_function()
def test(x, y):
    l = (x * x for x in range(1, 11) if x % 2 == 0)
    return l

ret = test(1, 5)
print('ret:{}'.format(ret))

结果如下:

ret:(4, 16, 36, 64, 100)

使用限制同列表生成式。

函数

Python内置函数

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

len

功能:求序列的长度。

调用:len(sequence)

入参:sequenceTupleListDictionary或者Tensor

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

示例如下:

import mindspore as ms
from mindspore import ms_function
import numpy as np

z = ms.Tensor(np.ones((6, 4, 5)))

@ms_function()
def test():
    x = (2, 3, 4)
    y = [2, 3, 4]
    d = {"a": 2, "b": 3}
    x_len = len(x)
    y_len = len(y)
    d_len = len(d)
    z_len = len(z)
    return x_len, y_len, d_len, z_len

x_len, y_len, d_len, z_len = test()
print('x_len:{}'.format(x_len))
print('y_len:{}'.format(y_len))
print('d_len:{}'.format(d_len))
print('z_len:{}'.format(z_len))

结果如下:

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

示例如下:

import mindspore as ms
from mindspore import ms_function
import numpy as np

z = ms.Tensor(np.ones((6, 4, 5)))

@ms_function()
def test():
    x = (2, 3, 4)
    y = [2, 3, 4]
    x_is_tuple = isinstance(x, tuple)
    y_is_list = isinstance(y, list)
    z_is_tensor = isinstance(z, Tensor)
    return x_is_tuple, y_is_list, z_is_tensor

x_is_tuple, y_is_list, z_is_tensor = test()
print('x_is_tuple:{}'.format(x_is_tuple))
print('y_is_list:{}'.format(y_is_list))
print('z_is_tensor:{}'.format(z_is_tensor))

结果如下:

x_is_tuple:True
y_is_list:True
z_is_tensor:True

partial

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

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

入参:

  • func – 函数。

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

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

示例如下:

from mindspore import ms_function, ops

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

@ms_function()
def test():
    add_ = ops.partial(add, x=2)
    m = add_(y=3)
    n = add_(y=5)
    return m, n

m, n = test()
print('m:{}'.format(m))
print('n:{}'.format(n))

结果如下:

m:5
n:7

map

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

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

入参:

  • func – 函数。

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

返回值:返回一个Tuple

示例如下:

from mindspore import ms_function

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

@ms_function()
def test():
    elements_a = (1, 2, 3)
    elements_b = (4, 5, 6)
    ret = map(add, elements_a, elements_b)
    return ret

ret = test()
print('ret:{}'.format(ret))

结果如下:

ret: (5, 7, 9)

zip

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

调用:zip(sequence, ...)

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

返回值:返回一个Tuple

示例如下:

from mindspore import ms_function

@ms_function()
def test():
    elements_a = (1, 2, 3)
    elements_b = (4, 5, 6)
    ret = zip(elements_a, elements_b)
    return ret

ret = test()
print('ret:{}'.format(ret))

结果如下:

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

示例如下:

from mindspore import ms_function

@ms_function()
def test():
    x = range(0, 6, 2)
    y = range(0, 5)
    z = range(3)
    return x, y, z

x, y, z = test()
print('x:{}'.format(x))
print('y:{}'.format(y))
print('z:{}'.format(z))

结果如下:

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

示例如下:

import mindspore as ms
from mindspore import ms_function
import numpy as np

y = ms.Tensor(np.array([[1, 2], [3, 4], [5, 6]]))

@ms_function()
def test():
    x = (100, 200, 300, 400)
    m = enumerate(x, 3)
    n = enumerate(y)
    return m, n

m, n = test()
print('m:{}'.format(m))
print('n:{}'.format(n))

结果如下:

m:((3, 100), (4, 200), (5, 300), (6, 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 – 对象。

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

示例如下:

from mindspore import nn

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

示例如下:

import mindspore as ms
from mindspore import ms_function
import numpy as np

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

@ms_function()
def test(x, y):
    return pow(x, y)

ret = test(x, y)

print('ret:{}'.format(ret))

结果如下:

ret:[ 1  4 27]

print

功能:用于打印。

调用:print(arg, ...)

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

返回值:无返回值。

示例如下:

import mindspore as ms
from mindspore import ms_function
import numpy as np

x = ms.Tensor(np.array([1, 2, 3]), ms.int32)
y = ms.Tensor(3, ms.int32)

@ms_function()
def test(x, y):
    print(x)
    print(y)
    return x, y

ret = test(x, y)

结果如下:

Tensor(shape=[3], dtype=Int32, value= [1 2 3])
3

filter

功能:根据提供的函数对一个序列的元素做判断,每个元素依次作为参数传入函数中,将返回结果不为0或False的元素组成新的序列。

调用:filter(func, sequence)

入参:

  • func – 函数。

  • sequence – 序列(TupleList)。

返回值:返回一个Tuple

示例如下:

from mindspore import ms_function

def is_odd(x):
    if x % 2:
        return True
    return False

@ms_function()
def test():
    elements = (1, 2, 3, 4, 5)
    ret = filter(is_odd, elements)
    return ret

ret = test()
print('ret:{}'.format(ret))

结果如下:

ret:(1, 3, 5)

函数参数

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

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

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

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

网络定义

网络入参

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

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

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

示例如下:

import mindspore as ms
from mindspore import nn, ops
import numpy as np

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 = ops.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 = ms.Tensor(np.ones((2, 3)).astype(np.float32))
input_y = 2
input_z = ms.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)

print('ret:{}'.format(ret))

结果如下:

ret:(Tensor(shape=[2, 3], dtype=Float32, value=
[[ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00],
 [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00]]), Tensor(shape=[2, 3], dtype=Float32, value=
[[ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00],
 [ 1.00000000e+00,  1.00000000e+00,  1.00000000e+00]]))

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

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

网络实例类型

网络构造组件

类别

内容

Cell实例

mindspore/nn/*、自定义Cell

Cell实例的成员函数

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

ms_class实例

使用@ms_class装饰的类。

Primitive算子

mindspore/ops/operations/*

Composite算子

mindspore/ops/composite/*

constexpr生成算子

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

函数

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

网络使用约束

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

    示例如下:

    import mindspore as ms
    from mindspore import nn
    import numpy as np
    
    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
            self.x = 2
            self.par = ms.Parameter(ms.Tensor(np.ones((2, 3, 4))), name="par")
    
        def construct(self, x, y):
            self.par[0] = y
            self.x = x
            return x + y
    
    net = Net()
    net(1, 2)
    

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

    结果报错如下:

    TypeError: 'self.x' should be initialized as a 'Parameter' type in the '__init__' function
    
  2. construct函数里,使用未定义的类成员时,不会像Python解释器那样抛出AttributeError,而是作为None处理。

    示例如下:

    from mindspore import nn
    
    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
    
        def construct(self, x):
            return x + self.y
    
    net = Net()
    net(1)
    

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

    结果报错如下:

    RuntimeError: mindspore/ccsrc/frontend/operator/composite/multitype_funcgraph.cc:161 GenerateFromTypes] The 'add' operation does not support the type [Int64, kMetaTypeNone]