自定义损失函数
损失函数用于衡量预测值与真实值差异的程度。深度学习中,模型训练就是通过不停地迭代来缩小损失函数值的过程。因此在模型训练过程中损失函数的选择非常重要,定义一个好的损失函数,可以有效提高模型的性能。
MindSpore提供了许多通用损失函数供用户选择,但这些通用损失函数并不适用于所有场景,有时需要用户自定义所需的损失函数。因此,本文介绍损失函数的自定义构建方法。
自定义损失函数示例
Cell
是MindSpore的基本网络单元,可以用于构建网络,损失函数也可以通过Cell
来定义。使用Cell
定义损失函数的方法与定义一个普通的网络相同,差别在于,其执行逻辑在于计算前向网络输出与真实值之间的误差。
下面使用Cell
定义损失函数L1Loss
,用于计算两个输入数据的绝对值误差:
[1]:
import mindspore.nn as nn
import mindspore.ops as ops
class L1Loss(nn.Cell):
def __init__(self):
super(L1Loss, self).__init__()
self.abs = ops.Abs()
self.reduce_mean = ops.ReduceMean()
def construct(self, predict, target):
x = self.abs(predict - target)
return self.reduce_mean(x)
首先,__init__
方法实例化所需的算子,并在construct
中调用这些算子。这样一个用于计算L1Loss
的损失函数就定义好了。
代码中使用nn.Cell
作为L1Loss
的基类,最后在construct
中调用基类提供的predict
, target
方法。reduction
的合法参数有mean
、sum
和none
,分别表示求均值、求和与输出原值。
在定义损失函数时还可以继承损失函数的基类LossBase
。LossBase
提供了get_loss
方法,用于对损失值求和或求均值,输出一个标量。L1Loss
使用LossBase
作为基类的定义如下:
[2]:
class L1Loss(nn.LossBase):
def __init__(self, reduction="mean"):
super(L1Loss, self).__init__(reduction)
self.abs = ops.Abs()
def construct(self, base, target):
x = self.abs(base - target)
return self.get_loss(x)
首先使用LossBase
作为L1Loss
的基类,然后给__init__
增加一个参数reduction
,并通过super
传给基类,最后在construct
中调用基类提供的get_loss
方法。reduction
的合法参数有mean
、sum
和none
,分别表示求均值、求和与输出原值。
损失函数与模型训练
接下来使用通过基类LossBase
定义的L1Loss
进行模型训练。以简单的线性拟场景作为样例。
线性拟合详细介绍可参考教程实现简单线性函数拟合。
定义数据集与网络
定义训练数据集生成函数,并增强为MindSpore可训练的数据类型。
get_data
:数据生成函数。create_dataset
:将numpy数据转换为MindSpore可训练的函数,并构造数据集的batch增强方法。
[3]:
import numpy as np
from mindspore import dataset as ds
# 生成随机数
def get_data(num, w=2.0, b=3.0):
for _ in range(num):
x = np.random.uniform(-10.0, 10.0)
noise = np.random.normal(0, 1)
y = x * w + b + noise
yield np.array([x]).astype(np.float32), np.array([y]).astype(np.float32)
def create_dataset(num_data, batch_size=16):
dataset = ds.GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
dataset = dataset.batch(batch_size)
return dataset
定义网络,nn.Dense
将数据集定义为所有的函数。
[4]:
from mindspore.common.initializer import Normal
class LinearNet(nn.Cell):
def __init__(self):
super(LinearNet, self).__init__()
self.fc = nn.Dense(1, 1, Normal(0.02), Normal(0.02))
def construct(self, x):
return self.fc(x)
使用Model进行模型训练
Model
是MindSpore提供的用于模型训练、评估和推理的高阶API。创建数据集并定义一个Model
就可以使用train
接口进行模型训练。接下来我们使用Model
来训练LinearNet
,选择MindSpore提供的Momemtum
作为优化器,并采用之前定义好的L1Loss
作为此次训练的损失函数。
[5]:
net = LinearNet()
loss = L1Loss()
opt = nn.Momentum(net.trainable_params(), learning_rate=0.005, momentum=0.9)
定义Model
时需要指定前向网络、损失函数和优化器,Model
内部会将它们关联起来,组成一张训练网。
[6]:
from mindspore import Model
model = Model(net, loss, opt)
创建数据集,并调用train
接口进行模型训练。
参数解释:
epoch
:训练数据集的迭代次数。train_dataset
:训练数据集。callbacks
:model.train
的回调函数参数,可监控训练过程中参数的变化情况。LossMonitor
:损失函数值监视器,用于打印训练过程中的模型损失值。dataset_sink_mode
(bool):数据下沉模式,可加快训练。Ascend和GPU平台支持开启该功能(True)。
[7]:
from mindspore.train.callback import LossMonitor
ds_train = create_dataset(num_data=160)
model.train(epoch=1, train_dataset=ds_train, callbacks=[LossMonitor()], dataset_sink_mode=False)
epoch: 1 step: 1, loss is 7.9989004
epoch: 1 step: 2, loss is 10.780429
epoch: 1 step: 3, loss is 12.113883
epoch: 1 step: 4, loss is 8.991383
epoch: 1 step: 5, loss is 9.228854
epoch: 1 step: 6, loss is 7.8051577
epoch: 1 step: 7, loss is 9.328038
epoch: 1 step: 8, loss is 7.665909
epoch: 1 step: 9, loss is 4.955902
epoch: 1 step: 10, loss is 7.7147307