模型训练

在线运行下载Notebook下载样例代码查看源文件

通过上面章节的学习,我们已经学会如何创建模型和构建数据集,现在开始学习如何设置超参和优化模型参数。

超参(Hyper-parametric)

超参是可以调整的参数,可以控制模型训练优化的过程,不同的超参数值可能会影响模型训练和收敛速度。目前深度学习模型多采用批量随机梯度下降算法进行优化,随机梯度下降算法的原理如下:

\[w_{t+1}=w_{t}-\eta \frac{1}{n} \sum_{x \in \mathcal{B}} \nabla l\left(x, w_{t}\right)\]

式中,\(n\)是批量大小(batch size),\(η\)是学习率(learning rate);另外,\(w_{t}\)为训练轮次t中权重参数,\(\nabla l\)为损失函数的导数。可知道除了梯度本身,这两个因子直接决定了模型的权重更新,从优化本身来看它们是影响模型性能收敛最重要的参数。一般会定义以下超参用于训练:

训练轮次(epoch):训练时遍历数据集的次数。

批次大小(batch size):数据集进行分批读取训练,设定每个批次数据的大小。batch size过小,花费时间多,同时梯度震荡严重,不利于收敛;batch size过大,不同batch的梯度方向没有任何变化,容易陷入局部极小值,因此需要选择合适的batch size,可以有效提高模型精度、全局收敛。

学习率(learning rate):如果学习率偏小,会导致收敛的速度变慢,如果学习率偏大则可能会导致训练不收敛等不可预测的结果。梯度下降法是一个广泛被用来最小化模型误差的参数优化算法。梯度下降法通过多次迭代,并在每一步中最小化损失函数来估计模型的参数。学习率就是在迭代过程中,会控制模型的学习进度。

learning-rate

[1]:
epochs = 10
batch_size = 32
momentum = 0.9
learning_rate = 1e-2

损失函数

损失函数用来评价模型的预测值目标值之间的误差,在这里,使用绝对误差损失函数L1Loss

\[\text { L1 Loss Function }=\sum_{i=1}^{n}\left|y_{true}-y_{predicted}\right|\]

mindspore.nn.loss也提供了许多其他常用的损失函数,如SoftmaxCrossEntropyWithLogitsMSELossSmoothL1Loss等。

我们给定预测值和目标值,通过损失函数计算预测值和目标值之间的误差(损失值),使用方法如下所示:

[2]:
import numpy as np
import mindspore.nn as nn
from mindspore import Tensor

loss = nn.L1Loss()
output_data = Tensor(np.array([[1, 2, 3], [2, 3, 4]]).astype(np.float32))
target_data = Tensor(np.array([[0, 2, 5], [3, 1, 1]]).astype(np.float32))

print(loss(output_data, target_data))
1.5

优化器函数

优化器函数用于计算和更新梯度,模型优化算法的选择直接关系到最终模型的性能。有时候最终模型效果不好,未必是特征或者模型设计的问题,很有可能是优化算法的问题。

MindSpore所有优化逻辑都封装在Optimizer对象中,在这里,我们使用Momentum优化器。mindspore.nn也提供了许多其他常用的优化器函数,如AdamSGDRMSProp等。

我们需要构建一个Optimizer对象,这个对象能够基于计算得到的梯度对参数进行更新。为了构建一个Optimizer,需要给它一个包含可优化的参数,如网络中所有可以训练的parameter,即设置优化器的入参为net.trainable_params()

然后,设置Optimizer的参数选项,比如学习率、权重衰减等。代码样例如下:

[3]:
from mindspore import nn
from mindvision.classification.models import lenet

net = lenet(num_classes=10, pretrained=False)
optim = nn.Momentum(net.trainable_params(), learning_rate, momentum)

模型训练

模型训练一般分为四个步骤:

  1. 构建数据集。

  2. 定义神经网络。

  3. 定义超参、损失函数及优化器。

  4. 输入训练轮次和数据集进行训练。

模型训练示例代码如下:

[4]:
import mindspore.nn as nn
from mindspore.train import Model

from mindvision.classification.dataset import Mnist
from mindvision.classification.models import lenet
from mindvision.engine.callback import LossMonitor

# 1. 构建数据集
download_train = Mnist(path="./mnist", split="train", batch_size=batch_size, repeat_num=1, shuffle=True, resize=32, download=True)
dataset_train = download_train.run()

# 2. 定义神经网络
network = lenet(num_classes=10, pretrained=False)
# 3.1 定义损失函数
net_loss = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction='mean')
# 3.2 定义优化器函数
net_opt = nn.Momentum(network.trainable_params(), learning_rate=learning_rate, momentum=momentum)
# 3.3 初始化模型参数
model = Model(network, loss_fn=net_loss, optimizer=net_opt, metrics={'acc'})

# 4. 对神经网络执行训练
model.train(epochs, dataset_train, callbacks=[LossMonitor(learning_rate, 1875)])
Epoch:[  0/ 10], step:[ 1875/ 1875], loss:[0.189/1.176], time:2.254 ms, lr:0.01000
Epoch time: 4286.163 ms, per step time: 2.286 ms, avg loss: 1.176
Epoch:[  1/ 10], step:[ 1875/ 1875], loss:[0.085/0.080], time:1.895 ms, lr:0.01000
Epoch time: 4064.532 ms, per step time: 2.168 ms, avg loss: 0.080
Epoch:[  2/ 10], step:[ 1875/ 1875], loss:[0.021/0.054], time:1.901 ms, lr:0.01000
Epoch time: 4194.333 ms, per step time: 2.237 ms, avg loss: 0.054
Epoch:[  3/ 10], step:[ 1875/ 1875], loss:[0.284/0.041], time:2.130 ms, lr:0.01000
Epoch time: 4252.222 ms, per step time: 2.268 ms, avg loss: 0.041
Epoch:[  4/ 10], step:[ 1875/ 1875], loss:[0.003/0.032], time:2.176 ms, lr:0.01000
Epoch time: 4216.039 ms, per step time: 2.249 ms, avg loss: 0.032
Epoch:[  5/ 10], step:[ 1875/ 1875], loss:[0.003/0.027], time:2.205 ms, lr:0.01000
Epoch time: 4400.771 ms, per step time: 2.347 ms, avg loss: 0.027
Epoch:[  6/ 10], step:[ 1875/ 1875], loss:[0.000/0.024], time:1.973 ms, lr:0.01000
Epoch time: 4554.252 ms, per step time: 2.429 ms, avg loss: 0.024
Epoch:[  7/ 10], step:[ 1875/ 1875], loss:[0.008/0.022], time:2.048 ms, lr:0.01000
Epoch time: 4361.135 ms, per step time: 2.326 ms, avg loss: 0.022
Epoch:[  8/ 10], step:[ 1875/ 1875], loss:[0.000/0.018], time:2.130 ms, lr:0.01000
Epoch time: 4547.597 ms, per step time: 2.425 ms, avg loss: 0.018
Epoch:[  9/ 10], step:[ 1875/ 1875], loss:[0.008/0.017], time:2.135 ms, lr:0.01000
Epoch time: 4601.861 ms, per step time: 2.454 ms, avg loss: 0.017

训练过程中会打印loss值,loss值会波动,但总体来说loss值会逐步减小,精度逐步提高。每个人运行的loss值有一定随机性,不一定完全相同。