神经网络模型由神经网络层和Tensor操作构成,mindspore.nn提供了常见的神经网络层的实现,其中Cell类作为所有网络基类,也是网络的基本单元。一个神经网络即为一个Cell,由不同的子Cell组成。由于这种嵌套结构,可以使用面向对向的编程思想对神经网络结构进行构建和管理。
1.网络实例
例如,用于Mnist数据集分类的神经网络模型可定义如下,其中Network类继承于nn.Cell类, 在在__init__方法中进行Cell实例化和状态管理, 在construct中实现Tensor操作。
!pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore == 2.2.14
import mindspore
from mindspore import nn, ops
import time
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())),'xxxx')
class Network(nn.Cell):
def __init__(self):
self.flatten = nn.Flatten()
self.dense_relu_sequential = nn.SequentialCell(
nn.Dense(28 * 28, 512, weight_init = "normal", bias_init = "zeros"),
nn.ReLU(),
nn.Dense(512, 512, weight_init = "normal", bias_init = "zeros"),
nn.ReLU(),
nn.Dense(512, 10, weight_init = "normal", bias_init = "zeros")
)
def construct(self, x):
x = self.flatten(x)
logits = self.dense_relu_sequential(x)
return logits
model = Network()
print(model)
2.construct与静态网络图简介
construct为神经网络计算图构建,相当于使用静态图来加速。
在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导入导出。
https://www.mindspore.cn/docs/zh-CN/r2.3/note/static_graph_syntax_support.html#%E6%A6%82%E8%BF%B0
3.网络分析
1)构造一个输入数据,直接调用模型,可以获得一个十维的Tensor输出,其包含每个类别的原始预测值。model.construct()方法不可直接调用
x = ops.ones((1,28,28), mindspore.float32)
logits = model(x)
logits
2)再通过一个nn.Softmax层实例来获得预测概率
pred_probab = nn.Softmax(axis = 1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class:{y_pred}")
4.模型层
本节中我们分解上节构造的神经网络模型中的每一层。
1)首先我们构造一个shape为(3, 28, 28)的随机数据(3个28x28的图像),依次通过每一个神经网络层来观察其效果。
input_image = ops.ones((3, 28, 28), mindspore.float32)
print(input_image.shape)
2)实例化nn.Flatten层,将28*28的2D张量转换为784大小的连续数组
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.shape)
3)nn.Dense为全连接层,使用权重和偏差对输入进行线性变换
layer1 = nn.Dense(in_channels = 28 * 28, out_channels = 20)
hidden1 = layer1(flag_image)
print(hidden1.shape)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
4)nn.ReLU给网络中加入非线性激活函数,帮助神经网络学习各种复杂的特征
print(f"Before ReLU:{hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU:{hidden1}")
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
5)nn.SequentialCell是一个有序的Cell容器,输入Tensor将有序通过其中的Cells
seq_modules = nn.SequentialCell(
flatten,
layer1,
nn.ReLU(),
nn.Dense(20, 10)
)
logits = seq_modules(input_image)
print(logits.shape)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
6)nn.Softmax将神经网络最后一个全连接层返回的logits值缩放为[0,1]中值,表示特征出现的概率。
softmax = nn.Softmax(axis = 1)
pred_probab = softmax(logits)
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
7)模型参数
内部神经网络层有权重参数和偏置参数(如nn.Dense),这些参数会在训练过程中优化,可通过model.parameters_and_names()获取参数名及对应参数详情
print(f"Model structure:{model}\n\n")
for name, param in model.parameters_and_names():
print(f"Layer:{name}\nSize:{param.shape}\nValues:{param[:2]}\n")
更多内置神经网络层详见mindspore.nn — MindSpore master 文档