评价指标
当训练任务结束,常常需要评价函数(Metrics)来评估模型的好坏。不同的训练任务往往需要不同的Metrics函数。例如,对于二分类问题,常用的评价指标有precision(准确率)、recall(召回率)等,而对于多分类任务,可使用宏平均(Macro)和微平均(Micro)来评估。
MindSpore提供了大部分常见任务的评价函数,如nn.Accuracy
、nn.Precision
、nn.MAE
和nn.MSE
等,由于MindSpore提供的评价函数无法满足所有任务的需求,很多情况下用户需要针对具体的任务自定义Metrics来评估训练的模型。
本章主要介绍如何自定义Metrics以及如何在nn.Model
中使用Metrics。
详情可参考评价指标。
自定义Metrics
自定义Metrics函数需要继承nn.Metric
父类,并重新实现父类中的clear
方法、update
方法和eval
方法。
clear
:初始化相关的内部参数。update
:接收网络预测输出和标签,计算误差,每次step后并更新内部评估结果。eval
:计算最终评估结果,在没次epoch结束后计算最终的评估结果。
平均绝对误差(MAE)算法如式(1)所示:
下面以简单的MAE算法为例,介绍clear
、update
和eval
三个函数及其使用方法。
[1]:
import numpy as np
import mindspore as ms
from mindspore import nn
class MyMAE(nn.Metric):
def __init__(self):
super(MyMAE, self).__init__()
self.clear()
def clear(self):
"""初始化变量_abs_error_sum和_samples_num"""
self._abs_error_sum = 0 # 保存误差和
self._samples_num = 0 # 累计数据量
def update(self, *inputs):
"""更新_abs_error_sum和_samples_num"""
y_pred = inputs[0].asnumpy()
y = inputs[1].asnumpy()
# 计算预测值与真实值的绝对误差
abs_error_sum = np.abs(y - y_pred)
self._abs_error_sum += abs_error_sum.sum()
# 样本的总数
self._samples_num += y.shape[0]
def eval(self):
"""计算最终评估结果"""
return self._abs_error_sum / self._samples_num
# 网络有两个输出
y_pred = ms.Tensor(np.array([[0.1, 0.2, 0.6, 0.9], [0.1, 0.2, 0.6, 0.9]]), ms.float32)
y = ms.Tensor(np.array([[0.1, 0.25, 0.7, 0.9], [0.1, 0.25, 0.7, 0.9]]), ms.float32)
error = MyMAE()
error.clear()
error.update(y_pred, y)
result = error.eval()
print(result)
0.1499999612569809
模型训练中使用Metrics
mindspore.Model是用于训练和评估的高层API,可以将自定义或MindSpore已有的Metrics作为参数传入,Model能够自动调用传入的Metrics进行评估。
在网络模型训练后,需要使用评价指标,来评估网络模型的训练效果,因此在演示具体代码之前首先简单拟定数据集,对数据集进行加载和定义一个简单的线性回归网络模型:
[2]:
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
使用内置评价指标
使用MindSpore内置的Metrics作为参数传入Model时,Metrics可以定义为一个字典类型,字典的key值为字符串类型,字典的value值为MindSpore内置的评价指标,如下示例使用nn.Accuracy
计算分类的准确率。
[3]:
import mindspore.nn as nn
from mindspore.nn import MAE
from mindspore import Model, LossMonitor
net = nn.Dense(1, 1)
loss_fn = nn.L1Loss()
optimizer = nn.Momentum(net.trainable_params(), learning_rate=0.005, momentum=0.9)
# 定义model,使用内置的Accuracy函数
model = Model(net, loss_fn, optimizer, metrics={"MAE": MAE()})
train_dataset = create_dataset(num_data=160)
eval_dataset = create_dataset(num_data=160)
train_dataset_size = train_dataset.get_dataset_size()
model.fit(10, train_dataset, eval_dataset, callbacks=LossMonitor(train_dataset_size))
epoch: 1 step: 10, loss is 6.0811052322387695
Eval result: epoch 1, metrics: {'MAE': 5.012505912780762}
epoch: 2 step: 10, loss is 2.7896716594696045
Eval result: epoch 2, metrics: {'MAE': 3.380072832107544}
epoch: 3 step: 10, loss is 3.0297815799713135
Eval result: epoch 3, metrics: {'MAE': 2.5002413272857664}
epoch: 4 step: 10, loss is 2.3680481910705566
Eval result: epoch 4, metrics: {'MAE': 2.4334578275680543}
epoch: 5 step: 10, loss is 1.8126990795135498
Eval result: epoch 5, metrics: {'MAE': 1.8317200541496277}
epoch: 6 step: 10, loss is 1.6006351709365845
Eval result: epoch 6, metrics: {'MAE': 1.521335732936859}
epoch: 7 step: 10, loss is 1.1064929962158203
Eval result: epoch 7, metrics: {'MAE': 1.2528185725212098}
epoch: 8 step: 10, loss is 0.9595810174942017
Eval result: epoch 8, metrics: {'MAE': 1.0719563841819764}
epoch: 9 step: 10, loss is 0.6517931222915649
Eval result: epoch 9, metrics: {'MAE': 0.9766222715377808}
epoch: 10 step: 10, loss is 0.9312882423400879
Eval result: epoch 10, metrics: {'MAE': 0.9238077104091644}
使用自定义评价指标
如下示例在Model
中传入上述自定义的评估指标MAE()
,将验证数据集传入model.fit()
接口边训练边验证。
验证结果为一个字典类型,验证结果的key值与metrics
的key值相同,验证结果的value值为预测值与实际值的平均绝对误差。
[4]:
train_dataset = create_dataset(num_data=160)
eval_dataset = create_dataset(num_data=160)
model = Model(net, loss_fn, optimizer, metrics={"MAE": MyMAE()})
# 定义model,将自定义metrics函数MAE传入Model中
model.fit(10, train_dataset, eval_dataset, callbacks=LossMonitor(train_dataset_size))
epoch: 1 step: 10, loss is 0.5679571628570557
Eval result: epoch 1, metrics: {'MAE': 0.7907268464565277}
epoch: 2 step: 10, loss is 0.8198273181915283
Eval result: epoch 2, metrics: {'MAE': 0.7729107916355134}
epoch: 3 step: 10, loss is 0.5721814036369324
Eval result: epoch 3, metrics: {'MAE': 0.7661101937294006}
epoch: 4 step: 10, loss is 0.6523740291595459
Eval result: epoch 4, metrics: {'MAE': 0.7704753875732422}
epoch: 5 step: 10, loss is 0.5641313791275024
Eval result: epoch 5, metrics: {'MAE': 0.7609358102083206}
epoch: 6 step: 10, loss is 0.774018406867981
Eval result: epoch 6, metrics: {'MAE': 0.7739883124828338}
epoch: 7 step: 10, loss is 0.7306548357009888
Eval result: epoch 7, metrics: {'MAE': 0.7757290184497834}
epoch: 8 step: 10, loss is 0.667199969291687
Eval result: epoch 8, metrics: {'MAE': 0.7627188444137574}
epoch: 9 step: 10, loss is 0.689708948135376
Eval result: epoch 9, metrics: {'MAE': 0.7673796474933624}
epoch: 10 step: 10, loss is 0.7661054134368896
Eval result: epoch 10, metrics: {'MAE': 0.7654164433479309}