目录
背景介绍
动态图模式
静态图模式
静态图模式的使用场景
静态图模式开启方式
基于装饰器的开启方式
基于context的开启方式
静态图的语法约束
JitConfig配置选项
静态图高级编程技巧
背景介绍
AI 编译框架主要包含两种运行模式,即动态图模式与静态图模式。在默认状况下,MindSpore 是以动态图模式进行运行的,不过同时也支持通过人工操作切换为静态图模式。
动态图模式
动态图的显著特点在于计算图的构建和计算同步进行(Define by run),这与 Python 的解释执行方式相契合。当在计算图中定义一个 Tensor 时,其值会即刻被计算并确定,所以在调试模型时颇为便捷,能够实时获取中间结果的值。然而,由于所有节点都需保存,致使难以对整个计算图予以优化。
在 MindSpore 里,动态图模式又称作 PyNative 模式。鉴于动态图的解释执行特性,在脚本开发以及网络流程调试阶段,建议使用动态图模式进行调试。若需手动控制框架采用 PyNative 模式,可通过以下代码来构建网络。
使用 MindSpore 框架构建了一个简单的神经网络模型,并对输入数据进行了前向传播计算,最后打印输出结果。
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
ms.set_context(mode=ms.PYNATIVE_MODE) # 使用set_context进行动态图模式的配置
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
model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
分析:首先,成功导入了所需的相关库,这里面有 numpy 以及 mindspore ,还有 mindspore 中的部分重要模块。
紧接着,定义了一个被命名为 Network 的类,此类别继承自 nn.Cell 。在该类的初始化方法 init 当中,精心定义了一系列的神经网络层,其中涵盖了展平层 Flatten ,以及一个由多层全连接和激活函数所构成的序列 nn.SequentialCell 。
在 construct 方法里,清晰地定义了前向传播的计算逻辑。具体来说,先是对输入数据实施展平操作,随后通过先前定义好的序列层来进行计算,从而获取到预测的 logits 。
随后,创建了 Network 类的实例 model ,并且成功生成了一个输入张量 input 。
最后,将这个输入张量传递进模型展开计算,进而得到输出 output ,并把这一结果予以打印输出
运行结果:
[[ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071]
... [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071] [ 0.16246006 -0.11432456 0.04079182 0.16045687 0.01581723 0.00070624 0.05681457 -0.02252093 -0.05198406 -0.02421071]]
静态图模式
相较于动态图来说,静态图具有一个显著的特点,那便是将计算图的构建与实际的计算过程相互分离(Define and run)。至于静态图模式的运行原理,大家可以参考静态图语法支持的相关内容。
在 MindSpore 当中,静态图模式还被称作 Graph 模式。处于 Graph 模式之下,借助于图优化、计算图整图下沉等一系列技术,编译器能够针对整个计算图展开全局性的优化操作,进而获取较为出色的性能表现。所以,这种模式相对而言更适合网络结构固定并且对性能要求较高的场景。
倘若需要手动把控框架采用静态图模式,能够通过如下代码来进行网络的构建:成功定义了一个神经网络模型 Network ,并针对输入数据实施了前向传播以计算输出。接下来,将介绍运用 mindspore 框架构建并运行一个简易神经网络模型的具体方法。
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
ms.set_context(mode=ms.GRAPH_MODE) # 使用set_context进行运行静态图模式的配置
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
model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
分析:首先导入了必要的库,如 numpy 、mindspore 等,并配置为静态图模式。
然后定义了一个名为 Network 的类,它继承自 nn.Cell 。在 __init__ 方法中,初始化了一些网络层,包括展平层 nn.Flatten 和一个包含多个全连接层及激活函数的序列 nn.SequentialCell 。
在 construct 方法中定义了前向传播的计算逻辑,先对输入进行展平操作,然后通过定义的序列层进行计算得到 logits 。
接着创建了 Network 类的实例 model ,并生成一个输入张量 input 。
最后将输入通过模型进行计算得到输出 output 并打印。
运行结果:
[[ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318]
... [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318] [ 0.08111228 -0.06155853 -0.16565546 0.05599653 -0.10597651 -0.13046513 0.05319815 0.13381606 0.15450898 -0.04248318]]
静态图模式的使用场景
MindSpore 编译器主要聚焦于 Tensor 数据的计算及其微分处理。故而,运用 MindSpore API 以及基于 Tensor 对象的操作,采用静态图编译优化会更为适宜。其他操作虽说能够部分纳入图编译,然而实际的优化效果却较为有限。再者,静态图模式所具有的先编译后执行的特性,致使其存在编译耗时的情况。所以,倘若函数无需多次执行,那么利用静态图来加速或许并无太大意义。
静态图模式开启方式
基于装饰器的开启方式
MindSpore 提供了 jit 装饰器,能够通过对 Python 函数或者 Python 类的成员函数进行修饰,使其被编译为计算图,借由图优化等技术来提升运行速度。此时,我们能够简便地针对期望进行性能优化的模块实施图编译加速,而模型的其他部分,依旧采用解释执行的方式,从而不会丧失动态图的灵活性。不管全局 context 是设定为静态图模式还是动态图模式,被 jit 修饰的部分始终会以静态图模式运行。
当需要对 Tensor 的某些运算进行编译加速时,可以在其定义的函数上运用 jit 装饰器,在调用该函数时,此模块会自动被编译成静态图。需要留意的是,jit 装饰器仅能用于修饰函数,无法对类进行修饰。jit 的使用示例如下:
即使用 MindSpore 框架构建了一个神经网络 Network ,然后使用 ms.jit 装饰器定义了一个名为 run 的函数,在这个函数中创建了 Network 模型实例,并将输入数据 input 传入模型进行计算,最后打印输出结果。
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
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 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)
分析:首先,定义了一个名为 Network 的类,继承自 nn.Cell ,在类中初始化了一些层,包括 Flatten 和一系列的 Dense 与 ReLU 层。
然后,定义了一个输入 input ,它是一个 Tensor 类型的数据。
接着,使用 ms.jit 装饰器修饰 run 函数,这意味着在运行 run 函数时,其中的操作会以静态图模式进行优化和执行。
在 run 函数内部,创建了 Network 模型的实例 model ,并将 input 传入模型计算得到结果并返回。
最后,将 run 函数的输出打印出来。
运行结果:
[[ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292]
... [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292] [ 0.0252679 0.0036834 0.08489509 0.07125469 0.19286017 -0.01487035 -0.04551143 0.1177191 -0.00667884 0.02147292]]
除使用修饰器外,也可使用函数变换方式调用jit方法,示例如下:
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
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
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)
分析:首先导入了所需的库和模块。然后定义了一个名为 Network 的类,它继承自 nn.Cell ,在类的初始化方法 __init__ 中定义了一些层,包括展平层 Flatten 和一个由全连接层 Dense 与激活函数 ReLU 组成的序列 dense_relu_sequential 。
接着创建了一个输入数据 input 。
之后定义了一个名为 run 的函数,在函数内部创建了 Network 类的实例 model ,并将输入 x 传入模型进行计算并返回结果。
然后通过 ms.jit(run) 将 run 函数转换为以静态图方式执行,并将其结果赋值给 run_with_jit 。
最后调用 run 函数并将输入 input 传入,得到输出并打印。
总的来说,这段代码构建了一个神经网络模型,并尝试以不同的方式(普通函数和静态图)来运行模型进行计算和输出结果。
运行结果:
[[-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849]
... [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849] [-0.26886722 -0.01613193 -0.02503425 -0.06268327 0.1372346 0.08339559 -0.05737131 -0.03662169 0.09235285 -0.12165849]]
当我们需要对神经网络的某部分进行加速时,可以直接在construct方法上使用jit修饰器,在调用实例化对象时,该模块自动被编译为静态图。示例如下:
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
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) ) @ms.jit # 使用ms.jit装饰器,使被装饰的函数以静态图模式运行 def construct(self, x): x = self.flatten(x) logits = self.dense_relu_sequential(x) return logits
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
model = Network()
output = model(input)
print(output)
分析:首先,导入了 numpy 库并命名为 np ,导入了 mindspore 库并命名为 ms ,还从 mindspore 库中导入了 nn 和 Tensor 。
然后,定义了一个名为 Network 的类,它继承自 nn.Cell 。在类的初始化方法 __init__ 中进行了一些基础设置。
接着,使用 ms.jit 装饰器修饰了 Network 类的 construct 方法,这意味着该方法在运行时会以静态图模式进行优化。
之后,创建了一个输入数据 input ,它是一个 Tensor 类型。
再然后,创建了 Network 类的实例 model 。
最后,将 input 传入 model 进行计算,得到输出 output 并打印出来。
总的来说,这段代码构建了一个基于 MindSpore 的神经网络模型,并对给定的输入数据进行计算和输出结果。
运行结果:
[[-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118]
... [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118] [-0.01447779 -0.02491043 -0.06172827 -0.12281439 0.05957274 -0.28446954 0.17217562 0.14563462 0.08131266 -0.02172118]]
基于context的开启方式
context模式是一种全局的设置模式。
代码如下:
import numpy as np
import mindspore as ms
from mindspore import nn, Tensor
ms.set_context(mode=ms.GRAPH_MODE) # 使用set_context进行运行静态图模式的配置
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
model = Network()
input = Tensor(np.ones([64, 1, 28, 28]).astype(np.float32))
output = model(input)
print(output)
分析:首先导入了 numpy 库并简称为 np ,导入了 mindspore 库并简称为 ms ,还从 mindspore 中导入了 nn 和 Tensor 。
然后使用 ms.set_context(mode=ms.GRAPH_MODE) 配置了 mindspore 的运行环境为静态图模式。
接着定义了一个名为 Network 的类,继承自 nn.Cell 。在类的初始化方法 __init__ 中进行了一些层的定义,包括展平层和一系列全连接层与激活函数层的组合。
之后创建了 Network 类的实例 model ,并创建了输入数据 input 。
最后将 input 传入 model 进行计算得到输出 output ,并将其打印出来。
总的来说,这段代码构建了一个神经网络模型,并在静态图模式下对输入数据进行处理和得到输出。
运行结果:
[[ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ]
... [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ] [ 0.11365249 -0.186111 -0.28579414 0.13091658 0.02833005 -0.17373694 0.28168008 0.04766882 0.0583384 0.0371065 ]]
静态图的语法约束
在 Graph 模式中,Python 代码并非交由 Python 解释器来执行,而是会先将其编译为静态计算图,后续再对静态计算图予以执行。正因如此,编译器难以对全部的 Python 语法提供支持。MindSpore 的静态图编译器精心维护了 Python 常用语法的子集部分,旨在为神经网络的构建以及训练提供有力支撑。
JitConfig配置选项
在图模式之下,能够通过运用 JitConfig 配置选项来在一定程度上对编译流程进行自定义。当下,JitConfig 所支持的配置参数具体如下:
jit_level:其作用是把控优化的等级。
exec_mode:用于掌控模型的执行方式。
jit_syntax_level:设定静态图语法的支持级别。
静态图高级编程技巧
使用静态图高级编程技巧可以有效地提高编译效率以及执行效率,并可以使程序运行的更加稳定。
运行截图: