常用网络组件
概述
MindSpore封装了一些常用的网络组件,用于网络的训练、推理、求梯度和数据处理等操作。
这些网络组件可以直接被用户使用,同样也会在model.train
和model.eval
等更高级的封装接口内部进行使用。
本节内容将会介绍三个网络组件,分别是GradOperation
、WithLossCell
和TrainOneStepCell
,将会从功能、用户使用和内部使用三个方面来进行介绍。
GradOperation
GradOperation组件用于生成输入函数的梯度,利用get_all
、get_by_list
和sens_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涉及梯度计算的其他组件,例如WithGradCell
和TrainOneStepCell
等,都用到了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
方法训练模型,在其内部实现中会用到
TrainOneStepCell
和WithLossCell
等许多网络组件,感兴趣的读者可以查看其内部实现。