大家好,我是刘明,明志科技创始人,华为昇思MindSpore布道师。
技术上主攻前端开发、鸿蒙开发和AI算法研究。
努力为大家带来持续的技术分享,如果你也喜欢我的文章,就点个关注吧
模型训练过程中,使用优化器更新网络参数,合适的优化器可以有效减少训练时间,提高模型性能。
最基本的优化器是随机梯度下降算法(SGD),很多优化器在SGD的基础上进行了改进,以实现目标函数能更快速更有效地收敛到全局最优点。MindSpore中的nn模块提供了常用的优化器,如nn.SGD、nn.Adam、nn.Momentum等。本章主要介绍如何配置MindSpore提供的优化器以及如何自定义优化器。
nn.optim
配置优化器
参数配置
在构建优化器实例时,需要通过优化器参数params配置模型网络中要训练和更新的权重。Parameter中包含了一个requires_grad的布尔型的类属性,用于表示模型中的网络参数是否需要进行更新。
网络中大部分参数的requires_grad默认值为True,少部分默认值为False,例如BatchNorm中的moving_mean和moving_variance。
MindSpore中的trainable_params方法会屏蔽掉Parameter中requires_grad为False的属性,在为优化器配置 params 入参时,可使用net.trainable_params()方法来指定需要优化和更新的网络参数。
import numpy as np
import mindspore
from mindspore import nn, ops
from mindspore import Tensor, Parameterclass Net(nn.Cell):def __init__(self):super().__init__()self.conv = nn.Conv2d(1, 6, 5, pad_mode="valid")self.param = Parameter(Tensor(np.array([1.0], np.float32)), 'param')def construct(self, x):x = self.conv(x)x = x * self.paramout = ops.matmul(x, x)return outnet = Net()# 配置优化器需要更新的参数
optim = nn.Adam(params=net.trainable_params())
print(net.trainable_params())
用户可以手动修改网络权重中 Parameter 的 requires_grad 属性的默认值,来决定哪些参数需要更新。
如下例所示,使用 net.get_parameters() 方法获取网络中所有参数,并手动修改巻积参数的 requires_grad 属性为False,训练过程中将只对非卷积参数进行更新。
conv_params = [param for param in net.get_parameters() if 'conv' in param.name]
for conv_param in conv_params:conv_param.requires_grad = False
print(net.trainable_params())
optim = nn.Adam(params=net.trainable_params())
学习率
学习率作为机器学习及深度学习中常见的超参,对目标函数能否收敛到局部最小值及何时收敛到最小值有重要影响。学习率过大容易导致目标函数波动较大,难以收敛到最优值,太小则会导致收敛过程耗时过长。除了设置固定学习率,MindSpore还支持设置动态学习率,这些方法在深度学习网络中能明显提升收敛效率。
固定学习率:
使用固定学习率时,优化器传入的learning_rate为浮点类型或标量Tensor。
以nn.Momentum为例,固定学习率为0.01,示例如下:
# 设置学习率为0.01
optim = nn.Momentum(params=net.trainable_params(), learning_rate=0.01, momentum=0.9)
动态学习率:
mindspore.nn提供了动态学习率的模块,分为Dynamic LR函数和LearningRateSchedule类。其中Dynamic LR函数会预先生成长度为total_step的学习率列表,将列表传入优化器中使用,训练过程中,第i步使用第i个学习率的值作为当前step的学习率,其中total_step的设置值不能小于训练的总步数;LearningRateSchedule类将实例传递给优化器,优化器根据当前step计算得到当前的学习率。
运行中修改优化器参数
运行中修改学习率
mindspore.experimental.optim.Optimizer 中学习率为 Parameter,除通过上述动态学习率模块 mindspore.experimental.optim.lr_scheduler 动态修改学习率,也支持使用 assign 赋值的方式修改学习率。
例如下述样例,在训练step中,设置如果损失值相比上一个step变化小于0.1,将优化器第1个参数组的学习率调整至0.01:
net = Net()
loss_fn = nn.MAELoss()
optimizer = optim.Adam(net.trainable_params(), lr=0.1)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)
last_step_loss = 0.1def forward_fn(data, label):logits = net(data)loss = loss_fn(logits, label)return lossgrad_fn = mindspore.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)def train_step(data, label):(loss, _), grads = grad_fn(data, label)optimizer(grads)if ops.abs(loss - last_step_loss) < 0.1:ops.assign(optimizer.param_groups[1]["lr"], Tensor(0.01))return loss
运行中修改除lr以外的优化器参数
下述样例,在训练step中,设置如果损失值相比上一个step变化小于0.1,将优化器第1个参数组的 weight_decay 调整至0.02:
net = Net()
loss_fn = nn.MAELoss()
optimizer = optim.Adam(net.trainable_params(), lr=0.1)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)
last_step_loss = 0.1def forward_fn(data, label):logits = net(data)loss = loss_fn(logits, label)return lossgrad_fn = mindspore.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)def train_step(data, label):(loss, _), grads = grad_fn(data, label)optimizer(grads)if ops.abs(loss - last_step_loss) < 0.1:optimizer.param_groups[1]["weight_decay"] = 0.02return loss
自定义优化器
与上述自定义优化器方式相同,自定义优化器时也可以继承优化器基类experimental.optim.Optimizer,并重写__init__方法和construct方法以自行设定参数更新策略。