添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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

在静态图模式下,MindSpore通过源码转换的方式,将Python的源码转换成中间表达IR(Intermediate Representation),并在此基础上对IR图进行优化,最终在硬件设备上执行优化后的图。MindSpore使用基于图表示的函数式IR,称为MindIR,详情可参考 中间表示MindIR

MindSpore的静态图执行过程实际包含两步,对应静态图的Define和Run阶段,但在实际使用中,在实例化的Cell对象被调用时用户并不会分别感知到这两阶段,MindSpore将两阶段均封装在Cell的 __call__ 方法中,因此实际调用过程为:

model(inputs) = model.compile(inputs) + model.construct(inputs) ,其中 model 为实例化Cell对象。

使用Graph模式有两种方式:一是调用 @jit 装饰器修饰函数或者类的成员方法,所修饰的函数或方法将会被编译成静态计算图。 jit 使用规则详见 jit API文档 。二是设置 ms.set_context(mode=ms.GRAPH_MODE) ,使用 Cell 类并且在 construct 函数中编写执行代码,此时 construct 函数的代码将会被编译成静态计算图。 Cell 定义详见 Cell API文档

由于语法解析的限制,当前在编译构图时,支持的数据类型、语法以及相关操作并没有完全与Python语法保持一致,部分使用受限。借鉴传统JIT编译的思路,从图模式的角度考虑动静图的统一,扩展图模式的语法能力,使得静态图提供接近动态图的语法使用体验,从而实现动静统一。为了便于用户选择是否扩展静态图语法,提供了JIT语法支持级别选项 jit_syntax_level ,其值必须在[STRICT,LAX]范围内,选择 STRICT 则认为使用基础语法,不扩展静态图语法。默认值为 LAX ,更多请参考本文的 扩展语法(LAX级别) 章节。全部级别都支持所有后端。

  • STRICT: 仅支持基础语法,且执行性能最佳。可用于MindIR导入导出。

  • LAX: 支持更多复杂语法,最大程度地兼容Python所有语法。由于存在可能无法导出的语法,不能用于MindIR导入导出。

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

    基础语法(STRICT级别)

    静态图内的常量与变量

    在静态图中,常量与变量是理解静态图语法的一个重要概念,很多语法在常量输入和变量输入情况下支持的方法与程度是不同的。因此,在介绍静态图具体支持的语法之前,本小节先会对静态图中常量与变量的概念进行说明。

    在静态图模式下,一段程序的运行会被分为编译期以及执行期。 在编译期,程序会被编译成一张中间表示图,并且程序不会真正的执行,而是通过抽象推导的方式对中间表示进行静态解析。这使得在编译期时,我们无法保证能获取到所有中间表示中节点的值。 常量和变量也就是通过能否能在编译器获取到其真实值来区分的。

  • 常量: 编译期内可以获取到值的量。

  • 变量: 编译期内无法获取到值的量。

  • 常量产生场景

  • 作为图模式输入的标量,列表以及元组均为常量(在不使用mutable接口的情况下)。例如:

    from mindspore import Tensor, jit
    a = 1
    b = [Tensor([1]), Tensor([2])]
    c = ["a", "b", "c"]
    def foo(a, b, c):
        return a, b, c
    

    上述代码中,输入abc均为常量。

  • 图模式内生成的标量或者Tensor为常量。例如:

    from mindspore import jit, Tensor
    def foo():
        a = 1
        b = "2"
        c = Tensor([1, 2, 3])
        return a, b, c
    

    上述代码中, abc均为常量。

  • 常量运算得到的结果为常量。例如:

    from mindspore import jit, Tensor
    def foo():
        a = Tensor([1, 2, 3])
        b = Tensor([1, 1, 1])
        c = a + b
        return c
    

    上述代码中,ab均为图模式内产生的Tensor为常量,因此其计算得到的结果也是常量。但如果其中之一为变量时,其返回值也会为变量。

  • 所有mutable接口的返回值均为变量(无论是在图外使用mutable还是在图内使用)。例如:

    from mindspore import Tensor, jit
    from mindspore import mutable
    a = mutable([Tensor([1]), Tensor([2])])
    def foo(a):
        b = mutable(Tensor([3]))
        c = mutable((Tensor([1]), Tensor([2])))
        return a, b, c
    

    上述代码中,a是在图外调用mutable接口的,bc是在图内调用mutable接口生成的,abc均为变量。

  • 作为静态图的输入的Tensor都是变量。例如:

    from mindspore import Tensor, jit
    a = Tensor([1])
    b = (Tensor([1]), Tensor([2]))
    def foo(a, b):
        return a, b
    

    上述代码中,a是作为图模式输入的Tensor,因此其为变量。但b是作为图模式输入的元组,非Tensor类型,即使其内部的元素均为Tensor,b也是常量。

  • 通过变量计算得到的是变量。

    如果一个量是算子的输出,那么其多数情况下为常量。例如:

    from mindspore import Tensor, jit, ops
    a = Tensor([1])
    b = Tensor([2])
    def foo(a, b):
        c = a + b
        return c
    

    在这种情况下,cab计算来的结果,且用来计算的输入ab均为变量,因此c也是变量。

    Number

    支持int(整型)、float(浮点型)、bool(布尔类型),不支持complex(复数)。

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

    当数据为常量时,编译时期可以获取到数值,在网络中可以支持强转Number的语法:y = int(x)y = float(x)y = bool(x)。 当数据为变量时,即需要在运行时期才可以获取到数值,也支持使用int(),float(),bool()等内置函数Python内置函数进行数据类型的转换。例如:

    from mindspore import Tensor, jit
    def foo(x):
      out1 = int(11.1)
      out2 = int(Tensor([10]))
      out3 = int(x.asnumpy())
      return out1, out2, out3
    res = foo(Tensor(2))
    print("res[0]:", res[0])
    print("res[1]:", res[1])
    print("res[2]:", res[2])
    

    结果如下:

    res[0]: 11
    res[1]: 10
    res[2]: 2
    

    支持返回Number类型。例如:

    import mindspore as ms
    @ms.jit
    def test_return_scalar(x, y):
        return x + y
    res = test_return_scalar(ms.mutable(1), ms.mutable(2))
    print(res)
    
    String

    支持在网络里构造String,即支持使用引号('")来创建字符串,如x = 'abcd'y = "efgh"。可以通过str()的方式进行将常量转换成字符串。支持对字符串连接,截取,以及使用成员运算符(innot in)判断字符串是否包含指定的字符。支持格式化字符串的输出,将一个值插入到一个有字符串格式符%s的字符串中。支持在常量场景下使用格式化字符串函数str.format()

    from mindspore import jit
    def foo():
      var1 = 'Hello!'
      var2 = "MindSpore"
      var3 = str(123)
      var4 = "{} is {}".format("string", var3)
      return var1[0], var2[4:9], var1 + var2, var2 * 2, "H" in var1, "My name is %s!" % var2, var4
    res = foo()
    print("res:", res)
    

    结果如下:

    res: ('H', 'Spore', 'Hello!MindSpore', 'MindSporeMindSpore', True, 'My name is MindSpore!', 'string is 123')
    
    List

    JIT_SYNTAX_LEVEL设置为LAX的情况下,静态图模式可以支持部分List对象的inplace操作,具体介绍详见支持列表就地修改操作章节。

    List的基础使用场景如下:

  • 图模式支持图内创建List

    支持在图模式内创建List对象,且List内对象的元素可以包含任意图模式支持的类型,也支持多层嵌套。例如:

    import numpy as np
    import mindspore as ms
    @ms.jit
    def generate_list():
      a = [1, 2, 3, 4]
      b = ["1", "2", "a"]
      c = [ms.Tensor([1]), ms.Tensor([2])]
      d = [a, b, c, (4, 5)]
      return d
    

    上述示例代码中,所有的List对象都可以被正常的创建。

  • 图模式支持返回List

    在MindSpore2.0版本之前,当图模式返回List 对象时,List会被转换为Tuple。MindSpore2.0版本已经可以支持返回List对象。例如:

    import mindspore as ms
    @ms.jit
    def list_func():
        a = [1, 2, 3, 4]
        return a
    output = list_func()  # output: [1, 2, 3, 4]
    

    与图模式内创建List 相同,图模式返回List对象可以包括任意图模式支持的类型,也支持多层嵌套。

  • 图模式支持从全局变量中获取List对象。

    import mindspore as ms
    global_list = [1, 2, 3, 4]
    @ms.jit
    def list_func():
        global_list.reverse()
        return global_list
    output = list_func()  # output: [4, 3, 2, 1]
    

    需要注意的是,在基础场景下图模式返回的列表与全局变量的列表不是同一个对象,当JIT_SYNTAX_LEVEL设置为LAX时,返回的对象与全局对象为统一对象。

  • 图模式支持以List作为输入。

    图模式支持List作为静态图的输入,作为输入的List对象的元素必须为图模式支持的输入类型,也支持多层嵌套。

    import mindspore as ms
    list_input = [1, 2, 3, 4]
    @ms.jit
    def list_func(x):
        return x
    output = list_func(list_input)  # output: [1, 2, 3, 4]
    

    需要注意的是,List作为静态图输入时,无论其内部的元素是什么类型,一律被视为常量。

  • 图模式支持List的内置方法。

    List 内置方法的详细介绍如下:

  • List索引取值

    基础语法:element = list_object[index]

    基础语义:将List对象中位于第index位的元素提取出来(index从0开始)。支持多层索引取值。

    索引值index支持类型包括intTensorslice。其中,int以及Tensor类型的输入可以支持常量以及变量,slice内部数据必须为编译时能够确定的常量。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def list_getitem_func():
        x = [[1, 2], 3, 4]
        a = x[0]
        b = x[0][ms.Tensor([1])]
        c = x[1:3:1]
        return a, b, c
    a, b, c = list_getitem_func()
    print('a:{}'.format(a))
    print('b:{}'.format(b))
    print('c:{}'.format(c))
    

    结果如下:

    a:[1, 2]
    c:[3, 4]
    
  • List索引赋值

    基础语法:list_object[index] = target_element

    基础语义:将List对象中位于第index位的元素赋值为 target_elementindex从0开始)。支持多层索引赋值。

    索引值index支持类型包括intTensorslice。其中,int 以及Tensor类型的输入可以支持常量以及变量,slice内部数据必须为编译时能够确定的常量。

    索引赋值对象target_element支持所有图模式支持的数据类型。

    目前,List索引赋值不支持inplace操作, 索引赋值后将会生成一个新的对象。该操作后续将会支持inplace操作。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def test_setitem_func():
        x = [[0, 1], 2, 3, 4]
        x[1] = 10
        x[2] = "ok"
        x[3] = (1, 2, 3)
        x[0][1] = 88
        return x
    output = test_setitem_func()
    print('output:{}'.format(output))
    

    结果如下:

    output:[[0, 88], 10, 'ok', (1, 2, 3)]
    
  • List.append

    基础语法:list_object.append(target_element)

    基础语义:向List对象list_object的最后追加元素target_element

    目前,List.append不支持inplace操作, 索引赋值后将会生成一个新的对象。该操作后续将会支持inplace操作。

    示例如下:

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

    结果如下:

    x:[1, 2, 3, 4]
    
  • List.clear

    基础语法:list_object.clear()

    基础语义:清空List对象 list_object中包含的元素。

    目前,List.clear不支持inplace, 索引赋值后将会生成一个新的对象。该操作后续将会支持inplace。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def test_list_clear():
        x = [1, 3, 4]
        x.clear()
        return x
    x = test_list_clear()
    print('x:{}'.format(x))
    

    结果如下:

  • List.extend

    基础语法:list_object.extend(target)

    基础语义:向List对象list_object的最后依次插入target内的所有元素。

    target支持的类型为TupleList以及Tensor。其中,如果target类型为Tensor的情况下,会先将该Tensor转换为List,再进行插入操作。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def test_list_extend():
        x1 = [1, 2, 3]
        x1.extend((4, "a"))
        x2 = [1, 2, 3]
        x2.extend(ms.Tensor([4, 5]))
        return x1, x2
    output1, output2 = test_list_extend()
    print('output1:{}'.format(output1))
    print('output2:{}'.format(output2))
    

    结果如下:

    output1:[1, 2, 3, 4, 'a']
    output2:[1, 2, 3, Tensor(shape=[1], dtype=Int64, value= [4]), Tensor(shape=[1], dtype=Int64, value= [5])]
    
  • List.pop

    基础语法:pop_element = list_object.pop(index=-1)

    基础语义:将List对象list_object 的第index个元素从list_object中删除,并返回该元素。

    index 要求必须为常量int, 当list_object的长度为list_obj_size时,index的取值范围为:[-list_obj_size,list_obj_size-1]index为负数,代表从后往前的位数。当没有输入index时,默认值为-1,即删除最后一个元素。

    import mindspore as ms
    @ms.jit()
    def test_list_pop():
        x = [1, 2, 3]
        b = x.pop()
        return b, x
    pop_element, res_list = test_list_pop()
    print('pop_element:{}'.format(pop_element))
    print('res_list:{}'.format(res_list))
    

    结果如下:

    pop_element:3
    res_list:[1, 2]
    
  • List.reverse

    基础语法:list_object.reverse()

    基础语义:将List对象list_object的元素顺序倒转。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def test_list_reverse():
        x = [1, 2, 3]
        x.reverse()
        return x
    output = test_list_reverse()
    print('output:{}'.format(output))
    

    结果如下:

    output1:[3, 2, 1]
    
  • List.insert

    基础语法:list_object.insert(index, target_obj)

    基础语义:将target_obj插入到list_object的第index位。

    index要求必须为常量int。如果list_object的长度为list_obj_size。当index < -list_obj_size时,插入到List的第一位。当index >= list_obj_size时,插入到List的最后。index为负数代表从后往前的位数。

    示例如下:

    import mindspore as ms
    @ms.jit()
    def test_list_insert():
        x = [1, 2, 3]
        x.insert(3, 4)
        return x
    output = test_list_insert()
    print('output:{}'.format(output))
    

    结果如下:

    output:[1, 2, 3, 4]
    
    Tuple

    支持在网络里构造元组Tuple,使用小括号包含元素,即支持语法y = (1, 2, 3)。元组Tuple的元素不能修改,但支持索引访问元组Tuple中的元素,支持对元组进行连接组合。

  • 支持索引取值。

    支持使用方括号加下标索引的形式来访问元组Tuple中的元素,索引值支持intsliceTensor,也支持多层索引取值,即支持语法data = tuple_x[index0][index1]...

    索引值为Tensor有如下限制:

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

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

  • 支持CPUGPUAscend后端。

  • intslice索引示例如下:

    import numpy as np
    import mindspore as ms
    t = ms.Tensor(np.array([1, 2, 3]))
    @ms.jit()
    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))
    

    结果如下:

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

    Tensor索引示例如下:

    import mindspore as ms
    from mindspore import nn, set_context
    set_context(mode=ms.GRAPH_MODE)
    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.]
    
  • 支持连接组合。

    与字符串String类似,元组支持使用+*进行组合,得到一个新的元组Tuple,例如:

    import mindspore as ms
    @ms.jit()
    def test_index():
        x = (1, 2, 3)
        y = (4, 5, 6)
        return x + y, x * 2
    out1, out2 = test_index()
    print('out1:{}'.format(out1))
    print('out2:{}'.format(out2))
    

    结果如下:

    out1:(1, 2, 3, 4, 5, 6)
    out2:(1, 2, 3, 1, 2, 3)
    
    Dictionary

    支持在网络里构造字典Dictionary,每个键值key:value用冒号:分割,每个键值对之间用逗号,分割,整个字典使用大括号{}包含键值对,即支持语法y = {"a": 1, "b": 2}

    key是唯一的,如果字典中存在多个相同的key,则重复的key以最后一个作为最终结果;而值value可以不是唯一的。键key需要保证是不可变的。当前键key支持StringNumber、常量Tensor以及只包含这些类型对象的Tuple;值value支持NumberTupleTensorListDictionaryNone

  • 支持接口。

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

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

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

    getdict.get(key[, value])返回指定key对应的value值,如果指定key不存在,返回默认值None或者设置的默认值value

    clear:删除dict里所有的元素。

    has_keydict.has_key(key)判断dict里是否存在指定key

    updatedict1.update(dict2)dict2中的元素更新到dict1中。

    fromkeysdict.fromkeys(seq([, value]))用于创建新的Dictionary,以序列seq中的元素做Dictionarykeyvalue为所有key对应的初始值。

    示例如下,其中返回值中的xnew_dict是一个Dictionary,在图模式JIT语法支持级别选项为LAX下扩展支持,更多Dictionary的高阶使用请参考本文的支持Dictionary的高阶用法章节。

    import mindspore as ms
    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.jit()
    def test_dict():
        x_keys = x.keys()
        x_values = x.values()
        x_items = x.items()
        value_a = x.get("a")
        check_key = x.has_key("a")
        y = {"a": ms.Tensor(np.array([0, 0, 0]))}
        x.update(y)
        new_dict = x.fromkeys("abcd", 123)
        return x_keys, x_values, x_items, value_a, check_key, x, new_dict
    x_keys, x_values, x_items, value_a, check_key, new_x, new_dict = test_dict()
    print('x_keys:{}'.format(x_keys))
    print('x_values:{}'.format(x_values))
    print('x_items:{}'.format(x_items))
    print('value_a:{}'.format(value_a))
    print('check_key:{}'.format(check_key))
    print('new_x:{}'.format(new_x))
    print('new_dict:{}'.format(new_dict))
    

    结果如下:

    x_keys:('a', 'b', 'c')
    x_values:(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]))
    x_items:[('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]))]
    value_a:[1 2 3]
    check_key:True
    new_x:{'a': Tensor(shape=[3], dtype=Int64, value= [0, 0, 0]), 'b': Tensor(shape=[3], dtype=Int64, value= [4, 5, 6]), 'c': Tensor(shape=[3], dtype=Int64, value= [7, 8, 9])}
    new_dict:{'a': 123, 'b': 123, 'c': 123, 'd': 123}
    
    Tensor

    Tensor的属性与接口详见Tensor API文档

    支持在静态图模式下创建和使用Tensor。创建方式有使用tensor函数接口和使用Tensor类接口。推荐使用tensor函数接口,用户可以使用指定所需要的dtype类型。代码用例如下。

    import mindspore as ms
    import mindspore.nn as nn
    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
        @ms.jit
        def construct(self, x):
            return ms.tensor(x.asnumpy(), dtype=ms.float32)
    ms.set_context(mode=ms.GRAPH_MODE)
    net = Net()
    x = ms.Tensor(1, dtype=ms.int32)
    print(net(x))
    

    示例如下:

    import mindspore as ms
    from mindspore import nn, ops, Tensor, set_context
    import numpy as np
    set_context(mode=ms.GRAPH_MODE)
    class Net(nn.Cell):
        def __init__(self):
            super().__init__()
        def construct(self, x):
            reduce_sum = ops.ReduceSum(True) #支持在construct里构造`Primitive`及其子类的实例
            ret = reduce_sum(x, axis=2)
            return ret
    x = Tensor(np.random.randn(3, 4, 5, 6).astype(np.float32))
    net = Net()
    ret = net(x)
    print('ret.shape:{}'.format(ret.shape))
    

    上面所定义的网络里,reduce_sum(x, axis=2)的参数不支持通过键值对方式传入,只能通过位置参数方式传入,即reduce_sum(x, 2)。

    结果报错如下:

    ValueError: For 'ReduceSum', the second input type should be tensor or scalar, but got invalid abstract type:AbstractKeywordArg.
    

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

    当前已定义的Primitive详见Primitive API文档

    Cell

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

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

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

    Cell定义详见Cell API文档

    Parameter

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

    Parameter的定义和使用详见Parameter API文档

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

  • 在JIT语法支持级别选项为LAX时,可以支持更多情况的属性修改,具体详见支持属性设置与修改

    示例如下:

    import mindspore as ms
    from mindspore import nn, set_context
    set_context(mode=ms.GRAPH_MODE)
    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的索引取详见Tensor 索引取值文档

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

    示例如下:

    import mindspore as ms
    from mindspore import nn, ops, set_context
    import numpy as np
    set_context(mode=ms.GRAPH_MODE)
    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.]]
    

    当前静态图模式支持部分Python语句,包括raise语句、assert语句、pass语句、return语句、break语句、continue语句、if语句、for语句、while语句、with语句、列表生成式、生成器表达式、函数定义语句等,详见Python语句

    Python内置函数

    当前静态图模式支持部分Python内置函数,其使用方法与对应的Python内置函数类似,详见Python内置函数

    网络定义

    网络入参

    在对整网入参求梯度的时候,会忽略非Tensor的入参,只计算Tensor入参的梯度。

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

    import numpy as np
    import mindspore as ms
    from mindspore import nn
    ms.set_context(mode=ms.GRAPH_MODE)
    class Net(nn.Cell):
        def __init__(self):
            super(Net, self).__init__()
        def construct(self, x, y, z):
            return x + y + z
    class GradNet(nn.Cell):
        def __init__(self, net):
            super(GradNet, self).__init__()
            self.forward_net = net
        def construct(self, x, y, z):
            return ms.grad(self.forward_net, grad_position=(0, 1, 2))(x, y, z)
    input_x = ms.Tensor([1])
    input_y = 2
    input_z = ms.Tensor([3])
    net = Net()
    grad_net = GradNet(net)
    ret = grad_net(input_x, input_y, input_z)
    print('ret:{}'.format(ret))
    

    结果如下:

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

    图模式下的执行图是从源码转换而来,并不是所有的Python语法都能支持。下面介绍在基础语法下存在的一些语法约束。更多网络编译问题可见网络编译

  • construct函数里,使用未定义的类成员时,将抛出AttributeError异常。示例如下:

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

    结果报错如下:

    AttributeError: External object has no attribute y
    
  • nn.Cell不支持classmethod修饰的类方法。示例如下:

    import mindspore as ms
    ms.set_context(mode=ms.GRAPH_MODE)
    class Net(ms.nn.Cell):
        @classmethod
        def func(cls, x, y):
            return x + y
        def construct(self, x, y):
            return self.func(x, y)
    net = Net()
    out = net(ms.Tensor(1), ms.Tensor(2))
    print(out)
    

    结果报错如下:

    TypeError: The parameters number of the function is 3, but the number of provided arguments is 2.
    
  • 在图模式下,有些Python语法难以转换成图模式下的中间表示MindIR。对标Python的关键字,存在部分关键字在图模式下是不支持的:AsyncFunctionDef、Delete、AnnAssign、AsyncFor、AsyncWith、Match、Try、Import、ImportFrom、Nonlocal、NamedExpr、Set、SetComp、Await、Yield、YieldFrom、Starred。如果在图模式下使用相关的语法,将会有相应的报错信息提醒用户。

    如果使用Try语句,示例如下:

    import mindspore as ms
    @ms.jit
    def test_try_except(x, y):
        global_out = 1
        try:
            global_out = x / y
        except ZeroDivisionError:
            print("division by zero, y is zero.")
        return global_out
    test_try_except_out = test_try_except(1, 0)
    print("out:", test_try_except_out)
    

    结果报错如下:

    RuntimeError: Unsupported statement 'Try'.
    
  • 对标Python内置数据类型,除去当前图模式下支持的Python内置数据类型,复数complex和集合set类型是不支持的。列表list和字典dictionary的一些高阶用法在基础语法场景下是不支持的,需要在JIT语法支持级别选项jit_syntax_levelLAX时才支持,更多请参考本文的扩展语法(LAX级别)章节。

  • 对标Python的内置函数,在基础语法场景下,除去当前图模式下支持的Python内置函数,仍存在部分内置函数在图模式下是不支持的,例如:basestring、bin、bytearray、callable、chr、cmp、compile、 delattr、dir、divmod、eval、execfile、file、frozenset、hash、hex、id、input、issubclass、iter、locals、long、memoryview、next、object、oct、open、ord、property、raw_input、reduce、reload、repr、reverse、set、slice、sorted、unichr、unicode、vars、xrange、__import__。

  • Python提供了很多第三方库,通常需要通过import语句调用。在图模式下JIT语法支持级别为STRICT时,不能直接使用第三方库。如果需要在图模式下使用第三方库的数据类型或者调用第三方库的方法,需要在JIT语法支持级别选项jit_syntax_levelLAX时才支持,更多请参考本文的扩展语法(LAX级别)中的调用第三方库章节。

  • 扩展语法(LAX级别)

    下面主要介绍当前扩展支持的静态图语法。

    调用第三方库

  • Python内置模块和Python标准库。例如ossysmathtime等模块。

  • 第三方代码库。路径在Python安装目录的site-packages目录下,需要先安装后导入,例如NumPySciPy等。需要注意的是,mindyolomindflow等MindSpore套件不被视作第三方库,具体列表可以参考parser文件的 _modules_from_mindspore 列表。

  • 通过环境变量MS_JIT_IGNORE_MODULES指定的模块。与之相对的有环境变量MS_JIT_MODULES,具体使用方法请参考环境变量

  • 支持第三方库的数据类型,允许调用和返回第三方库的对象。

    示例如下:

    import numpy as np
    import mindspore as ms
    @ms.jit
    def func():
        a = np.array([1, 2, 3])
        b = np.array([4, 5, 6])
        out = a + b
        return out
    print(func())
    

    结果如下:

    [5 7 9]
    
  • 支持调用第三方库的方法。

    示例如下:

    from scipy import linalg
    import mindspore as ms
    @ms.jit
    def func():
        x = [[1, 2], [3, 4]]
        return linalg.qr(x)
    out = func()
    print(out[0].shape)
    

    结果如下:

    (2, 2)
    
  • 支持使用NumPy第三方库数据类型创建Tensor对象。

    示例如下:

    import numpy as np
    import mindspore as ms
    @ms.jit
    def func():
        x = np.array([1, 2, 3])
        out = ms.Tensor(x) + 1
        return out
    print(func())
    

    结果如下:

  •