一、简介:
AI编译框架分为两种运行模式,分别是动态图模式以及静态图模式。MindSpore默认情况下是以动态图模式运行,但也支持手工切换为静态图模式。两种运行模式的详细介绍如下:
(1)动态图:
动态图的特点是计算图的构建和计算同时发生(Define by run),其符合Python的解释执行方式,在计算图中定义一个Tensor时,其值就已经被计算且确定,因此在调试模型时较为方便,能够实时得到中间结果的值,但由于所有节点都需要被保存,导致难以对整个计算图进行优化(也就是速度慢)。在MindSpore中,动态图模式又被称为PyNative模式。由于动态图的解释执行特性,在脚本开发和网络流程调试过程中,推荐使用动态图模式进行调试
(2)静态图:
相较于动态图而言,静态图的特点是将计算图的构建和实际计算分开(Define and run)。有关静态图模式的运行原理,可以参考静态图语法支持。
在MindSpore中,静态图模式又被称为Graph模式,在Graph模式下,基于图优化、计算图整图下沉等技术,编译器可以针对图进行全局的优化,获得较好的性能,因此比较适合网络固定且需要高性能的场景。
二、环境准备:
还是需要先下载MindSpore,再进行下面的操作,详情可见:昇思25天学习打卡营第1天|快速入门-CSDN博客
import time
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
构建一个简单的神经网络以展示MindSpore下静态图和动态图两种不同的模式:
class Network(nn.Cell):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.dense_relu_sequential = nn.SequentialCell(
nn.Dense(28*28, 512),
nn.ReLU(),
nn.Dense(512, 512),
nn.ReLU(),
nn.Dense(512, 10)
)
def construct(self, x):
x = self.flatten(x)
logits = self.dense_relu_sequential(x)
return logits
三、动态图VS静态图:
1、动态图下,神经网络的调用:
ms.set_context(mode=ms.PYNATIVE_MODE) # 开启pynative模式,即动态图
model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), "VertexGeek")
2、静态图下。神经网络的调用:
(1)全局context:
ms.set_context(mode=ms.GRAPH_MODE) # 开启静态图模式
model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), "VertexGeek")
如果出现小警告,不用管,大家都是老码农了只要能跑就不改的话我就不多说了(doge)!
(2)jit装饰器:
除了基于context全局模式下开启静态图以外,更多时候,我们在全局使用动态图的方式以实现更加灵活的神经网络构建方式,只在局部使用静态图加速计算,这里就用到了jit装饰器和函数变换实现对神经网络的局部加速:
装饰器:
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
@ms.jit # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行
def run(x):
model = Network()
return model(x)
output = run(input)
print(output)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), "VertexGeek")
函数变换:
这种方法就是非常常见的将函数作为参数传入ms.jit方法中,以实现更灵活的使用。
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
def run(x):
model = Network()
return model(x)
run_with_jit = ms.jit(run) # 通过调用jit将函数转换为以静态图方式执行
output = run(input)
print(output)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())), "VertexGeek")
四、静态图的高级用法:
1、直接在前向传播网络中使用:
当我们需要对神经网络的某部分进行加速时,可以直接在construct方法上使用jit修饰器,在调用实例化对象时,该模块自动被编译为静态图。
@ms.jit # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行
def construct(self, x):
x = self.flatten(x)
logits = self.dense_relu_sequential(x)
return logits
2、静态图语法约束:
在Graph模式下,Python代码并不是由Python解释器去执行,而是将代码编译成静态计算图,然后执行静态计算图。因此,编译器无法支持全量的Python语法。MindSpore的静态图编译器维护了Python常用语法子集,以支持神经网络的构建及训练。
在静态图模式下,MindSpore通过源码转换的方式,将Python的源码转换成中间表达IR(Intermediate Representation),并在此基础上对IR图进行优化,最终在硬件设备上执行优化后的图。MindSpore使用基于图表示的函数式IR,称为MindIR,是不是很眼熟,没错!就是上节课我们提到的用MindIR保存模型参数(doge)。
(1)当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)
(2)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)
(3)在图模式下,有些Python语法难以转换成图模式下的中间表示MindIR:
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)
对标Python的关键字,存在部分关键字在图模式下是不支持的:AsyncFunctionDef、Delete、AnnAssign、AsyncFor、AsyncWith、Match、Try、Import、ImportFrom、Nonlocal、NamedExpr、Set、SetComp、Await、Yield、YieldFrom、Starred。如果在图模式下使用相关的语法,将会有相应的报错信息提醒用户。
3、Jitconfig语法编辑:
在图模式下,可以通过使用JitConfig配置选项来一定程度的自定义编译流程,目前JitConfig支持的配置参数如下:
- jit_level: 用于控制优化等级。
- exec_mode: 用于控制模型执行方式。
- jit_syntax_level: 设置静态图语法支持级别,详细介绍请见静态图语法支持。
这里在执行下面这段代码之前,需要事先下载LeNet神经网络,gitee地址如下:docs/mindspore/code/lenet.py · MindSpore/docs - Gitee.com
from mindspore import JitConfig
jitconfig = JitConfig(jit_level="O1")
net = LeNet5()
net.set_jit_config(jitconfig)
静态图高级编程技巧感兴趣的宝子可以去点击此连接静态图高级编程技巧 — MindSpore master 文档,这里就不多做赘述(偷懒doge),好了到这次课程截至,我们基础部分就全部结束了,之后会向大家展示一些有趣的小案例!