# 动静态图结合

## MindSpore静态图

### Graph模式执行原理

Graph模式的代码用例如下所示：

[1]:

import numpy as np
import mindspore.nn as nn
import mindspore.ops as ops
import mindspore as ms

ms.set_context(mode=ms.GRAPH_MODE, device_target="CPU")

class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
self.mul = ops.Mul()

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

x = ms.Tensor(np.array([1.0, 2.0, 3.0]).astype(np.float32))
y = ms.Tensor(np.array([4.0, 5.0, 6.0]).astype(np.float32))

net = Net()
print(net(x, y))

[ 4. 10. 18.]


## MindSpore动态图

### PyNative模式执行原理

[2]:

import numpy as np
import mindspore.nn as nn
import mindspore as ms
import mindspore.ops as ops

ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU")
x = ms.Tensor(np.ones([1, 3, 3, 4]).astype(np.float32))
y = ms.Tensor(np.ones([1, 3, 3, 4]).astype(np.float32))
print(output.asnumpy())

[[[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]

[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]

[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]]]


### PyNative模式自动微分原理

[3]:

import numpy as np
import mindspore.nn as nn
import mindspore.ops as ops
import mindspore as ms

ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU")

class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
self.matmul = ops.MatMul()
self.z = ms.Parameter(ms.Tensor(np.array([2.0], np.float32)), name='z')

def construct(self, x, y):
x = x * self.z
out = self.matmul(x, y)
return out

def __init__(self, net):
self.net = net

def construct(self, x, y):

x = ms.Tensor([[0.8, 0.6, 0.2], [1.8, 1.3, 1.1]], dtype=ms.float32)
y = ms.Tensor([[0.11, 3.3, 1.1], [1.1, 0.2, 1.4], [1.1, 2.2, 0.3]], dtype=ms.float32)
print(output)

[[9.02      5.4       7.2000003]
[9.02      5.4       7.2000003]]


[4]:

from mindspore.ops._grad.grad_base import bprop_getters

@bprop_getters.register(ops.Mul)
def get_bprop_mul(self):
"""Grad definition for Mul operation."""
mul_func = P.Mul()

def bprop(x, y, out, dout):
bc_dx = mul_func(y, dout)
bc_dy = mul_func(x, dout)

return bprop


## 动静统一

### 动态图和静态图互相转换

[5]:

ms.set_context(mode=ms.PYNATIVE_MODE)


### 动静结合

MindSpore支持在动态图下使用静态编译的方式来进行混合执行，通过使用jit修饰需要用静态图来执行的函数对象，即可实现动态图和静态图的混合执行，更多jit的使用可参考jit文档

[6]:

import numpy as np
import mindspore as ms
import mindspore.nn as nn

def __init__(self):
self.param = ms.Parameter(ms.Tensor(0.5, ms.float32))

@ms.jit
def construct(self, x):
x = x + x
x = x * self.param
x = x * x
return x

class CellCallSingleCell(nn.Cell):
def __init__(self):
super(CellCallSingleCell, self).__init__()
self.bn = nn.BatchNorm2d(2, momentum=0.99, eps=0.00001, gamma_init="ones")
self.relu = nn.ReLU()

def construct(self, x):
x = self.conv(x)
x = self.bn(x)
x = self.relu(x)
return x

ms.set_context(mode=ms.PYNATIVE_MODE, device_target="CPU")
inputs = ms.Tensor(np.ones([1, 1, 2, 2]).astype(np.float32))
net = CellCallSingleCell()
out = net(inputs)
print(out)

[[[[15.99984]]

[[15.99984]]]]


### 静态图语法增强技术

JIT Fallback是从静态图的角度出发考虑静态图和动态图的统一。在编译过程中发现不支持的语法时，将该语法Fallback到Python解释器进行解释执行。通过JIT Fallback特性，静态图可以支持尽量多的动态图语法，使得静态图提供接近动态图的语法使用体验，从而实现动静统一。

