MindSpore入门——模型创建和训练
模型的创建和训练
模型创建
内置模块mindspore.nn
一般来说,神经网络模型由多个数据操作层组成,mindspore.nn提供了各种网络基础模块。在这里封装好了各种方法,卷积层通过Conv2d传参创建,采样层中的平均池化AvgPool2d和最大池化MaxPool2d都有对应的方法,激活函数提供了ReLU、Sigmoid 、Tanh 、LeakyReLU 、PReLU等方法,优化器有SGD、Momentum、Adagrad、RMSProp、Adam等方法,除此之外还有Flatten、Dense、SoftmaxCrossEntropyWithLogits等其他特别方便的方法供我们调用。
MindSpore的Cell类是构建所有网络的基类,也是网络的基本单元。构建神经网络时,需要继承Cell类,并重写__init__方法和construct方法。
LeNet-5网络模型的创建示例
import mindspore.nn as nn
class LeNet5(nn.Cell):
"""
LeNet-5网络结构
"""
def __init__(self, num_class=10, num_channel=1):
super(LeNet5, self).__init__()
# 卷积层,输入的通道数为num_channel,输出的通道数为6,卷积核大小为5*5
self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid')
# 卷积层,输入的通道数为6,输出的通道数为16,卷积核大小为5*5
self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid')
# 全连接层,输入个数为16*5*5,输出个数为120
self.fc1 = nn.Dense(16 * 5 * 5, 120)
# 全连接层,输入个数为120,输出个数为84
self.fc2 = nn.Dense(120, 84)
# 全连接层,输入个数为84,分类的个数为num_class
self.fc3 = nn.Dense(84, num_class)
# ReLU激活函数
self.relu = nn.ReLU()
# 池化层
self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
# 多维数组展平为一维数组
self.flatten = nn.Flatten()
def construct(self, x):
# 使用定义好的运算构建前向网络
x = self.conv1(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.conv2(x)
x = self.relu(x)
x = self.max_pool2d(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
x = self.relu(x)
x = self.fc3(x)
return x
在MindSpore里面是怎样创建网络模型的?
构建神经网络就像搭积木一样,在init中定义好了我们的积木,那么construct就是搭积木的过程。
首先编译使用到的算子,设定好当前一个卷积的kernels的大小,通道数和pad_mode,注意这个参数有一般有valid和same选择。定义完算子就到了construct模块,每一层网络其实就是一行代码,就像是搭积木,一层一层,一行一行的堆叠起来,比如LeNet-5网络模型,有卷积层、池化层、全连接层,按照一定的顺序搭建好,最后返回网络模型的结果,网络模型就创建好了。
pad_mode参数的选择?
因为卷积的特殊计算方式,在卷积核进行滤波操作的时候,图像最边缘的地方因为卷积核没办法去覆盖,所以最终计算的时候就会去掉边缘的值。比如我们输入图像为32 * 32,那么输出图像的大小希望是28*28,那么就需要选择valid模式;如果我们需要输入图像的大小和输出图像的大小相同,那么就选择same模式,因为这个模式会在卷积之前自动对边缘值进行补充,所以卷积的输入和输出大小是一样的。
模型的参数怎样查看?
网络内部的卷积层和全连接层等实例化后,即具有权重参数和偏置参数,这些参数会在训练过程中不断进行优化,在训练过程中可通过 get_parameters() 来查看网络各层的名字、形状、数据类型和是否反向计算等信息。
from mindvision.classification.models import lenet
# num_classes表示分类的数量,pretrained表示是否使用与训练模型进行训练
model = lenet(num_classes=10, pretrained=False)
for m in model.get_parameters():
print(f"layer:{m.name}, shape:{m.shape}, dtype:{m.dtype}, requeires_grad:{m.requires_grad}")
为什么要停止梯度计算?
在神经网络构建中,有一个神经或者卷积进行了梯度计算,另一个分支想要控制它不要进行梯度计算,或者在网络模型中插入其他图像处理操作,不需要对图像处理操作的算子进行求导。为了更加灵活的控制整个系统的梯度什么时候进行求导,什么时候停止求导,Ops.stop_gradient停止计算梯度。
模型训练
模型训练一般分为四个步骤:
- 构建数据集。
- 定义神经网络。
- 定义超参、损失函数及优化器。
- 输入训练轮次和数据集进行训练。
超参(Hyper-parametric):超参是可以调整的参数,可以控制模型训练优化的过程,不同的超参数值可能会影响模型训练效果和收敛速度。一般超参有训练轮次(epoch)、批次大小(batch_size)、学习率(learning_rate)等。可以借助MindInsight工具,在训练时对参数进行可视化的监控,便于调试和调优。
损失函数:损失函数是用来评价模型的预测值和目标值之间的误差。mindspore.nn.loss也提供了许多其他常用的损失函数,如SoftmaxCrossEntropyWithLogits、MSELoss、SmoothL1Loss等。
优化器函数:有时候我们的网络模型训练不收敛,精度不达标,不一定是我们的网络模型构建出问题了,还有可能是优化器没有选择好,或者超参没有设置好。mindspore.nn提供了许多常用的优化器函数,这些在前文已经提到过了,就不过多赘述。
训练过程中会打印loss值,loss值会波动,但总体来说loss值会逐步减小,精度逐步提高。每个人运行的loss值有一定随机性,不一定完全相同。
训练:
模型训练的逻辑其实很简单,在模型训练之前,设置好网络模型的超参,定义好损失函数、优化器,然后用模型调用train方法把相关对象传入,就正式开始训练了。通过LossMonitor函数,可以在训练过程中打印相关的信息,包括epoch、step、loss值、每个step的时间time。
在训练过程中,一般打印的loss值会波动,但总体来说loss值会逐步减小,精度逐步提高。每次运行的loss值有一定随机性,对于成功的训练,通过loss的平均值可以看出是逐渐变小的,也就是精度逐步提高。
昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链
更多推荐

所有评论(0)