常用网络组件

查看源文件    查看notebook    在线运行

概述

MindSpore封装了一些常用的网络组件,用于网络的训练、推理、求梯度和数据处理等操作。

这些网络组件可以直接被用户使用,同样也会在model.trainmodel.eval等更高级的封装接口内部进行使用。

本节内容将会介绍三个网络组件,分别是GradOperationWithLossCellTrainOneStepCell,将会从功能、用户使用和内部使用三个方面来进行介绍。

GradOperation

GradOperation组件用于生成输入函数的梯度,利用get_allget_by_listsens_param参数控制梯度的计算方式,细节内容详见API文档

GradOperation的使用实例如下:

import numpy as np
import mindspore.nn as nn
from mindspore import Tensor, Parameter
from mindspore import dtype as mstype
import mindspore.ops as ops


class Net(nn.Cell):
    def __init__(self):
        super(Net, self).__init__()
        self.matmul = ops.MatMul()
        self.z = Parameter(Tensor(np.array([1.0], np.float32)))
    def construct(self, x, y):
        x = x * self.z
        out = self.matmul(x, y)
        return out

class GradNetWrtX(nn.Cell):
    def __init__(self, net):
        super(GradNetWrtX, self).__init__()
        self.net = net
        self.grad_op = ops.GradOperation()
    def construct(self, x, y):
        gradient_function = self.grad_op(self.net)
        return gradient_function(x, y)

x = Tensor([[0.5, 0.6, 0.4], [1.2, 1.3, 1.1]], dtype=mstype.float32)
y = Tensor([[0.01, 0.3, 1.1], [0.1, 0.2, 1.3], [2.1, 1.2, 3.3]], dtype=mstype.float32)
GradNetWrtX(Net())(x, y)

上面的例子是计算Net相对与x的梯度值,首先需要定义网络Net作为GradOperation的输入,实例创建了包含梯度运算的GradNetWrtX。调用GradNetWrtX是将网络传入GradOperation生成梯度函数,将输入数据传入梯度函数中返回最终结果。

输出如下:

[[1.4100001 1.5999999 6.6      ]
 [1.4100001 1.5999999 6.6      ]]

MindSpore涉及梯度计算的其他组件,例如WithGradCellTrainOneStepCell等,都用到了GradOperation, 感兴趣的读者可以查看这些接口的内部实现。

WithLossCell

WithLossCell本质上是一个包含损失函数的Cell,构造WithLossCell需要事先定义好网络和损失函数。

下面通过一个实例来介绍其具体的使用, 首先需要构造一个网络,内容如下:

import numpy as np
import mindspore.context as context
import mindspore.nn as nn
from mindspore import Tensor
from mindspore.nn import TrainOneStepCell, WithLossCell
from mindspore.nn.optim import Momentum
import mindspore.ops as ops

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


class LeNet(nn.Cell):
    def __init__(self):
        super(LeNet, self).__init__()
        self.relu = ops.ReLU()
        self.batch_size = 32

        self.conv1 = nn.Conv2d(1, 6, kernel_size=5, stride=1, padding=0, has_bias=False, pad_mode='valid')
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1, padding=0, has_bias=False, pad_mode='valid')
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.reshape = ops.Reshape()
        self.fc1 = nn.Dense(400, 120)
        self.fc2 = nn.Dense(120, 84)
        self.fc3 = nn.Dense(84, 10)

    def construct(self, input_x):
        output = self.conv1(input_x)
        output = self.relu(output)
        output = self.pool(output)
        output = self.conv2(output)
        output = self.relu(output)
        output = self.pool(output)
        output = self.reshape(output, (self.batch_size, -1))
        output = self.fc1(output)
        output = self.relu(output)
        output = self.fc2(output)
        output = self.relu(output)
        output = self.fc3(output)
        return output

下面是WithLossCell的使用实例,分别定义好网络和损失函数,然后创建一个WithLossCell,传入输入数据和标签数据,WithLossCell内部根据网络和损失函数返回计算结果。

data = Tensor(np.ones([32, 1, 32, 32]).astype(np.float32) * 0.01)
label = Tensor(np.ones([32]).astype(np.int32))
net = LeNet()
criterion = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
net_with_criterion = WithLossCell(net, criterion)
loss = net_with_criterion(data, label)
print("+++++++++Loss+++++++++++++")
print(loss)

输出如下:

+++++++++Loss+++++++++++++
2.302585

TrainOneStepCell

TrainOneStepCell功能是执行网络的单步训练,返回每次训练结果后的loss结果。

下面构造一个使用TrainOneStepCell接口进行网络训练的实例,其中LeNet和包名的导入代码和上个用例共用。

data = Tensor(np.ones([32, 1, 32, 32]).astype(np.float32) * 0.01)
label = Tensor(np.ones([32]).astype(np.int32))
net = LeNet()
learning_rate = 0.01
momentum = 0.9

optimizer = Momentum(filter(lambda x: x.requires_grad, net.get_parameters()), learning_rate, momentum)
criterion = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
net_with_criterion = WithLossCell(net, criterion)
train_network = TrainOneStepCell(net_with_criterion, optimizer)  # optimizer
for i in range(5):
    train_network.set_train()
    res = train_network(data, label)
    print(f"+++++++++result:{i}++++++++++++")
    print(res)

用例中构造了优化器和一个WithLossCell的实例,然后传入TrainOneStepCell中初始化一个训练网络,用例循环五次,相当于网络训练了五次,并输出每次的loss结果,由结果可以看出每次训练后loss值在逐渐减小。

输出如下:

+++++++++result:0++++++++++++
2.302585
+++++++++result:1++++++++++++
2.2935824
+++++++++result:2++++++++++++
2.2765071
+++++++++result:3++++++++++++
2.2522228
+++++++++result:4++++++++++++
2.2215357

后续内容会介绍MindSpore使用更加高级封装的接口,即Model类中的train方法训练模型,在其内部实现中会用到 TrainOneStepCellWithLossCell 等许多网络组件,感兴趣的读者可以查看其内部实现。