#### 调用第三方库

• 支持第三方库(如NumPy、SciPy等)的数据类型，允许调用和返回第三方库的对象。

• 支持调用第三方库的方法。

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

• 暂不支持对第三方库数据类型的下标索引赋值。

#### 基础类型

##### 支持列表就地修改操作
• 支持从全局变量中获取原List对象。

• 不支持对输入List对象进行inplace操作。

• 支持部分List内置函数的就地修改操作。

##### 支持Dictionary的高阶用法
• 支持顶图返回Dictionary。

• 支持Dictionary索引取值和赋值。

##### 支持使用None

None是Python中的一个特殊值，表示空，可以赋值给任何变量。对于没有返回值语句的函数认为返回None。同时也支持None作为顶图或者子图的入参或者返回值。支持None作为切片的下标，作为ListTupleDictionary的输入。

#### 支持属性设置与修改

• 对自定义类对象以及第三方类型的属性进行设置与修改。

• 对Cell的self对象进行修改。

• 对静态图内的Cell对象以及jit_class对象进行设置与修改。

#### 使用须知

1. 对标动态图的支持能力，即：须在动态图语法范围内，包括但不限于数据类型等。

2. 在扩展静态图语法时，支持了更多的语法，但执行性能可能会受影响，不是最佳。

3. 在扩展静态图语法时，支持了更多的语法，由于使用Python的能力，不能使用MindIR导入导出的能力。

4. 暂不支持跨Python文件重复定义同名的全局变量，且这些全局变量在网络中会被用到。

### 动态图转静态图技术

MindSpore提供了一种在代码无需修改的情况下，直接将用户的动态图代码转换成静态图的功能——PIJit。该功能同时兼顾性能和易用性，去除动静模式切换的代价，真正做到动静统一。它基于Python字节码的分析，对Python的执行流进行图捕获，可以以静态图方式运行的子图便以静态图方式运行，Python语法不支持的子图便以动态图方式运行，同时通过修改调整字节码的方式链接静态图，达到动静混合执行。在满足易用性的前提下，尽可能地提高性能。

#### PIJit包含以下功能

1. 图捕获：对字节码预处理，动态跟踪解释执行，识别MindSpore可入图操作，提供裂图功能保证函数（字节码）功能的正确性。

1. 字节码支持：当前支持Python3.7和Python3.9的版本的字节码，并计划支持Python3.8与Python3.10。

1. 图优化：对图中生成的字节码进行优化，包括分支裁剪、字节码筛选、函数字节码内联等功能。

1. 异常捕获机制：支持with、try-except语法。

1. 支持循环处理：通过模拟字节码的操作栈实现图捕获、裂图等特性。

1. UD分析：通过变量的user-def链分析的方法，解决部分参数类型不能作为静态图的返回值问题（函数、Bool、None），同时减少无用的入参，提高图的执行效率，减少数据的拷贝。

1. 副作用分析处理：弥补静态图的副作用处理上的劣势，根据不同场景，收集记录产生副作用的变量及字节码，在保证程序语义的基础上，在静态图外补充副作用的处理。

1. 守护门禁：门禁（Guard）记录了子图/优化进入的输入需要满足的条件，检查输入是否适合对应的子图优化。

1. Cache：图管理（Cache）则缓存了子图/优化和门禁（Guard）对应关系。

• 未来计划支持Symbolic Shape

#### 使用方式

def jit(fn=None, input_signature=None, hash_args=None, jit_config=None, mode=“PIJit”):

#### 使用限制

• 不支持在静态图模式下，运行带装饰@jit(mode=”PIJit”)的函数，此时该装饰@jit(mode=”PIJit”)视为无效。

• 不支持在@jit(mode=”PSJit”)装饰的函数内部调用带装饰@jit(mode=”PIJit”)的函数，该装饰 @jit(mode=”PIJit”)视为无效。